https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/231046

>From 62cb9e60967d38451d3651342afca5970e609a96 Mon Sep 17 00:00:00 2001
From: Morris Hafner <[email protected]>
Date: Sun, 11 Oct 2026 22:49:43 +0000
Subject: [PATCH 1/2] [CIR] Support statements after co_return

Emit code for statements after a co_return in a new block, which may be 
reachable through a label. Unlike classic codegen, this patch still keeps 
unreachable code alive through flattening to stay closer to the source code, 
though this could still be changed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp     |  24 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  18 +-
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp          |   4 +
 .../CodeGenCoroutines/coro-fallthrough.cpp    | 499 +++++++++++++++++-
 4 files changed, 529 insertions(+), 16 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index ad34df762fe19..f432788242043 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -623,11 +623,17 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt 
&s) {
             res = mlir::failure();
         });
 
-    if (coro && !coro.getBody().empty() &&
-        !coro.getBody().back().mightHaveTerminator()) {
-      mlir::OpBuilder::InsertionGuard guard(builder);
-      builder.setInsertionPointAfter(&coro.getBody().back().back());
-      cir::YieldOp::create(builder, openCurlyLoc);
+    if (coro && !coro.getBody().empty()) {
+      mlir::Block &lastBlock = coro.getBody().back();
+      mlir::Block *prevBlock = lastBlock.getPrevNode();
+      if (lastBlock.empty() && lastBlock.hasNoPredecessors() && prevBlock &&
+          !prevBlock->empty() && isa<cir::CoReturnOp>(prevBlock->back())) {
+        lastBlock.erase();
+      } else if (!lastBlock.mightHaveTerminator()) {
+        mlir::OpBuilder::InsertionGuard guard(builder);
+        builder.setInsertionPointToEnd(&lastBlock);
+        cir::YieldOp::create(builder, openCurlyLoc);
+      }
     }
   }
 
@@ -878,7 +884,6 @@ RValue CIRGenFunction::emitCoyieldExpr(const CoyieldExpr &e,
 
 mlir::LogicalResult CIRGenFunction::emitCoreturnStmt(CoreturnStmt const &s) {
   ++curCoro.data->coreturnCount;
-  curLexScope->setCoreturn();
 
   const Expr *rv = s.getOperand();
   if (rv && rv->getType()->isVoidType() && !isa<InitListExpr>(rv)) {
@@ -890,11 +895,12 @@ mlir::LogicalResult 
CIRGenFunction::emitCoreturnStmt(CoreturnStmt const &s) {
 
   if (emitStmt(s.getPromiseCall(), /*useCurrentScope=*/true).failed())
     return mlir::failure();
-  // Create a new return block (if not existent) and add a branch to
-  // it. The actual return instruction is only inserted during current
-  // scope cleanup handling.
   mlir::Location loc = getLoc(s.getSourceRange());
   cir::CoReturnOp::create(builder, loc);
+  curLexScope->markCoreturnEmitted();
 
+  // Statements after a co_return may stil be reachable through a label.
+  // Continue codegen.
+  builder.createBlock(builder.getBlock()->getParent());
   return mlir::success();
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 6ca9f27748b28..9ec11f66e670e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1563,9 +1563,9 @@ class CIRGenFunction : public CIRGenTypeCache {
 
     // On a coroutine body, the OnFallthrough sub stmt holds the handler
     // (CoreturnStmt) for control flow falling off the body. Keep track
-    // of emitted co_return in this scope and allow OnFallthrough to be
-    // skipeed.
-    bool hasCoreturnStmt = false;
+    // of a co_return emitted in this scope and not followed by a label, and
+    // allow OnFallthrough to be skipped.
+    bool hasCoreturnSinceLastLabel = false;
 
     // Only Regular is used at the moment. Support for other kinds will be
     // added as the relevant statements/expressions are upstreamed.
@@ -1617,8 +1617,16 @@ class CIRGenFunction : public CIRGenTypeCache {
     // ---
     // Coroutine tracking
     // ---
-    bool hasCoreturn() const { return hasCoreturnStmt; }
-    void setCoreturn() { hasCoreturnStmt = true; }
+    bool hasCoreturn() const { return hasCoreturnSinceLastLabel; }
+    // Record an emitted co_return for fallthrough tracking.
+    // A later label clears this state.
+    void markCoreturnEmitted() { hasCoreturnSinceLastLabel = true; }
+    // A goto can reach a label after a co_return, and the code after it, so
+    // the end of this scope and of the enclosing ones may be reachable again.
+    void clearCoreturnInEnclosingScopes() {
+      for (LexicalScope *s = this; s; s = s->parentScope)
+        s->hasCoreturnSinceLastLabel = false;
+    }
 
     // ---
     // Kind
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index d06d32f5b33c0..41ae23fa19e36 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -792,6 +792,10 @@ mlir::LogicalResult CIRGenFunction::emitLabel(const 
clang::LabelDecl &d) {
 
   builder.setInsertionPointToEnd(labelBlock);
   cir::LabelOp::create(builder, getLoc(d.getSourceRange()), d.getName());
+  // In a coroutine, the label makes the end of the body reachable again even
+  // after a co_return, so the implicit `co_return;` must not be left out.
+  if (curLexScope)
+    curLexScope->clearCoreturnInEnclosingScopes();
   //  FIXME: emit debug info for labels, incrementProfileCounter
   assert(!cir::MissingFeatures::incrementProfileCounter());
   assert(!cir::MissingFeatures::generateDebugInfo());
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-fallthrough.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-fallthrough.cpp
index ff3e966ac3324..7ed7d47cb45b5 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-fallthrough.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-fallthrough.cpp
@@ -2,10 +2,12 @@
 // RUN: FileCheck --input-file=%t.cir %s -check-prefixes=CIR,CIR-NOEH
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu 
-fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t-eh.cir
 // RUN: FileCheck --input-file=%t-eh.cir %s -check-prefixes=CIR,CIR-EH
+// RUN: cir-opt -cir-flatten-cfg %t.cir -o %t-flat.cir
+// RUN: FileCheck --input-file=%t-flat.cir %s -check-prefix=CIR-FLAT
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm 
-disable-llvm-passes %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=OGCG,OGCG-NOEH
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=OGCG,OGCG-NOEH 
--implicit-check-not=_Z4deadv
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu 
-fcxx-exceptions -fexceptions -emit-llvm -disable-llvm-passes %s -o %t-eh.ll
-// RUN: FileCheck --input-file=%t-eh.ll %s -check-prefixes=OGCG,OGCG-EH
+// RUN: FileCheck --input-file=%t-eh.ll %s -check-prefixes=OGCG,OGCG-EH 
--implicit-check-not=_Z4deadv
 
 // When the body of a coroutine falls off its end, the implicit `co_return;`
 // runs after the body: the body's local variables are destroyed first, then
@@ -32,7 +34,19 @@ struct Task {
   };
 };
 
+struct IntTask {
+  struct promise_type {
+    IntTask get_return_object() noexcept;
+    std::suspend_always initial_suspend() noexcept;
+    std::suspend_always final_suspend() noexcept;
+    void return_value(int);
+    void unhandled_exception();
+  };
+};
+
 S make();
+void dead();
+void live();
 
 Task falls_off_end() {
   co_await std::suspend_always{};
@@ -55,6 +69,8 @@ Task falls_off_end() {
 // CIR-NEXT:        }
 // CIR-NEXT:        cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
 // CIR-NEXT:        cir.co_return
+// CIR-EH-NEXT:   ^bb1:
+// CIR-EH-NEXT:     cir.yield
 // CIR-EH-NEXT:   } catch all
 // CIR:         }, finalSuspend : {
 
@@ -94,6 +110,8 @@ Task falls_off_end_with_extended_temporary() {
 // CIR-NEXT:        }
 // CIR-NEXT:        cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
 // CIR-NEXT:        cir.co_return
+// CIR-EH-NEXT:   ^bb1:
+// CIR-EH-NEXT:     cir.yield
 // CIR-EH-NEXT:   } catch all
 // CIR:         }, finalSuspend : {
 
@@ -138,6 +156,8 @@ Task co_return_in_if(bool b) {
 // CIR-NEXT:        }
 // CIR-NEXT:        cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
 // CIR-NEXT:        cir.co_return
+// CIR-EH-NEXT:   ^bb1:
+// CIR-EH-NEXT:     cir.yield
 // CIR-EH-NEXT:   } catch all
 // CIR:         }, finalSuspend : {
 
@@ -174,6 +194,8 @@ Task co_return_at_end() {
 // CIR:             cir.cleanup.scope {
 // CIR-NEXT:          cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
 // CIR-NEXT:          cir.co_return
+// CIR-NEXT:        ^bb1:
+// CIR-NEXT:          cir.yield
 // CIR-NOEH-NEXT:   } cleanup normal {
 // CIR-EH-NEXT:     } cleanup all {
 // CIR-NEXT:          cir.call @_ZN1SD1Ev(%[[S]])
@@ -191,3 +213,476 @@ Task co_return_at_end() {
 // OGCG-EH-NEXT:   call void @_ZN1SD1Ev(
 // OGCG-NOT:     return_void
 // OGCG:         br label %coro.final
+
+// Statements after a co_return with no label are kept despite them being
+// unreachable. Classic codegen drops them.
+
+IntTask co_return_value(int v) {
+  co_return v + 1;
+  dead();
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z15co_return_valuei(
+// CIR:         }, body : {
+// CIR-EH:        cir.try {
+// CIR:             cir.call @_ZN7IntTask12promise_type12return_valueEi(
+// CIR-NEXT:        cir.co_return
+// CIR-NEXT:      ^bb1:  // no predecessors
+// CIR-NEXT:        cir.call @_Z4deadv()
+// CIR-NEXT:        cir.yield
+// CIR-EH-NEXT:   } catch all
+// CIR:         }, finalSuspend : {
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z15co_return_valuei(
+// CIR-FLAT:         cir.call @_ZN7IntTask12promise_type12return_valueEi(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+
+// OGCG-LABEL: define {{.*}} @_Z15co_return_valuei(
+// OGCG:         {{call|invoke}} void 
@_ZN7IntTask12promise_type12return_valueEi(
+
+// A co_return at the top level of the body still suppresses the implicit
+// co_return when unreachable statements follow it.
+
+Task co_return_void() {
+  co_return;
+  S s;
+  dead();
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z14co_return_voidv(
+// CIR:         }, body : {
+// CIR-EH:        cir.try {
+// CIR:             cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:        cir.co_return
+// CIR-NEXT:      ^bb1:  // no predecessors
+// CIR-NEXT:        cir.cleanup.scope {
+// CIR-NEXT:          cir.call @_Z4deadv()
+// CIR-NEXT:          cir.yield
+// CIR-NOEH-NEXT:   } cleanup normal {
+// CIR-EH-NEXT:     } cleanup all {
+// CIR-NEXT:          cir.call @_ZN1SD1Ev(
+// CIR-NEXT:          cir.yield
+// CIR-NEXT:        }
+// CIR-NEXT:        cir.yield
+// CIR-EH-NEXT:   } catch all
+// CIR-NOT:       @_ZN4Task12promise_type11return_voidEv
+// CIR:         }, finalSuspend : {
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z14co_return_voidv(
+// CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT:         cir.call @_Z4deadv()
+// CIR-FLAT-NOT:     @_ZN4Task12promise_type11return_voidEv
+// CIR-FLAT:       }, finalSuspend : {
+
+// OGCG-LABEL: define {{.*}} @_Z14co_return_voidv(
+// OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG-NOT:     @_ZN1SD1Ev
+// OGCG:       coro.final:
+
+// Without unreachable statements, the new block stays empty. It is erased at
+// the end of the body region. A cir.try terminates with a cir.yield.
+
+Task co_return_at_end_without_cleanup() {
+  co_await std::suspend_always{};
+  co_return;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z32co_return_at_end_without_cleanupv(
+// CIR:         }, body : {
+// CIR:             cir.await(user,
+// CIR:             cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:        cir.co_return
+// CIR-NOEH-NEXT: }, finalSuspend : {
+// CIR-EH-NEXT:   ^bb1:  // no predecessors
+// CIR-EH-NEXT:     cir.yield
+// CIR-EH-NEXT:   } catch all
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z32co_return_at_end_without_cleanupv(
+// CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  }, finalSuspend : {
+
+Task co_return_in_block() {
+  {
+    S s;
+    co_return;
+    dead();
+  }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z18co_return_in_blockv(
+// CIR:         }, body : {
+// CIR:             cir.scope {
+// CIR:               cir.cleanup.scope {
+// CIR-NEXT:            cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:            cir.co_return
+// CIR-NEXT:          ^bb1:  // no predecessors
+// CIR-NEXT:            cir.call @_Z4deadv()
+// CIR-NEXT:            cir.yield
+// CIR-NOEH-NEXT:     } cleanup normal {
+// CIR-EH-NEXT:       } cleanup all {
+// CIR-NEXT:            cir.call @_ZN1SD1Ev(
+// CIR-NEXT:            cir.yield
+// CIR-NEXT:          }
+// CIR-NEXT:        }
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z18co_return_in_blockv(
+// CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+
+// OGCG-LABEL: define {{.*}} @_Z18co_return_in_blockv(
+// OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         call void @_ZN1SD1Ev(
+
+Task co_return_in_if_with_dead_code(bool b) {
+  if (b) {
+    co_return;
+    dead();
+  } else {
+    co_return;
+    dead();
+  }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z30co_return_in_if_with_dead_codeb(
+// CIR:         }, body : {
+// CIR:             cir.if %{{.*}} {
+// CIR-NEXT:          cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:          cir.co_return
+// CIR-NEXT:        ^bb1:  // no predecessors
+// CIR-NEXT:          cir.call @_Z4deadv()
+// CIR-NEXT:          cir.yield
+// CIR-NEXT:        } else {
+// CIR-NEXT:          cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:          cir.co_return
+// CIR-NEXT:        ^bb1:  // no predecessors
+// CIR-NEXT:          cir.call @_Z4deadv()
+// CIR-NEXT:          cir.yield
+// CIR-NEXT:        }
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z30co_return_in_if_with_dead_codeb(
+// CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+// CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+
+Task co_return_in_loop(bool b) {
+  while (b) {
+    co_return;
+    dead();
+  }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z17co_return_in_loopb(
+// CIR:         }, body : {
+// CIR:             cir.while {
+// CIR:             } do {
+// CIR-NEXT:          cir.scope {
+// CIR-NEXT:            cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:            cir.co_return
+// CIR-NEXT:          ^bb1:  // no predecessors
+// CIR-NEXT:            cir.call @_Z4deadv()
+// CIR-NEXT:            cir.yield
+// CIR-NEXT:          }
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z17co_return_in_loopb(
+// CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+
+Task co_return_in_switch(int i) {
+  switch (i) {
+  case 0:
+    co_return;
+    dead();
+  default:
+    break;
+  }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z19co_return_in_switchi(
+// CIR:         }, body : {
+// CIR:             cir.case(equal, [#cir.int<0> : !s32i]) {
+// CIR-NEXT:          cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:          cir.co_return
+// CIR-NEXT:        ^bb1:  // no predecessors
+// CIR-NEXT:          cir.call @_Z4deadv()
+// CIR-NEXT:          cir.yield
+// CIR-NEXT:        }
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z19co_return_in_switchi(
+// CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+
+// An unreachable suspension point is emitted too.
+
+Task dead_co_await() {
+  co_return;
+  co_await std::suspend_never{};
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z13dead_co_awaitv(
+// CIR:         }, body : {
+// CIR:             cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:        cir.co_return
+// CIR-NEXT:      ^bb1:  // no predecessors
+// CIR-NEXT:        cir.await(user, ready : {
+// CIR-NEXT:          cir.call @_ZNSt13suspend_never11await_readyEv(
+// CIR-NOT:       @_ZN4Task12promise_type11return_voidEv
+// CIR:         }, finalSuspend : {
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z13dead_co_awaitv(
+// CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.await(user, ready : {
+
+// OGCG-LABEL: define {{.*}} @_Z13dead_co_awaitv(
+// OGCG-NOT:     suspend_never
+// OGCG:       coro.final:
+
+// A label after a co_return makes the statements after it reachable through a
+// goto, and with them the end of the body. The implicit co_return is then
+// emitted, as in classic codegen, which calls return_void() on that path.
+
+Task label_after_co_return(bool b) {
+  if (b)
+    goto l;
+  co_return;
+l:
+  live();
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z21label_after_co_returnb(
+// CIR:         }, body : {
+// CIR:             cir.goto "l"
+// CIR:             cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE:[0-9]+]])
+// CIR-NEXT:        cir.co_return
+// CIR-NEXT:      ^bb1:  // no predecessors
+// CIR-NEXT:        cir.label "l"
+// CIR-NEXT:        cir.call @_Z4livev()
+// CIR-NEXT:        cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
+// CIR-NEXT:        cir.co_return
+// CIR-NOEH-NEXT: }, finalSuspend : {
+// CIR-EH-NEXT:   ^bb2:  // no predecessors
+// CIR-EH-NEXT:     cir.yield
+// CIR-EH-NEXT:   } catch all
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z21label_after_co_returnb(
+// CIR-FLAT:         cir.goto "l"
+// CIR-FLAT:         cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.label "l"
+// CIR-FLAT-NEXT:    cir.call @_Z4livev()
+// CIR-FLAT-NEXT:    cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-FLAT-NEXT:    cir.co_return
+// CIR-FLAT-NEXT:  }, finalSuspend : {
+
+// OGCG-LABEL: define {{.*}} @_Z21label_after_co_returnb(
+// OGCG:       {{^}}l:
+// OGCG-NEXT:    {{call|invoke}} void @_Z4livev()
+// OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+
+Task label_in_block_after_co_return(bool b) {
+  if (b)
+    goto l;
+  co_return;
+  {
+  l:
+    live();
+  }
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z30label_in_block_after_co_returnb(
+// CIR:         }, body : {
+// CIR:             cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE:[0-9]+]])
+// CIR-NEXT:        cir.co_return
+// CIR-NEXT:      ^bb1:  // no predecessors
+// CIR-NEXT:        cir.scope {
+// CIR:               cir.label "l"
+// CIR-NEXT:          cir.call @_Z4livev()
+// CIR-NEXT:          cir.yield
+// CIR-NEXT:        }
+// CIR-NEXT:        cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
+// CIR-NEXT:        cir.co_return
+
+// OGCG-LABEL: define {{.*}} @_Z30label_in_block_after_co_returnb(
+// OGCG:       {{^}}l:
+// OGCG-NEXT:    {{call|invoke}} void @_Z4livev()
+// OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+
+Task empty_label_after_co_return(bool b) {
+  if (b)
+    goto l;
+  co_return;
+l:;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z27empty_label_after_co_returnb(
+// CIR:         }, body : {
+// CIR:             cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE:[0-9]+]])
+// CIR-NEXT:        cir.co_return
+// CIR-NEXT:      ^bb1:  // no predecessors
+// CIR-NEXT:        cir.label "l"
+// CIR-NEXT:        cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
+// CIR-NEXT:        cir.co_return
+
+// OGCG-LABEL: define {{.*}} @_Z27empty_label_after_co_returnb(
+// OGCG:       {{^}}l:
+// OGCG-NEXT:    {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+
+// A co_return after the label makes the end of the body unreachable again.
+
+Task co_return_after_label(bool b) {
+  if (b)
+    goto l;
+  co_return;
+l:
+  live();
+  co_return;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z21co_return_after_labelb(
+// CIR:         }, body : {
+// CIR:             cir.label "l"
+// CIR-NEXT:        cir.call @_Z4livev()
+// CIR-NEXT:        cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:        cir.co_return
+// CIR-NOT:         @_ZN4Task12promise_type11return_voidEv
+// CIR:         }, finalSuspend : {
+
+// A goto, __builtin_unreachable() or __builtin_trap() at the end of the body
+// leaves an empty block. If no implicit co_return is emitted, add cir.yield.
+
+IntTask goto_at_end() {
+l:
+  co_await std::suspend_always{};
+  goto l;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z11goto_at_endv(
+// CIR:         }, body : {
+// CIR:             cir.label "l"
+// CIR:             cir.goto "l"
+// CIR-NEXT:      ^bb{{[0-9]+}}:  // no predecessors
+// CIR-NEXT:        cir.yield
+// CIR-NOEH-NEXT: }, finalSuspend : {
+// CIR-EH-NEXT:   } catch all
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z11goto_at_endv(
+// CIR-FLAT:         cir.goto "l"
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.yield
+// CIR-FLAT-NEXT:  }, finalSuspend : {
+
+Task goto_after_co_return() {
+l:
+  co_await std::suspend_always{};
+  co_return;
+  goto l;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z20goto_after_co_returnv(
+// CIR:         }, body : {
+// CIR:             cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-NEXT:        cir.co_return
+// CIR-NEXT:      ^bb{{[0-9]+}}:  // no predecessors
+// CIR-NEXT:        cir.goto "l"
+// CIR-NEXT:      ^bb{{[0-9]+}}:  // no predecessors
+// CIR-NEXT:        cir.yield
+// CIR-NOEH-NEXT: }, finalSuspend : {
+// CIR-EH-NEXT:   } catch all
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z20goto_after_co_returnv(
+// CIR-FLAT:         cir.co_return
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.goto "l"
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.yield
+// CIR-FLAT-NEXT:  }, finalSuspend : {
+
+IntTask unreachable_after_switch(int i) {
+  switch (i) {
+  case 0:
+    co_return 1;
+  default:
+    co_return 2;
+  }
+  __builtin_unreachable();
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z24unreachable_after_switchi(
+// CIR:         }, body : {
+// CIR:             cir.switch
+// CIR:             cir.unreachable
+// CIR-NEXT:      ^bb{{[0-9]+}}:  // no predecessors
+// CIR-NEXT:        cir.yield
+// CIR-NOEH-NEXT: }, finalSuspend : {
+// CIR-EH-NEXT:   } catch all
+
+// CIR-FLAT-LABEL: cir.func {{.*}} @_Z24unreachable_after_switchi(
+// CIR-FLAT:         cir.unreachable
+// CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
+// CIR-FLAT-NEXT:    cir.yield
+// CIR-FLAT-NEXT:  }, finalSuspend : {
+
+IntTask trap_at_end() {
+  co_await std::suspend_always{};
+  __builtin_trap();
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z11trap_at_endv(
+// CIR:         }, body : {
+// CIR:             cir.trap
+// CIR-NEXT:      ^bb{{[0-9]+}}:  // no predecessors
+// CIR-NEXT:        cir.yield
+// CIR-NOEH-NEXT: }, finalSuspend : {
+// CIR-EH-NEXT:   } catch all
+
+#if __cpp_exceptions
+Task co_return_in_try() {
+  try {
+    co_return;
+    dead();
+  } catch (...) {
+    co_return;
+    dead();
+  }
+}
+#endif
+
+// CIR-EH-LABEL: cir.func coroutine {{.*}} @_Z16co_return_in_tryv(
+// CIR-EH:         }, body : {
+// CIR-EH:           cir.try {
+// CIR-EH:             cir.try {
+// CIR-EH-NEXT:          cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-EH-NEXT:          cir.co_return
+// CIR-EH-NEXT:        ^bb1:  // no predecessors
+// CIR-EH-NEXT:          cir.call @_Z4deadv()
+// CIR-EH-NEXT:          cir.yield
+// CIR-EH-NEXT:        } catch all
+// CIR-EH-NEXT:          cir.begin_catch
+// CIR-EH-NEXT:          cir.cleanup.scope {
+// CIR-EH-NEXT:            cir.call @_ZN4Task12promise_type11return_voidEv(
+// CIR-EH-NEXT:            cir.co_return
+// CIR-EH-NEXT:          ^bb1:  // no predecessors
+// CIR-EH-NEXT:            cir.call @_Z4deadv()
+// CIR-EH-NEXT:            cir.yield
+// CIR-EH-NEXT:          } cleanup all {
+// CIR-EH-NEXT:            cir.end_catch

>From f9534c1a4ffa282c66cbe09e0782ffd51c7cbf67 Mon Sep 17 00:00:00 2001
From: Morris Hafner <[email protected]>
Date: Mon, 12 Oct 2026 00:24:25 +0000
Subject: [PATCH 2/2] Add OGCG tests, remove mangling for dead and live

---
 .../CodeGenCoroutines/coro-fallthrough.cpp    | 127 ++++++++++++++----
 1 file changed, 101 insertions(+), 26 deletions(-)

diff --git a/clang/test/CIR/CodeGenCoroutines/coro-fallthrough.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-fallthrough.cpp
index 7ed7d47cb45b5..d912d5ba7351b 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-fallthrough.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-fallthrough.cpp
@@ -5,9 +5,9 @@
 // RUN: cir-opt -cir-flatten-cfg %t.cir -o %t-flat.cir
 // RUN: FileCheck --input-file=%t-flat.cir %s -check-prefix=CIR-FLAT
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm 
-disable-llvm-passes %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=OGCG,OGCG-NOEH 
--implicit-check-not=_Z4deadv
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=OGCG,OGCG-NOEH 
--implicit-check-not='@dead('
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu 
-fcxx-exceptions -fexceptions -emit-llvm -disable-llvm-passes %s -o %t-eh.ll
-// RUN: FileCheck --input-file=%t-eh.ll %s -check-prefixes=OGCG,OGCG-EH 
--implicit-check-not=_Z4deadv
+// RUN: FileCheck --input-file=%t-eh.ll %s -check-prefixes=OGCG,OGCG-EH 
--implicit-check-not='@dead('
 
 // When the body of a coroutine falls off its end, the implicit `co_return;`
 // runs after the body: the body's local variables are destroyed first, then
@@ -45,8 +45,8 @@ struct IntTask {
 };
 
 S make();
-void dead();
-void live();
+extern "C" void dead();
+extern "C" void live();
 
 Task falls_off_end() {
   co_await std::suspend_always{};
@@ -228,7 +228,7 @@ IntTask co_return_value(int v) {
 // CIR:             cir.call @_ZN7IntTask12promise_type12return_valueEi(
 // CIR-NEXT:        cir.co_return
 // CIR-NEXT:      ^bb1:  // no predecessors
-// CIR-NEXT:        cir.call @_Z4deadv()
+// CIR-NEXT:        cir.call @dead()
 // CIR-NEXT:        cir.yield
 // CIR-EH-NEXT:   } catch all
 // CIR:         }, finalSuspend : {
@@ -237,7 +237,7 @@ IntTask co_return_value(int v) {
 // CIR-FLAT:         cir.call @_ZN7IntTask12promise_type12return_valueEi(
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
-// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+// CIR-FLAT-NEXT:    cir.call @dead()
 
 // OGCG-LABEL: define {{.*}} @_Z15co_return_valuei(
 // OGCG:         {{call|invoke}} void 
@_ZN7IntTask12promise_type12return_valueEi(
@@ -258,7 +258,7 @@ Task co_return_void() {
 // CIR-NEXT:        cir.co_return
 // CIR-NEXT:      ^bb1:  // no predecessors
 // CIR-NEXT:        cir.cleanup.scope {
-// CIR-NEXT:          cir.call @_Z4deadv()
+// CIR-NEXT:          cir.call @dead()
 // CIR-NEXT:          cir.yield
 // CIR-NOEH-NEXT:   } cleanup normal {
 // CIR-EH-NEXT:     } cleanup all {
@@ -274,7 +274,7 @@ Task co_return_void() {
 // CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
-// CIR-FLAT:         cir.call @_Z4deadv()
+// CIR-FLAT:         cir.call @dead()
 // CIR-FLAT-NOT:     @_ZN4Task12promise_type11return_voidEv
 // CIR-FLAT:       }, finalSuspend : {
 
@@ -306,6 +306,11 @@ Task co_return_at_end_without_cleanup() {
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  }, finalSuspend : {
 
+// OGCG-LABEL: define {{.*}} @_Z32co_return_at_end_without_cleanupv(
+// OGCG:       await.ready:
+// OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+
 Task co_return_in_block() {
   {
     S s;
@@ -321,7 +326,7 @@ Task co_return_in_block() {
 // CIR-NEXT:            cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-NEXT:            cir.co_return
 // CIR-NEXT:          ^bb1:  // no predecessors
-// CIR-NEXT:            cir.call @_Z4deadv()
+// CIR-NEXT:            cir.call @dead()
 // CIR-NEXT:            cir.yield
 // CIR-NOEH-NEXT:     } cleanup normal {
 // CIR-EH-NEXT:       } cleanup all {
@@ -334,7 +339,7 @@ Task co_return_in_block() {
 // CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
-// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+// CIR-FLAT-NEXT:    cir.call @dead()
 
 // OGCG-LABEL: define {{.*}} @_Z18co_return_in_blockv(
 // OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
@@ -356,13 +361,13 @@ Task co_return_in_if_with_dead_code(bool b) {
 // CIR-NEXT:          cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-NEXT:          cir.co_return
 // CIR-NEXT:        ^bb1:  // no predecessors
-// CIR-NEXT:          cir.call @_Z4deadv()
+// CIR-NEXT:          cir.call @dead()
 // CIR-NEXT:          cir.yield
 // CIR-NEXT:        } else {
 // CIR-NEXT:          cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-NEXT:          cir.co_return
 // CIR-NEXT:        ^bb1:  // no predecessors
-// CIR-NEXT:          cir.call @_Z4deadv()
+// CIR-NEXT:          cir.call @dead()
 // CIR-NEXT:          cir.yield
 // CIR-NEXT:        }
 
@@ -370,11 +375,19 @@ Task co_return_in_if_with_dead_code(bool b) {
 // CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
-// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+// CIR-FLAT-NEXT:    cir.call @dead()
 // CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
-// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+// CIR-FLAT-NEXT:    cir.call @dead()
+
+// OGCG-LABEL: define {{.*}} @_Z30co_return_in_if_with_dead_codeb(
+// OGCG:       if.then:
+// OGCG-NEXT:    {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+// OGCG:       if.else:
+// OGCG-NEXT:    {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
 
 Task co_return_in_loop(bool b) {
   while (b) {
@@ -391,7 +404,7 @@ Task co_return_in_loop(bool b) {
 // CIR-NEXT:            cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-NEXT:            cir.co_return
 // CIR-NEXT:          ^bb1:  // no predecessors
-// CIR-NEXT:            cir.call @_Z4deadv()
+// CIR-NEXT:            cir.call @dead()
 // CIR-NEXT:            cir.yield
 // CIR-NEXT:          }
 
@@ -399,7 +412,15 @@ Task co_return_in_loop(bool b) {
 // CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
-// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+// CIR-FLAT-NEXT:    cir.call @dead()
+
+// OGCG-LABEL: define {{.*}} @_Z17co_return_in_loopb(
+// OGCG:       while.body:
+// OGCG-NEXT:    {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+// OGCG:       while.end:
+// OGCG-NEXT:    {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
 
 Task co_return_in_switch(int i) {
   switch (i) {
@@ -417,7 +438,7 @@ Task co_return_in_switch(int i) {
 // CIR-NEXT:          cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-NEXT:          cir.co_return
 // CIR-NEXT:        ^bb1:  // no predecessors
-// CIR-NEXT:          cir.call @_Z4deadv()
+// CIR-NEXT:          cir.call @dead()
 // CIR-NEXT:          cir.yield
 // CIR-NEXT:        }
 
@@ -425,7 +446,15 @@ Task co_return_in_switch(int i) {
 // CIR-FLAT:         cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
-// CIR-FLAT-NEXT:    cir.call @_Z4deadv()
+// CIR-FLAT-NEXT:    cir.call @dead()
+
+// OGCG-LABEL: define {{.*}} @_Z19co_return_in_switchi(
+// OGCG:       sw.bb:
+// OGCG-NEXT:    {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+// OGCG:       sw.epilog:
+// OGCG-NEXT:    {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
 
 // An unreachable suspension point is emitted too.
 
@@ -473,7 +502,7 @@ Task label_after_co_return(bool b) {
 // CIR-NEXT:        cir.co_return
 // CIR-NEXT:      ^bb1:  // no predecessors
 // CIR-NEXT:        cir.label "l"
-// CIR-NEXT:        cir.call @_Z4livev()
+// CIR-NEXT:        cir.call @live()
 // CIR-NEXT:        cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
 // CIR-NEXT:        cir.co_return
 // CIR-NOEH-NEXT: }, finalSuspend : {
@@ -486,14 +515,14 @@ Task label_after_co_return(bool b) {
 // CIR-FLAT:         cir.co_return
 // CIR-FLAT-NEXT:  ^bb{{[0-9]+}}:  // no predecessors
 // CIR-FLAT-NEXT:    cir.label "l"
-// CIR-FLAT-NEXT:    cir.call @_Z4livev()
+// CIR-FLAT-NEXT:    cir.call @live()
 // CIR-FLAT-NEXT:    cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-FLAT-NEXT:    cir.co_return
 // CIR-FLAT-NEXT:  }, finalSuspend : {
 
 // OGCG-LABEL: define {{.*}} @_Z21label_after_co_returnb(
 // OGCG:       {{^}}l:
-// OGCG-NEXT:    {{call|invoke}} void @_Z4livev()
+// OGCG-NEXT:    {{call|invoke}} void @live()
 // OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
 // OGCG:         br label %coro.final
 
@@ -514,7 +543,7 @@ Task label_in_block_after_co_return(bool b) {
 // CIR-NEXT:      ^bb1:  // no predecessors
 // CIR-NEXT:        cir.scope {
 // CIR:               cir.label "l"
-// CIR-NEXT:          cir.call @_Z4livev()
+// CIR-NEXT:          cir.call @live()
 // CIR-NEXT:          cir.yield
 // CIR-NEXT:        }
 // CIR-NEXT:        cir.call 
@_ZN4Task12promise_type11return_voidEv(%[[PROMISE]])
@@ -522,7 +551,7 @@ Task label_in_block_after_co_return(bool b) {
 
 // OGCG-LABEL: define {{.*}} @_Z30label_in_block_after_co_returnb(
 // OGCG:       {{^}}l:
-// OGCG-NEXT:    {{call|invoke}} void @_Z4livev()
+// OGCG-NEXT:    {{call|invoke}} void @live()
 // OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
 // OGCG:         br label %coro.final
 
@@ -561,12 +590,20 @@ Task co_return_after_label(bool b) {
 // CIR-LABEL: cir.func coroutine {{.*}} @_Z21co_return_after_labelb(
 // CIR:         }, body : {
 // CIR:             cir.label "l"
-// CIR-NEXT:        cir.call @_Z4livev()
+// CIR-NEXT:        cir.call @live()
 // CIR-NEXT:        cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-NEXT:        cir.co_return
 // CIR-NOT:         @_ZN4Task12promise_type11return_voidEv
 // CIR:         }, finalSuspend : {
 
+// OGCG-LABEL: define {{.*}} @_Z21co_return_after_labelb(
+// OGCG:       {{^}}l:
+// OGCG-NEXT:    {{call|invoke}} void @live()
+// OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+// OGCG-NOT:     @_ZN4Task12promise_type11return_voidEv(
+// OGCG:       {{^}}}
+
 // A goto, __builtin_unreachable() or __builtin_trap() at the end of the body
 // leaves an empty block. If no implicit co_return is emitted, add cir.yield.
 
@@ -591,6 +628,13 @@ IntTask goto_at_end() {
 // CIR-FLAT-NEXT:    cir.yield
 // CIR-FLAT-NEXT:  }, finalSuspend : {
 
+// OGCG-LABEL: define {{.*}} @_Z11goto_at_endv(
+// OGCG:       {{^}}l:
+// OGCG:       await.ready:
+// OGCG:         br label %l
+// OGCG-NOT:     @_ZN7IntTask12promise_type13final_suspendEv(
+// OGCG:       {{^}}}
+
 Task goto_after_co_return() {
 l:
   co_await std::suspend_always{};
@@ -617,6 +661,13 @@ Task goto_after_co_return() {
 // CIR-FLAT-NEXT:    cir.yield
 // CIR-FLAT-NEXT:  }, finalSuspend : {
 
+// OGCG-LABEL: define {{.*}} @_Z20goto_after_co_returnv(
+// OGCG:       await.ready:
+// OGCG:         {{call|invoke}} void @_ZN4Task12promise_type11return_voidEv(
+// OGCG:         br label %coro.final
+// OGCG-NOT:     br label %l
+// OGCG:       {{^}}}
+
 IntTask unreachable_after_switch(int i) {
   switch (i) {
   case 0:
@@ -642,6 +693,16 @@ IntTask unreachable_after_switch(int i) {
 // CIR-FLAT-NEXT:    cir.yield
 // CIR-FLAT-NEXT:  }, finalSuspend : {
 
+// OGCG-LABEL: define {{.*}} @_Z24unreachable_after_switchi(
+// OGCG:       sw.bb:
+// OGCG-NEXT:    {{call|invoke}} void 
@_ZN7IntTask12promise_type12return_valueEi({{.*}}i32{{.*}} 1)
+// OGCG:         br label %coro.final
+// OGCG:       sw.default:
+// OGCG-NEXT:    {{call|invoke}} void 
@_ZN7IntTask12promise_type12return_valueEi({{.*}}i32{{.*}} 2)
+// OGCG:         br label %coro.final
+// OGCG-NOT:   sw.epilog:
+// OGCG:       {{^}}}
+
 IntTask trap_at_end() {
   co_await std::suspend_always{};
   __builtin_trap();
@@ -655,6 +716,13 @@ IntTask trap_at_end() {
 // CIR-NOEH-NEXT: }, finalSuspend : {
 // CIR-EH-NEXT:   } catch all
 
+// OGCG-LABEL: define {{.*}} @_Z11trap_at_endv(
+// OGCG:       await.ready:
+// OGCG:         call void @llvm.trap()
+// OGCG-NEXT:    unreachable
+// OGCG-NOT:     @_ZN7IntTask12promise_type13final_suspendEv(
+// OGCG:       {{^}}}
+
 #if __cpp_exceptions
 Task co_return_in_try() {
   try {
@@ -674,7 +742,7 @@ Task co_return_in_try() {
 // CIR-EH-NEXT:          cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-EH-NEXT:          cir.co_return
 // CIR-EH-NEXT:        ^bb1:  // no predecessors
-// CIR-EH-NEXT:          cir.call @_Z4deadv()
+// CIR-EH-NEXT:          cir.call @dead()
 // CIR-EH-NEXT:          cir.yield
 // CIR-EH-NEXT:        } catch all
 // CIR-EH-NEXT:          cir.begin_catch
@@ -682,7 +750,14 @@ Task co_return_in_try() {
 // CIR-EH-NEXT:            cir.call @_ZN4Task12promise_type11return_voidEv(
 // CIR-EH-NEXT:            cir.co_return
 // CIR-EH-NEXT:          ^bb1:  // no predecessors
-// CIR-EH-NEXT:            cir.call @_Z4deadv()
+// CIR-EH-NEXT:            cir.call @dead()
 // CIR-EH-NEXT:            cir.yield
 // CIR-EH-NEXT:          } cleanup all {
 // CIR-EH-NEXT:            cir.end_catch
+
+// OGCG-EH-LABEL: define {{.*}} @_Z16co_return_in_tryv(
+// OGCG-EH:         invoke void @_ZN4Task12promise_type11return_voidEv(
+// OGCG-EH:         call ptr @__cxa_begin_catch(
+// OGCG-EH-NEXT:    invoke void @_ZN4Task12promise_type11return_voidEv(
+// OGCG-EH:         invoke void @__cxa_end_catch(
+// OGCG-EH:         br label %coro.final

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to