diff options
Diffstat (limited to 'clang/lib/CodeGen/CGExprCXX.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 418 |
1 files changed, 52 insertions, 366 deletions
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 0b5a415a0ea..47dc9fbbc73 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -1615,98 +1615,36 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { EmitBlock(DeleteEnd); } -static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) { - // void __cxa_bad_typeid(); - llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false); - - return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid"); -} - -static void EmitBadTypeidCall(CodeGenFunction &CGF) { - llvm::Value *Fn = getBadTypeidFn(CGF); - CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn(); - CGF.Builder.CreateUnreachable(); -} - -/// \brief Gets the offset to the virtual base that contains the vfptr for -/// MS-ABI polymorphic types. -static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF, - const CXXRecordDecl *RD, - llvm::Value *Value) { - const ASTContext &Context = RD->getASTContext(); - for (const CXXBaseSpecifier &Base : RD->vbases()) - if (Context.getASTRecordLayout(Base.getType()->getAsCXXRecordDecl()) - .hasExtendableVFPtr()) - return CGF.CGM.getCXXABI().GetVirtualBaseClassOffset( - CGF, Value, RD, Base.getType()->getAsCXXRecordDecl()); - llvm_unreachable("One of our vbases should be polymorphic."); -} - -static llvm::Value *emitRTtypeidCall(CodeGenFunction &CGF, - llvm::Value *Argument) { - llvm::Type *ArgTypes[] = {CGF.Int8PtrTy}; - llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction( - llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false), "__RTtypeid"); - llvm::Value *Args[] = {Argument}; - return CGF.EmitRuntimeCall(Function, Args); -} - static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, llvm::Type *StdTypeInfoPtrTy) { // Get the vtable pointer. llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress(); - if (CGF.getTarget().getCXXABI().isMicrosoft()) { - llvm::Value *CastPtr = CGF.Builder.CreateBitCast(ThisPtr, CGF.Int8PtrTy); - const CXXRecordDecl *RD = E->getType()->getAsCXXRecordDecl(); - if (CGF.getContext().getASTRecordLayout(RD).hasExtendableVFPtr()) - return CGF.Builder.CreateBitCast(emitRTtypeidCall(CGF, CastPtr), - StdTypeInfoPtrTy); - llvm::BasicBlock *EntryBlock = CGF.Builder.GetInsertBlock(); - llvm::BasicBlock *AdjustBlock = CGF.createBasicBlock("type_id.valid"); - llvm::BasicBlock *ExitBlock = CGF.createBasicBlock("type_id.call"); - CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNull(CastPtr), ExitBlock, - AdjustBlock); - // Emit the call block and code for it. - CGF.EmitBlock(AdjustBlock); - llvm::Value *AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP( - CastPtr, getPolymorphicOffset(CGF, RD, CastPtr)); - // Emit the call block and the phi nodes for it. - CGF.EmitBlock(ExitBlock); - llvm::PHINode *ValuePHI = CGF.Builder.CreatePHI(CGF.Int8PtrTy, 2); - ValuePHI->addIncoming(AdjustedThisPtr, AdjustBlock); - ValuePHI->addIncoming(llvm::Constant::getNullValue(CGF.Int8PtrTy), - EntryBlock); - return CGF.Builder.CreateBitCast(emitRTtypeidCall(CGF, ValuePHI), - StdTypeInfoPtrTy); - } - // C++ [expr.typeid]p2: // If the glvalue expression is obtained by applying the unary * operator to // a pointer and the pointer is a null pointer value, the typeid expression // throws the std::bad_typeid exception. - if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) { - if (UO->getOpcode() == UO_Deref) { - llvm::BasicBlock *BadTypeidBlock = + bool IsDeref = false; + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) + if (UO->getOpcode() == UO_Deref) + IsDeref = true; + + QualType SrcRecordTy = E->getType(); + if (CGF.CGM.getCXXABI().shouldTypeidBeNullChecked(IsDeref, SrcRecordTy)) { + llvm::BasicBlock *BadTypeidBlock = CGF.createBasicBlock("typeid.bad_typeid"); - llvm::BasicBlock *EndBlock = - CGF.createBasicBlock("typeid.end"); + llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end"); - llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr); - CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock); + llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr); + CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock); - CGF.EmitBlock(BadTypeidBlock); - EmitBadTypeidCall(CGF); - CGF.EmitBlock(EndBlock); - } + CGF.EmitBlock(BadTypeidBlock); + CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF); + CGF.EmitBlock(EndBlock); } - llvm::Value *Value = CGF.GetVTablePtr(ThisPtr, - StdTypeInfoPtrTy->getPointerTo()); - - // Load the type info. - Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL); - return CGF.Builder.CreateLoad(Value); + return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr, + StdTypeInfoPtrTy); } llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { @@ -1733,173 +1671,6 @@ llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { StdTypeInfoPtrTy); } -static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) { - // void *__dynamic_cast(const void *sub, - // const abi::__class_type_info *src, - // const abi::__class_type_info *dst, - // std::ptrdiff_t src2dst_offset); - - llvm::Type *Int8PtrTy = CGF.Int8PtrTy; - llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - - llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy }; - - llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); - - // Mark the function as nounwind readonly. - llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind, - llvm::Attribute::ReadOnly }; - llvm::AttributeSet Attrs = llvm::AttributeSet::get( - CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs); - - return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs); -} - -static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) { - // void __cxa_bad_cast(); - llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false); - return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast"); -} - -static void EmitBadCastCall(CodeGenFunction &CGF) { - llvm::Value *Fn = getBadCastFn(CGF); - CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn(); - CGF.Builder.CreateUnreachable(); -} - -/// \brief Compute the src2dst_offset hint as described in the -/// Itanium C++ ABI [2.9.7] -static CharUnits computeOffsetHint(ASTContext &Context, - const CXXRecordDecl *Src, - const CXXRecordDecl *Dst) { - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - - // If Dst is not derived from Src we can skip the whole computation below and - // return that Src is not a public base of Dst. Record all inheritance paths. - if (!Dst->isDerivedFrom(Src, Paths)) - return CharUnits::fromQuantity(-2ULL); - - unsigned NumPublicPaths = 0; - CharUnits Offset; - - // Now walk all possible inheritance paths. - for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end(); - I != E; ++I) { - if (I->Access != AS_public) // Ignore non-public inheritance. - continue; - - ++NumPublicPaths; - - for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) { - // If the path contains a virtual base class we can't give any hint. - // -1: no hint. - if (J->Base->isVirtual()) - return CharUnits::fromQuantity(-1ULL); - - if (NumPublicPaths > 1) // Won't use offsets, skip computation. - continue; - - // Accumulate the base class offsets. - const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class); - Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl()); - } - } - - // -2: Src is not a public base of Dst. - if (NumPublicPaths == 0) - return CharUnits::fromQuantity(-2ULL); - - // -3: Src is a multiple public base type but never a virtual base type. - if (NumPublicPaths > 1) - return CharUnits::fromQuantity(-3ULL); - - // Otherwise, the Src type is a unique public nonvirtual base type of Dst. - // Return the offset of Src from the origin of Dst. - return Offset; -} - -static llvm::Value * -EmitItaniumDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value, - QualType SrcTy, QualType DestTy, - llvm::BasicBlock *CastEnd) { - llvm::Type *PtrDiffLTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - llvm::Type *DestLTy = CGF.ConvertType(DestTy); - - if (const PointerType *PTy = DestTy->getAs<PointerType>()) { - if (PTy->getPointeeType()->isVoidType()) { - // C++ [expr.dynamic.cast]p7: - // If T is "pointer to cv void," then the result is a pointer to the - // most derived object pointed to by v. - - // Get the vtable pointer. - llvm::Value *VTable = CGF.GetVTablePtr(Value, PtrDiffLTy->getPointerTo()); - - // Get the offset-to-top from the vtable. - llvm::Value *OffsetToTop = - CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL); - OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top"); - - // Finally, add the offset to the pointer. - Value = CGF.EmitCastToVoidPtr(Value); - Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop); - - return CGF.Builder.CreateBitCast(Value, DestLTy); - } - } - - QualType SrcRecordTy; - QualType DestRecordTy; - - if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) { - SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType(); - DestRecordTy = DestPTy->getPointeeType(); - } else { - SrcRecordTy = SrcTy; - DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType(); - } - - assert(SrcRecordTy->isRecordType() && "source type must be a record type!"); - assert(DestRecordTy->isRecordType() && "dest type must be a record type!"); - - llvm::Value *SrcRTTI = - CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType()); - llvm::Value *DestRTTI = - CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType()); - - // Compute the offset hint. - const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl(); - const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl(); - llvm::Value *OffsetHint = - llvm::ConstantInt::get(PtrDiffLTy, - computeOffsetHint(CGF.getContext(), SrcDecl, - DestDecl).getQuantity()); - - // Emit the call to __dynamic_cast. - Value = CGF.EmitCastToVoidPtr(Value); - - llvm::Value *args[] = { Value, SrcRTTI, DestRTTI, OffsetHint }; - Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), args); - Value = CGF.Builder.CreateBitCast(Value, DestLTy); - - /// C++ [expr.dynamic.cast]p9: - /// A failed cast to reference type throws std::bad_cast - if (DestTy->isReferenceType()) { - llvm::BasicBlock *BadCastBlock = - CGF.createBasicBlock("dynamic_cast.bad_cast"); - - llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value); - CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd); - - CGF.EmitBlock(BadCastBlock); - EmitBadCastCall(CGF); - } - - return Value; -} - static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF, QualType DestTy) { llvm::Type *DestLTy = CGF.ConvertType(DestTy); @@ -1908,142 +1679,49 @@ static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF, /// C++ [expr.dynamic.cast]p9: /// A failed cast to reference type throws std::bad_cast - EmitBadCastCall(CGF); + if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF)) + return nullptr; CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end")); return llvm::UndefValue::get(DestLTy); } -namespace { -struct MSDynamicCastBuilder { - MSDynamicCastBuilder(CodeGenFunction &CGF, const CXXDynamicCastExpr *DCE); - llvm::Value *emitDynamicCastCall(llvm::Value *Value); - llvm::Value *emitDynamicCast(llvm::Value *Value); - - CodeGenFunction &CGF; - CGBuilderTy &Builder; - llvm::PointerType *Int8PtrTy; - QualType SrcTy, DstTy; - const CXXRecordDecl *SrcDecl; - bool IsPtrCast, IsCastToVoid, IsCastOfNull; -}; -} // namespace - -MSDynamicCastBuilder::MSDynamicCastBuilder(CodeGenFunction &CGF, - const CXXDynamicCastExpr *DCE) - : CGF(CGF), Builder(CGF.Builder), Int8PtrTy(CGF.Int8PtrTy), - SrcDecl(nullptr) { - DstTy = DCE->getTypeAsWritten(); - IsPtrCast = DstTy->isPointerType(); - // Get the PointeeTypes. After this point the original types are not used. - DstTy = IsPtrCast ? DstTy->castAs<PointerType>()->getPointeeType() - : DstTy->castAs<ReferenceType>()->getPointeeType(); - IsCastToVoid = DstTy->isVoidType(); - IsCastOfNull = DCE->isAlwaysNull(); - if (IsCastOfNull) - return; - SrcTy = DCE->getSubExpr()->getType(); - SrcTy = IsPtrCast ? SrcTy->castAs<PointerType>()->getPointeeType() : SrcTy; - SrcDecl = SrcTy->getAsCXXRecordDecl(); - // If we don't need a base adjustment, we don't need a SrcDecl so clear it - // here. Later we use the existence of the SrcDecl to determine the need for - // a base adjustment. - if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr()) - SrcDecl = nullptr; -} - -llvm::Value *MSDynamicCastBuilder::emitDynamicCastCall(llvm::Value *Value) { - llvm::IntegerType *Int32Ty = CGF.Int32Ty; - llvm::Value *Offset = llvm::ConstantInt::get(Int32Ty, 0); - Value = Builder.CreateBitCast(Value, Int8PtrTy); - // If we need to perform a base adjustment, do it here. - if (SrcDecl) { - Offset = getPolymorphicOffset(CGF, SrcDecl, Value); - Value = Builder.CreateInBoundsGEP(Value, Offset); - Offset = Builder.CreateTrunc(Offset, Int32Ty); - } - if (IsCastToVoid) { - // PVOID __RTCastToVoid( - // PVOID inptr) - llvm::Type *ArgTypes[] = {Int8PtrTy}; - llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction( - llvm::FunctionType::get(Int8PtrTy, ArgTypes, false), "__RTCastToVoid"); - llvm::Value *Args[] = {Value}; - return CGF.EmitRuntimeCall(Function, Args); - } - // PVOID __RTDynamicCast( - // PVOID inptr, - // LONG VfDelta, - // PVOID SrcType, - // PVOID TargetType, - // BOOL isReference) - llvm::Type *ArgTypes[] = {Int8PtrTy, Int32Ty, Int8PtrTy, Int8PtrTy, Int32Ty}; - llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction( - llvm::FunctionType::get(Int8PtrTy, ArgTypes, false), "__RTDynamicCast"); - llvm::Value *Args[] = { - Value, Offset, - CGF.CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType()), - CGF.CGM.GetAddrOfRTTIDescriptor(DstTy.getUnqualifiedType()), - llvm::ConstantInt::get(Int32Ty, IsPtrCast ? 0 : 1)}; - return CGF.EmitRuntimeCall(Function, Args); -} - -llvm::Value *MSDynamicCastBuilder::emitDynamicCast(llvm::Value *Value) { - // Note about undefined behavior: If the dynamic cast is casting to a - // reference type and the input is null, we hit a grey area in the standard. - // Here we're interpreting the behavior as undefined. The effects are the - // following: If the compiler determines that the argument is statically null - // or if the argument is dynamically null but does not require base - // adjustment, __RTDynamicCast will be called with a null argument and the - // isreference bit set. In this case __RTDynamicCast will throw - // std::bad_cast. If the argument is dynamically null and a base adjustment is - // required the resulting code will produce an out of bounds memory reference - // when trying to read VBTblPtr. In Itanium mode clang also emits a vtable - // load that fails at run time. - llvm::PointerType *DstLTy = CGF.ConvertType(DstTy)->getPointerTo(); - if (IsCastOfNull && IsPtrCast) - return Builder.CreateBitCast(Value, DstLTy); - if (IsCastOfNull || !IsPtrCast || !SrcDecl) - return Builder.CreateBitCast(emitDynamicCastCall(Value), DstLTy); - // !IsCastOfNull && IsPtrCast && SrcDecl - // In this case we have a pointer that requires a base adjustment. An - // adjustment is only required if the pointer is actually valid so here we - // perform a null check before doing the base adjustment and calling - // __RTDynamicCast. In the case that the argument is null we simply return - // null without calling __RTDynamicCast. - llvm::BasicBlock *EntryBlock = Builder.GetInsertBlock(); - llvm::BasicBlock *CallBlock = CGF.createBasicBlock("dynamic_cast.valid"); - llvm::BasicBlock *ExitBlock = CGF.createBasicBlock("dynamic_cast.call"); - Builder.CreateCondBr(Builder.CreateIsNull(Value), ExitBlock, CallBlock); - // Emit the call block and code for it. - CGF.EmitBlock(CallBlock); - Value = emitDynamicCastCall(Value); - // Emit the call block and the phi nodes for it. - CGF.EmitBlock(ExitBlock); - llvm::PHINode *ValuePHI = Builder.CreatePHI(Int8PtrTy, 2); - ValuePHI->addIncoming(Value, CallBlock); - ValuePHI->addIncoming(llvm::Constant::getNullValue(Int8PtrTy), EntryBlock); - return Builder.CreateBitCast(ValuePHI, DstLTy); -} - llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value, const CXXDynamicCastExpr *DCE) { - if (getTarget().getCXXABI().isMicrosoft()) { - MSDynamicCastBuilder Builder(*this, DCE); - return Builder.emitDynamicCast(Value); - } - QualType DestTy = DCE->getTypeAsWritten(); if (DCE->isAlwaysNull()) - return EmitDynamicCastToNull(*this, DestTy); + if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy)) + return T; QualType SrcTy = DCE->getSubExpr()->getType(); + // C++ [expr.dynamic.cast]p7: + // If T is "pointer to cv void," then the result is a pointer to the most + // derived object pointed to by v. + const PointerType *DestPTy = DestTy->getAs<PointerType>(); + + bool isDynamicCastToVoid; + QualType SrcRecordTy; + QualType DestRecordTy; + if (DestPTy) { + isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType(); + SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType(); + DestRecordTy = DestPTy->getPointeeType(); + } else { + isDynamicCastToVoid = false; + SrcRecordTy = SrcTy; + DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType(); + } + + assert(SrcRecordTy->isRecordType() && "source type must be a record type!"); + // C++ [expr.dynamic.cast]p4: // If the value of v is a null pointer value in the pointer case, the result // is the null pointer value of type T. - bool ShouldNullCheckSrcValue = SrcTy->isPointerType(); + bool ShouldNullCheckSrcValue = + CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(), + SrcRecordTy); llvm::BasicBlock *CastNull = nullptr; llvm::BasicBlock *CastNotNull = nullptr; @@ -2058,7 +1736,15 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value, EmitBlock(CastNotNull); } - Value = EmitItaniumDynamicCastCall(*this, Value, SrcTy, DestTy, CastEnd); + if (isDynamicCastToVoid) { + Value = CGM.getCXXABI().EmitDynamicCastToVoid(*this, Value, SrcRecordTy, + DestTy); + } else { + assert(DestRecordTy->isRecordType() && + "destination type must be a record type!"); + Value = CGM.getCXXABI().EmitDynamicCastCall(*this, Value, SrcRecordTy, + DestTy, DestRecordTy, CastEnd); + } if (ShouldNullCheckSrcValue) { EmitBranch(CastEnd); |