When we know that a dynamic_cast always returns null, we can make

CodeGenFunction::EmitDynamicCast always return null or throw a bad_cast 
exception.

llvm-svn: 129264
This commit is contained in:
Anders Carlsson 2011-04-11 01:45:29 +00:00
parent 267c0c930e
commit c1c9971cab
2 changed files with 51 additions and 10 deletions

View File

@ -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.

View File

@ -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<C*>(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<C&>(b);
}