aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h10
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp51
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp4
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h7
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp128
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp12
6 files changed, 192 insertions, 20 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index 7c1287a..ad1ad08d 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -287,6 +287,7 @@ public:
virtual bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
QualType SrcRecordTy) = 0;
+ virtual bool shouldEmitExactDynamicCast(QualType DestRecordTy) = 0;
virtual llvm::Value *emitDynamicCastCall(CodeGenFunction &CGF, Address Value,
QualType SrcRecordTy,
@@ -298,6 +299,15 @@ public:
Address Value,
QualType SrcRecordTy) = 0;
+ /// Emit a dynamic_cast from SrcRecordTy to DestRecordTy. The cast fails if
+ /// the dynamic type of Value is not exactly DestRecordTy.
+ virtual llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address Value,
+ QualType SrcRecordTy,
+ QualType DestTy,
+ QualType DestRecordTy,
+ llvm::BasicBlock *CastSuccess,
+ llvm::BasicBlock *CastFail) = 0;
+
virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;
virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 96435d9..6df5e37 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -2226,8 +2226,8 @@ static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))
return nullptr;
- CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end"));
- return llvm::UndefValue::get(DestLTy);
+ CGF.Builder.ClearInsertionPoint();
+ return llvm::PoisonValue::get(DestLTy);
}
llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr,
@@ -2240,17 +2240,16 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr,
// C++ [expr.dynamic.cast]p7:
// If T is "pointer to cv void," then the result is a pointer to the most
// derived object pointed to by v.
- const PointerType *DestPTy = DestTy->getAs<PointerType>();
-
- bool isDynamicCastToVoid;
+ bool IsDynamicCastToVoid = DestTy->isVoidPointerType();
QualType SrcRecordTy;
QualType DestRecordTy;
- if (DestPTy) {
- isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType();
+ if (IsDynamicCastToVoid) {
+ SrcRecordTy = SrcTy->getPointeeType();
+ // No DestRecordTy.
+ } else if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) {
SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
DestRecordTy = DestPTy->getPointeeType();
} else {
- isDynamicCastToVoid = false;
SrcRecordTy = SrcTy;
DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
}
@@ -2263,18 +2262,29 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr,
EmitTypeCheck(TCK_DynamicOperation, DCE->getExprLoc(), ThisAddr.getPointer(),
SrcRecordTy);
- if (DCE->isAlwaysNull())
- if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
+ if (DCE->isAlwaysNull()) {
+ if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy)) {
+ // Expression emission is expected to retain a valid insertion point.
+ if (!Builder.GetInsertBlock())
+ EmitBlock(createBasicBlock("dynamic_cast.unreachable"));
return T;
+ }
+ }
assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
+ // If the destination is effectively final, the cast succeeds if and only
+ // if the dynamic type of the pointer is exactly the destination type.
+ bool IsExact = !IsDynamicCastToVoid &&
+ DestRecordTy->getAsCXXRecordDecl()->isEffectivelyFinal() &&
+ CGM.getCXXABI().shouldEmitExactDynamicCast(DestRecordTy);
+
// 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.
bool ShouldNullCheckSrcValue =
- CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),
- SrcRecordTy);
+ IsExact || CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(
+ SrcTy->isPointerType(), SrcRecordTy);
llvm::BasicBlock *CastNull = nullptr;
llvm::BasicBlock *CastNotNull = nullptr;
@@ -2290,29 +2300,38 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr,
}
llvm::Value *Value;
- if (isDynamicCastToVoid) {
+ if (IsDynamicCastToVoid) {
Value = CGM.getCXXABI().emitDynamicCastToVoid(*this, ThisAddr, SrcRecordTy);
+ } else if (IsExact) {
+ // If the destination type is effectively final, this pointer points to the
+ // right type if and only if its vptr has the right value.
+ Value = CGM.getCXXABI().emitExactDynamicCast(
+ *this, ThisAddr, SrcRecordTy, DestTy, DestRecordTy, CastEnd, CastNull);
} else {
assert(DestRecordTy->isRecordType() &&
"destination type must be a record type!");
Value = CGM.getCXXABI().emitDynamicCastCall(*this, ThisAddr, SrcRecordTy,
DestTy, DestRecordTy, CastEnd);
- CastNotNull = Builder.GetInsertBlock();
}
+ CastNotNull = Builder.GetInsertBlock();
+ llvm::Value *NullValue = nullptr;
if (ShouldNullCheckSrcValue) {
EmitBranch(CastEnd);
EmitBlock(CastNull);
+ NullValue = EmitDynamicCastToNull(*this, DestTy);
+ CastNull = Builder.GetInsertBlock();
+
EmitBranch(CastEnd);
}
EmitBlock(CastEnd);
- if (ShouldNullCheckSrcValue) {
+ if (CastNull) {
llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2);
PHI->addIncoming(Value, CastNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull);
+ PHI->addIncoming(NullValue, CastNull);
Value = PHI;
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index ef49349..bb5d180 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -7152,9 +7152,7 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
// Return a bogus pointer if RTTI is disabled, unless it's for EH.
// FIXME: should we even be calling this method if RTTI is disabled
// and it's not for EH?
- if ((!ForEH && !getLangOpts().RTTI) || getLangOpts().CUDAIsDevice ||
- (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice &&
- getTriple().isNVPTX()))
+ if (!shouldEmitRTTI(ForEH))
return llvm::Constant::getNullValue(GlobalsInt8PtrTy);
if (ForEH && Ty->isObjCObjectPointerType() &&
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 2d2cce8..4903f09 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -926,6 +926,13 @@ public:
// Return the function body address of the given function.
llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
+ // Return whether RTTI information should be emitted for this target.
+ bool shouldEmitRTTI(bool ForEH = false) {
+ return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&
+ !(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice &&
+ getTriple().isNVPTX());
+ }
+
/// Get the address of the RTTI descriptor for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 8870383..79a926c 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -36,6 +36,8 @@
#include "llvm/IR/Value.h"
#include "llvm/Support/ScopedPrinter.h"
+#include <optional>
+
using namespace clang;
using namespace CodeGen;
@@ -185,11 +187,56 @@ public:
bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
QualType SrcRecordTy) override;
+ /// Determine whether we know that all instances of type RecordTy will have
+ /// the same vtable pointer values, that is distinct from all other vtable
+ /// pointers. While this is required by the Itanium ABI, it doesn't happen in
+ /// practice in some cases due to language extensions.
+ bool hasUniqueVTablePointer(QualType RecordTy) {
+ const CXXRecordDecl *RD = RecordTy->getAsCXXRecordDecl();
+
+ // Under -fapple-kext, multiple definitions of the same vtable may be
+ // emitted.
+ if (!CGM.getCodeGenOpts().AssumeUniqueVTables ||
+ getContext().getLangOpts().AppleKext)
+ return false;
+
+ // If the type_info* would be null, the vtable might be merged with that of
+ // another type.
+ if (!CGM.shouldEmitRTTI())
+ return false;
+
+ // If there's only one definition of the vtable in the program, it has a
+ // unique address.
+ if (!llvm::GlobalValue::isWeakForLinker(CGM.getVTableLinkage(RD)))
+ return true;
+
+ // Even if there are multiple definitions of the vtable, they are required
+ // by the ABI to use the same symbol name, so should be merged at load
+ // time. However, if the class has hidden visibility, there can be
+ // different versions of the class in different modules, and the ABI
+ // library might treat them as being the same.
+ if (CGM.GetLLVMVisibility(RD->getVisibility()) !=
+ llvm::GlobalValue::DefaultVisibility)
+ return false;
+
+ return true;
+ }
+
+ bool shouldEmitExactDynamicCast(QualType DestRecordTy) override {
+ return hasUniqueVTablePointer(DestRecordTy);
+ }
+
llvm::Value *emitDynamicCastCall(CodeGenFunction &CGF, Address Value,
QualType SrcRecordTy, QualType DestTy,
QualType DestRecordTy,
llvm::BasicBlock *CastEnd) override;
+ llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address ThisAddr,
+ QualType SrcRecordTy, QualType DestTy,
+ QualType DestRecordTy,
+ llvm::BasicBlock *CastSuccess,
+ llvm::BasicBlock *CastFail) override;
+
llvm::Value *emitDynamicCastToVoid(CodeGenFunction &CGF, Address Value,
QualType SrcRecordTy) override;
@@ -1202,7 +1249,8 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
// Track back to entry -2 and pull out the offset there.
llvm::Value *OffsetPtr = CGF.Builder.CreateConstInBoundsGEP1_64(
CGF.IntPtrTy, VTable, -2, "complete-offset.ptr");
- llvm::Value *Offset = CGF.Builder.CreateAlignedLoad(CGF.IntPtrTy, OffsetPtr, CGF.getPointerAlign());
+ llvm::Value *Offset = CGF.Builder.CreateAlignedLoad(CGF.IntPtrTy, OffsetPtr,
+ CGF.getPointerAlign());
// Apply the offset.
llvm::Value *CompletePtr =
@@ -1463,6 +1511,84 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall(
return Value;
}
+llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
+ CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
+ QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastSuccess,
+ llvm::BasicBlock *CastFail) {
+ ASTContext &Context = getContext();
+
+ // Find all the inheritance paths.
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ (void)DestDecl->isDerivedFrom(SrcDecl, Paths);
+
+ // Find an offset within `DestDecl` where a `SrcDecl` instance and its vptr
+ // might appear.
+ std::optional<CharUnits> Offset;
+ for (const CXXBasePath &Path : Paths) {
+ // dynamic_cast only finds public inheritance paths.
+ if (Path.Access != AS_public)
+ continue;
+
+ CharUnits PathOffset;
+ for (const CXXBasePathElement &PathElement : Path) {
+ // Find the offset along this inheritance step.
+ const CXXRecordDecl *Base =
+ PathElement.Base->getType()->getAsCXXRecordDecl();
+ if (PathElement.Base->isVirtual()) {
+ // For a virtual base class, we know that the derived class is exactly
+ // DestDecl, so we can use the vbase offset from its layout.
+ const ASTRecordLayout &L = Context.getASTRecordLayout(DestDecl);
+ PathOffset = L.getVBaseClassOffset(Base);
+ } else {
+ const ASTRecordLayout &L =
+ Context.getASTRecordLayout(PathElement.Class);
+ PathOffset += L.getBaseClassOffset(Base);
+ }
+ }
+
+ if (!Offset)
+ Offset = PathOffset;
+ else if (Offset != PathOffset) {
+ // Base appears in at least two different places. Find the most-derived
+ // object and see if it's a DestDecl. Note that the most-derived object
+ // must be at least as aligned as this base class subobject, and must
+ // have a vptr at offset 0.
+ ThisAddr = Address(emitDynamicCastToVoid(CGF, ThisAddr, SrcRecordTy),
+ CGF.VoidPtrTy, ThisAddr.getAlignment());
+ SrcDecl = DestDecl;
+ Offset = CharUnits::Zero();
+ break;
+ }
+ }
+
+ if (!Offset) {
+ // If there are no public inheritance paths, the cast always fails.
+ CGF.EmitBranch(CastFail);
+ return llvm::PoisonValue::get(CGF.VoidPtrTy);
+ }
+
+ // Compare the vptr against the expected vptr for the destination type at
+ // this offset. Note that we do not know what type ThisAddr points to in
+ // the case where the derived class multiply inherits from the base class
+ // so we can't use GetVTablePtr, so we load the vptr directly instead.
+ llvm::Instruction *VPtr = CGF.Builder.CreateLoad(
+ ThisAddr.withElementType(CGF.VoidPtrPtrTy), "vtable");
+ CGM.DecorateInstructionWithTBAA(
+ VPtr, CGM.getTBAAVTablePtrAccessInfo(CGF.VoidPtrPtrTy));
+ llvm::Value *Success = CGF.Builder.CreateICmpEQ(
+ VPtr, getVTableAddressPoint(BaseSubobject(SrcDecl, *Offset), DestDecl));
+ llvm::Value *Result = ThisAddr.getPointer();
+ if (!Offset->isZero())
+ Result = CGF.Builder.CreateInBoundsGEP(
+ CGF.CharTy, Result,
+ {llvm::ConstantInt::get(CGF.PtrDiffTy, -Offset->getQuantity())});
+ CGF.Builder.CreateCondBr(Success, CastSuccess, CastFail);
+ return Result;
+}
+
llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF,
Address ThisAddr,
QualType SrcRecordTy) {
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index ea63e76..a692aba 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -153,6 +153,18 @@ public:
bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
QualType SrcRecordTy) override;
+ bool shouldEmitExactDynamicCast(QualType DestRecordTy) override {
+ // TODO: Add support for exact dynamic_casts.
+ return false;
+ }
+ llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address Value,
+ QualType SrcRecordTy, QualType DestTy,
+ QualType DestRecordTy,
+ llvm::BasicBlock *CastSuccess,
+ llvm::BasicBlock *CastFail) override {
+ llvm_unreachable("unsupported");
+ }
+
llvm::Value *emitDynamicCastCall(CodeGenFunction &CGF, Address Value,
QualType SrcRecordTy, QualType DestTy,
QualType DestRecordTy,