-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[CIR] Handle operator delete with virtual destructors #165010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This adds support for emitting operator delete when used with classes that have a virtual destructor.
|
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesThis adds support for emitting operator delete when used with classes that have a virtual destructor. Full diff: https://github.com/llvm/llvm-project/pull/165010.diff 5 Files Affected:
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 598e826a473a6..89efe39650aa9 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -240,6 +240,7 @@ struct MissingFeatures {
static bool dataLayoutPtrHandlingBasedOnLangAS() { return false; }
static bool deferredCXXGlobalInit() { return false; }
static bool deleteArray() { return false; }
+ static bool devirtualizeDestructor() { return false; }
static bool devirtualizeMemberFunction() { return false; }
static bool ehCleanupFlags() { return false; }
static bool ehCleanupHasPrebranchedFallthrough() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index d3c7dac04dc67..13dc9f305945a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -187,6 +187,11 @@ class CIRGenCXXABI {
virtual void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor,
mlir::Value addr) = 0;
+ virtual void emitVirtualObjectDelete(CIRGenFunction &cgf,
+ const CXXDeleteExpr *de, Address ptr,
+ QualType elementType,
+ const CXXDestructorDecl *dtor) = 0;
+
/// Checks if ABI requires extra virtual offset for vtable field.
virtual bool
isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index a3cdf192bf9b8..7a35382e79a93 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -565,8 +565,10 @@ static void emitObjectDelete(CIRGenFunction &cgf, const CXXDeleteExpr *de,
dtor = rd->getDestructor();
if (dtor->isVirtual()) {
- cgf.cgm.errorNYI(de->getSourceRange(),
- "emitObjectDelete: virtual destructor");
+ assert(!cir::MissingFeatures::devirtualizeDestructor());
+ cgf.cgm.getCXXABI().emitVirtualObjectDelete(cgf, de, ptr, elementType,
+ dtor);
+ return;
}
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 2dce0b16e3043..065aba7b5278b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -74,6 +74,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
QualType thisTy) override;
void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor,
mlir::Value addr) override;
+ void emitVirtualObjectDelete(CIRGenFunction &cgf, const CXXDeleteExpr *de,
+ Address ptr, QualType elementType,
+ const CXXDestructorDecl *dtor) override;
void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
@@ -2175,6 +2178,22 @@ mlir::Value CIRGenItaniumCXXABI::emitDynamicCast(CIRGenFunction &cgf,
isRefCast, castInfo);
}
+/// The Itanium ABI always places an offset to the complete object
+/// at entry -2 in the vtable.
+void CIRGenItaniumCXXABI::emitVirtualObjectDelete(
+ CIRGenFunction &cgf, const CXXDeleteExpr *delExpr, Address ptr,
+ QualType elementType, const CXXDestructorDecl *dtor) {
+ bool useGlobalDelete = delExpr->isGlobalDelete();
+ if (useGlobalDelete) {
+ cgf.cgm.errorNYI(delExpr->getSourceRange(),
+ "emitVirtualObjectDelete: global delete");
+ return;
+ }
+
+ CXXDtorType dtorType = useGlobalDelete ? Dtor_Complete : Dtor_Deleting;
+ emitVirtualDestructorCall(cgf, dtor, dtorType, ptr, delExpr);
+}
+
/************************** Array allocation cookies **************************/
CharUnits CIRGenItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {
diff --git a/clang/test/CIR/CodeGen/delete.cpp b/clang/test/CIR/CodeGen/delete.cpp
index 69640aa04531f..44fb5415f6c5d 100644
--- a/clang/test/CIR/CodeGen/delete.cpp
+++ b/clang/test/CIR/CodeGen/delete.cpp
@@ -86,3 +86,42 @@ Container::~Container() { delete contents; }
// These functions are declared/defined below the calls in OGCG.
// OGCG: define linkonce_odr void @_ZN8ContentsD2Ev
// OGCG: declare void @_ZdlPvm(ptr noundef, i64 noundef)
+
+struct StructWithVirtualDestructor {
+ virtual ~StructWithVirtualDestructor();
+};
+
+void destroy(StructWithVirtualDestructor *x) {
+ delete x;
+}
+
+// CIR: cir.func {{.*}} @_Z7destroyP27StructWithVirtualDestructor(%[[X_ARG:.*]]: !cir.ptr<!rec_StructWithVirtualDestructor> {{.*}})
+// CIR: %[[X_ADDR:.*]] = cir.alloca !cir.ptr<!rec_StructWithVirtualDestructor>
+// CIR: cir.store %[[X_ARG]], %[[X_ADDR]]
+// CIR: %[[X:.*]] = cir.load{{.*}} %[[X_ADDR]]
+// CIR: %[[VTABLE_PTR:.*]] = cir.vtable.get_vptr %[[X]] : !cir.ptr<!rec_StructWithVirtualDestructor> -> !cir.ptr<!cir.vptr>
+// CIR: %[[VTABLE:.*]] = cir.load{{.*}} %[[VTABLE_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[DTOR_FN_ADDR_PTR:.*]] = cir.vtable.get_virtual_fn_addr %[[VTABLE]][1]
+// CIR: %[[DTOR_FN_ADDR:.*]] = cir.load{{.*}} %[[DTOR_FN_ADDR_PTR]]
+// CIR: cir.call %[[DTOR_FN_ADDR]](%[[X]])
+
+// LLVM: define {{.*}} void @_Z7destroyP27StructWithVirtualDestructor(ptr %[[X_ARG:.*]])
+// LLVM: %[[X_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[X_ARG]], ptr %[[X_ADDR]]
+// LLVM: %[[X:.*]] = load ptr, ptr %[[X_ADDR]]
+// LLVM: %[[VTABLE:.*]] = load ptr, ptr %[[X]]
+// LLVM: %[[DTOR_FN_ADDR_PTR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i32 1
+// LLVM: %[[DTOR_FN_ADDR:.*]] = load ptr, ptr %[[DTOR_FN_ADDR_PTR]]
+// LLVM: call void %[[DTOR_FN_ADDR]](ptr %[[X]])
+
+// OGCG: define {{.*}} void @_Z7destroyP27StructWithVirtualDestructor(ptr {{.*}} %[X_ARG:.*]])
+// OGCG: %[[X_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[X_ARG]], ptr %[[X_ADDR]]
+// OGCG: %[[X:.*]] = load ptr, ptr %[[X_ADDR]]
+// OGCG: %[[ISNULL:.*]] = icmp eq ptr %[[X]], null
+// OGCG: br i1 %[[ISNULL]], label %{{.*}}, label %[[DELETE_NOTNULL:.*]]
+// OGCG: [[DELETE_NOTNULL]]:
+// OGCG: %[[VTABLE:.*]] = load ptr, ptr %[[X]]
+// OGCG: %[[DTOR_FN_ADDR_PTR:.*]] = getelementptr inbounds ptr, ptr %[[VTABLE]], i32 1
+// OGCG: %[[DTOR_FN_ADDR:.*]] = load ptr, ptr %[[DTOR_FN_ADDR_PTR]]
+// OGCG: call void %[[DTOR_FN_ADDR]](ptr {{.*}} %[[X]])
|
bcardosolopes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, LGTM!
This adds support for emitting operator delete when used with classes that have a virtual destructor.
This adds support for emitting operator delete when used with classes that have a virtual destructor.
This adds support for emitting operator delete when used with classes that have a virtual destructor.
This adds support for emitting operator delete when used with classes that have a virtual destructor.