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

>From 856aceca89e83604933756e30dfaa24021b604fc Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Wed, 18 Jun 2025 15:09:21 +0100
Subject: [PATCH 1/3] [CIR] Add Minimal Destructor Definition Support

This patch upstreams support for writing inline and out of line C++ destructor 
definitions. Calling a destructor implcitly or explicitly is left for a future 
patch.

Because of that restriction complete destructors (D2 in Itanium mangling) do 
not call into the base (D1) destructors yet but simply behave like a base 
destructor. Deleting (D0) destructor support is not part of this patch.

Destructor aliases aren't supported, either. Because of this compilation with 
-mno-constructor-aliases may be required to avoid running into NYI errors.
---
 clang/include/clang/CIR/MissingFeatures.h     |   4 +
 clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp        |   7 ++
 clang/lib/CIR/CodeGen/CIRGenCXXABI.h          |  13 +++
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      | 100 +++++++++++++++++-
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |   1 +
 clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp |  41 +++++--
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        |  28 +++--
 clang/test/CIR/CodeGen/destructors.cpp        |  50 +++++++++
 8 files changed, 228 insertions(+), 16 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/destructors.cpp

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index c76737549a0fc..48e309063d38b 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -250,6 +250,10 @@ struct MissingFeatures {
   static bool typeChecks() { return false; }
   static bool weakRefReference() { return false; }
   static bool writebacks() { return false; }
+  static bool appleKext() { return false; }
+  static bool dtorCleanups() { return false; }
+  static bool completeDtors() { return false; }
+  static bool vtableInitialization() { return false; }
 
   // Missing types
   static bool dataMemberType() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
index 6cf4e5c658fb6..33b812ac81f6e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
@@ -41,6 +41,13 @@ void CIRGenCXXABI::buildThisParam(CIRGenFunction &cgf,
   assert(!cir::MissingFeatures::cxxabiThisAlignment());
 }
 
+cir::GlobalLinkageKind CIRGenCXXABI::getCXXDestructorLinkage(
+    GVALinkage linkage, const CXXDestructorDecl *dtor, CXXDtorType dt) const {
+  // Delegate back to cgm by default.
+  return cgm.getCIRLinkageForDeclarator(dtor, linkage,
+                                        /*isConstantVariable=*/false);
+}
+
 mlir::Value CIRGenCXXABI::loadIncomingCXXThis(CIRGenFunction &cgf) {
   ImplicitParamDecl *vd = getThisDecl(cgf);
   Address addr = cgf.getAddrOfLocalVar(vd);
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h 
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index 2d967fd307e01..eb079b877b7ff 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -72,6 +72,19 @@ class CIRGenCXXABI {
   /// Emit constructor variants required by this ABI.
   virtual void emitCXXConstructors(const clang::CXXConstructorDecl *d) = 0;
 
+  /// Emit dtor variants required by this ABI.
+  virtual void emitCXXDestructors(const clang::CXXDestructorDecl *d) = 0;
+
+  /// Returns true if the given destructor type should be emitted as a linkonce
+  /// delegating thunk, regardless of whether the dtor is defined in this TU or
+  /// not.
+  virtual bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
+                                      CXXDtorType dt) const = 0;
+
+  virtual cir::GlobalLinkageKind
+  getCXXDestructorLinkage(GVALinkage linkage, const CXXDestructorDecl *dtor,
+                          CXXDtorType dt) const;
+
   /// Returns true if the given constructor or destructor is one of the kinds
   /// that the ABI says returns 'this' (only applies when called non-virtually
   /// for destructors).
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index c4efabd6b12ab..73df9f7f97ce8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -463,7 +463,7 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl 
gd, cir::FuncOp fn,
     startFunction(gd, retTy, fn, funcType, args, loc, bodyRange.getBegin());
 
     if (isa<CXXDestructorDecl>(funcDecl)) {
-      getCIRGenModule().errorNYI(bodyRange, "C++ destructor definition");
+      emitDestructorBody(args);
     } else if (isa<CXXConstructorDecl>(funcDecl)) {
       emitConstructorBody(args);
     } else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice &&
@@ -540,6 +540,104 @@ void CIRGenFunction::emitConstructorBody(FunctionArgList 
&args) {
   }
 }
 
+/// Emits the body of the current destructor.
+void CIRGenFunction::emitDestructorBody(FunctionArgList &args) {
+  const CXXDestructorDecl *dtor = cast<CXXDestructorDecl>(curGD.getDecl());
+  CXXDtorType dtorType = curGD.getDtorType();
+
+  // For an abstract class, non-base destructors are never used (and can't
+  // be emitted in general, because vbase dtors may not have been validated
+  // by Sema), but the Itanium ABI doesn't make them optional and Clang may
+  // in fact emit references to them from other compilations, so emit them
+  // as functions containing a trap instruction.
+  if (dtorType != Dtor_Base && dtor->getParent()->isAbstract()) {
+    SourceLocation loc =
+        dtor->hasBody() ? dtor->getBody()->getBeginLoc() : dtor->getLocation();
+    builder.create<cir::TrapOp>(getLoc(loc));
+    // The corresponding clang/CodeGen logic clears the insertion point here,
+    // but MLIR's builder requires a valid insertion point, so we create a 
dummy
+    // block (since the trap is a block terminator).
+    builder.createBlock(builder.getBlock()->getParent());
+    return;
+  }
+
+  Stmt *body = dtor->getBody();
+  if (body)
+    assert(!cir::MissingFeatures::incrementProfileCounter());
+
+  // The call to operator delete in a deleting destructor happens
+  // outside of the function-try-block, which means it's always
+  // possible to delegate the destructor body to the complete
+  // destructor.  Do so.
+  if (dtorType == Dtor_Deleting) {
+    cgm.errorNYI("deleting destructor");
+    return;
+  }
+
+  // If the body is a function-try-block, enter the try before
+  // anything else.
+  const bool isTryBody = isa_and_nonnull<CXXTryStmt>(body);
+  if (isTryBody) {
+    cgm.errorNYI("function-try-block destructor");
+  }
+
+  assert(!cir::MissingFeatures::sanitizers());
+  assert(!cir::MissingFeatures::dtorCleanups());
+
+  // If this is the complete variant, just invoke the base variant;
+  // the epilogue will destruct the virtual bases.  But we can't do
+  // this optimization if the body is a function-try-block, because
+  // we'd introduce *two* handler blocks.  In the Microsoft ABI, we
+  // always delegate because we might not have a definition in this TU.
+  switch (dtorType) {
+  case Dtor_Comdat:
+    llvm_unreachable("not expecting a COMDAT");
+  case Dtor_Deleting:
+    llvm_unreachable("already handled deleting case");
+
+  case Dtor_Complete:
+    assert((body || getTarget().getCXXABI().isMicrosoft()) &&
+           "can't emit a dtor without a body for non-Microsoft ABIs");
+
+    assert(!cir::MissingFeatures::dtorCleanups());
+
+    // TODO(cir): A complete destructor is supposed to call the base 
destructor.
+    // Since we have to emit both dtor kinds we just fall through for now and.
+    // As long as we don't support virtual bases this should be functionally
+    // equivalent.
+    assert(!cir::MissingFeatures::completeDtors());
+
+    // Fallthrough: act like we're in the base variant.
+    [[fallthrough]];
+
+  case Dtor_Base:
+    assert(body);
+
+    assert(!cir::MissingFeatures::dtorCleanups());
+    assert(!cir::MissingFeatures::vtableInitialization());
+
+    if (isTryBody) {
+      cgm.errorNYI("function-try-block destructor");
+    } else if (body) {
+      (void)emitStmt(body, /*useCurrentScope=*/true);
+    } else {
+      assert(dtor->isImplicit() && "bodyless dtor not implicit");
+      // nothing to do besides what's in the epilogue
+    }
+    // -fapple-kext must inline any call to this dtor into
+    // the caller's body.
+    assert(!cir::MissingFeatures::appleKext());
+
+    break;
+  }
+
+  assert(!cir::MissingFeatures::dtorCleanups());
+
+  // Exit the try if applicable.
+  if (isTryBody)
+    cgm.errorNYI("function-try-block destructor");
+}
+
 /// Given a value of type T* that may not be to a complete object, construct
 /// an l-vlaue withi the natural pointee alignment of T.
 LValue CIRGenFunction::makeNaturalAlignPointeeAddrLValue(mlir::Value val,
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 5feb5fc94d983..1346333739bc1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -830,6 +830,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e);
 
   void emitConstructorBody(FunctionArgList &args);
+  void emitDestructorBody(FunctionArgList &args);
 
   mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 1044dfe507471..b0f92124457ad 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -43,7 +43,16 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
                                   CIRGenFunction &cgf) override;
 
   void emitCXXConstructors(const clang::CXXConstructorDecl *d) override;
+  void emitCXXDestructors(const clang::CXXDestructorDecl *d) override;
   void emitCXXStructor(clang::GlobalDecl gd) override;
+
+  bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
+                              CXXDtorType dt) const override {
+    // Itanium does not emit any destructor variant as an inline thunk.
+    // Delegating may occur as an optimization, but all variants are either
+    // emitted with external linkage or as linkonce if they are inline and 
used.
+    return false;
+  }
 };
 
 } // namespace
@@ -150,17 +159,15 @@ static void emitConstructorDestructorAlias(CIRGenModule 
&cgm,
 
 void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {
   auto *md = cast<CXXMethodDecl>(gd.getDecl());
-  auto *cd = dyn_cast<CXXConstructorDecl>(md);
-
   StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);
+  const auto *cd = dyn_cast<CXXConstructorDecl>(md);
+  const CXXDestructorDecl *dd = cd ? nullptr : cast<CXXDestructorDecl>(md);
 
-  if (!cd) {
-    cgm.errorNYI(md->getSourceRange(), "CXCABI emit destructor");
-    return;
-  }
-
-  if (gd.getCtorType() == Ctor_Complete) {
-    GlobalDecl baseDecl = gd.getWithCtorType(Ctor_Base);
+  if (cd ? gd.getCtorType() == Ctor_Complete
+         : gd.getDtorType() == Dtor_Complete) {
+    GlobalDecl baseDecl =
+        cd ? gd.getWithCtorType(Ctor_Base) : gd.getWithDtorType(Dtor_Base);
+    ;
 
     if (cirGenType == StructorCIRGen::Alias ||
         cirGenType == StructorCIRGen::COMDAT) {
@@ -197,6 +204,22 @@ void CIRGenItaniumCXXABI::emitCXXConstructors(const 
CXXConstructorDecl *d) {
   }
 }
 
+void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {
+  // The destructor used for destructing this as a base class; ignores
+  // virtual bases.
+  cgm.emitGlobal(GlobalDecl(d, Dtor_Base));
+
+  // The destructor used for destructing this as a most-derived class;
+  // call the base destructor and then destructs any virtual bases.
+  cgm.emitGlobal(GlobalDecl(d, Dtor_Complete));
+
+  // The destructor in a virtual table is always a 'deleting'
+  // destructor, which calls the complete destructor and then uses the
+  // appropriate operator delete.
+  if (d->isVirtual())
+    cgm.emitGlobal(GlobalDecl(d, Dtor_Deleting));
+}
+
 /// Return whether the given global decl needs a VTT (virtual table table)
 /// parameter, which it does if it's a base constructor or destructor with
 /// virtual bases.
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 8b2883b50d2e2..350270518156e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1111,14 +1111,14 @@ CIRGenModule::getCIRLinkageVarDefinition(const VarDecl 
*vd, bool isConstant) {
 }
 
 cir::GlobalLinkageKind CIRGenModule::getFunctionLinkage(GlobalDecl gd) {
-  const auto *fd = cast<FunctionDecl>(gd.getDecl());
+  const auto *d = cast<FunctionDecl>(gd.getDecl());
 
-  GVALinkage linkage = astContext.GetGVALinkageForFunction(fd);
+  GVALinkage linkage = astContext.GetGVALinkageForFunction(d);
 
-  if (isa<CXXDestructorDecl>(fd))
-    errorNYI(fd->getSourceRange(), "getFunctionLinkage: CXXDestructorDecl");
+  if (const auto *dtor = dyn_cast<CXXDestructorDecl>(d))
+    return getCXXABI().getCXXDestructorLinkage(linkage, dtor, 
gd.getDtorType());
 
-  return getCIRLinkageForDeclarator(fd, linkage, /*IsConstantVariable=*/false);
+  return getCIRLinkageForDeclarator(d, linkage, /*isConstantVariable=*/false);
 }
 
 static cir::GlobalOp
@@ -1274,6 +1274,9 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
   case Decl::CXXConstructor:
     getCXXABI().emitCXXConstructors(cast<CXXConstructorDecl>(decl));
     break;
+  case Decl::CXXDestructor:
+    getCXXABI().emitCXXDestructors(cast<CXXDestructorDecl>(decl));
+    break;
 
   // C++ Decls
   case Decl::LinkageSpec:
@@ -1335,6 +1338,17 @@ cir::FuncOp 
CIRGenModule::getAddrOfFunction(clang::GlobalDecl gd,
     funcType = convertType(fd->getType());
   }
 
+  // Devirtualized destructor calls may come through here instead of via
+  // getAddrOfCXXStructor. Make sure we use the MS ABI base destructor instead
+  // of the complete destructor when necessary.
+  if (const auto *dd = dyn_cast<CXXDestructorDecl>(gd.getDecl())) {
+    if (getTarget().getCXXABI().isMicrosoft() &&
+        gd.getDtorType() == Dtor_Complete &&
+        dd->getParent()->getNumVBases() == 0)
+      errorNYI(dd->getSourceRange(),
+               "getAddrOfFunction: MS ABI complete destructor");
+  }
+
   StringRef mangledName = getMangledName(gd);
   cir::FuncOp func =
       getOrCreateCIRFunction(mangledName, funcType, gd, forVTable, dontDefer,
@@ -1729,7 +1743,9 @@ cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
   // All MSVC dtors other than the base dtor are linkonce_odr and delegate to
   // each other bottoming out wiht the base dtor. Therefore we emit non-base
   // dtors on usage, even if there is no dtor definition in the TU.
-  if (isa_and_nonnull<CXXDestructorDecl>(d))
+  if (isa_and_nonnull<CXXDestructorDecl>(d) &&
+      getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(d),
+                                         gd.getDtorType()))
     errorNYI(d->getSourceRange(), "getOrCreateCIRFunction: dtor");
 
   // This is the first use or definition of a mangled name. If there is a
diff --git a/clang/test/CIR/CodeGen/destructors.cpp 
b/clang/test/CIR/CodeGen/destructors.cpp
new file mode 100644
index 0000000000000..c5e3cea39f63f
--- /dev/null
+++ b/clang/test/CIR/CodeGen/destructors.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu 
-Wno-unused-value -fclangir -emit-cir -mno-constructor-aliases %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu 
-Wno-unused-value -fclangir -emit-llvm %s -mno-constructor-aliases -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu 
-Wno-unused-value -emit-llvm %s -mno-constructor-aliases -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+void some_function() noexcept;
+
+struct out_of_line_destructor {
+    int prevent_tail_padding_reuse;
+    ~out_of_line_destructor();
+};
+
+out_of_line_destructor::~out_of_line_destructor() {
+    some_function();
+}
+
+// CIR: !rec_out_of_line_destructor = !cir.record<struct 
"out_of_line_destructor" {!s32i}>
+
+// CIR: cir.func dso_local @_ZN22out_of_line_destructorD2Ev(%{{.+}}: 
!cir.ptr<!rec_out_of_line_destructor>
+// CIR:   cir.call @_Z13some_functionv() nothrow : () -> () 
+// CIR:   cir.return 
+
+// LLVM: define dso_local void @_ZN22out_of_line_destructorD2Ev(ptr %{{.+}})
+// LLVM:   call void @_Z13some_functionv()
+// LLVM:   ret void
+
+// OGCG: define dso_local void @_ZN22out_of_line_destructorD2Ev(ptr 
{{.*}}%{{.+}})
+// OGCG:   call void @_Z13some_functionv()
+// OGCG:   ret void
+
+// CIR: cir.func dso_local @_ZN22out_of_line_destructorD1Ev(%{{.+}}: 
!cir.ptr<!rec_out_of_line_destructor>
+// CIR:  cir.call @_Z13some_functionv() nothrow : () -> ()
+// CIR:  cir.return
+
+// LLVM: define dso_local void @_ZN22out_of_line_destructorD1Ev(ptr %{{.+}})
+// LLVM:   call void @_Z13some_functionv()
+// LLVM:   ret void
+
+// OGCG: define dso_local void @_ZN22out_of_line_destructorD1Ev(ptr 
{{.*}}%{{.+}})
+// OGCG:   call void @_ZN22out_of_line_destructorD2Ev
+// OGCG:   ret void
+
+struct inline_destructor {
+    int prevent_tail_padding_reuse;
+    ~inline_destructor() noexcept(false) {
+        some_function();
+    }
+};

>From f62afec3e598533712e4df34bfe0fdc20f038569 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Wed, 18 Jun 2025 16:13:53 +0100
Subject: [PATCH 2/3] Add source ranges

---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      | 8 ++++----
 clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 1 -
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 73df9f7f97ce8..42cc4cc4314d0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -570,7 +570,7 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList 
&args) {
   // possible to delegate the destructor body to the complete
   // destructor.  Do so.
   if (dtorType == Dtor_Deleting) {
-    cgm.errorNYI("deleting destructor");
+    cgm.errorNYI(dtor->getSourceRange(), "deleting destructor");
     return;
   }
 
@@ -578,7 +578,7 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList 
&args) {
   // anything else.
   const bool isTryBody = isa_and_nonnull<CXXTryStmt>(body);
   if (isTryBody) {
-    cgm.errorNYI("function-try-block destructor");
+    cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
   }
 
   assert(!cir::MissingFeatures::sanitizers());
@@ -617,7 +617,7 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList 
&args) {
     assert(!cir::MissingFeatures::vtableInitialization());
 
     if (isTryBody) {
-      cgm.errorNYI("function-try-block destructor");
+      cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
     } else if (body) {
       (void)emitStmt(body, /*useCurrentScope=*/true);
     } else {
@@ -635,7 +635,7 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList 
&args) {
 
   // Exit the try if applicable.
   if (isTryBody)
-    cgm.errorNYI("function-try-block destructor");
+    cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
 }
 
 /// Given a value of type T* that may not be to a complete object, construct
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index b0f92124457ad..1496d877e7239 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -161,7 +161,6 @@ void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {
   auto *md = cast<CXXMethodDecl>(gd.getDecl());
   StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);
   const auto *cd = dyn_cast<CXXConstructorDecl>(md);
-  const CXXDestructorDecl *dd = cd ? nullptr : cast<CXXDestructorDecl>(md);
 
   if (cd ? gd.getCtorType() == Ctor_Complete
          : gd.getDtorType() == Dtor_Complete) {

>From 5a4e7f124479255d76784e2bf2857785045ebc9e Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Mon, 14 Jul 2025 17:33:32 +0200
Subject: [PATCH 3/3] Apply review feedback

---
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 14 +++-----------
 clang/test/CIR/CodeGen/destructors.cpp   |  7 +++++++
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 42cc4cc4314d0..e532b9d855843 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -551,19 +551,12 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList 
&args) {
   // in fact emit references to them from other compilations, so emit them
   // as functions containing a trap instruction.
   if (dtorType != Dtor_Base && dtor->getParent()->isAbstract()) {
-    SourceLocation loc =
-        dtor->hasBody() ? dtor->getBody()->getBeginLoc() : dtor->getLocation();
-    builder.create<cir::TrapOp>(getLoc(loc));
-    // The corresponding clang/CodeGen logic clears the insertion point here,
-    // but MLIR's builder requires a valid insertion point, so we create a 
dummy
-    // block (since the trap is a block terminator).
-    builder.createBlock(builder.getBlock()->getParent());
+    cgm.errorNYI(dtor->getSourceRange(), "abstract base class destructors");
     return;
   }
 
   Stmt *body = dtor->getBody();
-  if (body)
-    assert(!cir::MissingFeatures::incrementProfileCounter());
+  assert(body && !cir::MissingFeatures::incrementProfileCounter());
 
   // The call to operator delete in a deleting destructor happens
   // outside of the function-try-block, which means it's always
@@ -577,9 +570,8 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList 
&args) {
   // If the body is a function-try-block, enter the try before
   // anything else.
   const bool isTryBody = isa_and_nonnull<CXXTryStmt>(body);
-  if (isTryBody) {
+  if (isTryBody)
     cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor");
-  }
 
   assert(!cir::MissingFeatures::sanitizers());
   assert(!cir::MissingFeatures::dtorCleanups());
diff --git a/clang/test/CIR/CodeGen/destructors.cpp 
b/clang/test/CIR/CodeGen/destructors.cpp
index c5e3cea39f63f..d8f9f23ae191c 100644
--- a/clang/test/CIR/CodeGen/destructors.cpp
+++ b/clang/test/CIR/CodeGen/destructors.cpp
@@ -48,3 +48,10 @@ struct inline_destructor {
         some_function();
     }
 };
+
+// This inline destructor is not odr-used in this TU.
+// Make sure we don't emit a definition
+
+// CIR-NOT: cir.func {{.*}}inline_destructor{{.*}}
+// LLVM-NOT: define {{.*}}inline_destructor{{.*}}
+// OGCG-NOT: define {{.*}}inline_destructor{{.*}}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to