97 lines · cpp
1//===------------------------- MemberPointer.cpp ----------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MemberPointer.h"10#include "Context.h"11#include "FunctionPointer.h"12#include "Program.h"13#include "Record.h"14 15namespace clang {16namespace interp {17 18std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {19 if (!Dcl || isa<FunctionDecl>(Dcl))20 return Base;21 assert((isa<FieldDecl, IndirectFieldDecl>(Dcl)));22 23 if (!Base.isBlockPointer())24 return std::nullopt;25 26 unsigned BlockMDSize = Base.block()->getDescriptor()->getMetadataSize();27 28 if (PtrOffset >= 0) {29 // If the resulting base would be too small, return nullopt.30 if (Base.BS.Base < static_cast<unsigned>(PtrOffset) ||31 (Base.BS.Base - PtrOffset < BlockMDSize))32 return std::nullopt;33 }34 35 Pointer CastedBase =36 (PtrOffset < 0 ? Base.atField(-PtrOffset) : Base.atFieldSub(PtrOffset));37 38 const Record *BaseRecord = CastedBase.getRecord();39 if (!BaseRecord)40 return std::nullopt;41 42 unsigned Offset = 0;43 Offset += BlockMDSize;44 45 if (const auto *FD = dyn_cast<FieldDecl>(Dcl)) {46 if (FD->getParent() == BaseRecord->getDecl())47 return CastedBase.atField(BaseRecord->getField(FD)->Offset);48 49 const RecordDecl *FieldParent = FD->getParent();50 const Record *FieldRecord = Ctx.getRecord(FieldParent);51 52 Offset += FieldRecord->getField(FD)->Offset;53 if (Offset > CastedBase.block()->getSize())54 return std::nullopt;55 56 if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();57 BaseDecl != FieldParent)58 Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl);59 60 } else {61 const auto *IFD = cast<IndirectFieldDecl>(Dcl);62 63 for (const NamedDecl *ND : IFD->chain()) {64 const FieldDecl *F = cast<FieldDecl>(ND);65 const RecordDecl *FieldParent = F->getParent();66 const Record *FieldRecord = Ctx.getRecord(FieldParent);67 Offset += FieldRecord->getField(F)->Offset;68 }69 }70 71 assert(BaseRecord);72 if (Offset > CastedBase.block()->getSize())73 return std::nullopt;74 75 assert(Offset <= CastedBase.block()->getSize());76 return Pointer(const_cast<Block *>(Base.block()), Offset, Offset);77}78 79FunctionPointer MemberPointer::toFunctionPointer(const Context &Ctx) const {80 return FunctionPointer(Ctx.getProgram().getFunction(cast<FunctionDecl>(Dcl)));81}82 83APValue MemberPointer::toAPValue(const ASTContext &ASTCtx) const {84 if (isZero())85 return APValue(static_cast<ValueDecl *>(nullptr), /*IsDerivedMember=*/false,86 /*Path=*/{});87 88 if (hasBase())89 return Base.toAPValue(ASTCtx);90 91 return APValue(getDecl(), /*IsDerivedMember=*/false,92 /*Path=*/{});93}94 95} // namespace interp96} // namespace clang97