From: Anders Carlsson Date: Mon, 11 Apr 2011 01:45:29 +0000 (+0000) Subject: When we know that a dynamic_cast always returns null, we can make X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3ddcdd5d6c88902d24baa9e6bb240a3da88e68d4;p=clang When we know that a dynamic_cast always returns null, we can make CodeGenFunction::EmitDynamicCast always return null or throw a bad_cast exception. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129264 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index ff7b7112ca..a3d3f439b6 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -1416,6 +1416,18 @@ static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast"); } +static void EmitBadCastCall(CodeGenFunction &CGF) { + llvm::Value *F = getBadCastFn(CGF); + if (llvm::BasicBlock *InvokeDest = CGF.getInvokeDest()) { + llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); + CGF.Builder.CreateInvoke(F, Cont, InvokeDest)->setDoesNotReturn(); + CGF.EmitBlock(Cont); + } else + CGF.Builder.CreateCall(F)->setDoesNotReturn(); + + CGF.Builder.CreateUnreachable(); +} + static llvm::Value * EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value, QualType SrcTy, QualType DestTy, @@ -1484,25 +1496,35 @@ EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value, CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd); CGF.EmitBlock(BadCastBlock); - llvm::Value *F = getBadCastFn(CGF); - if (llvm::BasicBlock *InvokeDest = CGF.getInvokeDest()) { - llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); - CGF.Builder.CreateInvoke(F, Cont, InvokeDest)->setDoesNotReturn(); - CGF.EmitBlock(Cont); - } else - CGF.Builder.CreateCall(F)->setDoesNotReturn(); - - CGF.Builder.CreateUnreachable(); + EmitBadCastCall(CGF); } return Value; } +static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF, + QualType DestTy) { + const llvm::Type *DestLTy = CGF.ConvertType(DestTy); + if (DestTy->isPointerType()) + return llvm::Constant::getNullValue(DestLTy); + + /// C++ [expr.dynamic.cast]p9: + /// A failed cast to reference type throws std::bad_cast + EmitBadCastCall(CGF); + + CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end")); + return llvm::UndefValue::get(DestLTy); +} + llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value, const CXXDynamicCastExpr *DCE) { - QualType SrcTy = DCE->getSubExpr()->getType(); QualType DestTy = DCE->getTypeAsWritten(); + if (DCE->isAlwaysNull()) + return EmitDynamicCastToNull(*this, DestTy); + + QualType SrcTy = DCE->getSubExpr()->getType(); + // 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. diff --git a/test/CodeGenCXX/dynamic-cast-always-null.cpp b/test/CodeGenCXX/dynamic-cast-always-null.cpp new file mode 100644 index 0000000000..48ec69226c --- /dev/null +++ b/test/CodeGenCXX/dynamic-cast-always-null.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -std=c++0x -o - | FileCheck %s +struct A { virtual ~A(); }; +struct B final : A { }; +struct C { virtual ~C(); }; + +// CHECK: @_Z1fP1B +C *f(B* b) { + // CHECK-NOT: call i8* @__dynamic_cast + // CHECK: ret %struct.C* null + return dynamic_cast(b); +} + +// CHECK: @_Z1fR1B +C &f(B& b) { + // CHECK-NOT: call i8* @__dynamic_cast + // CHECK: call void @__cxa_bad_cast() noreturn + // CHECK: ret %struct.C* undef + return dynamic_cast(b); +}