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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "MemberPointer.h" 10 #include "Context.h" 11 #include "FunctionPointer.h" 12 #include "Program.h" 13 #include "Record.h" 14 15 namespace clang { 16 namespace interp { 17 18 std::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 Pointer CastedBase = 27 (PtrOffset < 0 ? Base.atField(-PtrOffset) : Base.atFieldSub(PtrOffset)); 28 29 const Record *BaseRecord = CastedBase.getRecord(); 30 if (!BaseRecord) 31 return std::nullopt; 32 33 unsigned Offset = 0; 34 Offset += CastedBase.block()->getDescriptor()->getMetadataSize(); 35 36 if (const auto *FD = dyn_cast<FieldDecl>(Dcl)) { 37 if (FD->getParent() == BaseRecord->getDecl()) 38 return CastedBase.atField(BaseRecord->getField(FD)->Offset); 39 40 const RecordDecl *FieldParent = FD->getParent(); 41 const Record *FieldRecord = Ctx.getRecord(FieldParent); 42 43 Offset += FieldRecord->getField(FD)->Offset; 44 if (Offset > CastedBase.block()->getSize()) 45 return std::nullopt; 46 47 if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl(); 48 BaseDecl != FieldParent) 49 Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl); 50 51 } else { 52 const auto *IFD = cast<IndirectFieldDecl>(Dcl); 53 54 for (const NamedDecl *ND : IFD->chain()) { 55 const FieldDecl *F = cast<FieldDecl>(ND); 56 const RecordDecl *FieldParent = F->getParent(); 57 const Record *FieldRecord = Ctx.getRecord(FieldParent); 58 Offset += FieldRecord->getField(F)->Offset; 59 } 60 } 61 62 assert(BaseRecord); 63 if (Offset > CastedBase.block()->getSize()) 64 return std::nullopt; 65 66 assert(Offset <= CastedBase.block()->getSize()); 67 return Pointer(const_cast<Block *>(Base.block()), Offset, Offset); 68 } 69 70 FunctionPointer MemberPointer::toFunctionPointer(const Context &Ctx) const { 71 return FunctionPointer(Ctx.getProgram().getFunction(cast<FunctionDecl>(Dcl))); 72 } 73 74 APValue MemberPointer::toAPValue(const ASTContext &ASTCtx) const { 75 if (isZero()) 76 return APValue(static_cast<ValueDecl *>(nullptr), /*IsDerivedMember=*/false, 77 /*Path=*/{}); 78 79 if (hasBase()) 80 return Base.toAPValue(ASTCtx); 81 82 return APValue(getDecl(), /*IsDerivedMember=*/false, 83 /*Path=*/{}); 84 } 85 86 } // namespace interp 87 } // namespace clang 88