-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[CIR] Add support for virtual destructor calls #162725
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -130,13 +130,11 @@ RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr( | |||||||||
const CXXMethodDecl *calleeDecl = | ||||||||||
devirtualizedMethod ? devirtualizedMethod : md; | ||||||||||
const CIRGenFunctionInfo *fInfo = nullptr; | ||||||||||
if (isa<CXXDestructorDecl>(calleeDecl)) { | ||||||||||
cgm.errorNYI(ce->getSourceRange(), | ||||||||||
"emitCXXMemberOrOperatorMemberCallExpr: destructor call"); | ||||||||||
return RValue::get(nullptr); | ||||||||||
} | ||||||||||
|
||||||||||
fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(calleeDecl); | ||||||||||
if (const auto *dtor = dyn_cast<CXXDestructorDecl>(calleeDecl)) | ||||||||||
fInfo = &cgm.getTypes().arrangeCXXStructorDeclaration( | ||||||||||
GlobalDecl(dtor, Dtor_Complete)); | ||||||||||
else | ||||||||||
fInfo = &cgm.getTypes().arrangeCXXMethodDeclaration(calleeDecl); | ||||||||||
|
||||||||||
cir::FuncType ty = cgm.getTypes().getFunctionType(*fInfo); | ||||||||||
|
||||||||||
|
@@ -151,9 +149,34 @@ RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr( | |||||||||
// because then we know what the type is. | ||||||||||
bool useVirtualCall = canUseVirtualCall && !devirtualizedMethod; | ||||||||||
|
||||||||||
if (isa<CXXDestructorDecl>(calleeDecl)) { | ||||||||||
cgm.errorNYI(ce->getSourceRange(), | ||||||||||
"emitCXXMemberOrOperatorMemberCallExpr: destructor call"); | ||||||||||
if (const auto *dtor = dyn_cast<CXXDestructorDecl>(calleeDecl)) { | ||||||||||
assert(ce->arg_begin() == ce->arg_end() && | ||||||||||
"Destructor shouldn't have explicit parameters"); | ||||||||||
assert(returnValue.isNull() && "Destructor shouldn't have return value"); | ||||||||||
if (useVirtualCall) { | ||||||||||
cgm.getCXXABI().emitVirtualDestructorCall(*this, dtor, Dtor_Complete, | ||||||||||
thisPtr.getAddress(), | ||||||||||
cast<CXXMemberCallExpr>(ce)); | ||||||||||
} else { | ||||||||||
GlobalDecl globalDecl(dtor, Dtor_Complete); | ||||||||||
CIRGenCallee callee; | ||||||||||
assert(!cir::MissingFeatures::appleKext()); | ||||||||||
if (!devirtualizedMethod) { | ||||||||||
callee = CIRGenCallee::forDirect( | ||||||||||
cgm.getAddrOfCXXStructor(globalDecl, fInfo, ty), globalDecl); | ||||||||||
} else { | ||||||||||
cgm.errorNYI(ce->getSourceRange(), "devirtualized destructor call"); | ||||||||||
return RValue::get(nullptr); | ||||||||||
} | ||||||||||
|
||||||||||
QualType thisTy = | ||||||||||
isArrow ? base->getType()->getPointeeType() : base->getType(); | ||||||||||
// CIRGen does not pass CallOrInvoke here (different from OG LLVM codegen) | ||||||||||
// because in practice it always null even in OG. | ||||||||||
emitCXXDestructorCall(globalDecl, callee, thisPtr.getPointer(), thisTy, | ||||||||||
/*ImplicitParam=*/nullptr, | ||||||||||
/*ImplicitParamTy=*/QualType(), ce); | ||||||||||
|
/*ImplicitParam=*/nullptr, | |
/*ImplicitParamTy=*/QualType(), ce); | |
/*implicitParam=*/nullptr, | |
/*implicitParamTy=*/QualType(), ce); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -678,7 +678,13 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList &args) { | |||||||||
// possible to delegate the destructor body to the complete | ||||||||||
// destructor. Do so. | ||||||||||
if (dtorType == Dtor_Deleting) { | ||||||||||
cgm.errorNYI(dtor->getSourceRange(), "deleting destructor"); | ||||||||||
RunCleanupsScope dtorEpilogue(*this); | ||||||||||
enterDtorCleanups(dtor, Dtor_Deleting); | ||||||||||
if (haveInsertPoint()) { | ||||||||||
QualType thisTy = dtor->getFunctionObjectParameterType(); | ||||||||||
emitCXXDestructorCall(dtor, Dtor_Complete, /*ForVirtualBase=*/false, | ||||||||||
/*Delegating=*/false, loadCXXThisAddress(), thisTy); | ||||||||||
|
emitCXXDestructorCall(dtor, Dtor_Complete, /*ForVirtualBase=*/false, | |
/*Delegating=*/false, loadCXXThisAddress(), thisTy); | |
emitCXXDestructorCall(dtor, Dtor_Complete, /*forVirtualBase=*/false, | |
/*delegating=*/false, loadCXXThisAddress(), thisTy); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -95,7 +95,10 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { | |||||||||||||
clang::GlobalDecl gd, Address thisAddr, | ||||||||||||||
mlir::Type ty, | ||||||||||||||
SourceLocation loc) override; | ||||||||||||||
|
||||||||||||||
mlir::Value emitVirtualDestructorCall(CIRGenFunction &cgf, | ||||||||||||||
const CXXDestructorDecl *dtor, | ||||||||||||||
CXXDtorType dtorType, Address thisAddr, | ||||||||||||||
DeleteOrMemberCallExpr e) override; | ||||||||||||||
mlir::Value getVTableAddressPoint(BaseSubobject base, | ||||||||||||||
const CXXRecordDecl *vtableClass) override; | ||||||||||||||
mlir::Value getVTableAddressPointInStructorWithVTT( | ||||||||||||||
|
@@ -465,6 +468,32 @@ void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt, | |||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
mlir::Value CIRGenItaniumCXXABI::emitVirtualDestructorCall( | ||||||||||||||
CIRGenFunction &cgf, const CXXDestructorDecl *dtor, CXXDtorType dtorType, | ||||||||||||||
Address thisAddr, DeleteOrMemberCallExpr expr) { | ||||||||||||||
auto *callExpr = dyn_cast<const CXXMemberCallExpr *>(expr); | ||||||||||||||
auto *delExpr = dyn_cast<const CXXDeleteExpr *>(expr); | ||||||||||||||
assert((callExpr != nullptr) ^ (delExpr != nullptr)); | ||||||||||||||
assert(callExpr == nullptr || callExpr->arg_begin() == callExpr->arg_end()); | ||||||||||||||
assert(dtorType == Dtor_Deleting || dtorType == Dtor_Complete); | ||||||||||||||
|
||||||||||||||
GlobalDecl globalDecl(dtor, dtorType); | ||||||||||||||
const CIRGenFunctionInfo *fnInfo = | ||||||||||||||
&cgm.getTypes().arrangeCXXStructorDeclaration(globalDecl); | ||||||||||||||
const cir::FuncType &fnTy = cgm.getTypes().getFunctionType(*fnInfo); | ||||||||||||||
auto callee = CIRGenCallee::forVirtual(callExpr, globalDecl, thisAddr, fnTy); | ||||||||||||||
|
||||||||||||||
QualType thisTy; | ||||||||||||||
if (callExpr) | ||||||||||||||
thisTy = callExpr->getObjectType(); | ||||||||||||||
else | ||||||||||||||
thisTy = delExpr->getDestroyedType(); | ||||||||||||||
|
QualType thisTy; | |
if (callExpr) | |
thisTy = callExpr->getObjectType(); | |
else | |
thisTy = delExpr->getDestroyedType(); | |
QualType thisTy = callExpr ? callExpr->getObjectType() : delExpr->getDestroyedType(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -std=c++20 -mconstructor-aliases -O0 -fclangir -emit-cir %s -o %t.cir | ||
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s | ||
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -std=c++20 -mconstructor-aliases -O0 -fclangir -emit-llvm %s -o %t-cir.ll | ||
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s | ||
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -std=c++20 -mconstructor-aliases -O0 -emit-llvm %s -o %t.ll | ||
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s | ||
|
||
// TODO(cir): Try to emit base destructor as an alias at O1 or higher. | ||
|
||
// FIXME: LLVM IR dialect does not yet support function ptr globals, which precludes | ||
// a lot of the proper semantics for properly representing alias functions in LLVM | ||
// (see the note on LLVM_O1 below). | ||
|
||
struct Member { | ||
~Member(); | ||
}; | ||
|
||
struct A { | ||
virtual ~A(); | ||
}; | ||
|
||
struct B : A { | ||
Member m; | ||
virtual ~B(); | ||
}; | ||
|
||
B::~B() { } | ||
|
||
// Aliases are inserted before the function definitions in LLVM IR | ||
// FIXME: These should have unnamed_addr set. | ||
// LLVM: @_ZN1BD1Ev = alias void (ptr), ptr @_ZN1BD2Ev | ||
// LLVM: @_ZN1CD1Ev = alias void (ptr), ptr @_ZN1CD2Ev | ||
|
||
// OGCG: @_ZN1BD1Ev = unnamed_addr alias void (ptr), ptr @_ZN1BD2Ev | ||
// OGCG: @_ZN1CD1Ev = unnamed_addr alias void (ptr), ptr @_ZN1CD2Ev | ||
|
||
|
||
// Base (D2) dtor for B: calls A's base dtor. | ||
|
||
// CIR: cir.func{{.*}} @_ZN1BD2Ev | ||
// CIR: cir.call @_ZN6MemberD1Ev | ||
// CIR: cir.call @_ZN1AD2Ev | ||
|
||
// LLVM: define{{.*}} void @_ZN1BD2Ev | ||
// LLVM: call void @_ZN6MemberD1Ev | ||
// LLVM: call void @_ZN1AD2Ev | ||
|
||
// OGCG: define{{.*}} @_ZN1BD2Ev | ||
// OGCG: call void @_ZN6MemberD1Ev | ||
// OGCG: call void @_ZN1AD2Ev | ||
|
||
// Complete (D1) dtor for B: just an alias because there are no virtual bases. | ||
|
||
// CIR: cir.func{{.*}} @_ZN1BD1Ev(!cir.ptr<!rec_B>) alias(@_ZN1BD2Ev) | ||
// This is defined above for LLVM and OGCG. | ||
|
||
// Deleting (D0) dtor for B: defers to the complete dtor but also calls operator delete. | ||
|
||
// CIR: cir.func{{.*}} @_ZN1BD0Ev | ||
// CIR: cir.call @_ZN1BD1Ev(%[[THIS:.*]]) nothrow : (!cir.ptr<!rec_B>) -> () | ||
// CIR: %[[THIS_VOID:.*]] = cir.cast bitcast %[[THIS]] : !cir.ptr<!rec_B> -> !cir.ptr<!void> | ||
// CIR: %[[SIZE:.*]] = cir.const #cir.int<16> | ||
// CIR: cir.call @_ZdlPvm(%[[THIS_VOID]], %[[SIZE]]) | ||
|
||
// LLVM: define{{.*}} void @_ZN1BD0Ev | ||
// LLVM: call void @_ZN1BD1Ev(ptr %[[THIS:.*]]) | ||
// LLVM: call void @_ZdlPvm(ptr %[[THIS]], i64 16) | ||
|
||
// OGCG: define{{.*}} @_ZN1BD0Ev | ||
// OGCG: call void @_ZN1BD1Ev(ptr{{.*}} %[[THIS:.*]]) | ||
// OGCG: call void @_ZdlPvm(ptr{{.*}} %[[THIS]], i64{{.*}} 16) | ||
|
||
struct C : B { | ||
~C(); | ||
}; | ||
|
||
C::~C() { } | ||
|
||
// Base (D2) dtor for C: calls B's base dtor. | ||
|
||
// CIR: cir.func{{.*}} @_ZN1CD2Ev | ||
// CIR: %[[B:.*]] = cir.base_class_addr %[[THIS:.*]] : !cir.ptr<!rec_C> nonnull [0] -> !cir.ptr<!rec_B> | ||
// CIR: cir.call @_ZN1BD2Ev(%[[B]]) | ||
|
||
// LLVM: define{{.*}} void @_ZN1CD2Ev | ||
// LLVM: call void @_ZN1BD2Ev | ||
|
||
// OGCG: define{{.*}} @_ZN1CD2Ev | ||
// OGCG: call void @_ZN1BD2Ev | ||
|
||
// Complete (D1) dtor for C: just an alias because there are no virtual bases. | ||
|
||
// CIR: cir.func{{.*}} @_ZN1CD1Ev(!cir.ptr<!rec_C>) alias(@_ZN1CD2Ev) | ||
// This is defined above for LLVM and OGCG. | ||
|
||
|
||
// Deleting (D0) dtor for C: defers to the complete dtor but also calls operator delete. | ||
|
||
// CIR: cir.func{{.*}} @_ZN1CD0Ev | ||
// CIR: cir.call @_ZN1CD1Ev(%[[THIS:.*]]) nothrow : (!cir.ptr<!rec_C>) -> () | ||
// CIR: %[[THIS_VOID:.*]] = cir.cast bitcast %[[THIS]] : !cir.ptr<!rec_C> -> !cir.ptr<!void> | ||
// CIR: %[[SIZE:.*]] = cir.const #cir.int<16> | ||
// CIR: cir.call @_ZdlPvm(%[[THIS_VOID]], %[[SIZE]]) | ||
|
||
// LLVM: define{{.*}} void @_ZN1CD0Ev | ||
// LLVM: call void @_ZN1CD1Ev(ptr %[[THIS:.*]]) | ||
// LLVM: call void @_ZdlPvm(ptr %[[THIS]], i64 16) | ||
|
||
// OGCG: define{{.*}} @_ZN1CD0Ev | ||
// OGCG: call void @_ZN1CD1Ev(ptr{{.*}} %[[THIS:.*]]) | ||
// OGCG: call void @_ZdlPvm(ptr{{.*}} %[[THIS]], i64{{.*}} 16) | ||
|
||
namespace PR12798 { | ||
// A qualified call to a base class destructor should not undergo virtual | ||
// dispatch. Template instantiation used to lose the qualifier. | ||
struct A { virtual ~A(); }; | ||
template<typename T> void f(T *p) { p->A::~A(); } | ||
|
||
// CIR: cir.func{{.*}} @_ZN7PR127981fINS_1AEEEvPT_ | ||
// CIR: cir.call @_ZN7PR127981AD1Ev | ||
|
||
// LLVM: define{{.*}} @_ZN7PR127981fINS_1AEEEvPT_ | ||
// LLVM: call void @_ZN7PR127981AD1Ev | ||
|
||
// OGCG: define{{.*}} @_ZN7PR127981fINS_1AEEEvPT_ | ||
// OGCG: call void @_ZN7PR127981AD1Ev | ||
|
||
template void f(A*); | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Is it worth changing the comment to a more accurate assert on missing feature?
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.
For sure. We even already have the MissingFeature I needed.