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
9 changes: 6 additions & 3 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,15 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_BaseToDerived: {
if (!this->delegate(SubExpr))
return false;

unsigned DerivedOffset =
collectBaseOffset(SubExpr->getType(), CE->getType());

return this->emitGetPtrDerivedPop(
DerivedOffset, /*NullOK=*/CE->getType()->isPointerType(), CE);
const Type *TargetType = CE->getType().getTypePtr();
if (TargetType->isPointerOrReferenceType())
TargetType = TargetType->getPointeeType().getTypePtr();
return this->emitGetPtrDerivedPop(DerivedOffset,
/*NullOK=*/CE->getType()->isPointerType(),
TargetType, CE);
}

case CK_FloatingCast: {
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1643,7 +1643,7 @@ inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
}

inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
bool NullOK) {
bool NullOK, const Type *TargetType) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))
return false;
Expand All @@ -1661,6 +1661,20 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
if (!CheckDowncast(S, OpPC, Ptr, Off))
return false;

const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
assert(TargetRecord);

if (TargetRecord->getDecl()
->getTypeForDecl()
->getAsCXXRecordDecl()
->getCanonicalDecl() !=
TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
QualType MostDerivedType = Ptr.getDeclDesc()->getType();
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
<< MostDerivedType << QualType(TargetType, 0);
return false;
}

S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def GetMemberPtrBasePop : Opcode {
def FinishInitPop : Opcode;
def FinishInit : Opcode;

def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool]; }
def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool, ArgTypePtr]; }

// [Pointer] -> [Pointer]
def GetPtrVirtBasePop : Opcode {
Expand Down
12 changes: 12 additions & 0 deletions clang/test/AST/ByteCode/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1830,3 +1830,15 @@ namespace NullDtor {
static_assert(foo() == 10, ""); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
}

namespace DiamondDowncast {
struct Top {};
struct Middle1 : Top {};
struct Middle2 : Top {};
struct Bottom : Middle1, Middle2 {};

constexpr Bottom bottom;
constexpr Top &top1 = (Middle1&)bottom;
constexpr Middle2 &fail = (Middle2&)top1; // both-error {{must be initialized by a constant expression}} \
// both-note {{cannot cast object of dynamic type 'const Bottom' to type 'Middle2'}}
}