Skip to content

Commit

Permalink
[OpenCL] Improve destructor support in C++ for OpenCL
Browse files Browse the repository at this point in the history
This re-applies r366422 with a fix for Bug PR42665 and a new regression
test.

llvm-svn: 366670
  • Loading branch information
mantognini committed Jul 22, 2019
1 parent 6771a89 commit 8855963
Show file tree
Hide file tree
Showing 17 changed files with 312 additions and 116 deletions.
14 changes: 11 additions & 3 deletions clang/include/clang/AST/DeclCXX.h
Expand Up @@ -2232,30 +2232,38 @@ class CXXMethodDecl : public FunctionDecl {

overridden_method_range overridden_methods() const;

/// Returns the parent of this method declaration, which
/// Return the parent of this method declaration, which
/// is the class in which this method is defined.
const CXXRecordDecl *getParent() const {
return cast<CXXRecordDecl>(FunctionDecl::getParent());
}

/// Returns the parent of this method declaration, which
/// Return the parent of this method declaration, which
/// is the class in which this method is defined.
CXXRecordDecl *getParent() {
return const_cast<CXXRecordDecl *>(
cast<CXXRecordDecl>(FunctionDecl::getParent()));
}

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

/// Return the type of the object pointed by \c this.
///
/// See getThisType() for usage restriction.
QualType getThisObjectType() const;

static QualType getThisType(const FunctionProtoType *FPT,
const CXXRecordDecl *Decl);

static QualType getThisObjectType(const FunctionProtoType *FPT,
const CXXRecordDecl *Decl);

Qualifiers getMethodQualifiers() const {
return getType()->getAs<FunctionProtoType>()->getMethodQuals();
}
Expand Down
11 changes: 8 additions & 3 deletions clang/include/clang/AST/ExprCXX.h
Expand Up @@ -185,15 +185,20 @@ class CXXMemberCallExpr final : public CallExpr {
static CXXMemberCallExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
EmptyShell Empty);

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

/// Retrieves the declaration of the called method.
/// Retrieve the type of the object argument.
///
/// Note that this always returns a non-pointer type.
QualType getObjectType() const;

/// Retrieve the declaration of the called method.
CXXMethodDecl *getMethodDecl() const;

/// Retrieves the CXXRecordDecl for the underlying type of
/// Retrieve the CXXRecordDecl for the underlying type of
/// the implicit object argument.
///
/// Note that this is may not be the same declaration as that of the class
Expand Down
25 changes: 22 additions & 3 deletions clang/lib/AST/DeclCXX.cpp
Expand Up @@ -2253,12 +2253,23 @@ CXXMethodDecl::overridden_methods() const {
return getASTContext().overridden_methods(this);
}

static QualType getThisObjectType(ASTContext &C, const FunctionProtoType *FPT,
const CXXRecordDecl *Decl) {
QualType ClassTy = C.getTypeDeclType(Decl);
return C.getQualifiedType(ClassTy, FPT->getMethodQuals());
}

QualType CXXMethodDecl::getThisType(const FunctionProtoType *FPT,
const CXXRecordDecl *Decl) {
ASTContext &C = Decl->getASTContext();
QualType ClassTy = C.getTypeDeclType(Decl);
ClassTy = C.getQualifiedType(ClassTy, FPT->getMethodQuals());
return C.getPointerType(ClassTy);
QualType ObjectTy = ::getThisObjectType(C, FPT, Decl);
return C.getPointerType(ObjectTy);
}

QualType CXXMethodDecl::getThisObjectType(const FunctionProtoType *FPT,
const CXXRecordDecl *Decl) {
ASTContext &C = Decl->getASTContext();
return ::getThisObjectType(C, FPT, Decl);
}

QualType CXXMethodDecl::getThisType() const {
Expand All @@ -2273,6 +2284,14 @@ QualType CXXMethodDecl::getThisType() const {
getParent());
}

QualType CXXMethodDecl::getThisObjectType() const {
// Ditto getThisType.
assert(isInstance() && "No 'this' for static methods!");

return CXXMethodDecl::getThisObjectType(getType()->getAs<FunctionProtoType>(),
getParent());
}

bool CXXMethodDecl::hasInlineBody() const {
// If this function is a template instantiation, look at the template from
// which it was instantiated.
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/ExprCXX.cpp
Expand Up @@ -651,6 +651,13 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() const {
return nullptr;
}

QualType CXXMemberCallExpr::getObjectType() const {
QualType Ty = getImplicitObjectArgument()->getType();
if (Ty->isPointerType())
Ty = Ty->getPointeeType();
return Ty;
}

CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
if (const auto *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
Expand Down
14 changes: 9 additions & 5 deletions clang/lib/CodeGen/CGCXXABI.h
Expand Up @@ -378,7 +378,7 @@ class CGCXXABI {
virtual void EmitDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *DD, CXXDtorType Type,
bool ForVirtualBase, bool Delegating,
Address This) = 0;
Address This, QualType ThisTy) = 0;

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

using DeleteOrMemberCallExpr =
llvm::PointerUnion<const CXXDeleteExpr *, const CXXMemberCallExpr *>;

/// Emit the ABI-specific virtual destructor call.
virtual llvm::Value *
EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, Address This,
const CXXMemberCallExpr *CE) = 0;
virtual llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
CXXDtorType DtorType,
Address This,
DeleteOrMemberCallExpr E) = 0;

virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
GlobalDecl GD,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGCall.cpp
Expand Up @@ -3505,7 +3505,7 @@ struct DestroyUnpassedArg final : EHScopeStack::Cleanup {
const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
assert(!Dtor->isTrivial());
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false,
/*Delegating=*/false, Addr);
/*Delegating=*/false, Addr, Ty);
} else {
CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Ty));
}
Expand Down
40 changes: 25 additions & 15 deletions clang/lib/CodeGen/CGClass.cpp
Expand Up @@ -491,12 +491,15 @@ namespace {
cast<CXXMethodDecl>(CGF.CurCodeDecl)->getParent();

const CXXDestructorDecl *D = BaseClass->getDestructor();
// We are already inside a destructor, so presumably the object being
// destroyed should have the expected type.
QualType ThisTy = D->getThisObjectType();
Address Addr =
CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThisAddress(),
DerivedClass, BaseClass,
BaseIsVirtual);
CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual,
/*Delegating=*/false, Addr);
/*Delegating=*/false, Addr, ThisTy);
}
};

Expand Down Expand Up @@ -1440,9 +1443,11 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
if (DtorType == Dtor_Deleting) {
RunCleanupsScope DtorEpilogue(*this);
EnterDtorCleanups(Dtor, Dtor_Deleting);
if (HaveInsertPoint())
if (HaveInsertPoint()) {
QualType ThisTy = Dtor->getThisObjectType();
EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
/*Delegating=*/false, LoadCXXThisAddress());
/*Delegating=*/false, LoadCXXThisAddress(), ThisTy);
}
return;
}

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

if (!isTryBody) {
QualType ThisTy = Dtor->getThisObjectType();
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
/*Delegating=*/false, LoadCXXThisAddress());
/*Delegating=*/false, LoadCXXThisAddress(), ThisTy);
break;
}

Expand Down Expand Up @@ -2013,7 +2019,7 @@ void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
const CXXDestructorDecl *dtor = record->getDestructor();
assert(!dtor->isTrivial());
CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false,
/*Delegating=*/false, addr);
/*Delegating=*/false, addr, type);
}

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

void Emit(CodeGenFunction &CGF, Flags flags) override {
// We are calling the destructor from within the constructor.
// Therefore, "this" should have the expected type.
QualType ThisTy = Dtor->getThisObjectType();
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
/*Delegating=*/true, Addr);
/*Delegating=*/true, Addr, ThisTy);
}
};
} // end anonymous namespace
Expand Down Expand Up @@ -2402,31 +2411,32 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
bool ForVirtualBase,
bool Delegating,
Address This) {
bool Delegating, Address This,
QualType ThisTy) {
CGM.getCXXABI().EmitDestructorCall(*this, DD, Type, ForVirtualBase,
Delegating, This);
Delegating, This, ThisTy);
}

namespace {
struct CallLocalDtor final : EHScopeStack::Cleanup {
const CXXDestructorDecl *Dtor;
Address Addr;
QualType Ty;

CallLocalDtor(const CXXDestructorDecl *D, Address Addr)
: Dtor(D), Addr(Addr) {}
CallLocalDtor(const CXXDestructorDecl *D, Address Addr, QualType Ty)
: Dtor(D), Addr(Addr), Ty(Ty) {}

void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false,
/*Delegating=*/false, Addr);
/*Delegating=*/false, Addr, Ty);
}
};
} // end anonymous namespace

void CodeGenFunction::PushDestructorCleanup(const CXXDestructorDecl *D,
Address Addr) {
EHStack.pushCleanup<CallLocalDtor>(NormalAndEHCleanup, D, Addr);
QualType T, Address Addr) {
EHStack.pushCleanup<CallLocalDtor>(NormalAndEHCleanup, D, Addr, T);
}

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

const CXXDestructorDecl *D = ClassDecl->getDestructor();
assert(D && D->isUsed() && "destructor not marked as used!");
PushDestructorCleanup(D, Addr);
PushDestructorCleanup(D, T, Addr);
}

void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {
Expand Down
21 changes: 10 additions & 11 deletions clang/lib/CodeGen/CGDecl.cpp
Expand Up @@ -480,11 +480,12 @@ namespace {

template <class Derived>
struct DestroyNRVOVariable : EHScopeStack::Cleanup {
DestroyNRVOVariable(Address addr, llvm::Value *NRVOFlag)
: NRVOFlag(NRVOFlag), Loc(addr) {}
DestroyNRVOVariable(Address addr, QualType type, llvm::Value *NRVOFlag)
: NRVOFlag(NRVOFlag), Loc(addr), Ty(type) {}

llvm::Value *NRVOFlag;
Address Loc;
QualType Ty;

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

struct DestroyNRVOVariableCXX final
: DestroyNRVOVariable<DestroyNRVOVariableCXX> {
DestroyNRVOVariableCXX(Address addr, const CXXDestructorDecl *Dtor,
llvm::Value *NRVOFlag)
: DestroyNRVOVariable<DestroyNRVOVariableCXX>(addr, NRVOFlag),
Dtor(Dtor) {}
DestroyNRVOVariableCXX(Address addr, QualType type,
const CXXDestructorDecl *Dtor, llvm::Value *NRVOFlag)
: DestroyNRVOVariable<DestroyNRVOVariableCXX>(addr, type, NRVOFlag),
Dtor(Dtor) {}

const CXXDestructorDecl *Dtor;

void emitDestructorCall(CodeGenFunction &CGF) {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false,
/*Delegating=*/false, Loc);
/*Delegating=*/false, Loc, Ty);
}
};

struct DestroyNRVOVariableC final
: DestroyNRVOVariable<DestroyNRVOVariableC> {
DestroyNRVOVariableC(Address addr, llvm::Value *NRVOFlag, QualType Ty)
: DestroyNRVOVariable<DestroyNRVOVariableC>(addr, NRVOFlag), Ty(Ty) {}

QualType Ty;
: DestroyNRVOVariable<DestroyNRVOVariableC>(addr, Ty, NRVOFlag) {}

void emitDestructorCall(CodeGenFunction &CGF) {
CGF.destroyNonTrivialCStruct(CGF, Loc, Ty);
Expand Down Expand Up @@ -1940,7 +1939,7 @@ void CodeGenFunction::emitAutoVarTypeCleanup(
if (emission.NRVOFlag) {
assert(!type->isArrayType());
CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
EHStack.pushCleanup<DestroyNRVOVariableCXX>(cleanupKind, addr, dtor,
EHStack.pushCleanup<DestroyNRVOVariableCXX>(cleanupKind, addr, type, dtor,
emission.NRVOFlag);
return;
}
Expand Down
31 changes: 24 additions & 7 deletions clang/lib/CodeGen/CGExprCXX.cpp
Expand Up @@ -10,12 +10,13 @@
//
//===----------------------------------------------------------------------===//

#include "CodeGenFunction.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/IR/Intrinsics.h"
Expand Down Expand Up @@ -90,12 +91,26 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
}

RValue CodeGenFunction::EmitCXXDestructorCall(
GlobalDecl Dtor, const CGCallee &Callee, llvm::Value *This,
GlobalDecl Dtor, const CGCallee &Callee, llvm::Value *This, QualType ThisTy,
llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *CE) {
const CXXMethodDecl *DtorDecl = cast<CXXMethodDecl>(Dtor.getDecl());

assert(!ThisTy.isNull());
assert(ThisTy->getAsCXXRecordDecl() == DtorDecl->getParent() &&
"Pointer/Object mixup");

LangAS SrcAS = ThisTy.getAddressSpace();
LangAS DstAS = DtorDecl->getMethodQualifiers().getAddressSpace();
if (SrcAS != DstAS) {
QualType DstTy = DtorDecl->getThisType();
llvm::Type *NewType = CGM.getTypes().ConvertType(DstTy);
This = getTargetHooks().performAddrSpaceCast(*this, This, SrcAS, DstAS,
NewType);
}

CallArgList Args;
commonEmitCXXMemberOrOperatorCall(*this, cast<CXXMethodDecl>(Dtor.getDecl()),
This, ImplicitParam, ImplicitParamTy, CE,
Args, nullptr);
commonEmitCXXMemberOrOperatorCall(*this, DtorDecl, This, ImplicitParam,
ImplicitParamTy, CE, Args, nullptr);
return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee,
ReturnValueSlot(), Args);
}
Expand Down Expand Up @@ -345,7 +360,9 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
Callee = CGCallee::forDirect(CGM.GetAddrOfFunction(GD, Ty), GD);
}

EmitCXXDestructorCall(GD, Callee, This.getPointer(),
QualType ThisTy =
IsArrow ? Base->getType()->getPointeeType() : Base->getType();
EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy,
/*ImplicitParam=*/nullptr,
/*ImplicitParamTy=*/QualType(), nullptr);
}
Expand Down Expand Up @@ -1883,7 +1900,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false,
/*Delegating=*/false,
Ptr);
Ptr, ElementType);
else if (auto Lifetime = ElementType.getObjCLifetime()) {
switch (Lifetime) {
case Qualifiers::OCL_None:
Expand Down

0 comments on commit 8855963

Please sign in to comment.