xref: /freebsd/contrib/llvm-project/clang/include/clang/AST/RecordLayout.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
26 namespace clang {
27 
28 class ASTContext;
29 class 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.
38 class ASTRecordLayout {
39 public:
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;
VBaseInfoVBaseInfo53     VBaseInfo(CharUnits VBaseOffset, bool hasVtorDisp)
54         : VBaseOffset(VBaseOffset), HasVtorDisp(hasVtorDisp) {}
55 
hasVtorDispVBaseInfo56     bool hasVtorDisp() const { return HasVtorDisp; }
57   };
58 
59   using VBaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, VBaseInfo>;
60 
61 private:
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   // PreferredAlignment - Preferred alignment of record in characters. This
74   // can be different than Alignment in cases where it is beneficial for
75   // performance or backwards compatibility preserving (e.g. AIX-ABI).
76   CharUnits PreferredAlignment;
77 
78   // UnadjustedAlignment - Alignment of record in characters before alignment
79   // adjustments. Maximum of the alignments of the record members and base
80   // classes in characters.
81   CharUnits UnadjustedAlignment;
82 
83   /// RequiredAlignment - The required alignment of the object.  In the MS-ABI
84   /// the __declspec(align()) trumps #pramga pack and must always be obeyed.
85   CharUnits RequiredAlignment;
86 
87   /// FieldOffsets - Array of field offsets in bits.
88   ASTVector<uint64_t> FieldOffsets;
89 
90   /// CXXRecordLayoutInfo - Contains C++ specific layout information.
91   struct CXXRecordLayoutInfo {
92     /// NonVirtualSize - The non-virtual size (in chars) of an object, which is
93     /// the size of the object without virtual bases.
94     CharUnits NonVirtualSize;
95 
96     /// NonVirtualAlignment - The non-virtual alignment (in chars) of an object,
97     /// which is the alignment of the object without virtual bases.
98     CharUnits NonVirtualAlignment;
99 
100     /// PreferredNVAlignment - The preferred non-virtual alignment (in chars) of
101     /// an object, which is the preferred alignment of the object without
102     /// virtual bases.
103     CharUnits PreferredNVAlignment;
104 
105     /// SizeOfLargestEmptySubobject - The size of the largest empty subobject
106     /// (either a base or a member). Will be zero if the class doesn't contain
107     /// any empty subobjects.
108     CharUnits SizeOfLargestEmptySubobject;
109 
110     /// VBPtrOffset - Virtual base table offset (Microsoft-only).
111     CharUnits VBPtrOffset;
112 
113     /// HasOwnVFPtr - Does this class provide a virtual function table
114     /// (vtable in Itanium, vftbl in Microsoft) that is independent from
115     /// its base classes?
116     bool HasOwnVFPtr : 1;
117 
118     /// HasVFPtr - Does this class have a vftable that could be extended by
119     /// a derived class.  The class may have inherited this pointer from
120     /// a primary base class.
121     bool HasExtendableVFPtr : 1;
122 
123     /// EndsWithZeroSizedObject - True if this class contains a zero sized
124     /// member or base or a base with a zero sized member or base.
125     /// Only used for MS-ABI.
126     bool EndsWithZeroSizedObject : 1;
127 
128     /// True if this class is zero sized or first base is zero sized or
129     /// has this property.  Only used for MS-ABI.
130     bool LeadsWithZeroSizedBase : 1;
131 
132     /// PrimaryBase - The primary base info for this record.
133     llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
134 
135     /// BaseSharingVBPtr - The base we share vbptr with.
136     const CXXRecordDecl *BaseSharingVBPtr;
137 
138     /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
139     using BaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, CharUnits>;
140 
141     /// BaseOffsets - Contains a map from base classes to their offset.
142     BaseOffsetsMapTy BaseOffsets;
143 
144     /// VBaseOffsets - Contains a map from vbase classes to their offset.
145     VBaseOffsetsMapTy VBaseOffsets;
146   };
147 
148   /// CXXInfo - If the record layout is for a C++ record, this will have
149   /// C++ specific information about the record.
150   CXXRecordLayoutInfo *CXXInfo = nullptr;
151 
152   ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
153                   CharUnits preferredAlignment, CharUnits unadjustedAlignment,
154                   CharUnits requiredAlignment, CharUnits datasize,
155                   ArrayRef<uint64_t> fieldoffsets);
156 
157   using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy;
158 
159   // Constructor for C++ records.
160   ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
161                   CharUnits preferredAlignment, CharUnits unadjustedAlignment,
162                   CharUnits requiredAlignment, bool hasOwnVFPtr,
163                   bool hasExtendableVFPtr, CharUnits vbptroffset,
164                   CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
165                   CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
166                   CharUnits preferrednvalignment,
167                   CharUnits SizeOfLargestEmptySubobject,
168                   const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual,
169                   const CXXRecordDecl *BaseSharingVBPtr,
170                   bool EndsWithZeroSizedObject, bool LeadsWithZeroSizedBase,
171                   const BaseOffsetsMapTy &BaseOffsets,
172                   const VBaseOffsetsMapTy &VBaseOffsets);
173 
174   ~ASTRecordLayout() = default;
175 
176   void Destroy(ASTContext &Ctx);
177 
178 public:
179   ASTRecordLayout(const ASTRecordLayout &) = delete;
180   ASTRecordLayout &operator=(const ASTRecordLayout &) = delete;
181 
182   /// getAlignment - Get the record alignment in characters.
getAlignment()183   CharUnits getAlignment() const { return Alignment; }
184 
185   /// getPreferredFieldAlignment - Get the record preferred alignment in
186   /// characters.
getPreferredAlignment()187   CharUnits getPreferredAlignment() const { return PreferredAlignment; }
188 
189   /// getUnadjustedAlignment - Get the record alignment in characters, before
190   /// alignment adjustment.
getUnadjustedAlignment()191   CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
192 
193   /// getSize - Get the record size in characters.
getSize()194   CharUnits getSize() const { return Size; }
195 
196   /// getFieldCount - Get the number of fields in the layout.
getFieldCount()197   unsigned getFieldCount() const { return FieldOffsets.size(); }
198 
199   /// getFieldOffset - Get the offset of the given field index, in
200   /// bits.
getFieldOffset(unsigned FieldNo)201   uint64_t getFieldOffset(unsigned FieldNo) const {
202     return FieldOffsets[FieldNo];
203   }
204 
205   /// getDataSize() - Get the record data size, which is the record size
206   /// without tail padding, in characters.
getDataSize()207   CharUnits getDataSize() const { return DataSize; }
208 
209   /// getNonVirtualSize - Get the non-virtual size (in chars) of an object,
210   /// which is the size of the object without virtual bases.
getNonVirtualSize()211   CharUnits getNonVirtualSize() const {
212     assert(CXXInfo && "Record layout does not have C++ specific info!");
213 
214     return CXXInfo->NonVirtualSize;
215   }
216 
217   /// getNonVirtualAlignment - Get the non-virtual alignment (in chars) of an
218   /// object, which is the alignment of the object without virtual bases.
getNonVirtualAlignment()219   CharUnits getNonVirtualAlignment() const {
220     assert(CXXInfo && "Record layout does not have C++ specific info!");
221 
222     return CXXInfo->NonVirtualAlignment;
223   }
224 
225   /// getPreferredNVAlignment - Get the preferred non-virtual alignment (in
226   /// chars) of an object, which is the preferred alignment of the object
227   /// without virtual bases.
getPreferredNVAlignment()228   CharUnits getPreferredNVAlignment() const {
229     assert(CXXInfo && "Record layout does not have C++ specific info!");
230 
231     return CXXInfo->PreferredNVAlignment;
232   }
233 
234   /// getPrimaryBase - Get the primary base for this record.
getPrimaryBase()235   const CXXRecordDecl *getPrimaryBase() const {
236     assert(CXXInfo && "Record layout does not have C++ specific info!");
237 
238     return CXXInfo->PrimaryBase.getPointer();
239   }
240 
241   /// isPrimaryBaseVirtual - Get whether the primary base for this record
242   /// is virtual or not.
isPrimaryBaseVirtual()243   bool isPrimaryBaseVirtual() const {
244     assert(CXXInfo && "Record layout does not have C++ specific info!");
245 
246     return CXXInfo->PrimaryBase.getInt();
247   }
248 
249   /// getBaseClassOffset - Get the offset, in chars, for the given base class.
getBaseClassOffset(const CXXRecordDecl * Base)250   CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const {
251     assert(CXXInfo && "Record layout does not have C++ specific info!");
252 
253     Base = Base->getDefinition();
254     assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
255 
256     return CXXInfo->BaseOffsets[Base];
257   }
258 
259   /// getVBaseClassOffset - Get the offset, in chars, for the given base class.
getVBaseClassOffset(const CXXRecordDecl * VBase)260   CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const {
261     assert(CXXInfo && "Record layout does not have C++ specific info!");
262 
263     VBase = VBase->getDefinition();
264     assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
265 
266     return CXXInfo->VBaseOffsets[VBase].VBaseOffset;
267   }
268 
getSizeOfLargestEmptySubobject()269   CharUnits getSizeOfLargestEmptySubobject() const {
270     assert(CXXInfo && "Record layout does not have C++ specific info!");
271     return CXXInfo->SizeOfLargestEmptySubobject;
272   }
273 
274   /// hasOwnVFPtr - Does this class provide its own virtual-function
275   /// table pointer, rather than inheriting one from a primary base
276   /// class?  If so, it is at offset zero.
277   ///
278   /// This implies that the ABI has no primary base class, meaning
279   /// that it has no base classes that are suitable under the conditions
280   /// of the ABI.
hasOwnVFPtr()281   bool hasOwnVFPtr() const {
282     assert(CXXInfo && "Record layout does not have C++ specific info!");
283     return CXXInfo->HasOwnVFPtr;
284   }
285 
286   /// hasVFPtr - Does this class have a virtual function table pointer
287   /// that can be extended by a derived class?  This is synonymous with
288   /// this class having a VFPtr at offset zero.
hasExtendableVFPtr()289   bool hasExtendableVFPtr() const {
290     assert(CXXInfo && "Record layout does not have C++ specific info!");
291     return CXXInfo->HasExtendableVFPtr;
292   }
293 
294   /// hasOwnVBPtr - Does this class provide its own virtual-base
295   /// table pointer, rather than inheriting one from a primary base
296   /// class?
297   ///
298   /// This implies that the ABI has no primary base class, meaning
299   /// that it has no base classes that are suitable under the conditions
300   /// of the ABI.
hasOwnVBPtr()301   bool hasOwnVBPtr() const {
302     assert(CXXInfo && "Record layout does not have C++ specific info!");
303     return hasVBPtr() && !CXXInfo->BaseSharingVBPtr;
304   }
305 
306   /// hasVBPtr - Does this class have a virtual function table pointer.
hasVBPtr()307   bool hasVBPtr() const {
308     assert(CXXInfo && "Record layout does not have C++ specific info!");
309     return !CXXInfo->VBPtrOffset.isNegative();
310   }
311 
getRequiredAlignment()312   CharUnits getRequiredAlignment() const { return RequiredAlignment; }
313 
endsWithZeroSizedObject()314   bool endsWithZeroSizedObject() const {
315     return CXXInfo && CXXInfo->EndsWithZeroSizedObject;
316   }
317 
leadsWithZeroSizedBase()318   bool leadsWithZeroSizedBase() const {
319     assert(CXXInfo && "Record layout does not have C++ specific info!");
320     return CXXInfo->LeadsWithZeroSizedBase;
321   }
322 
323   /// getVBPtrOffset - Get the offset for virtual base table pointer.
324   /// This is only meaningful with the Microsoft ABI.
getVBPtrOffset()325   CharUnits getVBPtrOffset() const {
326     assert(CXXInfo && "Record layout does not have C++ specific info!");
327     return CXXInfo->VBPtrOffset;
328   }
329 
getBaseSharingVBPtr()330   const CXXRecordDecl *getBaseSharingVBPtr() const {
331     assert(CXXInfo && "Record layout does not have C++ specific info!");
332     return CXXInfo->BaseSharingVBPtr;
333   }
334 
getVBaseOffsetsMap()335   const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
336     assert(CXXInfo && "Record layout does not have C++ specific info!");
337     return CXXInfo->VBaseOffsets;
338   }
339 };
340 
341 } // namespace clang
342 
343 #endif // LLVM_CLANG_AST_RECORDLAYOUT_H
344