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