xref: /llvm-project/clang/lib/AST/ByteCode/MemberPointer.cpp (revision f3111cc77bea8d4f6b3ca90ee5457cff5faeb3fc)
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