1//===------------------------- MemberPointer.h ------------------*- 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#ifndef LLVM_CLANG_AST_INTERP_MEMBER_POINTER_H
10#define LLVM_CLANG_AST_INTERP_MEMBER_POINTER_H
11
12#include "Pointer.h"
13#include "llvm/ADT/PointerIntPair.h"
14#include <optional>
15
16namespace clang {
17class ASTContext;
18class CXXRecordDecl;
19namespace interp {
20
21class Context;
22
23class MemberPointer final {
24private:
25 Pointer Base;
26 /// The member declaration, and a flag indicating
27 /// whether the member is a member of some class derived from the class type
28 /// of the member pointer.
29 llvm::PointerIntPair<const ValueDecl *, 1, bool> DeclAndIsDerivedMember;
30 /// The path of base/derived classes from the member declaration's
31 /// class (exclusive) to the class type of the member pointer (inclusive).
32 /// This a allocated by the InterpState or the Program.
33 const CXXRecordDecl **Path = nullptr;
34 int32_t PtrOffset = 0;
35 uint8_t PathLength = 0;
36
37 MemberPointer(Pointer Base, const ValueDecl *Dcl, int32_t PtrOffset,
38 uint8_t PathLength = 0, const CXXRecordDecl **Path = nullptr,
39 bool IsDerived = false)
40 : Base(Base), DeclAndIsDerivedMember(Dcl, IsDerived), Path(Path),
41 PtrOffset(PtrOffset), PathLength(PathLength) {}
42
43public:
44 MemberPointer() = default;
45 MemberPointer(Pointer Base, const ValueDecl *Dcl)
46 : Base(Base), DeclAndIsDerivedMember(Dcl) {}
47 MemberPointer(uint32_t Address, const Descriptor *D) {
48 // We only reach this for Address == 0, when creating a null member pointer.
49 assert(Address == 0);
50 }
51
52 MemberPointer(const ValueDecl *D) : DeclAndIsDerivedMember(D) {
53 assert((isa<FieldDecl, IndirectFieldDecl, CXXMethodDecl>(D)));
54 }
55
56 uint64_t getIntegerRepresentation() const {
57 assert(
58 false &&
59 "getIntegerRepresentation() shouldn't be reachable for MemberPointers");
60 return 17;
61 }
62
63 /// Does this member pointer have a base declaration?
64 bool hasDecl() const { return DeclAndIsDerivedMember.getPointer(); }
65 bool isDerivedMember() const { return DeclAndIsDerivedMember.getInt(); }
66 /// Return the base declaration. Might be null.
67 const ValueDecl *getDecl() const {
68 return DeclAndIsDerivedMember.getPointer();
69 }
70 /// Does this member pointer have a path (i.e. path length is > 0)?
71 bool hasPath() const { return PathLength != 0; }
72 /// Return the length of the cast path.
73 unsigned getPathLength() const { return PathLength; }
74 /// Return the cast path entry at the given position.
75 const CXXRecordDecl *getPathEntry(unsigned Index) const {
76 assert(Index < PathLength);
77 return Path[Index];
78 }
79 /// Return the cast path. Might return null.
80 const CXXRecordDecl **path() const { return Path; }
81 bool isZero() const { return Base.isZero() && !hasDecl(); }
82 bool hasBase() const { return !Base.isZero(); }
83 bool isWeak() const {
84 if (const auto *MF = getMemberFunction())
85 return MF->isWeak();
86 return false;
87 }
88
89 /// Sets the path of this member pointer. After this call,
90 /// the memory pointed to by \p NewPath is assumed to be owned
91 /// by this member pointer.
92 void takePath(const CXXRecordDecl **NewPath) {
93 assert(Path != NewPath);
94 Path = NewPath;
95 }
96
97 // Pretend we always have a path.
98 bool singleWord() const { return false; }
99 ComparisonCategoryResult compare(const MemberPointer &RHS) const;
100
101 std::optional<Pointer> toPointer(const Context &Ctx) const;
102
103 bool isBaseCastPossible() const {
104 if (PtrOffset < 0)
105 return true;
106 return static_cast<uint64_t>(PtrOffset) <= Base.getByteOffset();
107 }
108
109 Pointer getBase() const {
110 if (PtrOffset < 0)
111 return Base.atField(Off: -PtrOffset);
112 return Base.atFieldSub(Off: PtrOffset);
113 }
114 /// Is the base declaration a member function?
115 bool isMemberFunctionPointer() const {
116 return isa_and_nonnull<CXXMethodDecl>(Val: DeclAndIsDerivedMember.getPointer());
117 }
118 /// Return the base declaration as a CXXMethodDecl. Might return null.
119 const CXXMethodDecl *getMemberFunction() const {
120 return dyn_cast_if_present<CXXMethodDecl>(
121 Val: DeclAndIsDerivedMember.getPointer());
122 }
123 /// Return the base declaration as a FieldDecl. Might return null.
124 const FieldDecl *getField() const {
125 return dyn_cast_if_present<FieldDecl>(Val: DeclAndIsDerivedMember.getPointer());
126 }
127 /// Returns the record decl this member pointer points into.
128 const CXXRecordDecl *getRecordDecl() const {
129 if (const FieldDecl *FD = getField())
130 return cast<CXXRecordDecl>(Val: FD->getParent());
131
132 if (const CXXMethodDecl *MD = getMemberFunction())
133 return MD->getParent();
134 return nullptr;
135 }
136
137 MemberPointer atInstanceBase(unsigned Offset, uint8_t PathLength = 0,
138 const CXXRecordDecl **Path = nullptr,
139 bool NewIsDerived = false) const {
140 if (Base.isZero())
141 return MemberPointer(Base, DeclAndIsDerivedMember.getPointer(), Offset,
142 PathLength, Path, NewIsDerived);
143 return MemberPointer(this->Base, DeclAndIsDerivedMember.getPointer(),
144 Offset + PtrOffset, PathLength, Path, NewIsDerived);
145 }
146
147 MemberPointer takeInstance(Pointer Instance) const {
148 assert(this->Base.isZero());
149 return MemberPointer(Instance, DeclAndIsDerivedMember.getPointer(),
150 this->PtrOffset);
151 }
152
153 APValue toAPValue(const ASTContext &) const;
154
155 void print(llvm::raw_ostream &OS) const {
156 OS << "MemberPtr(" << Base << " " << (const void *)getDecl() << " + "
157 << PtrOffset << ". PathLength: " << getPathLength()
158 << ". IsDerived: " << isDerivedMember() << ")";
159 }
160
161 std::string toDiagnosticString(const ASTContext &Ctx) const {
162 return toAPValue(Ctx).getAsString(Ctx, Ty: getDecl()->getType());
163 }
164};
165
166inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
167 const MemberPointer &FP) {
168 FP.print(OS);
169 return OS;
170}
171
172} // namespace interp
173} // namespace clang
174
175#endif
176