//===------------------------- 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 MemberPointer::toPointer(const Context &Ctx) const { if (!getDecl() || isa(getDecl())) return Base; assert((isa(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(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(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(getDecl()); for (const NamedDecl *ND : IFD->chain()) { const FieldDecl *F = cast(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(Base.block()), Offset, Offset); } APValue MemberPointer::toAPValue(const ASTContext &ASTCtx) const { if (isZero()) return APValue(static_cast(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