1//===- RecordLayout.h - Layout information for a struct/union ---*- 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//  This file defines the RecordLayout interface.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_RECORDLAYOUT_H
14#define LLVM_CLANG_AST_RECORDLAYOUT_H
15
16#include "clang/AST/ASTVector.h"
17#include "clang/AST/CharUnits.h"
18#include "clang/AST/DeclCXX.h"
19#include "clang/Basic/LLVM.h"
20#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/PointerIntPair.h"
23#include <cassert>
24#include <cstdint>
25
26namespace clang {
27
28class ASTContext;
29class CXXRecordDecl;
30
31/// ASTRecordLayout -
32/// This class contains layout information for one RecordDecl,
33/// which is a struct/union/class.  The decl represented must be a definition,
34/// not a forward declaration.
35/// This class is also used to contain layout information for one
36/// ObjCInterfaceDecl. FIXME - Find appropriate name.
37/// These objects are managed by ASTContext.
38class ASTRecordLayout {
39public:
40  struct VBaseInfo {
41    /// The offset to this virtual base in the complete-object layout
42    /// of this class.
43    CharUnits VBaseOffset;
44
45  private:
46    /// Whether this virtual base requires a vtordisp field in the
47    /// Microsoft ABI.  These fields are required for certain operations
48    /// in constructors and destructors.
49    bool HasVtorDisp = false;
50
51  public:
52    VBaseInfo() = default;
53    VBaseInfo(CharUnits VBaseOffset, bool hasVtorDisp)
54        : VBaseOffset(VBaseOffset), HasVtorDisp(hasVtorDisp) {}
55
56    bool hasVtorDisp() const { return HasVtorDisp; }
57  };
58
59  using VBaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, VBaseInfo>;
60
61private:
62  friend class ASTContext;
63
64  /// Size - Size of record in characters.
65  CharUnits Size;
66
67  /// DataSize - Size of record in characters without tail padding.
68  CharUnits DataSize;
69
70  // Alignment - Alignment of record in characters.
71  CharUnits Alignment;
72
73  // UnadjustedAlignment - Maximum of the alignments of the record members in
74  // characters.
75  CharUnits UnadjustedAlignment;
76
77  /// RequiredAlignment - The required alignment of the object.  In the MS-ABI
78  /// the __declspec(align()) trumps #pramga pack and must always be obeyed.
79  CharUnits RequiredAlignment;
80
81  /// FieldOffsets - Array of field offsets in bits.
82  ASTVector<uint64_t> FieldOffsets;
83
84  /// CXXRecordLayoutInfo - Contains C++ specific layout information.
85  struct CXXRecordLayoutInfo {
86    /// NonVirtualSize - The non-virtual size (in chars) of an object, which is
87    /// the size of the object without virtual bases.
88    CharUnits NonVirtualSize;
89
90    /// NonVirtualAlignment - The non-virtual alignment (in chars) of an object,
91    /// which is the alignment of the object without virtual bases.
92    CharUnits NonVirtualAlignment;
93
94    /// SizeOfLargestEmptySubobject - The size of the largest empty subobject
95    /// (either a base or a member). Will be zero if the class doesn't contain
96    /// any empty subobjects.
97    CharUnits SizeOfLargestEmptySubobject;
98
99    /// VBPtrOffset - Virtual base table offset (Microsoft-only).
100    CharUnits VBPtrOffset;
101
102    /// HasOwnVFPtr - Does this class provide a virtual function table
103    /// (vtable in Itanium, vftbl in Microsoft) that is independent from
104    /// its base classes?
105    bool HasOwnVFPtr : 1;
106
107    /// HasVFPtr - Does this class have a vftable that could be extended by
108    /// a derived class.  The class may have inherited this pointer from
109    /// a primary base class.
110    bool HasExtendableVFPtr : 1;
111
112    /// EndsWithZeroSizedObject - True if this class contains a zero sized
113    /// member or base or a base with a zero sized member or base.
114    /// Only used for MS-ABI.
115    bool EndsWithZeroSizedObject : 1;
116
117    /// True if this class is zero sized or first base is zero sized or
118    /// has this property.  Only used for MS-ABI.
119    bool LeadsWithZeroSizedBase : 1;
120
121    /// PrimaryBase - The primary base info for this record.
122    llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
123
124    /// BaseSharingVBPtr - The base we share vbptr with.
125    const CXXRecordDecl *BaseSharingVBPtr;
126
127    /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
128    using BaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, CharUnits>;
129
130    /// BaseOffsets - Contains a map from base classes to their offset.
131    BaseOffsetsMapTy BaseOffsets;
132
133    /// VBaseOffsets - Contains a map from vbase classes to their offset.
134    VBaseOffsetsMapTy VBaseOffsets;
135  };
136
137  /// CXXInfo - If the record layout is for a C++ record, this will have
138  /// C++ specific information about the record.
139  CXXRecordLayoutInfo *CXXInfo = nullptr;
140
141  ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
142                  CharUnits unadjustedAlignment,
143                  CharUnits requiredAlignment, CharUnits datasize,
144                  ArrayRef<uint64_t> fieldoffsets);
145
146  using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy;
147
148  // Constructor for C++ records.
149  ASTRecordLayout(const ASTContext &Ctx,
150                  CharUnits size, CharUnits alignment,
151                  CharUnits unadjustedAlignment,
152                  CharUnits requiredAlignment,
153                  bool hasOwnVFPtr, bool hasExtendableVFPtr,
154                  CharUnits vbptroffset,
155                  CharUnits datasize,
156                  ArrayRef<uint64_t> fieldoffsets,
157                  CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
158                  CharUnits SizeOfLargestEmptySubobject,
159                  const CXXRecordDecl *PrimaryBase,
160                  bool IsPrimaryBaseVirtual,
161                  const CXXRecordDecl *BaseSharingVBPtr,
162                  bool EndsWithZeroSizedObject,
163                  bool LeadsWithZeroSizedBase,
164                  const BaseOffsetsMapTy& BaseOffsets,
165                  const VBaseOffsetsMapTy& VBaseOffsets);
166
167  ~ASTRecordLayout() = default;
168
169  void Destroy(ASTContext &Ctx);
170
171public:
172  ASTRecordLayout(const ASTRecordLayout &) = delete;
173  ASTRecordLayout &operator=(const ASTRecordLayout &) = delete;
174
175  /// getAlignment - Get the record alignment in characters.
176  CharUnits getAlignment() const { return Alignment; }
177
178  /// getUnadjustedAlignment - Get the record alignment in characters, before
179  /// alignment adjustement.
180  CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
181
182  /// getSize - Get the record size in characters.
183  CharUnits getSize() const { return Size; }
184
185  /// getFieldCount - Get the number of fields in the layout.
186  unsigned getFieldCount() const { return FieldOffsets.size(); }
187
188  /// getFieldOffset - Get the offset of the given field index, in
189  /// bits.
190  uint64_t getFieldOffset(unsigned FieldNo) const {
191    return FieldOffsets[FieldNo];
192  }
193
194  /// getDataSize() - Get the record data size, which is the record size
195  /// without tail padding, in characters.
196  CharUnits getDataSize() const {
197    return DataSize;
198  }
199
200  /// getNonVirtualSize - Get the non-virtual size (in chars) of an object,
201  /// which is the size of the object without virtual bases.
202  CharUnits getNonVirtualSize() const {
203    assert(CXXInfo && "Record layout does not have C++ specific info!");
204
205    return CXXInfo->NonVirtualSize;
206  }
207
208  /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object,
209  /// which is the alignment of the object without virtual bases.
210  CharUnits getNonVirtualAlignment() const {
211    assert(CXXInfo && "Record layout does not have C++ specific info!");
212
213    return CXXInfo->NonVirtualAlignment;
214  }
215
216  /// getPrimaryBase - Get the primary base for this record.
217  const CXXRecordDecl *getPrimaryBase() const {
218    assert(CXXInfo && "Record layout does not have C++ specific info!");
219
220    return CXXInfo->PrimaryBase.getPointer();
221  }
222
223  /// isPrimaryBaseVirtual - Get whether the primary base for this record
224  /// is virtual or not.
225  bool isPrimaryBaseVirtual() const {
226    assert(CXXInfo && "Record layout does not have C++ specific info!");
227
228    return CXXInfo->PrimaryBase.getInt();
229  }
230
231  /// getBaseClassOffset - Get the offset, in chars, for the given base class.
232  CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const {
233    assert(CXXInfo && "Record layout does not have C++ specific info!");
234    assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
235
236    return CXXInfo->BaseOffsets[Base];
237  }
238
239  /// getVBaseClassOffset - Get the offset, in chars, for the given base class.
240  CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const {
241    assert(CXXInfo && "Record layout does not have C++ specific info!");
242    assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
243
244    return CXXInfo->VBaseOffsets[VBase].VBaseOffset;
245  }
246
247  CharUnits getSizeOfLargestEmptySubobject() const {
248    assert(CXXInfo && "Record layout does not have C++ specific info!");
249    return CXXInfo->SizeOfLargestEmptySubobject;
250  }
251
252  /// hasOwnVFPtr - Does this class provide its own virtual-function
253  /// table pointer, rather than inheriting one from a primary base
254  /// class?  If so, it is at offset zero.
255  ///
256  /// This implies that the ABI has no primary base class, meaning
257  /// that it has no base classes that are suitable under the conditions
258  /// of the ABI.
259  bool hasOwnVFPtr() const {
260    assert(CXXInfo && "Record layout does not have C++ specific info!");
261    return CXXInfo->HasOwnVFPtr;
262  }
263
264  /// hasVFPtr - Does this class have a virtual function table pointer
265  /// that can be extended by a derived class?  This is synonymous with
266  /// this class having a VFPtr at offset zero.
267  bool hasExtendableVFPtr() const {
268    assert(CXXInfo && "Record layout does not have C++ specific info!");
269    return CXXInfo->HasExtendableVFPtr;
270  }
271
272  /// hasOwnVBPtr - Does this class provide its own virtual-base
273  /// table pointer, rather than inheriting one from a primary base
274  /// class?
275  ///
276  /// This implies that the ABI has no primary base class, meaning
277  /// that it has no base classes that are suitable under the conditions
278  /// of the ABI.
279  bool hasOwnVBPtr() const {
280    assert(CXXInfo && "Record layout does not have C++ specific info!");
281    return hasVBPtr() && !CXXInfo->BaseSharingVBPtr;
282  }
283
284  /// hasVBPtr - Does this class have a virtual function table pointer.
285  bool hasVBPtr() const {
286    assert(CXXInfo && "Record layout does not have C++ specific info!");
287    return !CXXInfo->VBPtrOffset.isNegative();
288  }
289
290  CharUnits getRequiredAlignment() const {
291    return RequiredAlignment;
292  }
293
294  bool endsWithZeroSizedObject() const {
295    return CXXInfo && CXXInfo->EndsWithZeroSizedObject;
296  }
297
298  bool leadsWithZeroSizedBase() const {
299    assert(CXXInfo && "Record layout does not have C++ specific info!");
300    return CXXInfo->LeadsWithZeroSizedBase;
301  }
302
303  /// getVBPtrOffset - Get the offset for virtual base table pointer.
304  /// This is only meaningful with the Microsoft ABI.
305  CharUnits getVBPtrOffset() const {
306    assert(CXXInfo && "Record layout does not have C++ specific info!");
307    return CXXInfo->VBPtrOffset;
308  }
309
310  const CXXRecordDecl *getBaseSharingVBPtr() const {
311    assert(CXXInfo && "Record layout does not have C++ specific info!");
312    return CXXInfo->BaseSharingVBPtr;
313  }
314
315  const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
316    assert(CXXInfo && "Record layout does not have C++ specific info!");
317    return CXXInfo->VBaseOffsets;
318  }
319};
320
321} // namespace clang
322
323#endif // LLVM_CLANG_AST_RECORDLAYOUT_H
324