108 lines
3.3 KiB
C++
108 lines
3.3 KiB
C++
//===------------------------- MemberPointer.cpp ----------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MemberPointer.h"
|
|
#include "Context.h"
|
|
#include "Program.h"
|
|
#include "Record.h"
|
|
|
|
namespace clang {
|
|
namespace interp {
|
|
|
|
std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
|
|
if (!getDecl() || isa<FunctionDecl>(getDecl()))
|
|
return Base;
|
|
assert((isa<FieldDecl, IndirectFieldDecl>(getDecl())));
|
|
|
|
if (!Base.isBlockPointer())
|
|
return std::nullopt;
|
|
|
|
unsigned BlockMDSize = Base.block()->getDescriptor()->getMetadataSize();
|
|
|
|
if (PtrOffset >= 0) {
|
|
// If the resulting base would be too small, return nullopt.
|
|
if (Base.BS.Base < static_cast<unsigned>(PtrOffset) ||
|
|
(Base.BS.Base - PtrOffset < BlockMDSize))
|
|
return std::nullopt;
|
|
}
|
|
|
|
Pointer CastedBase =
|
|
(PtrOffset < 0 ? Base.atField(-PtrOffset) : Base.atFieldSub(PtrOffset));
|
|
|
|
const Record *BaseRecord = CastedBase.getRecord();
|
|
if (!BaseRecord)
|
|
return std::nullopt;
|
|
|
|
unsigned Offset = 0;
|
|
Offset += BlockMDSize;
|
|
|
|
if (const auto *FD = dyn_cast<FieldDecl>(getDecl())) {
|
|
if (FD->getParent() == BaseRecord->getDecl())
|
|
return CastedBase.atField(BaseRecord->getField(FD)->Offset);
|
|
|
|
const RecordDecl *FieldParent = FD->getParent();
|
|
const Record *FieldRecord = Ctx.getRecord(FieldParent);
|
|
|
|
Offset += FieldRecord->getField(FD)->Offset;
|
|
if (Offset > CastedBase.block()->getSize())
|
|
return std::nullopt;
|
|
|
|
if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();
|
|
BaseDecl != FieldParent)
|
|
Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl);
|
|
|
|
} else {
|
|
const auto *IFD = cast<IndirectFieldDecl>(getDecl());
|
|
|
|
for (const NamedDecl *ND : IFD->chain()) {
|
|
const FieldDecl *F = cast<FieldDecl>(ND);
|
|
const RecordDecl *FieldParent = F->getParent();
|
|
const Record *FieldRecord = Ctx.getRecord(FieldParent);
|
|
Offset += FieldRecord->getField(F)->Offset;
|
|
}
|
|
}
|
|
|
|
assert(BaseRecord);
|
|
if (Offset > CastedBase.block()->getSize())
|
|
return std::nullopt;
|
|
|
|
assert(Offset <= CastedBase.block()->getSize());
|
|
return Pointer(const_cast<Block *>(Base.block()), Offset, Offset);
|
|
}
|
|
|
|
APValue MemberPointer::toAPValue(const ASTContext &ASTCtx) const {
|
|
if (isZero())
|
|
return APValue(static_cast<ValueDecl *>(nullptr), /*IsDerivedMember=*/false,
|
|
/*Path=*/{});
|
|
|
|
if (hasBase())
|
|
return Base.toAPValue(ASTCtx);
|
|
|
|
return APValue(getDecl(), /*IsDerivedMember=*/isDerivedMember(),
|
|
/*Path=*/ArrayRef(Path, PathLength));
|
|
}
|
|
|
|
ComparisonCategoryResult
|
|
MemberPointer::compare(const MemberPointer &RHS) const {
|
|
if (this->getDecl() == RHS.getDecl()) {
|
|
|
|
if (this->PathLength != RHS.PathLength)
|
|
return ComparisonCategoryResult::Unordered;
|
|
|
|
if (PathLength != 0 &&
|
|
std::memcmp(Path, RHS.Path, PathLength * sizeof(CXXRecordDecl *)) != 0)
|
|
return ComparisonCategoryResult::Unordered;
|
|
|
|
return ComparisonCategoryResult::Equal;
|
|
}
|
|
return ComparisonCategoryResult::Unordered;
|
|
}
|
|
|
|
} // namespace interp
|
|
} // namespace clang
|