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
15namespace clang {
16namespace interp {
17
18std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
19 if (!Dcl || isa<FunctionDecl>(Val: Dcl))
20 return Base;
21 const FieldDecl *FD = cast<FieldDecl>(Val: Dcl);
22 assert(FD);
23
24 if (!Base.isBlockPointer())
25 return std::nullopt;
26
27 Pointer CastedBase =
28 (PtrOffset < 0 ? Base.atField(Off: -PtrOffset) : Base.atFieldSub(Off: PtrOffset));
29
30 const Record *BaseRecord = CastedBase.getRecord();
31 if (!BaseRecord)
32 return std::nullopt;
33
34 assert(BaseRecord);
35 if (FD->getParent() == BaseRecord->getDecl())
36 return CastedBase.atField(Off: BaseRecord->getField(FD)->Offset);
37
38 const RecordDecl *FieldParent = FD->getParent();
39 const Record *FieldRecord = Ctx.getRecord(D: FieldParent);
40
41 unsigned Offset = 0;
42 Offset += FieldRecord->getField(FD)->Offset;
43 Offset += CastedBase.block()->getDescriptor()->getMetadataSize();
44
45 if (Offset > CastedBase.block()->getSize())
46 return std::nullopt;
47
48 if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();
49 BaseDecl != FieldParent)
50 Offset += Ctx.collectBaseOffset(BaseDecl: FieldParent, DerivedDecl: BaseDecl);
51
52 if (Offset > CastedBase.block()->getSize())
53 return std::nullopt;
54
55 assert(Offset <= CastedBase.block()->getSize());
56 return Pointer(const_cast<Block *>(Base.block()), Offset, Offset);
57}
58
59FunctionPointer MemberPointer::toFunctionPointer(const Context &Ctx) const {
60 return FunctionPointer(Ctx.getProgram().getFunction(F: cast<FunctionDecl>(Val: Dcl)));
61}
62
63APValue MemberPointer::toAPValue(const ASTContext &ASTCtx) const {
64 if (isZero())
65 return APValue(static_cast<ValueDecl *>(nullptr), /*IsDerivedMember=*/false,
66 /*Path=*/{});
67
68 if (hasBase())
69 return Base.toAPValue(ASTCtx);
70
71 return APValue(cast<ValueDecl>(Val: getDecl()), /*IsDerivedMember=*/false,
72 /*Path=*/{});
73}
74
75} // namespace interp
76} // namespace clang
77