diff options
Diffstat (limited to 'clang/lib/CodeGen/CGCXXExpr.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGCXXExpr.cpp | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/clang/lib/CodeGen/CGCXXExpr.cpp b/clang/lib/CodeGen/CGCXXExpr.cpp index 9fb1059e881..918ea0b5a98 100644 --- a/clang/lib/CodeGen/CGCXXExpr.cpp +++ b/clang/lib/CodeGen/CGCXXExpr.cpp @@ -388,7 +388,8 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { const llvm::FunctionType *FTy; FTy = llvm::FunctionType::get(ResultType, false); llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid"); - Builder.CreateCall(F); + Builder.CreateCall(F)->setDoesNotReturn(); + // FIXME: Should we have the below? Builder.CreateUnreachable(); EmitBlock(NonZeroBlock); } @@ -403,3 +404,111 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { ErrorUnsupported(E, "typeid expression"); return 0; } + +llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, + const CXXDynamicCastExpr *DCE) { + QualType CastTy = DCE->getTypeAsWritten(); + QualType ArgTy = DCE->getSubExpr()->getType(); + const llvm::Type *LArgTy = ConvertType(ArgTy); + const llvm::Type *LTy = ConvertType(DCE->getType()); + CXXRecordDecl *SrcTy; + CXXRecordDecl *DstTy; + QualType Ty = CastTy.getTypePtr()->getPointeeType(); + CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType(); + DstTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl()); + Ty = ArgTy; + if (ArgTy.getTypePtr()->isPointerType() + || ArgTy.getTypePtr()->isReferenceType()) + Ty = Ty.getTypePtr()->getPointeeType(); + CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType(); + SrcTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl()); + bool CanBeZero = false; + bool ThrowOnBad = false; + bool ToVoid = false; + QualType InnerType = CastTy->getPointeeType(); + if (CastTy->isPointerType()) { + // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this + CanBeZero = true; + if (InnerType->isVoidType()) + ToVoid = true; + } else { + LTy = LTy->getPointerTo(); + ThrowOnBad = true; + } + + // FIXME: Add support for ToVoid + + // FIXME: Ensure non-runtime casts are done before this point. + + llvm::BasicBlock *ContBlock = createBasicBlock(); + llvm::BasicBlock *NullBlock = 0; + llvm::BasicBlock *NonZeroBlock = 0; + if (CanBeZero) { + NonZeroBlock = createBasicBlock(); + NullBlock = createBasicBlock(); + llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy); + Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), + NonZeroBlock, NullBlock); + EmitBlock(NonZeroBlock); + } + + + /// Call __dynamic_cast + const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext); + const llvm::FunctionType *FTy; + std::vector<const llvm::Type*> ArgTys; + const llvm::Type *PtrToInt8Ty + = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType()); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrDiffTy); + FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + + // FIXME: Calculate better hint. + llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); + llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy); + llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy); + V = Builder.CreateBitCast(V, PtrToInt8Ty); + V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), + V, SrcArg, DstArg, hint); + V = Builder.CreateBitCast(V, LTy); + + llvm::BasicBlock *BadCastBlock = 0; + if (ThrowOnBad) { + BadCastBlock = createBasicBlock(); + + llvm::Value *Zero = llvm::Constant::getNullValue(LTy); + Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), + ContBlock, BadCastBlock); + EmitBlock(BadCastBlock); + /// Call __cxa_bad_cast + ResultType = llvm::Type::getVoidTy(VMContext); + const llvm::FunctionType *FBadTy; + FTy = llvm::FunctionType::get(ResultType, false); + llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast"); + Builder.CreateCall(F)->setDoesNotReturn(); + // Builder.CreateUnreachable(); + } + + if (CanBeZero) { + Builder.CreateBr(ContBlock); + EmitBlock(NullBlock); + Builder.CreateBr(ContBlock); + } + EmitBlock(ContBlock); + if (CanBeZero) { + llvm::PHINode *PHI = Builder.CreatePHI(LTy); + PHI->reserveOperandSpace(3); + PHI->addIncoming(V, NonZeroBlock); + PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock); + if (ThrowOnBad) + PHI->addIncoming(llvm::Constant::getNullValue(LTy), BadCastBlock); + V = PHI; + } + + return V; +} |