[clang] 9b64d05 - [CIR] Implement partial array destroy handling (#190834)

via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 8 12:22:24 PDT 2026


Author: Andy Kaylor
Date: 2026-04-08T12:22:15-07:00
New Revision: 9b64d05e594a8b04393e1cd24c245a435826d47c

URL: https://github.com/llvm/llvm-project/commit/9b64d05e594a8b04393e1cd24c245a435826d47c
DIFF: https://github.com/llvm/llvm-project/commit/9b64d05e594a8b04393e1cd24c245a435826d47c.diff

LOG: [CIR] Implement partial array destroy handling (#190834)

This implements EH cleanup handling that performs regular partial array
destruction for array constructor loops with a destructed type. Because
CIR represents array construction using an abstract operation, we do not
go through the normal EH stack mechanism. Instead, we add a partial_dtor
region to the cir.array.ctor operation indicating how a single element
should be destructed. When the cir.array.ctor operation is expanded
during LoweringPrepare, we create a cleanup scope with a partial array
dtor loop in an EH cleanup region. This gets further expanded during CFG
flattening to produce a control flow equivalent to that generated by
classic codegen.

Assisted-by: Cursor / claude-4.6-opus-high

Added: 
    clang/test/CIR/CodeGen/partial-array-cleanup.cpp

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIROps.td
    clang/lib/CIR/CodeGen/CIRGenClass.cpp
    clang/lib/CIR/Dialect/IR/CIRDialect.cpp
    clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
    clang/test/CIR/CodeGen/array-ctor.cpp
    clang/test/CIR/CodeGen/array-dtor.cpp
    clang/test/CIR/CodeGen/global-array-dtor.cpp
    clang/test/CIR/CodeGen/global-init.cpp
    clang/test/CIR/CodeGen/new.cpp
    clang/test/CIR/IR/array-ctor.cir
    clang/test/CIR/IR/array-dtor.cir
    clang/test/CIR/IR/invalid-array-structor.cir

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d2fd2df7ab7d1..93ca0172b2a7f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4574,12 +4574,23 @@ def CIR_TrapOp : CIR_Op<"trap", [Terminator]> {
 // ArrayCtor & ArrayDtor
 //===----------------------------------------------------------------------===//
 
-def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
+def CIR_ArrayCtor : CIR_Op<"array.ctor", [
+  SingleBlockImplicitTerminator<"cir::YieldOp">
+]> {
   let summary = "Initialize array elements with C++ constructors";
   let description = [{
     Initialize each array element using the same C++ constructor. This
-    operation has one region, with one single block. The block has an
-    incoming argument for the current array element to initialize.
+    operation has a `body` region and an optional `partial_dtor` region.
+    Both regions have a single block whose argument is a pointer to the
+    current array element.
+
+    The `body` region contains the constructor call for one element.
+
+    The `partial_dtor` region, when non-empty, contains the destructor call
+    for one element. During lowering, it is used to build a cleanup that
+    destroys already-constructed elements if a constructor throws. When the
+    element type has a trivial destructor or exceptions are disabled, the
+    `partial_dtor` region is left empty.
 
     When `num_elements` is absent, `addr` must be a pointer to a fixed-size
     CIR array type and the element count is derived from that array type.
@@ -4591,16 +4602,25 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
     Examples:
 
     ```mlir
+    // Fixed size without partial destructor:
     cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) {
       ^bb0(%arg0: !cir.ptr<!rec_S>):
         cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> ()
-        cir.yield
     }
 
+    // Variable size without partial destructor:
     cir.array.ctor(%ptr, %n : !cir.ptr<!rec_S>, !u64i) {
       ^bb0(%arg0: !cir.ptr<!rec_S>):
         cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> ()
-        cir.yield
+    }
+
+    // Fixed size with partial destructor:
+    cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) {
+      ^bb0(%arg0: !cir.ptr<!rec_S>):
+        cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> ()
+    } partial_dtor {
+      ^bb0(%arg0: !cir.ptr<!rec_S>):
+        cir.call @some_dtor(%arg0) : (!cir.ptr<!rec_S>) -> ()
     }
     ```
   }];
@@ -4610,32 +4630,46 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
     Optional<CIR_AnyIntType>:$num_elements
   );
 
-  let regions = (region SizedRegion<1>:$body);
+  let regions = (region SizedRegion<1>:$body, AnyRegion:$partial_dtor);
   let assemblyFormat = [{
     $addr (`,` $num_elements^)? `:` qualified(type($addr))
-    (`,` type($num_elements)^)? $body attr-dict
+    (`,` type($num_elements)^)? $body
+    (`partial_dtor` $partial_dtor^)?
+    attr-dict
   }];
 
   let builders = [
     // Static form: addr is ptr<array<T x N>>, no num_elements.
     OpBuilder<(ins "mlir::Value":$addr,
-      "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$regionBuilder), [{
-        assert(regionBuilder && "builder callback expected");
+      "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$bodyBuilder,
+      "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$partialDtorBuilder), [{
+        assert(bodyBuilder && "builder callback expected");
         mlir::OpBuilder::InsertionGuard guard($_builder);
-        mlir::Region *r = $_state.addRegion();
         $_state.addOperands(ValueRange{addr});
-        $_builder.createBlock(r);
-        regionBuilder($_builder, $_state.location);
+        mlir::Region *body = $_state.addRegion();
+        $_builder.createBlock(body);
+        bodyBuilder($_builder, $_state.location);
+        mlir::Region *partialDtor = $_state.addRegion();
+        if (partialDtorBuilder) {
+          $_builder.createBlock(partialDtor);
+          partialDtorBuilder($_builder, $_state.location);
+        }
     }]>,
     // Dynamic form: addr is ptr<T>, num_elements is the runtime count.
     OpBuilder<(ins "mlir::Value":$addr, "mlir::Value":$num_elements,
-      "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$regionBuilder), [{
-        assert(regionBuilder && "builder callback expected");
+      "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$bodyBuilder,
+      "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$partialDtorBuilder), [{
+        assert(bodyBuilder && "builder callback expected");
         mlir::OpBuilder::InsertionGuard guard($_builder);
-        mlir::Region *r = $_state.addRegion();
         $_state.addOperands({addr, num_elements});
-        $_builder.createBlock(r);
-        regionBuilder($_builder, $_state.location);
+        mlir::Region *body = $_state.addRegion();
+        $_builder.createBlock(body);
+        bodyBuilder($_builder, $_state.location);
+        mlir::Region *partialDtor = $_state.addRegion();
+        if (partialDtorBuilder) {
+          $_builder.createBlock(partialDtor);
+          partialDtorBuilder($_builder, $_state.location);
+        }
     }]>
   ];
 
@@ -4643,7 +4677,9 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
   let hasLLVMLowering = false;
 }
 
-def CIR_ArrayDtor : CIR_Op<"array.dtor"> {
+def CIR_ArrayDtor : CIR_Op<"array.dtor", [
+  SingleBlockImplicitTerminator<"cir::YieldOp">
+]> {
   let summary = "Destroy array elements with C++ destructors";
   let description = [{
     Destroy each array element using the same C++ destructor. This operation
@@ -4666,14 +4702,12 @@ def CIR_ArrayDtor : CIR_Op<"array.dtor"> {
     cir.array.dtor %0 : !cir.ptr<!cir.array<!rec_S x 42>> {
       ^bb0(%arg0: !cir.ptr<!rec_S>):
         cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
-        cir.yield
     }
 
     // Dynamic count (delete[] with destructor):
     cir.array.dtor %ptr, %n : !cir.ptr<!rec_S>, !u64i {
       ^bb0(%arg0: !cir.ptr<!rec_S>):
         cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
-        cir.yield
     }
     ```
   }];

diff  --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index f8d65fa9a6d33..748d450d6dc10 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -783,20 +783,14 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
   {
     RunCleanupsScope scope(*this);
 
-    // Evaluate the constructor and its arguments in a regular
-    // partial-destroy cleanup.
-    if (getLangOpts().Exceptions &&
-        !ctor->getParent()->hasTrivialDestructor()) {
-      cgm.errorNYI(e->getSourceRange(), "partial array cleanups");
-    }
+    bool needsPartialArrayCleanup =
+        getLangOpts().Exceptions && !ctor->getParent()->hasTrivialDestructor();
 
     auto emitCtorBody = [&](mlir::OpBuilder &b, mlir::Location l) {
       mlir::BlockArgument arg =
           b.getInsertionBlock()->addArgument(ptrToElmType, l);
       Address curAddr = Address(arg, elementType, eltAlignment);
       assert(!cir::MissingFeatures::sanitizers());
-      // Match CGClass::EmitCXXAggrConstructorCall: zero-initialize each element
-      // in the array-ctor loop before invoking the constructor for that slot.
       if (zeroInitialize)
         emitNullInitialization(l, curAddr, type);
       auto currAVS = AggValueSlot::forAddr(
@@ -809,16 +803,30 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
       cir::YieldOp::create(b, l);
     };
 
-    // Emit the per-element initialization.
+    llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>
+        emitPartialDtorBody = nullptr;
+    auto partialDtorBuilder = [&](mlir::OpBuilder &b, mlir::Location l) {
+      mlir::BlockArgument arg =
+          b.getInsertionBlock()->addArgument(ptrToElmType, l);
+      Address curAddr = Address(arg, elementType, eltAlignment);
+      emitCXXDestructorCall(ctor->getParent()->getDestructor(), Dtor_Complete,
+                            /*forVirtualBase=*/false,
+                            /*delegating=*/false, curAddr, type);
+      cir::YieldOp::create(b, l);
+    };
+    if (needsPartialArrayCleanup)
+      emitPartialDtorBody = partialDtorBuilder;
+
     if (useDynamicArrayCtor) {
       cir::ArrayCtor::create(builder, loc, dynamicElPtr, numElements,
-                             emitCtorBody);
+                             emitCtorBody, emitPartialDtorBody);
     } else {
       cir::ArrayType arrayTy =
           cir::ArrayType::get(elementType, constElementCount);
       mlir::Value arrayOp =
           builder.createPtrBitcast(arrayBase.getPointer(), arrayTy);
-      cir::ArrayCtor::create(builder, loc, arrayOp, emitCtorBody);
+      cir::ArrayCtor::create(builder, loc, arrayOp, emitCtorBody,
+                             emitPartialDtorBody);
     }
   }
 }

diff  --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index ab1c0b453ac18..e99faf840c15a 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -341,7 +341,23 @@ template <typename Op> static LogicalResult verifyArrayCtorDtor(Op op) {
   return success();
 }
 
-LogicalResult cir::ArrayCtor::verify() { return verifyArrayCtorDtor(*this); }
+LogicalResult cir::ArrayCtor::verify() {
+  if (failed(verifyArrayCtorDtor(*this)))
+    return failure();
+
+  mlir::Region &partialDtor = getPartialDtor();
+  if (!partialDtor.empty()) {
+    mlir::Block &dtorBlock = partialDtor.front();
+    if (dtorBlock.getNumArguments() != 1)
+      return emitOpError("partial_dtor must have exactly one block argument");
+
+    auto bodyArgTy = getBody().front().getArgument(0).getType();
+    if (dtorBlock.getArgument(0).getType() != bodyArgTy)
+      return emitOpError("partial_dtor block argument type must match "
+                         "the body block argument type");
+  }
+  return success();
+}
 LogicalResult cir::ArrayDtor::verify() { return verifyArrayCtorDtor(*this); }
 
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 91f082725711f..482e73f9f3050 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1369,13 +1369,16 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() {
   cir::ReturnOp::create(builder, f.getLoc());
 }
 
+/// Lower a cir.array.ctor or cir.array.dtor into a do-while loop that
+/// iterates over every element.  For cir.array.ctor ops whose partial_dtor
+/// region is non-empty, the ctor loop is wrapped in a cir.cleanup.scope whose
+/// EH cleanup performs a reverse destruction loop using the partial dtor body.
 static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder,
                                        clang::ASTContext *astCtx,
                                        mlir::Operation *op, mlir::Type eltTy,
                                        mlir::Value addr,
                                        mlir::Value numElements,
                                        uint64_t arrayLen, bool isCtor) {
-  // Generate loop to call into ctor/dtor for every element.
   mlir::Location loc = op->getLoc();
   bool isDynamic = numElements != nullptr;
 
@@ -1443,34 +1446,87 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder,
     }
   };
 
-  builder.createDoWhile(
-      loc,
-      /*condBuilder=*/
-      [&](mlir::OpBuilder &b, mlir::Location loc) {
-        auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
-        auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
-                                      currentElement, stop);
-        builder.createCondition(cmp);
-      },
-      /*bodyBuilder=*/
-      [&](mlir::OpBuilder &b, mlir::Location loc) {
-        auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
-        if (isCtor) {
-          cloneRegionBodyInto(bodyBlock, currentElement);
-          mlir::Value stride = builder.getUnsignedInt(loc, 1, sizeTypeSize);
-          auto nextElement = cir::PtrStrideOp::create(builder, loc, eltTy,
-                                                      currentElement, stride);
-          builder.createStore(loc, nextElement, tmpAddr);
-        } else {
-          mlir::Value stride = builder.getSignedInt(loc, -1, sizeTypeSize);
-          auto prevElement = cir::PtrStrideOp::create(builder, loc, eltTy,
-                                                      currentElement, stride);
-          builder.createStore(loc, prevElement, tmpAddr);
-          cloneRegionBodyInto(bodyBlock, prevElement);
-        }
-
-        builder.createYield(loc);
-      });
+  mlir::Block *partialDtorBlock = nullptr;
+  if (auto arrayCtor = mlir::dyn_cast<cir::ArrayCtor>(op)) {
+    mlir::Region &partialDtor = arrayCtor.getPartialDtor();
+    if (!partialDtor.empty())
+      partialDtorBlock = &partialDtor.front();
+  }
+
+  auto emitCtorDtorLoop = [&]() {
+    builder.createDoWhile(
+        loc,
+        /*condBuilder=*/
+        [&](mlir::OpBuilder &b, mlir::Location loc) {
+          auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
+          auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
+                                        currentElement, stop);
+          builder.createCondition(cmp);
+        },
+        /*bodyBuilder=*/
+        [&](mlir::OpBuilder &b, mlir::Location loc) {
+          auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
+          if (isCtor) {
+            cloneRegionBodyInto(bodyBlock, currentElement);
+            mlir::Value stride = builder.getUnsignedInt(loc, 1, sizeTypeSize);
+            auto nextElement = cir::PtrStrideOp::create(builder, loc, eltTy,
+                                                        currentElement, stride);
+            builder.createStore(loc, nextElement, tmpAddr);
+          } else {
+            mlir::Value stride = builder.getSignedInt(loc, -1, sizeTypeSize);
+            auto prevElement = cir::PtrStrideOp::create(builder, loc, eltTy,
+                                                        currentElement, stride);
+            builder.createStore(loc, prevElement, tmpAddr);
+            cloneRegionBodyInto(bodyBlock, prevElement);
+          }
+
+          cir::YieldOp::create(b, loc);
+        });
+  };
+
+  if (partialDtorBlock) {
+    cir::CleanupScopeOp::create(
+        builder, loc, cir::CleanupKind::EH,
+        /*bodyBuilder=*/
+        [&](mlir::OpBuilder &b, mlir::Location loc) {
+          emitCtorDtorLoop();
+          cir::YieldOp::create(b, loc);
+        },
+        /*cleanupBuilder=*/
+        [&](mlir::OpBuilder &b, mlir::Location loc) {
+          auto cur = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
+          auto cmp =
+              cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, cur, begin);
+          cir::IfOp::create(
+              builder, loc, cmp, /*withElseRegion=*/false,
+              [&](mlir::OpBuilder &b, mlir::Location loc) {
+                builder.createDoWhile(
+                    loc,
+                    /*condBuilder=*/
+                    [&](mlir::OpBuilder &b, mlir::Location loc) {
+                      auto el = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
+                      auto neq = cir::CmpOp::create(
+                          builder, loc, cir::CmpOpKind::ne, el, begin);
+                      builder.createCondition(neq);
+                    },
+                    /*bodyBuilder=*/
+                    [&](mlir::OpBuilder &b, mlir::Location loc) {
+                      auto el = cir::LoadOp::create(b, loc, eltTy, tmpAddr);
+                      mlir::Value negOne =
+                          builder.getSignedInt(loc, -1, sizeTypeSize);
+                      auto prev = cir::PtrStrideOp::create(builder, loc, eltTy,
+                                                           el, negOne);
+                      builder.createStore(loc, prev, tmpAddr);
+                      cloneRegionBodyInto(partialDtorBlock, prev);
+                      builder.createYield(loc);
+                    });
+                cir::YieldOp::create(builder, loc);
+              });
+          cir::YieldOp::create(b, loc);
+        });
+  } else {
+    emitCtorDtorLoop();
+  }
 
   if (ifOp)
     cir::YieldOp::create(builder, loc);

diff  --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp
index 2233529a192c8..4a3a4f51db13b 100644
--- a/clang/test/CIR/CodeGen/array-ctor.cpp
+++ b/clang/test/CIR/CodeGen/array-ctor.cpp
@@ -19,7 +19,6 @@ void foo() {
 // CIR-BEFORE-LPP:   cir.array.ctor %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 42>> {
 // CIR-BEFORE-LPP:    ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>):
 // CIR-BEFORE-LPP:      cir.call @_ZN1SC1Ev(%[[ARG]]) : (!cir.ptr<!rec_S>{{.*}}) -> ()
-// CIR-BEFORE-LPP:      cir.yield
 // CIR-BEFORE-LPP:    }
 // CIR-BEFORE-LPP:   cir.return
 // CIR-BEFORE-LPP: }
@@ -115,7 +114,6 @@ void multi_dimensional() {
 // CIR-BEFORE-LPP:       cir.array.ctor %[[FLAT]] : !cir.ptr<!cir.array<!rec_S x 15>> {
 // CIR-BEFORE-LPP:        ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>):
 // CIR-BEFORE-LPP:          cir.call @_ZN1SC1Ev(%[[ARG]]) : (!cir.ptr<!rec_S>{{.*}}) -> ()
-// CIR-BEFORE-LPP:          cir.yield
 // CIR-BEFORE-LPP:       }
 // CIR-BEFORE-LPP:       cir.return
 

diff  --git a/clang/test/CIR/CodeGen/array-dtor.cpp b/clang/test/CIR/CodeGen/array-dtor.cpp
index d37b6323575d6..5bfe9ac897cb7 100644
--- a/clang/test/CIR/CodeGen/array-dtor.cpp
+++ b/clang/test/CIR/CodeGen/array-dtor.cpp
@@ -19,7 +19,6 @@ void test_cleanup_array() {
 // CIR-BEFORE-LPP:   cir.array.dtor %[[S]] : !cir.ptr<!cir.array<!rec_S x 42>> {
 // CIR-BEFORE-LPP:   ^bb0(%arg0: !cir.ptr<!rec_S>
 // CIR-BEFORE-LPP:     cir.call @_ZN1SD1Ev(%arg0) nothrow : (!cir.ptr<!rec_S> {{.*}}) -> ()
-// CIR-BEFORE-LPP:     cir.yield
 // CIR-BEFORE-LPP:   }
 // CIR-BEFORE-LPP:   cir.return
 
@@ -113,7 +112,6 @@ void multi_dimensional() {
 // CIR-BEFORE-LPP:       cir.array.dtor %[[FLAT]] : !cir.ptr<!cir.array<!rec_S x 15>> {
 // CIR-BEFORE-LPP:       ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>):
 // CIR-BEFORE-LPP:         cir.call @_ZN1SD1Ev(%[[ARG]]) nothrow : (!cir.ptr<!rec_S> {{.*}}) -> ()
-// CIR-BEFORE-LPP:         cir.yield
 // CIR-BEFORE-LPP:       }
 // CIR-BEFORE-LPP:       cir.return
 

diff  --git a/clang/test/CIR/CodeGen/global-array-dtor.cpp b/clang/test/CIR/CodeGen/global-array-dtor.cpp
index 61b1717b156fb..49c8e279c2678 100644
--- a/clang/test/CIR/CodeGen/global-array-dtor.cpp
+++ b/clang/test/CIR/CodeGen/global-array-dtor.cpp
@@ -22,7 +22,6 @@ ArrayDtor arrDtor[16];
 // CIR-BEFORE-LPP:          cir.array.dtor %[[THIS]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> {
 // CIR-BEFORE-LPP:          ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_ArrayDtor>):
 // CIR-BEFORE-LPP:            cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr<!rec_ArrayDtor> {{.*}}) -> ()
-// CIR-BEFORE-LPP:            cir.yield
 // CIR-BEFORE-LPP:          }
 // CIR-BEFORE-LPP:        }
 

diff  --git a/clang/test/CIR/CodeGen/global-init.cpp b/clang/test/CIR/CodeGen/global-init.cpp
index 7c6405543b3fe..7ef21cab24940 100644
--- a/clang/test/CIR/CodeGen/global-init.cpp
+++ b/clang/test/CIR/CodeGen/global-init.cpp
@@ -183,7 +183,6 @@ ArrayDtor arrDtor[16];
 // CIR-BEFORE-LPP:          cir.array.dtor %[[THIS]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> {
 // CIR-BEFORE-LPP:          ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_ArrayDtor>):
 // CIR-BEFORE-LPP:            cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr<!rec_ArrayDtor> {{.*}}) -> ()
-// CIR-BEFORE-LPP:            cir.yield
 // CIR-BEFORE-LPP:          }
 // CIR-BEFORE-LPP:        }
 

diff  --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp
index 7da943de355ef..503b395244bd8 100644
--- a/clang/test/CIR/CodeGen/new.cpp
+++ b/clang/test/CIR/CodeGen/new.cpp
@@ -742,7 +742,6 @@ void test_array_new_with_ctor_init() {
 // CIR-BEFORE-LPP:    cir.array.ctor %[[ARRAY_PTR]] : !cir.ptr<!cir.array<!rec_F x 3>> {
 // CIR-BEFORE-LPP:    ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_F>):
 // CIR-BEFORE-LPP:      cir.call @_ZN1FC1Ev(%[[ARG]]) : (!cir.ptr<!rec_F> {{.*}}) -> ()
-// CIR-BEFORE-LPP:      cir.yield
 // CIR-BEFORE-LPP:    }
 // CIR-BEFORE-LPP:    cir.store{{.*}} %[[BEGIN]], %[[P_ADDR]] : !cir.ptr<!rec_F>, !cir.ptr<!cir.ptr<!rec_F>>
 // CIR-BEFORE-LPP:    cir.return
@@ -868,7 +867,6 @@ void test_const_array_new_value_init() {
 // CIR-BEFORE-LPP:     cir.const #cir.zero : !rec_OuterZero
 // CIR-BEFORE-LPP:     cir.store{{.*}} %{{.*}}, %[[EL]] : !rec_OuterZero, !cir.ptr<!rec_OuterZero>
 // CIR-BEFORE-LPP:     cir.call @_ZN9OuterZeroC1Ev(%[[EL]])
-// CIR-BEFORE-LPP:     cir.yield
 // CIR-BEFORE-LPP:   }
 
 // CHECK: cir.func{{.*}} @_Z31test_const_array_new_value_initv
@@ -949,7 +947,6 @@ void test_var_array_new_value_init(int n) {
 // CIR-BEFORE-LPP-NEXT:    cir.const #cir.zero : !rec_OuterZero
 // CIR-BEFORE-LPP-NEXT:    cir.store{{.*}} %{{.*}}, %[[EL]] : !rec_OuterZero, !cir.ptr<!rec_OuterZero>
 // CIR-BEFORE-LPP-NEXT:    cir.call @_ZN9OuterZeroC1Ev(%[[EL]]) : (!cir.ptr<!rec_OuterZero> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nonnull, llvm.noundef}) -> ()
-// CIR-BEFORE-LPP-NEXT:    cir.yield
 // CIR-BEFORE-LPP-NEXT:  }
 
 // CHECK-LABEL: cir.func{{.*}} @_Z29test_var_array_new_value_initi
@@ -990,7 +987,6 @@ void test_multidim_array_new_with_ctor() {
 // CIR-BEFORE-LPP:   cir.array.ctor %[[FLAT]] : !cir.ptr<!cir.array<!rec_F x 6>> {
 // CIR-BEFORE-LPP:   ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_F>):
 // CIR-BEFORE-LPP:     cir.call @_ZN1FC1Ev(%[[ARG]])
-// CIR-BEFORE-LPP:     cir.yield
 // CIR-BEFORE-LPP:   }
 // CIR-BEFORE-LPP:   cir.store{{.*}} %[[PTR3]],
 
@@ -1059,7 +1055,6 @@ void test_multidim_var_array_new_with_ctor(int n) {
 // CIR-BEFORE-LPP:    cir.array.ctor %[[ELPTR]], %[[TOTAL]] : !cir.ptr<!rec_F>, !u64i {
 // CIR-BEFORE-LPP:    ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_F>):
 // CIR-BEFORE-LPP:      cir.call @_ZN1FC1Ev(%[[ARG]])
-// CIR-BEFORE-LPP:      cir.yield
 // CIR-BEFORE-LPP:    }
 
 // CHECK-LABEL: cir.func{{.*}} @_Z37test_multidim_var_array_new_with_ctori
@@ -1129,7 +1124,6 @@ void test_array_new_with_ctor_partial_init_list() {
 // CIR-BEFORE-LPP:    cir.array.ctor %[[TAIL_ARRAY]] : !cir.ptr<!cir.array<!rec_G x 6>> {
 // CIR-BEFORE-LPP:    ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_G>):
 // CIR-BEFORE-LPP:      cir.call @_ZN1GC1Ev(%[[ELEM]]) : (!cir.ptr<!rec_G> {{.*}}) -> ()
-// CIR-BEFORE-LPP:      cir.yield
 // CIR-BEFORE-LPP:    }
 // CIR-BEFORE-LPP:    cir.store{{.*}} %[[BEGIN]], %[[P_ADDR]]
 // CIR-BEFORE-LPP:    cir.return

diff  --git a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
new file mode 100644
index 0000000000000..7c260a6f13cb0
--- /dev/null
+++ b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
@@ -0,0 +1,161 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -fexceptions -fcxx-exceptions -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir  2> %t-before-lp.cir
+// RUN: FileCheck --input-file=%t-before-lp.cir %s -check-prefix=CIR-BEFORE-LPP
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fexceptions -fcxx-exceptions -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fexceptions -fcxx-exceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+struct S {
+    S();
+    ~S();
+};
+
+void test_partial_array_cleanup() {
+    S s[4];
+}
+
+// CIR-BEFORE-LPP:     cir.func {{.*}} @_Z26test_partial_array_cleanupv()
+// CIR-BEFORE-LPP:       %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 4>, !cir.ptr<!cir.array<!rec_S x 4>>, ["s", init]
+// CIR-BEFORE-LPP:       cir.array.ctor %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 4>> {
+// CIR-BEFORE-LPP:       ^bb0(%[[CTOR_ARG:.*]]: !cir.ptr<!rec_S>):
+// CIR-BEFORE-LPP:         cir.call @_ZN1SC1Ev(%[[CTOR_ARG]]) : (!cir.ptr<!rec_S>{{.*}}) -> ()
+// CIR-BEFORE-LPP:       } partial_dtor {
+// CIR-BEFORE-LPP:       ^bb0(%[[DTOR_ARG:.*]]: !cir.ptr<!rec_S>):
+// CIR-BEFORE-LPP:         cir.call @_ZN1SD1Ev(%[[DTOR_ARG]]){{.*}} : (!cir.ptr<!rec_S>{{.*}}) -> ()
+// CIR-BEFORE-LPP:       }
+
+// CIR:     cir.func {{.*}} @_Z26test_partial_array_cleanupv()
+// CIR:       %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 4>, !cir.ptr<!cir.array<!rec_S x 4>>, ["s", init]
+// CIR:       %[[CONST4:.*]] = cir.const #cir.int<4> : !u64i
+// CIR:       %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 4>> -> !cir.ptr<!rec_S>
+// CIR:       %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[CONST4]] : (!cir.ptr<!rec_S>, !u64i) -> !cir.ptr<!rec_S>
+// CIR:       %[[ITER:.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["__array_idx"]
+// CIR:       cir.store %[[BEGIN]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>
+// CIR:       cir.cleanup.scope {
+// CIR:         cir.do {
+// CIR:           %[[CUR:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:           cir.call @_ZN1SC1Ev(%[[CUR]]) : (!cir.ptr<!rec_S>{{.*}}) -> ()
+// CIR:           %[[CONST1:.*]] = cir.const #cir.int<1> : !u64i
+// CIR:           %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[CONST1]] : (!cir.ptr<!rec_S>, !u64i) -> !cir.ptr<!rec_S>
+// CIR:           cir.store %[[NEXT]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>
+// CIR:           cir.yield
+// CIR:         } while {
+// CIR:           %[[CUR2:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:           %[[CMP:.*]] = cir.cmp ne %[[CUR2]], %[[END]] : !cir.ptr<!rec_S>
+// CIR:           cir.condition(%[[CMP]])
+// CIR:         }
+// CIR:         cir.yield
+// CIR:       } cleanup eh {
+// CIR:         %[[CUR3:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:         %[[NE:.*]] = cir.cmp ne %[[CUR3]], %[[BEGIN]] : !cir.ptr<!rec_S>
+// CIR:         cir.if %[[NE]] {
+// CIR:           cir.do {
+// CIR:             %[[EL:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:             %[[NEG1:.*]] = cir.const #cir.int<-1> : !s64i
+// CIR:             %[[PREV:.*]] = cir.ptr_stride %[[EL]], %[[NEG1]] : (!cir.ptr<!rec_S>, !s64i) -> !cir.ptr<!rec_S>
+// CIR:             cir.store %[[PREV]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>
+// CIR:             cir.call @_ZN1SD1Ev(%[[PREV]]){{.*}} : (!cir.ptr<!rec_S>{{.*}}) -> ()
+// CIR:             cir.yield
+// CIR:           } while {
+// CIR:             %[[EL2:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:             %[[NE2:.*]] = cir.cmp ne %[[EL2]], %[[BEGIN]] : !cir.ptr<!rec_S>
+// CIR:             cir.condition(%[[NE2]])
+// CIR:           }
+// CIR:         }
+// CIR:         cir.yield
+// CIR:       }
+
+// LLVM:     define dso_local void @_Z26test_partial_array_cleanupv()
+// LLVM:       %[[ARRAY:.*]] = alloca [4 x %struct.S]
+// LLVM:       %[[BEGIN:.*]] = getelementptr %struct.S, ptr %[[ARRAY]], i32 0
+// LLVM:       %[[END:.*]] = getelementptr %struct.S, ptr %[[BEGIN]], i64 4
+// LLVM:       %[[ITER:.*]] = alloca ptr
+// LLVM:       store ptr %[[BEGIN]], ptr %[[ITER]]
+//
+//            --- ctor loop condition ---
+// LLVM:     [[CLEANUP_SCOPE:.*]]:
+// LLVM:       br label %[[CTOR_LOOP_COND:.*]]
+//
+// LLVM:     [[CTOR_LOOP_COND:]]:
+// LLVM:       %[[COND_CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       %[[CTOR_DONE:.*]] = icmp ne ptr %[[COND_CUR]], %[[END]]
+// LLVM:       br i1 %[[CTOR_DONE]], label %[[CTOR_BODY:.*]], label %[[CTOR_EXIT:.*]]
+//
+//            --- ctor loop body ---
+// LLVM:     [[CTOR_BODY]]:
+// LLVM:       %[[CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       invoke void @_ZN1SC1Ev(ptr{{.*}} %[[CUR]])
+// LLVM:         to label %[[CTOR_CONT:.*]] unwind label %[[LPAD:.*]]
+//
+// LLVM:     [[CTOR_CONT]]:
+// LLVM:       %[[NEXT:.*]] = getelementptr %struct.S, ptr %[[CUR]], i64 1
+// LLVM:       store ptr %[[NEXT]], ptr %[[ITER]]
+// LLVM:       br label %[[CTOR_LOOP_COND]]
+//
+//            --- landing pad + cleanup guard ---
+// LLVM:     [[LPAD]]:
+// LLVM:       landingpad { ptr, i32 }
+// LLVM:         cleanup
+// LLVM:       %[[PAD_CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       %[[GUARD:.*]] = icmp ne ptr %[[PAD_CUR]], %[[BEGIN]]
+// LLVM:       br i1 %[[GUARD]], label %[[DTOR_ENTRY:.*]], label %[[EH_RESUME:.*]]
+//
+//            --- partial dtor do-while entry ---
+// LLVM:     [[DTOR_ENTRY]]:
+// LLVM:       br label %[[DTOR_BODY:.*]]
+//
+//            --- partial dtor loop condition (back-edge) ---
+// LLVM:     [[DTOR_LOOP_COND:.*]]:
+// LLVM:       %[[DTOR_CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       %[[DTOR_CONT:.*]] = icmp ne ptr %[[DTOR_CUR]], %[[BEGIN]]
+// LLVM:       br i1 %[[DTOR_CONT]], label %[[DTOR_BODY]], label %[[DTOR_DONE:.*]]
+//
+//            --- partial dtor loop body ---
+// LLVM:     [[DTOR_BODY]]:
+// LLVM:       %[[DCUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       %[[PREV:.*]] = getelementptr %struct.S, ptr %[[DCUR]], i64 -1
+// LLVM:       store ptr %[[PREV]], ptr %[[ITER]]
+// LLVM:       call void @_ZN1SD1Ev(ptr{{.*}} %[[PREV]])
+// LLVM:       br label %[[DTOR_LOOP_COND]]
+//
+// LLVM:     [[DTOR_DONE]]:
+// LLVM:       br label %[[EH_RESUME]]
+//
+// LLVM:     [[EH_RESUME]]:
+// LLVM:       resume { ptr, i32 }
+
+// OGCG:     define dso_local void @_Z26test_partial_array_cleanupv()
+// OGCG:     [[ENTRY:.*]]:
+// OGCG:       %[[ARRAY:.*]] = alloca [4 x %struct.S]
+// OGCG:       %[[BEGIN:.*]] = getelementptr inbounds [4 x %struct.S], ptr %[[ARRAY]], i32 0, i32 0
+// OGCG:       %[[END:.*]] = getelementptr inbounds %struct.S, ptr %[[BEGIN]], i64 4
+//
+//            --- ctor loop ---
+// OGCG:     [[CTOR_BODY:.*]]:
+// OGCG:       %[[CUR:.*]] = phi ptr [ %[[BEGIN]], %[[ENTRY]] ], [ %[[NEXT:.*]], %[[CONT:.*]] ]
+// OGCG:       invoke void @_ZN1SC1Ev(ptr{{.*}})
+// OGCG:         to label %[[CONT]] unwind label %[[LPAD:.*]]
+//
+// OGCG:     [[CONT]]:
+// OGCG:       %[[NEXT]] = getelementptr inbounds %struct.S, ptr %[[CUR]], i64 1
+// OGCG:       %[[DONE:.*]] = icmp eq ptr %[[NEXT]], %[[END]]
+// OGCG:       br i1 %[[DONE]], label %[[CTOR_EXIT:.*]], label %[[CTOR_BODY:.*]]
+//
+//            --- landing pad + cleanup guard ---
+// OGCG:     [[LPAD]]:
+// OGCG:       landingpad { ptr, i32 }
+// OGCG:         cleanup
+// OGCG:       %[[ISEMPTY:.*]] = icmp eq ptr %[[BEGIN]], %[[CUR]]
+// OGCG:       br i1 %[[ISEMPTY]], label %[[EH_RESUME:.*]], label %[[DTOR_LOOP:.*]]
+//
+//            --- partial dtor loop ---
+// OGCG:     [[DTOR_LOOP]]:
+// OGCG:       %[[PAST:.*]] = phi ptr [ %[[CUR]], %[[LPAD]] ], [ %[[PREV:.*]], %[[DTOR_LOOP]] ]
+// OGCG:       %[[PREV]] = getelementptr inbounds %struct.S, ptr %[[PAST]], i64 -1
+// OGCG:       call void @_ZN1SD1Ev(ptr{{.*}} %[[PREV]])
+// OGCG:       %[[DDONE:.*]] = icmp eq ptr %[[PREV]], %[[BEGIN]]
+// OGCG:       br i1 %[[DDONE]], label %[[EH_RESUME]], label %[[DTOR_LOOP]]
+//
+// OGCG:     [[EH_RESUME]]:
+// OGCG:       resume { ptr, i32 }

diff  --git a/clang/test/CIR/IR/array-ctor.cir b/clang/test/CIR/IR/array-ctor.cir
index 0a71b1e4dee6d..b68108b1763eb 100644
--- a/clang/test/CIR/IR/array-ctor.cir
+++ b/clang/test/CIR/IR/array-ctor.cir
@@ -12,7 +12,6 @@ module {
     cir.array.ctor %0 : !cir.ptr<!cir.array<!rec_S x 42>> {
     ^bb0(%arg0: !cir.ptr<!rec_S>):
       cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
-      cir.yield
     }
     cir.return
   }
@@ -23,7 +22,6 @@ module {
   // CHECK:   cir.array.ctor %0 : !cir.ptr<!cir.array<!rec_S x 42>> {
   // CHECK:   ^bb0(%arg0: !cir.ptr<!rec_S>):
   // CHECK:     cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
-  // CHECK:     cir.yield
   // CHECK:   }
   // CHECK:   cir.return
   // CHECK: }
@@ -32,7 +30,6 @@ module {
     cir.array.ctor %p, %n : !cir.ptr<!rec_S>, !u64i {
     ^bb0(%e: !cir.ptr<!rec_S>):
       cir.call @_ZN1SC1Ev(%e) : (!cir.ptr<!rec_S>) -> ()
-      cir.yield
     }
     cir.return
   }
@@ -41,7 +38,6 @@ module {
   // CHECK:   cir.array.ctor %{{.*}}, %{{.*}} : !cir.ptr<!rec_S>, !u64i {
   // CHECK:   ^bb0(%{{.*}}: !cir.ptr<!rec_S>):
   // CHECK:     cir.call @_ZN1SC1Ev(%{{.*}}) : (!cir.ptr<!rec_S>) -> ()
-  // CHECK:     cir.yield
   // CHECK:   }
   // CHECK:   cir.return
   // CHECK: }

diff  --git a/clang/test/CIR/IR/array-dtor.cir b/clang/test/CIR/IR/array-dtor.cir
index 1bb9ff9169a9d..37515f98626be 100644
--- a/clang/test/CIR/IR/array-dtor.cir
+++ b/clang/test/CIR/IR/array-dtor.cir
@@ -10,7 +10,6 @@ module {
     cir.array.dtor %0 : !cir.ptr<!cir.array<!rec_S x 42>> {
     ^bb0(%arg0: !cir.ptr<!rec_S>):
       cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
-      cir.yield
     }
     cir.return
   }
@@ -21,7 +20,6 @@ module {
   // CHECK:   cir.array.dtor %0 : !cir.ptr<!cir.array<!rec_S x 42>> {
   // CHECK:   ^bb0(%arg0: !cir.ptr<!rec_S>):
   // CHECK:     cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
-  // CHECK:     cir.yield
   // CHECK:   }
   // CHECK:   cir.return
   // CHECK: }

diff  --git a/clang/test/CIR/IR/invalid-array-structor.cir b/clang/test/CIR/IR/invalid-array-structor.cir
index 0ab030231f703..233b3524a2369 100644
--- a/clang/test/CIR/IR/invalid-array-structor.cir
+++ b/clang/test/CIR/IR/invalid-array-structor.cir
@@ -10,7 +10,6 @@ module {
     // expected-error at +1 {{'cir.array.ctor' op when 'num_elements' is present, 'addr' must be a pointer to a !cir.record type}}
     cir.array.ctor %p, %n : !cir.ptr<!cir.array<!rec_S x 10>>, !u64i {
     ^bb0(%e: !cir.ptr<!cir.array<!rec_S x 10>>):
-      cir.yield
     }
     cir.return
   }
@@ -31,7 +30,6 @@ module {
     cir.array.ctor %p : !cir.ptr<!rec_S> {
     ^bb0(%e: !cir.ptr<!rec_S>):
       cir.call @_ZN1SC1Ev(%e) : (!cir.ptr<!rec_S>) -> ()
-      cir.yield
     }
     cir.return
   }
@@ -51,7 +49,6 @@ module {
     cir.array.ctor %p : !cir.ptr<!cir.array<!u8i x 4>> {
     ^bb0(%e: !cir.ptr<!u8i>):
       cir.call @construct_int(%e) : (!cir.ptr<!u8i>) -> ()
-      cir.yield
     }
     cir.return
   }
@@ -72,7 +69,6 @@ module {
     // expected-error at +1 {{'cir.array.ctor' op block argument pointee type must match the innermost array element type}}
     cir.array.ctor %p : !cir.ptr<!cir.array<!rec_S x 10>> {
     ^bb0(%e: !cir.ptr<!rec_T>):
-      cir.yield
     }
     cir.return
   }
@@ -94,7 +90,6 @@ module {
     cir.array.ctor %p, %n : !cir.ptr<!rec_T>, !u64i {
     ^bb0(%e: !cir.ptr<!rec_S>):
       cir.call @_ZN1SC1Ev(%e) : (!cir.ptr<!rec_S>) -> ()
-      cir.yield
     }
     cir.return
   }
@@ -111,7 +106,6 @@ module {
     // expected-error at +1 {{'cir.array.dtor' op when 'num_elements' is present, 'addr' must be a pointer to a !cir.record type}}
     cir.array.dtor %p, %n : !cir.ptr<!cir.array<!rec_S x 10>>, !u64i {
     ^bb0(%e: !cir.ptr<!cir.array<!rec_S x 10>>):
-      cir.yield
     }
     cir.return
   }
@@ -129,7 +123,6 @@ module {
     // expected-error at +1 {{'cir.array.dtor' op when 'num_elements' is absent, 'addr' must be a pointer to a !cir.array type}}
     cir.array.dtor %p : !cir.ptr<!rec_S> {
     ^bb0(%e: !cir.ptr<!rec_S>):
-      cir.yield
     }
     cir.return
   }
@@ -149,7 +142,6 @@ module {
     cir.array.dtor %p : !cir.ptr<!cir.array<!u8i x 4>> {
     ^bb0(%e: !cir.ptr<!u8i>):
       cir.call @destroy_int(%e) : (!cir.ptr<!u8i>) -> ()
-      cir.yield
     }
     cir.return
   }
@@ -168,7 +160,6 @@ module {
     // expected-error at +1 {{'cir.array.dtor' op block argument pointee type must match the innermost array element type}}
     cir.array.dtor %p: !cir.ptr<!cir.array<!rec_S x 10>> {
     ^bb0(%e: !cir.ptr<!rec_T>):
-      cir.yield
     }
     cir.return
   }
@@ -189,7 +180,6 @@ module {
     // expected-error at +1 {{'cir.array.dtor' op block argument pointee type must match the innermost array element type}}
     cir.array.dtor %p : !cir.ptr<!cir.array<!rec_S x 10>> {
     ^bb0(%e: !cir.ptr<!rec_T>):
-      cir.yield
     }
     cir.return
   }
@@ -211,7 +201,6 @@ module {
     cir.array.dtor %p, %n : !cir.ptr<!rec_T>, !u64i {
     ^bb0(%e: !cir.ptr<!rec_S>):
       cir.call @_ZN1SD1Ev(%e) : (!cir.ptr<!rec_S>) -> ()
-      cir.yield
     }
     cir.return
   }


        


More information about the cfe-commits mailing list