1//===--- Record.h - struct and class metadata for the VM --------*- 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// A record is part of a program to describe the layout and methods of a struct.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_RECORD_H
14#define LLVM_CLANG_AST_INTERP_RECORD_H
15
16#include "PrimType.h"
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclCXX.h"
19#include "llvm/ADT/ArrayRef.h"
20
21namespace clang {
22namespace interp {
23class Program;
24struct Descriptor;
25
26/// Structure/Class descriptor.
27class Record final {
28public:
29 /// Describes a record field.
30 struct Field {
31 const FieldDecl *Decl;
32 const Descriptor *Desc;
33 unsigned Offset;
34 OptPrimType T;
35 bool IsBitField;
36 bool IsUnnamedBitField;
37
38 bool isBitField() const { return IsBitField; }
39 bool isUnnamedBitField() const { return IsUnnamedBitField; }
40 unsigned bitWidth() const {
41 assert(isBitField());
42 return Decl->getBitWidthValue();
43 }
44
45 Field(const FieldDecl *D, const Descriptor *Desc, unsigned Offset,
46 OptPrimType T)
47 : Decl(D), Desc(Desc), Offset(Offset), T(T) {
48 IsBitField = Decl->isBitField();
49 IsUnnamedBitField = IsBitField && Decl->isUnnamedBitField();
50 }
51 };
52
53 /// Describes a base class.
54 struct Base {
55 const RecordDecl *Decl;
56 const Descriptor *Desc;
57 const Record *R;
58 unsigned Offset;
59
60 Base(const RecordDecl *D, const Descriptor *Desc, const Record *R,
61 unsigned Offset)
62 : Decl(D), Desc(Desc), R(R), Offset(Offset) {}
63 };
64
65public:
66 /// Returns the underlying declaration.
67 const RecordDecl *getDecl() const { return Decl; }
68 /// Returns the name of the underlying declaration.
69 std::string getName() const;
70 /// Checks if the record is a union.
71 bool isUnion() const { return IsUnion; }
72 /// Checks if the record is an anonymous union.
73 bool isAnonymousUnion() const { return IsAnonymousUnion; }
74 /// Returns the size of the record.
75 unsigned getSize() const { return BaseSize; }
76 /// Returns the full size of the record, including records.
77 unsigned getFullSize() const { return BaseSize + VirtualSize; }
78 /// Returns the destructor of the record, if any.
79 const CXXDestructorDecl *getDestructor() const {
80 if (const auto *CXXDecl = dyn_cast<CXXRecordDecl>(Val: Decl))
81 return CXXDecl->getDestructor();
82 return nullptr;
83 }
84 /// If this record (or any of its bases) contains a field of type PT_Ptr.
85 bool hasPtrField() const { return HasPtrField; }
86
87 /// Returns true for anonymous unions and records
88 /// with no destructor or for those with a trivial destructor.
89 bool hasTrivialDtor() const;
90
91 using const_field_iter = ArrayRef<Field>::const_iterator;
92 llvm::iterator_range<const_field_iter> fields() const {
93 return llvm::make_range(x: Fields.begin(), y: Fields.end());
94 }
95
96 unsigned getNumFields() const { return Fields.size(); }
97 const Field *getField(unsigned I) const { return &Fields[I]; }
98 /// Find a field with the given offset.
99 /// This does a linear search, so use sparingly.
100 const Field *findField(unsigned Offset) const;
101 /// Returns a field.
102 const Field *getField(const FieldDecl *FD) const {
103 return &Fields[FD->getFieldIndex()];
104 }
105
106 using const_base_iter = ArrayRef<Base>::const_iterator;
107 llvm::iterator_range<const_base_iter> bases() const {
108 return llvm::make_range(x: Bases.begin(), y: Bases.end());
109 }
110
111 unsigned getNumBases() const { return Bases.size(); }
112 const Base *getBase(unsigned I) const {
113 assert(I < getNumBases());
114 return &Bases[I];
115 }
116 /// Returns a base descriptor.
117 const Base *getBase(QualType T) const;
118 /// Returns a base descriptor.
119 const Base *getBase(const RecordDecl *RD) const;
120 const Base *getBaseOrNull(const RecordDecl *RD) const;
121 const Base *findBase(unsigned Offset) const;
122
123 llvm::iterator_range<const_base_iter> virtual_bases() const {
124 return llvm::make_range(x: VirtualBases.begin(), y: VirtualBases.end());
125 }
126
127 unsigned getNumVirtualBases() const { return VirtualBases.size(); }
128 const Base *getVirtualBase(unsigned I) const { return &VirtualBases[I]; }
129 /// Returns a virtual base descriptor.
130 const Base *findVirtualBase(const RecordDecl *RD) const;
131
132 void dump(llvm::raw_ostream &OS, unsigned Indentation = 0,
133 unsigned Offset = 0) const;
134 void dump() const { dump(OS&: llvm::errs()); }
135
136private:
137 /// Constructor used by Program to create record descriptors.
138 Record(const RecordDecl *, ArrayRef<Base> Bases, ArrayRef<Field> Fields,
139 ArrayRef<Base> VirtualBases, unsigned VirtualSize, unsigned BaseSize,
140 bool HasPtrField = true);
141
142private:
143 friend class Program;
144
145 /// Original declaration.
146 const RecordDecl *Decl;
147 /// List of all base classes.
148 ArrayRef<Base> Bases;
149 /// List of all the fields in the record.
150 ArrayRef<Field> Fields;
151 /// List of all virtual bases.
152 ArrayRef<Base> VirtualBases;
153
154 /// Mapping from declarations to bases.
155 llvm::DenseMap<const RecordDecl *, const Base *> BaseMap;
156 /// Size of the structure.
157 unsigned BaseSize;
158 /// Size of all virtual bases.
159 unsigned VirtualSize;
160 /// If this record is a union.
161 bool IsUnion;
162 /// If this is an anonymous union.
163 bool IsAnonymousUnion;
164 /// If any of the fields are pointers (or references).
165 bool HasPtrField = false;
166};
167
168} // namespace interp
169} // namespace clang
170
171#endif
172