diff options
author | Anders Carlsson <andersca@mac.com> | 2009-08-16 21:13:42 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-08-16 21:13:42 +0000 |
commit | 60e282cc1e508be327b0481cecedc206873cb86a (patch) | |
tree | fcb1c0b02abf18159dfdcecca6977bf2bb0c7b1c | |
parent | 1352590383c6cf677a3531043a6a41a565ca6e99 (diff) |
Improve handling of delete expressions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79205 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 57 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 1 | ||||
-rw-r--r-- | test/CodeGenCXX/delete.cpp | 25 |
4 files changed, 87 insertions, 0 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 1c9c5634ab..5e71064797 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -514,6 +514,63 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { return NewPtr; } +void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { + if (E->isArrayForm()) { + ErrorUnsupported(E, "delete[] expression"); + return; + }; + + QualType DeleteTy = + E->getArgument()->getType()->getAs<PointerType>()->getPointeeType(); + + llvm::Value *Ptr = EmitScalarExpr(E->getArgument()); + + // Null check the pointer. + llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); + llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(Ptr, llvm::Constant::getNullValue(Ptr->getType()), + "isnull"); + + Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); + EmitBlock(DeleteNotNull); + + // Call the destructor if necessary. + if (const RecordType *RT = DeleteTy->getAs<RecordType>()) { + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (!RD->hasTrivialDestructor()) { + const CXXDestructorDecl *Dtor = RD->getDestructor(getContext()); + if (Dtor->isVirtual()) { + ErrorUnsupported(E, "delete expression with virtual destructor"); + return; + } + + EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr); + } + } + } + + // Call delete. + FunctionDecl *DeleteFD = E->getOperatorDelete(); + const FunctionProtoType *DeleteFTy = + DeleteFD->getType()->getAsFunctionProtoType(); + + CallArgList DeleteArgs; + + QualType ArgTy = DeleteFTy->getArgType(0); + llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); + DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); + + // Emit the call to delete. + EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), + DeleteArgs), + CGM.GetAddrOfFunction(GlobalDecl(DeleteFD)), + DeleteArgs, DeleteFD); + + EmitBlock(DeleteEnd); +} + static bool canGenerateCXXstructor(const CXXRecordDecl *RD, ASTContext &Context) { // The class has base classes - we don't support that right now. diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 0b8cb8cb76..37d2995142 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -293,6 +293,10 @@ public: Value *VisitCXXNewExpr(const CXXNewExpr *E) { return CGF.EmitCXXNewExpr(E); } + Value *VisitCXXDeleteExpr(const CXXDeleteExpr *E) { + CGF.EmitCXXDeleteExpr(E); + return 0; + } // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 3bf17b32b3..c41af94e20 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -607,6 +607,7 @@ public: void PopCXXTemporary(); llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); + void EmitCXXDeleteExpr(const CXXDeleteExpr *E); //===--------------------------------------------------------------------===// // Declaration Emission diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp new file mode 100644 index 0000000000..8367dd8945 --- /dev/null +++ b/test/CodeGenCXX/delete.cpp @@ -0,0 +1,25 @@ +// RUN: clang-cc %s -emit-llvm -o %t && + +void t1(int *a) { + delete a; +} + +struct S { + int a; +}; + +// POD types. +void t3(S *s) { + delete s; +} + +// Non-POD +struct T { + ~T(); + int a; +}; + +void t4(T *t) { + // RUN: grep "call void @_ZN1TD1Ev" %t | count 1 + delete t; +} |