Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
26 changes: 22 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
34 changes: 34 additions & 0 deletions clang/test/CIR/CodeGen/dynamic-cast-exact.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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