[clang] b4a95fe - [CIR] Fix destructor calls with temporary objects (#161922)

via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 6 15:46:51 PDT 2025


Author: Andy Kaylor
Date: 2025-10-06T15:46:47-07:00
New Revision: b4a95fe9f1643227a54612f25c8498ec7f16952b

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

LOG: [CIR] Fix destructor calls with temporary objects (#161922)

This fixes a few problems where destructors were not called for
temporary objects and, after calling was enabled, they were placed
incorrectly relative to cir.yield operations.

Added: 
    clang/test/CIR/CodeGen/dtors.cpp

Modified: 
    clang/lib/CIR/CodeGen/CIRGenClass.cpp
    clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
    clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
    clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/lib/CIR/CodeGen/CIRGenValue.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index 9d12a13dd79c0..8f4377b435775 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -690,7 +690,7 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
   // every temporary created in a default argument expression is sequenced
   // before the construction of the next array element, if any.
   {
-    assert(!cir::MissingFeatures::runCleanupsScope());
+    RunCleanupsScope scope(*this);
 
     // Evaluate the constructor and its arguments in a regular
     // partial-destroy cleanup.

diff  --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
index 4d4d10be40024..870069715df22 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
@@ -28,6 +28,12 @@ using namespace clang::CIRGen;
 // CIRGenFunction cleanup related
 //===----------------------------------------------------------------------===//
 
+/// Emits all the code to cause the given temporary to be cleaned up.
+void CIRGenFunction::emitCXXTemporary(const CXXTemporary *temporary,
+                                      QualType tempType, Address ptr) {
+  pushDestroy(NormalAndEHCleanup, ptr, tempType, destroyCXXObject);
+}
+
 //===----------------------------------------------------------------------===//
 // EHScopeStack
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 60ccf18b743df..901b937e4e3e7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -46,6 +46,12 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
     return dest;
   }
 
+  void ensureDest(mlir::Location loc, QualType ty) {
+    if (!dest.isIgnored())
+      return;
+    dest = cgf.createAggTemp(ty, loc, "agg.tmp.ensured");
+  }
+
 public:
   AggExprEmitter(CIRGenFunction &cgf, AggValueSlot dest)
       : cgf(cgf), dest(dest) {}
@@ -96,10 +102,22 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
     Visit(die->getExpr());
   }
   void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *e) {
-    assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());
+    // Ensure that we have a slot, but if we already do, remember
+    // whether it was externally destructed.
+    bool wasExternallyDestructed = dest.isExternallyDestructed();
+    ensureDest(cgf.getLoc(e->getSourceRange()), e->getType());
+
+    // We're going to push a destructor if there isn't already one.
+    dest.setExternallyDestructed();
+
     Visit(e->getSubExpr());
+
+    // Push that destructor we promised.
+    if (!wasExternallyDestructed)
+      cgf.emitCXXTemporary(e->getTemporary(), e->getType(), dest.getAddress());
   }
   void VisitLambdaExpr(LambdaExpr *e);
+  void VisitExprWithCleanups(ExprWithCleanups *e);
 
   // Stubs -- These should be moved up when they are implemented.
   void VisitCastExpr(CastExpr *e) {
@@ -241,11 +259,6 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
     cgf.cgm.errorNYI(e->getSourceRange(),
                      "AggExprEmitter: VisitCXXStdInitializerListExpr");
   }
-
-  void VisitExprWithCleanups(ExprWithCleanups *e) {
-    cgf.cgm.errorNYI(e->getSourceRange(),
-                     "AggExprEmitter: VisitExprWithCleanups");
-  }
   void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
     cgf.cgm.errorNYI(e->getSourceRange(),
                      "AggExprEmitter: VisitCXXScalarValueInitExpr");
@@ -588,6 +601,11 @@ void AggExprEmitter::VisitLambdaExpr(LambdaExpr *e) {
   }
 }
 
+void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) {
+  CIRGenFunction::RunCleanupsScope cleanups(cgf);
+  Visit(e->getSubExpr());
+}
+
 void AggExprEmitter::VisitCallExpr(const CallExpr *e) {
   if (e->getCallReturnType(cgf.getContext())->isReferenceType()) {
     cgf.cgm.errorNYI(e->getSourceRange(), "reference return type");

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 768d75dc35394..5d3496a637268 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -1099,15 +1099,17 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
           CIRGenFunction::LexicalScope lexScope{cgf, loc,
                                                 b.getInsertionBlock()};
           cgf.curLexScope->setAsTernary();
-          b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));
+          mlir::Value res = cgf.evaluateExprAsBool(e->getRHS());
+          lexScope.forceCleanup();
+          cir::YieldOp::create(b, loc, res);
         },
         /*falseBuilder*/
         [&](mlir::OpBuilder &b, mlir::Location loc) {
           CIRGenFunction::LexicalScope lexScope{cgf, loc,
                                                 b.getInsertionBlock()};
           cgf.curLexScope->setAsTernary();
-          auto res = b.create<cir::ConstantOp>(loc, builder.getFalseAttr());
-          b.create<cir::YieldOp>(loc, res.getRes());
+          auto res = cir::ConstantOp::create(b, loc, builder.getFalseAttr());
+          cir::YieldOp::create(b, loc, res.getRes());
         });
     return maybePromoteBoolResult(resOp.getResult(), resTy);
   }
@@ -1143,15 +1145,17 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
           CIRGenFunction::LexicalScope lexScope{cgf, loc,
                                                 b.getInsertionBlock()};
           cgf.curLexScope->setAsTernary();
-          auto res = b.create<cir::ConstantOp>(loc, builder.getTrueAttr());
-          b.create<cir::YieldOp>(loc, res.getRes());
+          auto res = cir::ConstantOp::create(b, loc, builder.getTrueAttr());
+          cir::YieldOp::create(b, loc, res.getRes());
         },
         /*falseBuilder*/
         [&](mlir::OpBuilder &b, mlir::Location loc) {
           CIRGenFunction::LexicalScope lexScope{cgf, loc,
                                                 b.getInsertionBlock()};
           cgf.curLexScope->setAsTernary();
-          b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));
+          mlir::Value res = cgf.evaluateExprAsBool(e->getRHS());
+          lexScope.forceCleanup();
+          cir::YieldOp::create(b, loc, res);
         });
 
     return maybePromoteBoolResult(resOp.getResult(), resTy);

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index dfd9d2ccf0313..cbc0f4a068d7b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1258,6 +1258,9 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr);
 
+  void emitCXXTemporary(const CXXTemporary *temporary, QualType tempType,
+                        Address ptr);
+
   void emitCXXThrowExpr(const CXXThrowExpr *e);
 
   void emitCtorPrologue(const clang::CXXConstructorDecl *ctor,

diff  --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h
index ea8625a0fbee5..25b6ecb503a6e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -371,6 +371,13 @@ class AggValueSlot {
                    mayOverlap, isZeroed);
   }
 
+  IsDestructed_t isExternallyDestructed() const {
+    return IsDestructed_t(destructedFlag);
+  }
+  void setExternallyDestructed(bool destructed = true) {
+    destructedFlag = destructed;
+  }
+
   clang::Qualifiers getQualifiers() const { return quals; }
 
   Address getAddress() const { return addr; }

diff  --git a/clang/test/CIR/CodeGen/dtors.cpp b/clang/test/CIR/CodeGen/dtors.cpp
new file mode 100644
index 0000000000000..66554b70e1700
--- /dev/null
+++ b/clang/test/CIR/CodeGen/dtors.cpp
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -mconstructor-aliases -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 -std=c++20 -mconstructor-aliases -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+struct A {
+  ~A();
+};
+
+void test_temporary_dtor() {
+  A();
+}
+
+// CIR: cir.func dso_local @_Z19test_temporary_dtorv()
+// CIR:   %[[ALLOCA:.*]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["agg.tmp0"]
+// CIR:   cir.call @_ZN1AD1Ev(%[[ALLOCA]]) nothrow : (!cir.ptr<!rec_A>) -> ()
+
+// LLVM: define dso_local void @_Z19test_temporary_dtorv()
+// LLVM:   %[[ALLOCA:.*]] = alloca %struct.A, i64 1, align 1
+// LLVM:   call void @_ZN1AD1Ev(ptr %[[ALLOCA]])
+
+// OGCG: define dso_local void @_Z19test_temporary_dtorv()
+// OGCG:   %[[ALLOCA:.*]] = alloca %struct.A, align 1
+// OGCG:   call void @_ZN1AD1Ev(ptr {{.*}} %[[ALLOCA]])
+
+struct B {
+  int n;
+  B(int n) : n(n) {}
+  ~B() {}
+};
+
+bool make_temp(const B &) { return false; }
+bool test_temp_or() { return make_temp(1) || make_temp(2); }
+
+// CIR: cir.func{{.*}} @_Z12test_temp_orv()
+// CIR:   %[[SCOPE:.*]] = cir.scope {
+// CIR:     %[[REF_TMP0:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp0"]
+// CIR:     %[[ONE:.*]] = cir.const #cir.int<1>
+// CIR:     cir.call @_ZN1BC2Ei(%[[REF_TMP0]], %[[ONE]])
+// CIR:     %[[MAKE_TEMP0:.*]] = cir.call @_Z9make_tempRK1B(%[[REF_TMP0]])
+// CIR:     %[[TERNARY:.*]] = cir.ternary(%[[MAKE_TEMP0]], true {
+// CIR:       %[[TRUE:.*]] = cir.const #true
+// CIR:       cir.yield %[[TRUE]] : !cir.bool
+// CIR:     }, false {
+// CIR:       %[[REF_TMP1:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp1"]
+// CIR:       %[[TWO:.*]] = cir.const #cir.int<2>
+// CIR:       cir.call @_ZN1BC2Ei(%[[REF_TMP1]], %[[TWO]])
+// CIR:       %[[MAKE_TEMP1:.*]] = cir.call @_Z9make_tempRK1B(%[[REF_TMP1]])
+// CIR:       cir.call @_ZN1BD2Ev(%[[REF_TMP1]])
+// CIR:       cir.yield %[[MAKE_TEMP1]] : !cir.bool
+// CIR:     })
+// CIR:     cir.call @_ZN1BD2Ev(%[[REF_TMP0]])
+// CIR:     cir.yield %[[TERNARY]] : !cir.bool
+// CIR:   } : !cir.bool
+
+// LLVM: define{{.*}} i1 @_Z12test_temp_orv() {
+// LLVM:   %[[REF_TMP0:.*]] = alloca %struct.B
+// LLVM:   %[[REF_TMP1:.*]] = alloca %struct.B
+// LLVM:   br label %[[LOR_BEGIN:.*]]
+// LLVM: [[LOR_BEGIN]]:
+// LLVM:   call void @_ZN1BC2Ei(ptr %[[REF_TMP0]], i32 1)
+// LLVM:   %[[MAKE_TEMP0:.*]] = call i1 @_Z9make_tempRK1B(ptr %[[REF_TMP0]])
+// LLVM:   br i1 %[[MAKE_TEMP0]], label %[[LHS_TRUE_BLOCK:.*]], label %[[LHS_FALSE_BLOCK:.*]]
+// LLVM: [[LHS_TRUE_BLOCK]]:
+// LLVM:   br label %[[RESULT_BLOCK:.*]]
+// LLVM: [[LHS_FALSE_BLOCK]]:
+// LLVM:   call void @_ZN1BC2Ei(ptr %[[REF_TMP1]], i32 2)
+// LLVM:   %[[MAKE_TEMP1:.*]] = call i1 @_Z9make_tempRK1B(ptr %[[REF_TMP1]])
+// LLVM:   call void @_ZN1BD2Ev(ptr %[[REF_TMP1]])
+// LLVM:   br label %[[RESULT_BLOCK]]
+// LLVM: [[RESULT_BLOCK]]:
+// LLVM:   %[[RESULT:.*]] = phi i1 [ %[[MAKE_TEMP1]], %[[LHS_FALSE_BLOCK]] ], [ true, %[[LHS_TRUE_BLOCK]] ]
+// LLVM:   br label %[[LOR_END:.*]]
+// LLVM: [[LOR_END]]:
+// LLVM:   call void @_ZN1BD2Ev(ptr %[[REF_TMP0]])
+
+// OGCG: define {{.*}} i1 @_Z12test_temp_orv()
+// OGCG: [[ENTRY:.*]]:
+// OGCG:   %[[RETVAL:.*]] = alloca i1
+// OGCG:   %[[REF_TMP0:.*]] = alloca %struct.B
+// OGCG:   %[[REF_TMP1:.*]] = alloca %struct.B
+// OGCG:   %[[CLEANUP_COND:.*]] = alloca i1
+// OGCG:   call void @_ZN1BC2Ei(ptr {{.*}} %[[REF_TMP0]], i32 {{.*}} 1)
+// OGCG:   %[[MAKE_TEMP0:.*]] = call {{.*}} i1 @_Z9make_tempRK1B(ptr {{.*}} %[[REF_TMP0]])
+// OGCG:   store i1 false, ptr %cleanup.cond
+// OGCG:   br i1 %[[MAKE_TEMP0]], label %[[LOR_END:.*]], label %[[LOR_RHS:.*]]
+// OGCG: [[LOR_RHS]]:
+// OGCG:   call void @_ZN1BC2Ei(ptr {{.*}} %[[REF_TMP1]], i32 {{.*}} 2)
+// OGCG:   store i1 true, ptr %[[CLEANUP_COND]]
+// OGCG:   %[[MAKE_TEMP1:.*]] = call {{.*}} i1 @_Z9make_tempRK1B(ptr {{.*}} %[[REF_TMP1]])
+// OGCG:   br label %[[LOR_END]]
+// OGCG: [[LOR_END]]:
+// OGCG:    %[[PHI:.*]] = phi i1 [ true, %[[ENTRY]] ], [ %[[MAKE_TEMP1]], %[[LOR_RHS]] ]
+// OGCG:   store i1 %[[PHI]], ptr %[[RETVAL]]
+// OGCG:   %[[CLEANUP_IS_ACTIVE:.*]] = load i1, ptr %[[CLEANUP_COND]]
+// OGCG:   br i1 %[[CLEANUP_IS_ACTIVE]], label %[[CLEANUP_ACTION:.*]], label %[[CLEANUP_DONE:.*]]
+// OGCG: [[CLEANUP_ACTION]]:
+// OGCG:   call void @_ZN1BD2Ev(ptr {{.*}} %[[REF_TMP1]])
+// OGCG:   br label %[[CLEANUP_DONE]]
+// OGCG: [[CLEANUP_DONE]]:
+// OGCG:   call void @_ZN1BD2Ev(ptr {{.*}} %[[REF_TMP0]])
+
+bool test_temp_and() { return make_temp(1) && make_temp(2); }
+
+// CIR: cir.func{{.*}} @_Z13test_temp_andv()
+// CIR:   %[[SCOPE:.*]] = cir.scope {
+// CIR:     %[[REF_TMP0:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp0"]
+// CIR:     %[[ONE:.*]] = cir.const #cir.int<1>
+// CIR:     cir.call @_ZN1BC2Ei(%[[REF_TMP0]], %[[ONE]])
+// CIR:     %[[MAKE_TEMP0:.*]] = cir.call @_Z9make_tempRK1B(%[[REF_TMP0]])
+// CIR:     %[[TERNARY:.*]] = cir.ternary(%[[MAKE_TEMP0]], true {
+// CIR:       %[[REF_TMP1:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp1"]
+// CIR:       %[[TWO:.*]] = cir.const #cir.int<2>
+// CIR:       cir.call @_ZN1BC2Ei(%[[REF_TMP1]], %[[TWO]])
+// CIR:       %[[MAKE_TEMP1:.*]] = cir.call @_Z9make_tempRK1B(%[[REF_TMP1]])
+// CIR:       cir.call @_ZN1BD2Ev(%[[REF_TMP1]])
+// CIR:       cir.yield %[[MAKE_TEMP1]] : !cir.bool
+// CIR:     }, false {
+// CIR:       %[[FALSE:.*]] = cir.const #false
+// CIR:       cir.yield %[[FALSE]] : !cir.bool
+// CIR:     })
+// CIR:     cir.call @_ZN1BD2Ev(%[[REF_TMP0]])
+// CIR:     cir.yield %[[TERNARY]] : !cir.bool
+// CIR:   } : !cir.bool
+
+// LLVM: define{{.*}} i1 @_Z13test_temp_andv() {
+// LLVM:   %[[REF_TMP0:.*]] = alloca %struct.B
+// LLVM:   %[[REF_TMP1:.*]] = alloca %struct.B
+// LLVM:   br label %[[LAND_BEGIN:.*]]
+// LLVM: [[LAND_BEGIN]]:
+// LLVM:   call void @_ZN1BC2Ei(ptr %[[REF_TMP0]], i32 1)
+// LLVM:   %[[MAKE_TEMP0:.*]] = call i1 @_Z9make_tempRK1B(ptr %[[REF_TMP0]])
+// LLVM:   br i1 %[[MAKE_TEMP0]], label %[[LHS_TRUE_BLOCK:.*]], label %[[LHS_FALSE_BLOCK:.*]]
+// LLVM: [[LHS_TRUE_BLOCK]]:
+// LLVM:   call void @_ZN1BC2Ei(ptr %[[REF_TMP1]], i32 2)
+// LLVM:   %[[MAKE_TEMP1:.*]] = call i1 @_Z9make_tempRK1B(ptr %[[REF_TMP1]])
+// LLVM:   call void @_ZN1BD2Ev(ptr %[[REF_TMP1]])
+// LLVM:   br label %[[RESULT_BLOCK:.*]]
+// LLVM: [[LHS_FALSE_BLOCK]]:
+// LLVM:   br label %[[RESULT_BLOCK]]
+// LLVM: [[RESULT_BLOCK]]:
+// LLVM:   %[[RESULT:.*]] = phi i1 [ false, %[[LHS_FALSE_BLOCK]] ], [ %[[MAKE_TEMP1]], %[[LHS_TRUE_BLOCK]] ]
+// LLVM:   br label %[[LAND_END:.*]]
+// LLVM: [[LAND_END]]:
+// LLVM:   call void @_ZN1BD2Ev(ptr %[[REF_TMP0]])
+
+// OGCG: define {{.*}} i1 @_Z13test_temp_andv()
+// OGCG: [[ENTRY:.*]]:
+// OGCG:   %[[RETVAL:.*]] = alloca i1
+// OGCG:   %[[REF_TMP0:.*]] = alloca %struct.B
+// OGCG:   %[[REF_TMP1:.*]] = alloca %struct.B
+// OGCG:   %[[CLEANUP_COND:.*]] = alloca i1
+// OGCG:   call void @_ZN1BC2Ei(ptr {{.*}} %[[REF_TMP0]], i32 {{.*}} 1)
+// OGCG:   %[[MAKE_TEMP0:.*]] = call {{.*}} i1 @_Z9make_tempRK1B(ptr {{.*}} %[[REF_TMP0]])
+// OGCG:   store i1 false, ptr %cleanup.cond
+// OGCG:   br i1 %[[MAKE_TEMP0]], label %[[LAND_RHS:.*]], label %[[LAND_END:.*]]
+// OGCG: [[LAND_RHS]]:
+// OGCG:   call void @_ZN1BC2Ei(ptr {{.*}} %[[REF_TMP1]], i32 {{.*}} 2)
+// OGCG:   store i1 true, ptr %[[CLEANUP_COND]]
+// OGCG:   %[[MAKE_TEMP1:.*]] = call {{.*}} i1 @_Z9make_tempRK1B(ptr {{.*}} %[[REF_TMP1]])
+// OGCG:   br label %[[LAND_END]]
+// OGCG: [[LAND_END]]:
+// OGCG:   %[[PHI:.*]] = phi i1 [ false, %[[ENTRY]] ], [ %[[MAKE_TEMP1]], %[[LAND_RHS]] ]
+// OGCG:   store i1 %[[PHI]], ptr %[[RETVAL]]
+// OGCG:   %[[CLEANUP_IS_ACTIVE:.*]] = load i1, ptr %[[CLEANUP_COND]]
+// OGCG:   br i1 %[[CLEANUP_IS_ACTIVE]], label %[[CLEANUP_ACTION:.*]], label %[[CLEANUP_DONE:.*]]
+// OGCG: [[CLEANUP_ACTION]]:
+// OGCG:   call void @_ZN1BD2Ev(ptr {{.*}} %[[REF_TMP1]])
+// OGCG:   br label %[[CLEANUP_DONE]]
+// OGCG: [[CLEANUP_DONE]]:
+// OGCG:   call void @_ZN1BD2Ev(ptr {{.*}} %[[REF_TMP0]])


        


More information about the cfe-commits mailing list