Skip to content

Commit 83748cc

Browse files
committed
[OpenCL] Improve destructor support in C++ for OpenCL
Summary: This patch does mainly three things: 1. It fixes a false positive error detection in Sema that is similar to D62156. The error happens when explicitly calling an overloaded destructor for different address spaces. 2. It selects the correct destructor when multiple overloads for address spaces are available. 3. It inserts the expected address space cast when invoking a destructor, if needed, and therefore fixes a crash due to the unmet assertion in llvm::CastInst::Create. The following is a reproducer of the three issues: struct MyType { ~MyType() {} ~MyType() __constant {} }; __constant MyType myGlobal{}; kernel void foo() { myGlobal.~MyType(); // 1 and 2. // 1. error: cannot initialize object parameter of type // '__generic MyType' with an expression of type '__constant MyType' // 2. error: no matching member function for call to '~MyType' } kernel void bar() { // 3. The implicit call to the destructor crashes due to: // Assertion `castIsValid(op, S, Ty) && "Invalid cast!"' failed. // in llvm::CastInst::Create. MyType myLocal; } The added test depends on D62413 and covers a few more things than the above reproducer. Subscribers: yaxunl, Anastasia, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D64569 llvm-svn: 366422
1 parent 46b55fa commit 83748cc

14 files changed

+234
-113
lines changed

clang/include/clang/AST/DeclCXX.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,30 +2232,38 @@ class CXXMethodDecl : public FunctionDecl {
22322232

22332233
overridden_method_range overridden_methods() const;
22342234

2235-
/// Returns the parent of this method declaration, which
2235+
/// Return the parent of this method declaration, which
22362236
/// is the class in which this method is defined.
22372237
const CXXRecordDecl *getParent() const {
22382238
return cast<CXXRecordDecl>(FunctionDecl::getParent());
22392239
}
22402240

2241-
/// Returns the parent of this method declaration, which
2241+
/// Return the parent of this method declaration, which
22422242
/// is the class in which this method is defined.
22432243
CXXRecordDecl *getParent() {
22442244
return const_cast<CXXRecordDecl *>(
22452245
cast<CXXRecordDecl>(FunctionDecl::getParent()));
22462246
}
22472247

2248-
/// Returns the type of the \c this pointer.
2248+
/// Return the type of the \c this pointer.
22492249
///
22502250
/// Should only be called for instance (i.e., non-static) methods. Note
22512251
/// that for the call operator of a lambda closure type, this returns the
22522252
/// desugared 'this' type (a pointer to the closure type), not the captured
22532253
/// 'this' type.
22542254
QualType getThisType() const;
22552255

2256+
/// Return the type of the object pointed by \c this.
2257+
///
2258+
/// See getThisType() for usage restriction.
2259+
QualType getThisObjectType() const;
2260+
22562261
static QualType getThisType(const FunctionProtoType *FPT,
22572262
const CXXRecordDecl *Decl);
22582263

2264+
static QualType getThisObjectType(const FunctionProtoType *FPT,
2265+
const CXXRecordDecl *Decl);
2266+
22592267
Qualifiers getMethodQualifiers() const {
22602268
return getType()->getAs<FunctionProtoType>()->getMethodQuals();
22612269
}

clang/lib/AST/DeclCXX.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2253,12 +2253,23 @@ CXXMethodDecl::overridden_methods() const {
22532253
return getASTContext().overridden_methods(this);
22542254
}
22552255

2256+
static QualType getThisObjectType(ASTContext &C, const FunctionProtoType *FPT,
2257+
const CXXRecordDecl *Decl) {
2258+
QualType ClassTy = C.getTypeDeclType(Decl);
2259+
return C.getQualifiedType(ClassTy, FPT->getMethodQuals());
2260+
}
2261+
22562262
QualType CXXMethodDecl::getThisType(const FunctionProtoType *FPT,
22572263
const CXXRecordDecl *Decl) {
22582264
ASTContext &C = Decl->getASTContext();
2259-
QualType ClassTy = C.getTypeDeclType(Decl);
2260-
ClassTy = C.getQualifiedType(ClassTy, FPT->getMethodQuals());
2261-
return C.getPointerType(ClassTy);
2265+
QualType ObjectTy = ::getThisObjectType(C, FPT, Decl);
2266+
return C.getPointerType(ObjectTy);
2267+
}
2268+
2269+
QualType CXXMethodDecl::getThisObjectType(const FunctionProtoType *FPT,
2270+
const CXXRecordDecl *Decl) {
2271+
ASTContext &C = Decl->getASTContext();
2272+
return ::getThisObjectType(C, FPT, Decl);
22622273
}
22632274

22642275
QualType CXXMethodDecl::getThisType() const {
@@ -2273,6 +2284,14 @@ QualType CXXMethodDecl::getThisType() const {
22732284
getParent());
22742285
}
22752286

2287+
QualType CXXMethodDecl::getThisObjectType() const {
2288+
// Ditto getThisType.
2289+
assert(isInstance() && "No 'this' for static methods!");
2290+
2291+
return CXXMethodDecl::getThisObjectType(getType()->getAs<FunctionProtoType>(),
2292+
getParent());
2293+
}
2294+
22762295
bool CXXMethodDecl::hasInlineBody() const {
22772296
// If this function is a template instantiation, look at the template from
22782297
// which it was instantiated.

clang/lib/CodeGen/CGCXXABI.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ class CGCXXABI {
378378
virtual void EmitDestructorCall(CodeGenFunction &CGF,
379379
const CXXDestructorDecl *DD, CXXDtorType Type,
380380
bool ForVirtualBase, bool Delegating,
381-
Address This) = 0;
381+
Address This, QualType ThisTy) = 0;
382382

383383
/// Emits the VTable definitions required for the given record type.
384384
virtual void emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -421,11 +421,15 @@ class CGCXXABI {
421421
llvm::Type *Ty,
422422
SourceLocation Loc) = 0;
423423

424+
using DeleteOrMemberCallExpr =
425+
llvm::PointerUnion<const CXXDeleteExpr *, const CXXMemberCallExpr *>;
426+
424427
/// Emit the ABI-specific virtual destructor call.
425-
virtual llvm::Value *
426-
EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor,
427-
CXXDtorType DtorType, Address This,
428-
const CXXMemberCallExpr *CE) = 0;
428+
virtual llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
429+
const CXXDestructorDecl *Dtor,
430+
CXXDtorType DtorType,
431+
Address This,
432+
DeleteOrMemberCallExpr E) = 0;
429433

430434
virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
431435
GlobalDecl GD,

clang/lib/CodeGen/CGCall.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3502,7 +3502,7 @@ struct DestroyUnpassedArg final : EHScopeStack::Cleanup {
35023502
const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
35033503
assert(!Dtor->isTrivial());
35043504
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false,
3505-
/*Delegating=*/false, Addr);
3505+
/*Delegating=*/false, Addr, Ty);
35063506
} else {
35073507
CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Ty));
35083508
}

clang/lib/CodeGen/CGClass.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -491,12 +491,15 @@ namespace {
491491
cast<CXXMethodDecl>(CGF.CurCodeDecl)->getParent();
492492

493493
const CXXDestructorDecl *D = BaseClass->getDestructor();
494+
// We are already inside a destructor, so presumably the object being
495+
// destroyed should have the expected type.
496+
QualType ThisTy = D->getThisObjectType();
494497
Address Addr =
495498
CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThisAddress(),
496499
DerivedClass, BaseClass,
497500
BaseIsVirtual);
498501
CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual,
499-
/*Delegating=*/false, Addr);
502+
/*Delegating=*/false, Addr, ThisTy);
500503
}
501504
};
502505

@@ -1440,9 +1443,11 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14401443
if (DtorType == Dtor_Deleting) {
14411444
RunCleanupsScope DtorEpilogue(*this);
14421445
EnterDtorCleanups(Dtor, Dtor_Deleting);
1443-
if (HaveInsertPoint())
1446+
if (HaveInsertPoint()) {
1447+
QualType ThisTy = Dtor->getThisObjectType();
14441448
EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
1445-
/*Delegating=*/false, LoadCXXThisAddress());
1449+
/*Delegating=*/false, LoadCXXThisAddress(), ThisTy);
1450+
}
14461451
return;
14471452
}
14481453

@@ -1473,8 +1478,9 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14731478
EnterDtorCleanups(Dtor, Dtor_Complete);
14741479

14751480
if (!isTryBody) {
1481+
QualType ThisTy = Dtor->getThisObjectType();
14761482
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
1477-
/*Delegating=*/false, LoadCXXThisAddress());
1483+
/*Delegating=*/false, LoadCXXThisAddress(), ThisTy);
14781484
break;
14791485
}
14801486

@@ -2013,7 +2019,7 @@ void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
20132019
const CXXDestructorDecl *dtor = record->getDestructor();
20142020
assert(!dtor->isTrivial());
20152021
CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false,
2016-
/*Delegating=*/false, addr);
2022+
/*Delegating=*/false, addr, type);
20172023
}
20182024

20192025
void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
@@ -2363,8 +2369,11 @@ namespace {
23632369
: Dtor(D), Addr(Addr), Type(Type) {}
23642370

23652371
void Emit(CodeGenFunction &CGF, Flags flags) override {
2372+
// We are calling the destructor from within the constructor.
2373+
// Therefore, "this" should have the expected type.
2374+
QualType ThisTy = Dtor->getThisObjectType();
23662375
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
2367-
/*Delegating=*/true, Addr);
2376+
/*Delegating=*/true, Addr, ThisTy);
23682377
}
23692378
};
23702379
} // end anonymous namespace
@@ -2402,31 +2411,32 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
24022411
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
24032412
CXXDtorType Type,
24042413
bool ForVirtualBase,
2405-
bool Delegating,
2406-
Address This) {
2414+
bool Delegating, Address This,
2415+
QualType ThisTy) {
24072416
CGM.getCXXABI().EmitDestructorCall(*this, DD, Type, ForVirtualBase,
2408-
Delegating, This);
2417+
Delegating, This, ThisTy);
24092418
}
24102419

24112420
namespace {
24122421
struct CallLocalDtor final : EHScopeStack::Cleanup {
24132422
const CXXDestructorDecl *Dtor;
24142423
Address Addr;
2424+
QualType Ty;
24152425

2416-
CallLocalDtor(const CXXDestructorDecl *D, Address Addr)
2417-
: Dtor(D), Addr(Addr) {}
2426+
CallLocalDtor(const CXXDestructorDecl *D, Address Addr, QualType Ty)
2427+
: Dtor(D), Addr(Addr), Ty(Ty) {}
24182428

24192429
void Emit(CodeGenFunction &CGF, Flags flags) override {
24202430
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
24212431
/*ForVirtualBase=*/false,
2422-
/*Delegating=*/false, Addr);
2432+
/*Delegating=*/false, Addr, Ty);
24232433
}
24242434
};
24252435
} // end anonymous namespace
24262436

24272437
void CodeGenFunction::PushDestructorCleanup(const CXXDestructorDecl *D,
2428-
Address Addr) {
2429-
EHStack.pushCleanup<CallLocalDtor>(NormalAndEHCleanup, D, Addr);
2438+
QualType T, Address Addr) {
2439+
EHStack.pushCleanup<CallLocalDtor>(NormalAndEHCleanup, D, Addr, T);
24302440
}
24312441

24322442
void CodeGenFunction::PushDestructorCleanup(QualType T, Address Addr) {
@@ -2436,7 +2446,7 @@ void CodeGenFunction::PushDestructorCleanup(QualType T, Address Addr) {
24362446

24372447
const CXXDestructorDecl *D = ClassDecl->getDestructor();
24382448
assert(D && D->isUsed() && "destructor not marked as used!");
2439-
PushDestructorCleanup(D, Addr);
2449+
PushDestructorCleanup(D, T, Addr);
24402450
}
24412451

24422452
void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {

clang/lib/CodeGen/CGDecl.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -480,11 +480,12 @@ namespace {
480480

481481
template <class Derived>
482482
struct DestroyNRVOVariable : EHScopeStack::Cleanup {
483-
DestroyNRVOVariable(Address addr, llvm::Value *NRVOFlag)
484-
: NRVOFlag(NRVOFlag), Loc(addr) {}
483+
DestroyNRVOVariable(Address addr, QualType type, llvm::Value *NRVOFlag)
484+
: NRVOFlag(NRVOFlag), Loc(addr), Ty(type) {}
485485

486486
llvm::Value *NRVOFlag;
487487
Address Loc;
488+
QualType Ty;
488489

489490
void Emit(CodeGenFunction &CGF, Flags flags) override {
490491
// Along the exceptions path we always execute the dtor.
@@ -511,26 +512,24 @@ namespace {
511512

512513
struct DestroyNRVOVariableCXX final
513514
: DestroyNRVOVariable<DestroyNRVOVariableCXX> {
514-
DestroyNRVOVariableCXX(Address addr, const CXXDestructorDecl *Dtor,
515-
llvm::Value *NRVOFlag)
516-
: DestroyNRVOVariable<DestroyNRVOVariableCXX>(addr, NRVOFlag),
517-
Dtor(Dtor) {}
515+
DestroyNRVOVariableCXX(Address addr, QualType type,
516+
const CXXDestructorDecl *Dtor, llvm::Value *NRVOFlag)
517+
: DestroyNRVOVariable<DestroyNRVOVariableCXX>(addr, type, NRVOFlag),
518+
Dtor(Dtor) {}
518519

519520
const CXXDestructorDecl *Dtor;
520521

521522
void emitDestructorCall(CodeGenFunction &CGF) {
522523
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
523524
/*ForVirtualBase=*/false,
524-
/*Delegating=*/false, Loc);
525+
/*Delegating=*/false, Loc, Ty);
525526
}
526527
};
527528

528529
struct DestroyNRVOVariableC final
529530
: DestroyNRVOVariable<DestroyNRVOVariableC> {
530531
DestroyNRVOVariableC(Address addr, llvm::Value *NRVOFlag, QualType Ty)
531-
: DestroyNRVOVariable<DestroyNRVOVariableC>(addr, NRVOFlag), Ty(Ty) {}
532-
533-
QualType Ty;
532+
: DestroyNRVOVariable<DestroyNRVOVariableC>(addr, Ty, NRVOFlag) {}
534533

535534
void emitDestructorCall(CodeGenFunction &CGF) {
536535
CGF.destroyNonTrivialCStruct(CGF, Loc, Ty);
@@ -1940,7 +1939,7 @@ void CodeGenFunction::emitAutoVarTypeCleanup(
19401939
if (emission.NRVOFlag) {
19411940
assert(!type->isArrayType());
19421941
CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
1943-
EHStack.pushCleanup<DestroyNRVOVariableCXX>(cleanupKind, addr, dtor,
1942+
EHStack.pushCleanup<DestroyNRVOVariableCXX>(cleanupKind, addr, type, dtor,
19441943
emission.NRVOFlag);
19451944
return;
19461945
}

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "CodeGenFunction.h"
1413
#include "CGCUDARuntime.h"
1514
#include "CGCXXABI.h"
1615
#include "CGDebugInfo.h"
1716
#include "CGObjCRuntime.h"
17+
#include "CodeGenFunction.h"
1818
#include "ConstantEmitter.h"
19+
#include "TargetInfo.h"
1920
#include "clang/Basic/CodeGenOptions.h"
2021
#include "clang/CodeGen/CGFunctionInfo.h"
2122
#include "llvm/IR/Intrinsics.h"
@@ -90,12 +91,26 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
9091
}
9192

9293
RValue CodeGenFunction::EmitCXXDestructorCall(
93-
GlobalDecl Dtor, const CGCallee &Callee, llvm::Value *This,
94+
GlobalDecl Dtor, const CGCallee &Callee, llvm::Value *This, QualType ThisTy,
9495
llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *CE) {
96+
const CXXMethodDecl *DtorDecl = cast<CXXMethodDecl>(Dtor.getDecl());
97+
98+
assert(!ThisTy.isNull());
99+
assert(ThisTy->getAsCXXRecordDecl() == DtorDecl->getParent() &&
100+
"Pointer/Object mixup");
101+
102+
LangAS SrcAS = ThisTy.getAddressSpace();
103+
LangAS DstAS = DtorDecl->getMethodQualifiers().getAddressSpace();
104+
if (SrcAS != DstAS) {
105+
QualType DstTy = DtorDecl->getThisType();
106+
llvm::Type *NewType = CGM.getTypes().ConvertType(DstTy);
107+
This = getTargetHooks().performAddrSpaceCast(*this, This, SrcAS, DstAS,
108+
NewType);
109+
}
110+
95111
CallArgList Args;
96-
commonEmitCXXMemberOrOperatorCall(*this, cast<CXXMethodDecl>(Dtor.getDecl()),
97-
This, ImplicitParam, ImplicitParamTy, CE,
98-
Args, nullptr);
112+
commonEmitCXXMemberOrOperatorCall(*this, DtorDecl, This, ImplicitParam,
113+
ImplicitParamTy, CE, Args, nullptr);
99114
return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee,
100115
ReturnValueSlot(), Args);
101116
}
@@ -345,7 +360,9 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
345360
Callee = CGCallee::forDirect(CGM.GetAddrOfFunction(GD, Ty), GD);
346361
}
347362

348-
EmitCXXDestructorCall(GD, Callee, This.getPointer(),
363+
QualType ThisTy =
364+
IsArrow ? Base->getType()->getPointeeType() : Base->getType();
365+
EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy,
349366
/*ImplicitParam=*/nullptr,
350367
/*ImplicitParamTy=*/QualType(), nullptr);
351368
}
@@ -1883,7 +1900,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
18831900
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
18841901
/*ForVirtualBase=*/false,
18851902
/*Delegating=*/false,
1886-
Ptr);
1903+
Ptr, ElementType);
18871904
else if (auto Lifetime = ElementType.getObjCLifetime()) {
18881905
switch (Lifetime) {
18891906
case Qualifiers::OCL_None:

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,8 @@ class CodeGenFunction : public CodeGenTypeCache {
675675
/// PushDestructorCleanup - Push a cleanup to call the
676676
/// complete-object variant of the given destructor on the object at
677677
/// the given address.
678-
void PushDestructorCleanup(const CXXDestructorDecl *Dtor, Address Addr);
678+
void PushDestructorCleanup(const CXXDestructorDecl *Dtor, QualType T,
679+
Address Addr);
679680

680681
/// PopCleanupBlock - Will pop the cleanup entry on the stack and
681682
/// process all branch fixups.
@@ -2554,8 +2555,8 @@ class CodeGenFunction : public CodeGenTypeCache {
25542555
static Destroyer destroyCXXObject;
25552556

25562557
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
2557-
bool ForVirtualBase, bool Delegating,
2558-
Address This);
2558+
bool ForVirtualBase, bool Delegating, Address This,
2559+
QualType ThisTy);
25592560

25602561
void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
25612562
llvm::Type *ElementTy, Address NewPtr,
@@ -3677,9 +3678,9 @@ class CodeGenFunction : public CodeGenTypeCache {
36773678
llvm::Value *ImplicitParam,
36783679
QualType ImplicitParamTy, const CallExpr *E,
36793680
CallArgList *RtlArgs);
3680-
RValue EmitCXXDestructorCall(GlobalDecl Dtor,
3681-
const CGCallee &Callee,
3682-
llvm::Value *This, llvm::Value *ImplicitParam,
3681+
RValue EmitCXXDestructorCall(GlobalDecl Dtor, const CGCallee &Callee,
3682+
llvm::Value *This, QualType ThisTy,
3683+
llvm::Value *ImplicitParam,
36833684
QualType ImplicitParamTy, const CallExpr *E);
36843685
RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
36853686
ReturnValueSlot ReturnValue);

0 commit comments

Comments
 (0)