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