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 assert((isa<FieldDecl, IndirectFieldDecl>(Dcl)));
22
23 if (!Base.isBlockPointer())
24 return std::nullopt;
25
26 Pointer CastedBase =
27 (PtrOffset < 0 ? Base.atField(Off: -PtrOffset) : Base.atFieldSub(Off: 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>(Val: Dcl)) {
37 if (FD->getParent() == BaseRecord->getDecl())
38 return CastedBase.atField(Off: BaseRecord->getField(FD)->Offset);
39
40 const RecordDecl *FieldParent = FD->getParent();
41 const Record *FieldRecord = Ctx.getRecord(D: 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(BaseDecl: FieldParent, DerivedDecl: BaseDecl);
50
51 } else {
52 const auto *IFD = cast<IndirectFieldDecl>(Val: Dcl);
53
54 for (const NamedDecl *ND : IFD->chain()) {
55 const FieldDecl *F = cast<FieldDecl>(Val: ND);
56 const RecordDecl *FieldParent = F->getParent();
57 const Record *FieldRecord = Ctx.getRecord(D: FieldParent);
58 Offset += FieldRecord->getField(FD: 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
70FunctionPointer MemberPointer::toFunctionPointer(const Context &Ctx) const {
71 return FunctionPointer(Ctx.getProgram().getFunction(F: cast<FunctionDecl>(Val: Dcl)));
72}
73
74APValue 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