]> granicus.if.org Git - clang/commitdiff
When we know that a dynamic_cast always returns null, we can make
authorAnders Carlsson <andersca@mac.com>
Mon, 11 Apr 2011 01:45:29 +0000 (01:45 +0000)
committerAnders Carlsson <andersca@mac.com>
Mon, 11 Apr 2011 01:45:29 +0000 (01:45 +0000)
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

lib/CodeGen/CGExprCXX.cpp
test/CodeGenCXX/dynamic-cast-always-null.cpp [new file with mode: 0644]

index ff7b7112ca0e280cda5e57cb19c63ce046e5a990..a3d3f439b63e9f424d308673423ee224f4ccbf3b 100644 (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.
diff --git a/test/CodeGenCXX/dynamic-cast-always-null.cpp b/test/CodeGenCXX/dynamic-cast-always-null.cpp
new file mode 100644 (file)
index 0000000..48ec692
--- /dev/null
@@ -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);
+}