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