forked from OSchip/llvm-project
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:
parent
267c0c930e
commit
c1c9971cab
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue