[clang] 6b054fd - [CIR] Implement EH handling for field initializers (#192360)

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 16 11:49:03 PDT 2026


Author: Andy Kaylor
Date: 2026-04-16T11:48:58-07:00
New Revision: 6b054fdbcd8bd7b3fb850794e0feaa6d6525c793

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

LOG: [CIR] Implement EH handling for field initializers (#192360)

This implements the handling to call the dtor for any previously
initialized fields of destructed type if an exception is thrown later in
the initialization of the containing class.

The basic infrastructure to handle this was already in place. We just
needed a function to push an EH-only destroy cleanup on the EH stack and
a call to that function.

Added: 
    clang/test/CIR/CodeGen/field-init-eh.cpp

Modified: 
    clang/lib/CIR/CodeGen/CIRGenClass.cpp
    clang/lib/CIR/CodeGen/CIRGenDecl.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index f195b43ab1e57..5f9fdfba9d31b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -620,8 +620,7 @@ void CIRGenFunction::emitInitializerForField(FieldDecl *field, LValue lhs,
   // Ensure that we destroy this object if an exception is thrown later in the
   // constructor.
   QualType::DestructionKind dtorKind = fieldType.isDestructedType();
-  if (needsEHCleanup(dtorKind))
-    cgm.errorNYI(init->getSourceRange(), "call field destructor");
+  pushEHDestroyIfNeeded(dtorKind, lhs.getAddress(), fieldType);
 }
 
 Address CIRGenFunction::emitCXXMemberDataPointerAddress(

diff  --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 7e9f6a8a230f3..be86d34545a2c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -1071,6 +1071,17 @@ void CIRGenFunction::pushIrregularPartialArrayCleanup(mlir::Value arrayBegin,
       destroyer);
 }
 
+/// pushEHDestroyIfNeeded - Push the standard destructor for the given type as
+/// an EH-only cleanup. If EH cleanup is not needed, just return.
+void CIRGenFunction::pushEHDestroyIfNeeded(QualType::DestructionKind dtorKind,
+                                           Address addr, QualType type) {
+  if (!needsEHCleanup(dtorKind))
+    return;
+
+  assert(!cir::MissingFeatures::useEHCleanupForArray());
+  pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind));
+}
+
 /// Push the standard destructor for the given type as
 /// at least a normal cleanup.
 void CIRGenFunction::pushDestroy(QualType::DestructionKind dtorKind,

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index e1ae2745e88ff..7cbea29a7c3f9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1395,6 +1395,9 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   static Destroyer destroyCXXObject;
 
+  void pushEHDestroyIfNeeded(QualType::DestructionKind dtorKind, Address addr,
+                             QualType type);
+
   void pushDestroy(QualType::DestructionKind dtorKind, Address addr,
                    QualType type);
 

diff  --git a/clang/test/CIR/CodeGen/field-init-eh.cpp b/clang/test/CIR/CodeGen/field-init-eh.cpp
new file mode 100644
index 0000000000000..37065d5c952de
--- /dev/null
+++ b/clang/test/CIR/CodeGen/field-init-eh.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fexceptions -fcxx-exceptions -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 -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 -fexceptions -fcxx-exceptions -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+
+class Contained {
+public:
+  Contained(int);
+  ~Contained();
+};
+
+void mayThrow();
+
+class Container {
+public:
+  Container() : x(0), contained(1) { mayThrow(); }
+
+  int x;
+  Contained contained;
+};
+
+void test_field_initializer() {
+  Container c;
+}
+
+// CIR: cir.func {{.*}} @_ZN9ContainerC2Ev
+// CIR:   %[[THIS:.*]] = cir.load %{{.*}}
+// CIR:   %[[X_ADDR:.*]] = cir.get_member %[[THIS]][0] {name = "x"} : !cir.ptr<!rec_Container> -> !cir.ptr<!s32i>
+// CIR:   %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR:   cir.store align(4) %[[ZERO]], %[[X_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[VOID_PTR_THIS:.*]] = cir.cast bitcast %[[THIS]] : !cir.ptr<!rec_Container> -> !cir.ptr<!u8i>
+// CIR:   %[[FOUR:.*]] = cir.const #cir.int<4> : !u64i
+// CIR:   %[[CONTAINED_ADDR_VOID:.*]] = cir.ptr_stride %[[VOID_PTR_THIS]], %[[FOUR]] : (!cir.ptr<!u8i>, !u64i) -> !cir.ptr<!u8i>
+// CIR:   %[[CONTAINED_ADDR:.*]] = cir.cast bitcast %[[CONTAINED_ADDR_VOID]] : !cir.ptr<!u8i> -> !cir.ptr<!rec_Contained>
+// CIR:   %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
+// CIR:   cir.call @_ZN9ContainedC1Ei(%[[CONTAINED_ADDR]], %[[ONE]])
+// CIR:   cir.cleanup.scope {
+// CIR:     cir.call @_Z8mayThrowv() : () -> ()
+// CIR:     cir.yield
+// CIR:   } cleanup eh {
+// CIR:     cir.call @_ZN9ContainedD1Ev(%[[CONTAINED_ADDR]])
+// CIR:     cir.yield
+// CIR:   }
+
+// LLVM: define {{.*}} void @_ZN9ContainerC2Ev
+// LLVM:   %[[THIS:.*]] = load ptr, ptr %{{.*}}
+// LLVM:   %[[X_ADDR:.*]] = getelementptr %class.Container, ptr %[[THIS]], i32 0, i32 0
+// LLVM:   store i32 0, ptr %[[X_ADDR]]
+// LLVM:   %[[CONTAINED_ADDR:.*]] = getelementptr i8, ptr %[[THIS]], i64 4
+// LLVM:   call void @_ZN9ContainedC1Ei(ptr {{.*}} %[[CONTAINED_ADDR]], i32 {{.*}} 1)
+// LLVM:   invoke void @_Z8mayThrowv()
+// LLVM:           to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]]
+// LLVM:   [[INVOKE_CONT:.*]]:
+// LLVM:     br label %[[EXIT:.*]]
+// LLVM:   [[LPAD:.*]]:
+// LLVM:     %[[EXN:.*]] = landingpad { ptr, i32 }
+// LLVM:       cleanup
+// LLVM:       br label %[[EH_CLEANUP:.*]]
+// LLVM:   [[EH_CLEANUP:.*]]:
+// LLVM:     call void @_ZN9ContainedD1Ev(ptr {{.*}} %[[CONTAINED_ADDR]])
+// LLVM:     resume { ptr, i32 } %{{.*}}        
+// LLVM:   [[EXIT:.*]]:
+// LLVM:     ret void
+
+// OGCG: define {{.*}} void @_ZN9ContainerC2Ev
+// OGCG:   %[[THIS:.*]] = load ptr, ptr %{{.*}}
+// OGCG:   %[[X_ADDR:.*]] = getelementptr inbounds nuw %class.Container, ptr %[[THIS]], i32 0, i32 0
+// OGCG:   store i32 0, ptr %[[X_ADDR]]
+// OGCG:   %[[CONTAINED_ADDR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 4
+// OGCG:   call void @_ZN9ContainedC1Ei(ptr {{.*}} %[[CONTAINED_ADDR]], i32 {{.*}} 1)
+// OGCG:   invoke void @_Z8mayThrowv()
+// OGCG:           to label %[[INVOKE_CONT:.*]] unwind label %[[LPAD:.*]]
+// OGCG: [[INVOKE_CONT:.*]]:
+// OGCG:   ret void
+// OGCG: [[LPAD:.*]]:
+// OGCG:   %[[EXN:.*]] = landingpad { ptr, i32 }
+// OGCG:                    cleanup
+// OGCG:   call void @_ZN9ContainedD1Ev(ptr {{.*}} %[[CONTAINED_ADDR]])
+// OGCG:   br label %[[EH_RESUME:.*]]
+// OGCG: [[EH_RESUME:.*]]:
+// OGCG:   resume { ptr, i32 } %{{.*}}


        


More information about the cfe-commits mailing list