Author: Andy Kaylor
Date: 2025-10-23T10:01:08-07:00
New Revision: ede9dd3951e29632a29e13b2fd8c4b6b9d185643

URL: 
https://github.com/llvm/llvm-project/commit/ede9dd3951e29632a29e13b2fd8c4b6b9d185643
DIFF: 
https://github.com/llvm/llvm-project/commit/ede9dd3951e29632a29e13b2fd8c4b6b9d185643.diff

LOG: [CIR] Handle dynamic cast to null (#164732)

This adds support for handling dynamic casts that are known at compile
time to always result in a null pointer. For pointer casts, this emits a
null pointer value. For reference casts, it calls the __bad_cast
function.

Added: 
    

Modified: 
    clang/lib/CIR/CodeGen/CIRGenCXXABI.h
    clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
    clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
    clang/test/CIR/CodeGen/dynamic-cast-exact.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h 
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index c78f9b0ea8a26..d3c7dac04dc67 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -124,6 +124,8 @@ class CIRGenCXXABI {
   virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0;
   virtual void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) = 0;
 
+  virtual void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) = 0;
+
   virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
                                                   QualType ty) = 0;
 

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index fe9e21064263b..a3cdf192bf9b8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -801,6 +801,26 @@ void CIRGenFunction::emitDeleteCall(const FunctionDecl 
*deleteFD,
   emitNewDeleteCall(*this, deleteFD, deleteFTy, deleteArgs);
 }
 
+static mlir::Value emitDynamicCastToNull(CIRGenFunction &cgf,
+                                         mlir::Location loc, QualType destTy) {
+  mlir::Type destCIRTy = cgf.convertType(destTy);
+  assert(mlir::isa<cir::PointerType>(destCIRTy) &&
+         "result of dynamic_cast should be a ptr");
+
+  if (!destTy->isPointerType()) {
+    mlir::Region *currentRegion = cgf.getBuilder().getBlock()->getParent();
+    /// C++ [expr.dynamic.cast]p9:
+    ///   A failed cast to reference type throws std::bad_cast
+    cgf.cgm.getCXXABI().emitBadCastCall(cgf, loc);
+
+    // The call to bad_cast will terminate the current block. Create a new 
block
+    // to hold any follow up code.
+    cgf.getBuilder().createBlock(currentRegion, currentRegion->end());
+  }
+
+  return cgf.getBuilder().getNullPtr(destCIRTy, loc);
+}
+
 mlir::Value CIRGenFunction::emitDynamicCast(Address thisAddr,
                                             const CXXDynamicCastExpr *dce) {
   mlir::Location loc = getLoc(dce->getSourceRange());
@@ -831,10 +851,8 @@ mlir::Value CIRGenFunction::emitDynamicCast(Address 
thisAddr,
   assert(srcRecordTy->isRecordType() && "source type must be a record type!");
   assert(!cir::MissingFeatures::emitTypeCheck());
 
-  if (dce->isAlwaysNull()) {
-    cgm.errorNYI(dce->getSourceRange(), "emitDynamicCastToNull");
-    return {};
-  }
+  if (dce->isAlwaysNull())
+    return emitDynamicCastToNull(*this, loc, destTy);
 
   auto destCirTy = mlir::cast<cir::PointerType>(convertType(destTy));
   return cgm.getCXXABI().emitDynamicCast(*this, loc, srcRecordTy, destRecordTy,

diff  --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index f7c4d181cba66..2dce0b16e3043 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -120,6 +120,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
     return true;
   }
 
+  void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override;
+
   mlir::Value
   getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
                             Address thisAddr, const CXXRecordDecl *classDecl,
@@ -1883,6 +1885,11 @@ static void emitCallToBadCast(CIRGenFunction &cgf, 
mlir::Location loc) {
   cgf.getBuilder().clearInsertionPoint();
 }
 
+void CIRGenItaniumCXXABI::emitBadCastCall(CIRGenFunction &cgf,
+                                          mlir::Location loc) {
+  emitCallToBadCast(cgf, loc);
+}
+
 // TODO(cir): This could be shared with classic codegen.
 static CharUnits computeOffsetHint(ASTContext &astContext,
                                    const CXXRecordDecl *src,

diff  --git a/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp 
b/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp
index e3b853321ac7d..9ddb68fbf7355 100644
--- a/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp
+++ b/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp
@@ -172,3 +172,37 @@ B *offset_cast(A *a) {
 // OGCG-NEXT:   br label %[[LABEL_END]]
 //      OGCG: [[LABEL_END]]:
 // OGCG-NEXT:   phi ptr [ %[[RESULT]], %[[LABEL_NOTNULL]] ], [ null, 
%[[LABEL_NULL]] ]
+
+Derived *ptr_cast_always_fail(Base2 *ptr) {
+    return dynamic_cast<Derived *>(ptr);
+  }
+
+//      CIR: cir.func {{.*}} @_Z20ptr_cast_always_failP5Base2
+//      CIR:   %{{.+}} = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Base2>>, !cir.ptr<!rec_Base2>
+// CIR-NEXT:   %[[RESULT:.*]] = cir.const #cir.ptr<null> : 
!cir.ptr<!rec_Derived>
+// CIR-NEXT:   cir.store %[[RESULT]], %{{.*}} : !cir.ptr<!rec_Derived>, 
!cir.ptr<!cir.ptr<!rec_Derived>>
+
+//      LLVM: define {{.*}} ptr @_Z20ptr_cast_always_failP5Base2
+// LLVM-NEXT:   ret ptr null
+
+//      OGCG: define {{.*}} ptr @_Z20ptr_cast_always_failP5Base2
+// OGCG-NEXT: entry:
+// OGCG-NEXT:   ret ptr null
+
+Derived &ref_cast_always_fail(Base2 &ref) {
+  return dynamic_cast<Derived &>(ref);
+}
+
+//      CIR: cir.func {{.*}} @_Z20ref_cast_always_failR5Base2
+//      CIR:   %{{.+}} = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Base2>>, !cir.ptr<!rec_Base2>
+// CIR-NEXT:   cir.call @__cxa_bad_cast() : () -> ()
+// CIR-NEXT:   cir.unreachable
+
+//      LLVM: define {{.*}} ptr @_Z20ref_cast_always_failR5Base2
+// LLVM-NEXT:   tail call void @__cxa_bad_cast()
+// LLVM-NEXT:   unreachable
+
+//      OGCG: define {{.*}} ptr @_Z20ref_cast_always_failR5Base2
+// OGCG-NEXT: entry:
+// OGCG-NEXT:   tail call void @__cxa_bad_cast()
+// OGCG-NEXT:   unreachable


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to