Skip to content

Commit 8855963

Browse files
committed
[OpenCL] Improve destructor support in C++ for OpenCL
This re-applies r366422 with a fix for Bug PR42665 and a new regression test. llvm-svn: 366670
1 parent 6771a89 commit 8855963

17 files changed

+312
-116
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/include/clang/AST/ExprCXX.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,20 @@ class CXXMemberCallExpr final : public CallExpr {
185185
static CXXMemberCallExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
186186
EmptyShell Empty);
187187

188-
/// Retrieves the implicit object argument for the member call.
188+
/// Retrieve the implicit object argument for the member call.
189189
///
190190
/// For example, in "x.f(5)", this returns the sub-expression "x".
191191
Expr *getImplicitObjectArgument() const;
192192

193-
/// Retrieves the declaration of the called method.
193+
/// Retrieve the type of the object argument.
194+
///
195+
/// Note that this always returns a non-pointer type.
196+
QualType getObjectType() const;
197+
198+
/// Retrieve the declaration of the called method.
194199
CXXMethodDecl *getMethodDecl() const;
195200

196-
/// Retrieves the CXXRecordDecl for the underlying type of
201+
/// Retrieve the CXXRecordDecl for the underlying type of
197202
/// the implicit object argument.
198203
///
199204
/// Note that this is may not be the same declaration as that of the class

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/AST/ExprCXX.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,13 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() const {
651651
return nullptr;
652652
}
653653

654+
QualType CXXMemberCallExpr::getObjectType() const {
655+
QualType Ty = getImplicitObjectArgument()->getType();
656+
if (Ty->isPointerType())
657+
Ty = Ty->getPointeeType();
658+
return Ty;
659+
}
660+
654661
CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
655662
if (const auto *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
656663
return cast<CXXMethodDecl>(MemExpr->getMemberDecl());

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
@@ -3505,7 +3505,7 @@ struct DestroyUnpassedArg final : EHScopeStack::Cleanup {
35053505
const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
35063506
assert(!Dtor->isTrivial());
35073507
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false,
3508-
/*Delegating=*/false, Addr);
3508+
/*Delegating=*/false, Addr, Ty);
35093509
} else {
35103510
CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Ty));
35113511
}

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:

0 commit comments

Comments
 (0)