Skip to content

Commit 2b6761e

Browse files
author
git apple-llvm automerger
committed
Merge commit 'c548c47476ee' from llvm.org/main into next
2 parents 1bddc79 + c548c47 commit 2b6761e

File tree

7 files changed

+147
-41
lines changed

7 files changed

+147
-41
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ Bug Fixes to C++ Support
182182
- Fix a crash when deleting a pointer to an incomplete array (#GH150359).
183183
- Fix an assertion failure when expression in assumption attribute
184184
(``[[assume(expr)]]``) creates temporary objects.
185+
- Fix the dynamic_cast to final class optimization to correctly handle
186+
casts that are guaranteed to fail (#GH137518).
185187

186188
Bug Fixes to AST Handling
187189
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/CodeGen/CGCXXABI.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,22 @@ class CGCXXABI {
294294
Address Value,
295295
QualType SrcRecordTy) = 0;
296296

297+
struct ExactDynamicCastInfo {
298+
bool RequiresCastToPrimaryBase;
299+
CharUnits Offset;
300+
};
301+
302+
virtual std::optional<ExactDynamicCastInfo>
303+
getExactDynamicCastInfo(QualType SrcRecordTy, QualType DestTy,
304+
QualType DestRecordTy) = 0;
305+
297306
/// Emit a dynamic_cast from SrcRecordTy to DestRecordTy. The cast fails if
298307
/// the dynamic type of Value is not exactly DestRecordTy.
299-
virtual llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address Value,
300-
QualType SrcRecordTy,
301-
QualType DestTy,
302-
QualType DestRecordTy,
303-
llvm::BasicBlock *CastSuccess,
304-
llvm::BasicBlock *CastFail) = 0;
308+
virtual llvm::Value *emitExactDynamicCast(
309+
CodeGenFunction &CGF, Address Value, QualType SrcRecordTy,
310+
QualType DestTy, QualType DestRecordTy,
311+
const ExactDynamicCastInfo &CastInfo, llvm::BasicBlock *CastSuccess,
312+
llvm::BasicBlock *CastFail) = 0;
305313

306314
virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;
307315

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2296,6 +2296,18 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr,
22962296
CGM.getCXXABI().shouldEmitExactDynamicCast(DestRecordTy) &&
22972297
!getLangOpts().PointerAuthCalls;
22982298

2299+
std::optional<CGCXXABI::ExactDynamicCastInfo> ExactCastInfo;
2300+
if (IsExact) {
2301+
ExactCastInfo = CGM.getCXXABI().getExactDynamicCastInfo(SrcRecordTy, DestTy,
2302+
DestRecordTy);
2303+
if (!ExactCastInfo) {
2304+
llvm::Value *NullValue = EmitDynamicCastToNull(*this, DestTy);
2305+
if (!Builder.GetInsertBlock())
2306+
EmitBlock(createBasicBlock("dynamic_cast.unreachable"));
2307+
return NullValue;
2308+
}
2309+
}
2310+
22992311
// C++ [expr.dynamic.cast]p4:
23002312
// If the value of v is a null pointer value in the pointer case, the result
23012313
// is the null pointer value of type T.
@@ -2323,7 +2335,8 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr,
23232335
// If the destination type is effectively final, this pointer points to the
23242336
// right type if and only if its vptr has the right value.
23252337
Value = CGM.getCXXABI().emitExactDynamicCast(
2326-
*this, ThisAddr, SrcRecordTy, DestTy, DestRecordTy, CastEnd, CastNull);
2338+
*this, ThisAddr, SrcRecordTy, DestTy, DestRecordTy, *ExactCastInfo,
2339+
CastEnd, CastNull);
23272340
} else {
23282341
assert(DestRecordTy->isRecordType() &&
23292342
"destination type must be a record type!");

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
227227
return hasUniqueVTablePointer(DestRecordTy);
228228
}
229229

230+
std::optional<ExactDynamicCastInfo>
231+
getExactDynamicCastInfo(QualType SrcRecordTy, QualType DestTy,
232+
QualType DestRecordTy) override;
233+
230234
llvm::Value *emitDynamicCastCall(CodeGenFunction &CGF, Address Value,
231235
QualType SrcRecordTy, QualType DestTy,
232236
QualType DestRecordTy,
@@ -235,6 +239,7 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
235239
llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address ThisAddr,
236240
QualType SrcRecordTy, QualType DestTy,
237241
QualType DestRecordTy,
242+
const ExactDynamicCastInfo &CastInfo,
238243
llvm::BasicBlock *CastSuccess,
239244
llvm::BasicBlock *CastFail) override;
240245

@@ -1699,10 +1704,11 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall(
16991704
return Value;
17001705
}
17011706

1702-
llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
1703-
CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
1704-
QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastSuccess,
1705-
llvm::BasicBlock *CastFail) {
1707+
std::optional<CGCXXABI::ExactDynamicCastInfo>
1708+
ItaniumCXXABI::getExactDynamicCastInfo(QualType SrcRecordTy, QualType DestTy,
1709+
QualType DestRecordTy) {
1710+
assert(shouldEmitExactDynamicCast(DestRecordTy));
1711+
17061712
ASTContext &Context = getContext();
17071713

17081714
// Find all the inheritance paths.
@@ -1740,41 +1746,56 @@ llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
17401746
if (!Offset)
17411747
Offset = PathOffset;
17421748
else if (Offset != PathOffset) {
1743-
// Base appears in at least two different places. Find the most-derived
1744-
// object and see if it's a DestDecl. Note that the most-derived object
1745-
// must be at least as aligned as this base class subobject, and must
1746-
// have a vptr at offset 0.
1747-
ThisAddr = Address(emitDynamicCastToVoid(CGF, ThisAddr, SrcRecordTy),
1748-
CGF.VoidPtrTy, ThisAddr.getAlignment());
1749-
SrcDecl = DestDecl;
1750-
Offset = CharUnits::Zero();
1751-
break;
1749+
// Base appears in at least two different places.
1750+
return ExactDynamicCastInfo{/*RequiresCastToPrimaryBase=*/true,
1751+
CharUnits::Zero()};
17521752
}
17531753
}
1754+
if (!Offset)
1755+
return std::nullopt;
1756+
return ExactDynamicCastInfo{/*RequiresCastToPrimaryBase=*/false, *Offset};
1757+
}
17541758

1755-
if (!Offset) {
1756-
// If there are no public inheritance paths, the cast always fails.
1757-
CGF.EmitBranch(CastFail);
1758-
return llvm::PoisonValue::get(CGF.VoidPtrTy);
1759-
}
1759+
llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
1760+
CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
1761+
QualType DestTy, QualType DestRecordTy,
1762+
const ExactDynamicCastInfo &ExactCastInfo, llvm::BasicBlock *CastSuccess,
1763+
llvm::BasicBlock *CastFail) {
1764+
const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
1765+
const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
1766+
1767+
llvm::Value *VTable = nullptr;
1768+
if (ExactCastInfo.RequiresCastToPrimaryBase) {
1769+
// Base appears in at least two different places. Find the most-derived
1770+
// object and see if it's a DestDecl. Note that the most-derived object
1771+
// must be at least as aligned as this base class subobject, and must
1772+
// have a vptr at offset 0.
1773+
llvm::Value *PrimaryBase =
1774+
emitDynamicCastToVoid(CGF, ThisAddr, SrcRecordTy);
1775+
ThisAddr = Address(PrimaryBase, CGF.VoidPtrTy, ThisAddr.getAlignment());
1776+
SrcDecl = DestDecl;
1777+
Address VTablePtrPtr = ThisAddr.withElementType(CGF.VoidPtrPtrTy);
1778+
VTable = CGF.Builder.CreateLoad(VTablePtrPtr, "vtable");
1779+
} else
1780+
VTable = CGF.GetVTablePtr(ThisAddr, CGF.UnqualPtrTy, SrcDecl);
17601781

17611782
// Compare the vptr against the expected vptr for the destination type at
1762-
// this offset. Note that we do not know what type ThisAddr points to in
1763-
// the case where the derived class multiply inherits from the base class
1764-
// so we can't use GetVTablePtr, so we load the vptr directly instead.
1765-
llvm::Instruction *VPtr = CGF.Builder.CreateLoad(
1766-
ThisAddr.withElementType(CGF.VoidPtrPtrTy), "vtable");
1767-
CGM.DecorateInstructionWithTBAA(
1768-
VPtr, CGM.getTBAAVTablePtrAccessInfo(CGF.VoidPtrPtrTy));
1769-
llvm::Value *Success = CGF.Builder.CreateICmpEQ(
1770-
VPtr, getVTableAddressPoint(BaseSubobject(SrcDecl, *Offset), DestDecl));
1771-
llvm::Value *Result = ThisAddr.emitRawPointer(CGF);
1772-
if (!Offset->isZero())
1773-
Result = CGF.Builder.CreateInBoundsGEP(
1774-
CGF.CharTy, Result,
1775-
{llvm::ConstantInt::get(CGF.PtrDiffTy, -Offset->getQuantity())});
1783+
// this offset.
1784+
llvm::Constant *ExpectedVTable = getVTableAddressPoint(
1785+
BaseSubobject(SrcDecl, ExactCastInfo.Offset), DestDecl);
1786+
llvm::Value *Success = CGF.Builder.CreateICmpEQ(VTable, ExpectedVTable);
1787+
llvm::Value *AdjustedThisPtr = ThisAddr.emitRawPointer(CGF);
1788+
1789+
if (!ExactCastInfo.Offset.isZero()) {
1790+
CharUnits::QuantityType Offset = ExactCastInfo.Offset.getQuantity();
1791+
llvm::Constant *OffsetConstant =
1792+
llvm::ConstantInt::get(CGF.PtrDiffTy, -Offset);
1793+
AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP(CGF.CharTy, AdjustedThisPtr,
1794+
OffsetConstant);
1795+
}
1796+
17761797
CGF.Builder.CreateCondBr(Success, CastSuccess, CastFail);
1777-
return Result;
1798+
return AdjustedThisPtr;
17781799
}
17791800

17801801
llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF,

clang/lib/CodeGen/MicrosoftCXXABI.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,15 @@ class MicrosoftCXXABI : public CGCXXABI {
158158
// TODO: Add support for exact dynamic_casts.
159159
return false;
160160
}
161+
std::optional<ExactDynamicCastInfo>
162+
getExactDynamicCastInfo(QualType SrcRecordTy, QualType DestTy,
163+
QualType DestRecordTy) override {
164+
llvm_unreachable("unsupported");
165+
}
161166
llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address Value,
162167
QualType SrcRecordTy, QualType DestTy,
163168
QualType DestRecordTy,
169+
const ExactDynamicCastInfo &CastInfo,
164170
llvm::BasicBlock *CastSuccess,
165171
llvm::BasicBlock *CastFail) override {
166172
llvm_unreachable("unsupported");

clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,19 @@ B *exact(A *a) {
1414
// EXACT-NOT: call {{.*}} @__dynamic_cast
1515
return dynamic_cast<B*>(a);
1616
}
17+
18+
struct C {
19+
virtual ~C();
20+
};
21+
22+
struct D final : private C {
23+
24+
};
25+
26+
// CHECK-LABEL: @_Z5exactP1C
27+
D *exact(C *a) {
28+
// INEXACT: call {{.*}} @__dynamic_cast
29+
// EXACT: entry:
30+
// EXACT-NEXT: ret ptr null
31+
return dynamic_cast<D*>(a);
32+
}

clang/test/CodeGenCXX/dynamic-cast-exact.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct E : A { int e; };
99
struct F : virtual A { int f; };
1010
struct G : virtual A { int g; };
1111
struct H final : C, D, E, F, G { int h; };
12+
struct H1 final: C, private D { int h1; };
1213

1314
// CHECK-LABEL: @_Z7inexactP1A
1415
C *inexact(A *a) {
@@ -77,10 +78,49 @@ H *exact_multi(A *a) {
7778
return dynamic_cast<H*>(a);
7879
}
7980

81+
// CHECK-LABEL: @_Z19exact_invalid_multiP1D
82+
H1 *exact_invalid_multi(D* d) {
83+
// CHECK: entry:
84+
// CHECK-NEXT: %d.addr = alloca ptr
85+
// CHECK-NEXT: store ptr %d, ptr %d.addr
86+
// CHECK-NEXT: load ptr, ptr %d.addr
87+
// CHECK-NEXT: ret ptr null
88+
return dynamic_cast<H1*>(d);
89+
}
90+
91+
// CHECK-LABEL: @_Z19exact_invalid_multiR1D
92+
H1 &exact_invalid_multi(D& d) {
93+
// CHECK: entry:
94+
// CHECK-NEXT: %d.addr = alloca ptr
95+
// CHECK-NEXT: store ptr %d, ptr %d.addr
96+
// CHECK-NEXT: load ptr, ptr %d.addr
97+
// CHECK-NEXT: call void @__cxa_bad_cast()
98+
// CHECK-NEXT: unreachable
99+
// CHECK: dynamic_cast.unreachable:
100+
// CHECK-NEXT: ret ptr poison
101+
return dynamic_cast<H1&>(d);
102+
}
103+
104+
namespace GH137518 {
105+
class base { virtual void fn() = 0; };
106+
class test final : base { virtual void fn() { } };
107+
test* new_test() { return new test(); }
108+
109+
// CHECK-LABEL: @_ZN8GH1375184castEPNS_4baseE(
110+
test* cast(base* b) {
111+
// CHECK: entry:
112+
// CHECK-NEXT: %b.addr = alloca ptr
113+
// CHECK-NEXT: store ptr %b, ptr %b.addr
114+
// CHECK-NEXT: load ptr, ptr %b.addr
115+
// CHECK-NEXT: ret ptr null
116+
return dynamic_cast<test*>(b);
117+
}
118+
}
119+
80120
namespace GH64088 {
81121
// Ensure we mark the B vtable as used here, because we're going to emit a
82122
// reference to it.
83-
// CHECK: define {{.*}} @_ZN7GH640881BD0
123+
// CHECK: define {{.*}} void @_ZN7GH640881BD0Ev(
84124
struct A { virtual ~A(); };
85125
struct B final : A { virtual ~B() = default; };
86126
B *cast(A *p) { return dynamic_cast<B*>(p); }

0 commit comments

Comments
 (0)