1327952Sdim//===- RecordLayout.h - Layout information for a struct/union ---*- C++ -*-===//
2193326Sed//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6193326Sed//
7193326Sed//===----------------------------------------------------------------------===//
8193326Sed//
9193326Sed//  This file defines the RecordLayout interface.
10193326Sed//
11193326Sed//===----------------------------------------------------------------------===//
12193326Sed
13280031Sdim#ifndef LLVM_CLANG_AST_RECORDLAYOUT_H
14280031Sdim#define LLVM_CLANG_AST_RECORDLAYOUT_H
15193326Sed
16327952Sdim#include "clang/AST/ASTVector.h"
17218893Sdim#include "clang/AST/CharUnits.h"
18199482Srdivacky#include "clang/AST/DeclCXX.h"
19327952Sdim#include "clang/Basic/LLVM.h"
20327952Sdim#include "llvm/ADT/ArrayRef.h"
21239462Sdim#include "llvm/ADT/DenseMap.h"
22327952Sdim#include "llvm/ADT/PointerIntPair.h"
23327952Sdim#include <cassert>
24327952Sdim#include <cstdint>
25193326Sed
26193326Sednamespace clang {
27193326Sed
28327952Sdimclass ASTContext;
29327952Sdimclass CXXRecordDecl;
30327952Sdim
31198092Srdivacky/// ASTRecordLayout -
32193326Sed/// This class contains layout information for one RecordDecl,
33193326Sed/// which is a struct/union/class.  The decl represented must be a definition,
34198092Srdivacky/// not a forward declaration.
35198092Srdivacky/// This class is also used to contain layout information for one
36193326Sed/// ObjCInterfaceDecl. FIXME - Find appropriate name.
37193326Sed/// These objects are managed by ASTContext.
38193326Sedclass ASTRecordLayout {
39239462Sdimpublic:
40239462Sdim  struct VBaseInfo {
41239462Sdim    /// The offset to this virtual base in the complete-object layout
42239462Sdim    /// of this class.
43239462Sdim    CharUnits VBaseOffset;
44239462Sdim
45239462Sdim  private:
46239462Sdim    /// Whether this virtual base requires a vtordisp field in the
47239462Sdim    /// Microsoft ABI.  These fields are required for certain operations
48239462Sdim    /// in constructors and destructors.
49327952Sdim    bool HasVtorDisp = false;
50239462Sdim
51239462Sdim  public:
52327952Sdim    VBaseInfo() = default;
53327952Sdim    VBaseInfo(CharUnits VBaseOffset, bool hasVtorDisp)
54327952Sdim        : VBaseOffset(VBaseOffset), HasVtorDisp(hasVtorDisp) {}
55327952Sdim
56239462Sdim    bool hasVtorDisp() const { return HasVtorDisp; }
57239462Sdim  };
58239462Sdim
59327952Sdim  using VBaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, VBaseInfo>;
60239462Sdim
61239462Sdimprivate:
62327952Sdim  friend class ASTContext;
63327952Sdim
64218893Sdim  /// Size - Size of record in characters.
65218893Sdim  CharUnits Size;
66198092Srdivacky
67218893Sdim  /// DataSize - Size of record in characters without tail padding.
68218893Sdim  CharUnits DataSize;
69198092Srdivacky
70239462Sdim  // Alignment - Alignment of record in characters.
71239462Sdim  CharUnits Alignment;
72239462Sdim
73341825Sdim  // UnadjustedAlignment - Maximum of the alignments of the record members in
74341825Sdim  // characters.
75341825Sdim  CharUnits UnadjustedAlignment;
76341825Sdim
77276479Sdim  /// RequiredAlignment - The required alignment of the object.  In the MS-ABI
78276479Sdim  /// the __declspec(align()) trumps #pramga pack and must always be obeyed.
79276479Sdim  CharUnits RequiredAlignment;
80276479Sdim
81198092Srdivacky  /// FieldOffsets - Array of field offsets in bits.
82309124Sdim  ASTVector<uint64_t> FieldOffsets;
83198092Srdivacky
84199990Srdivacky  /// CXXRecordLayoutInfo - Contains C++ specific layout information.
85198092Srdivacky  struct CXXRecordLayoutInfo {
86218893Sdim    /// NonVirtualSize - The non-virtual size (in chars) of an object, which is
87198092Srdivacky    /// the size of the object without virtual bases.
88218893Sdim    CharUnits NonVirtualSize;
89198092Srdivacky
90276479Sdim    /// NonVirtualAlignment - The non-virtual alignment (in chars) of an object,
91198092Srdivacky    /// which is the alignment of the object without virtual bases.
92276479Sdim    CharUnits NonVirtualAlignment;
93198092Srdivacky
94208600Srdivacky    /// SizeOfLargestEmptySubobject - The size of the largest empty subobject
95208600Srdivacky    /// (either a base or a member). Will be zero if the class doesn't contain
96208600Srdivacky    /// any empty subobjects.
97218893Sdim    CharUnits SizeOfLargestEmptySubobject;
98234353Sdim
99234353Sdim    /// VBPtrOffset - Virtual base table offset (Microsoft-only).
100226633Sdim    CharUnits VBPtrOffset;
101239462Sdim
102239462Sdim    /// HasOwnVFPtr - Does this class provide a virtual function table
103239462Sdim    /// (vtable in Itanium, vftbl in Microsoft) that is independent from
104239462Sdim    /// its base classes?
105261991Sdim    bool HasOwnVFPtr : 1;
106261991Sdim
107261991Sdim    /// HasVFPtr - Does this class have a vftable that could be extended by
108261991Sdim    /// a derived class.  The class may have inherited this pointer from
109261991Sdim    /// a primary base class.
110261991Sdim    bool HasExtendableVFPtr : 1;
111261991Sdim
112309124Sdim    /// EndsWithZeroSizedObject - True if this class contains a zero sized
113309124Sdim    /// member or base or a base with a zero sized member or base.
114309124Sdim    /// Only used for MS-ABI.
115309124Sdim    bool EndsWithZeroSizedObject : 1;
116276479Sdim
117341825Sdim    /// True if this class is zero sized or first base is zero sized or
118276479Sdim    /// has this property.  Only used for MS-ABI.
119276479Sdim    bool LeadsWithZeroSizedBase : 1;
120276479Sdim
121199990Srdivacky    /// PrimaryBase - The primary base info for this record.
122218893Sdim    llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
123261991Sdim
124261991Sdim    /// BaseSharingVBPtr - The base we share vbptr with.
125261991Sdim    const CXXRecordDecl *BaseSharingVBPtr;
126341825Sdim
127205219Srdivacky    /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
128327952Sdim    using BaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, CharUnits>;
129341825Sdim
130198092Srdivacky    /// BaseOffsets - Contains a map from base classes to their offset.
131205219Srdivacky    BaseOffsetsMapTy BaseOffsets;
132198092Srdivacky
133198092Srdivacky    /// VBaseOffsets - Contains a map from vbase classes to their offset.
134239462Sdim    VBaseOffsetsMapTy VBaseOffsets;
135198092Srdivacky  };
136198092Srdivacky
137198092Srdivacky  /// CXXInfo - If the record layout is for a C++ record, this will have
138198092Srdivacky  /// C++ specific information about the record.
139327952Sdim  CXXRecordLayoutInfo *CXXInfo = nullptr;
140198092Srdivacky
141218893Sdim  ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
142341825Sdim                  CharUnits unadjustedAlignment,
143309124Sdim                  CharUnits requiredAlignment, CharUnits datasize,
144309124Sdim                  ArrayRef<uint64_t> fieldoffsets);
145193326Sed
146327952Sdim  using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy;
147327952Sdim
148198092Srdivacky  // Constructor for C++ records.
149218893Sdim  ASTRecordLayout(const ASTContext &Ctx,
150234353Sdim                  CharUnits size, CharUnits alignment,
151341825Sdim                  CharUnits unadjustedAlignment,
152276479Sdim                  CharUnits requiredAlignment,
153261991Sdim                  bool hasOwnVFPtr, bool hasExtendableVFPtr,
154261991Sdim                  CharUnits vbptroffset,
155226633Sdim                  CharUnits datasize,
156309124Sdim                  ArrayRef<uint64_t> fieldoffsets,
157276479Sdim                  CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
158218893Sdim                  CharUnits SizeOfLargestEmptySubobject,
159208600Srdivacky                  const CXXRecordDecl *PrimaryBase,
160218893Sdim                  bool IsPrimaryBaseVirtual,
161261991Sdim                  const CXXRecordDecl *BaseSharingVBPtr,
162309124Sdim                  bool EndsWithZeroSizedObject,
163276479Sdim                  bool LeadsWithZeroSizedBase,
164205219Srdivacky                  const BaseOffsetsMapTy& BaseOffsets,
165239462Sdim                  const VBaseOffsetsMapTy& VBaseOffsets);
166193326Sed
167288943Sdim  ~ASTRecordLayout() = default;
168193326Sed
169204962Srdivacky  void Destroy(ASTContext &Ctx);
170341825Sdim
171327952Sdimpublic:
172288943Sdim  ASTRecordLayout(const ASTRecordLayout &) = delete;
173327952Sdim  ASTRecordLayout &operator=(const ASTRecordLayout &) = delete;
174198092Srdivacky
175218893Sdim  /// getAlignment - Get the record alignment in characters.
176218893Sdim  CharUnits getAlignment() const { return Alignment; }
177193326Sed
178341825Sdim  /// getUnadjustedAlignment - Get the record alignment in characters, before
179341825Sdim  /// alignment adjustement.
180341825Sdim  CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
181341825Sdim
182218893Sdim  /// getSize - Get the record size in characters.
183218893Sdim  CharUnits getSize() const { return Size; }
184198092Srdivacky
185193326Sed  /// getFieldCount - Get the number of fields in the layout.
186309124Sdim  unsigned getFieldCount() const { return FieldOffsets.size(); }
187198092Srdivacky
188193326Sed  /// getFieldOffset - Get the offset of the given field index, in
189193326Sed  /// bits.
190193326Sed  uint64_t getFieldOffset(unsigned FieldNo) const {
191193326Sed    return FieldOffsets[FieldNo];
192193326Sed  }
193198092Srdivacky
194198092Srdivacky  /// getDataSize() - Get the record data size, which is the record size
195218893Sdim  /// without tail padding, in characters.
196218893Sdim  CharUnits getDataSize() const {
197198092Srdivacky    return DataSize;
198193326Sed  }
199198092Srdivacky
200218893Sdim  /// getNonVirtualSize - Get the non-virtual size (in chars) of an object,
201198092Srdivacky  /// which is the size of the object without virtual bases.
202218893Sdim  CharUnits getNonVirtualSize() const {
203198092Srdivacky    assert(CXXInfo && "Record layout does not have C++ specific info!");
204198092Srdivacky
205198092Srdivacky    return CXXInfo->NonVirtualSize;
206198092Srdivacky  }
207198092Srdivacky
208218893Sdim  /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object,
209198092Srdivacky  /// which is the alignment of the object without virtual bases.
210276479Sdim  CharUnits getNonVirtualAlignment() const {
211198092Srdivacky    assert(CXXInfo && "Record layout does not have C++ specific info!");
212198092Srdivacky
213276479Sdim    return CXXInfo->NonVirtualAlignment;
214198092Srdivacky  }
215198092Srdivacky
216218893Sdim  /// getPrimaryBase - Get the primary base for this record.
217218893Sdim  const CXXRecordDecl *getPrimaryBase() const {
218198092Srdivacky    assert(CXXInfo && "Record layout does not have C++ specific info!");
219198092Srdivacky
220218893Sdim    return CXXInfo->PrimaryBase.getPointer();
221198092Srdivacky  }
222198092Srdivacky
223218893Sdim  /// isPrimaryBaseVirtual - Get whether the primary base for this record
224218893Sdim  /// is virtual or not.
225218893Sdim  bool isPrimaryBaseVirtual() const {
226218893Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
227198092Srdivacky
228218893Sdim    return CXXInfo->PrimaryBase.getInt();
229199990Srdivacky  }
230199990Srdivacky
231218893Sdim  /// getBaseClassOffset - Get the offset, in chars, for the given base class.
232218893Sdim  CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const {
233198092Srdivacky    assert(CXXInfo && "Record layout does not have C++ specific info!");
234198092Srdivacky    assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
235198092Srdivacky
236198092Srdivacky    return CXXInfo->BaseOffsets[Base];
237198092Srdivacky  }
238198092Srdivacky
239218893Sdim  /// getVBaseClassOffset - Get the offset, in chars, for the given base class.
240218893Sdim  CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const {
241198092Srdivacky    assert(CXXInfo && "Record layout does not have C++ specific info!");
242198092Srdivacky    assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
243198092Srdivacky
244239462Sdim    return CXXInfo->VBaseOffsets[VBase].VBaseOffset;
245198092Srdivacky  }
246218893Sdim
247218893Sdim  CharUnits getSizeOfLargestEmptySubobject() const {
248199990Srdivacky    assert(CXXInfo && "Record layout does not have C++ specific info!");
249218893Sdim    return CXXInfo->SizeOfLargestEmptySubobject;
250199990Srdivacky  }
251226633Sdim
252239462Sdim  /// hasOwnVFPtr - Does this class provide its own virtual-function
253239462Sdim  /// table pointer, rather than inheriting one from a primary base
254239462Sdim  /// class?  If so, it is at offset zero.
255239462Sdim  ///
256239462Sdim  /// This implies that the ABI has no primary base class, meaning
257239462Sdim  /// that it has no base classes that are suitable under the conditions
258239462Sdim  /// of the ABI.
259239462Sdim  bool hasOwnVFPtr() const {
260234353Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
261239462Sdim    return CXXInfo->HasOwnVFPtr;
262234353Sdim  }
263234353Sdim
264261991Sdim  /// hasVFPtr - Does this class have a virtual function table pointer
265261991Sdim  /// that can be extended by a derived class?  This is synonymous with
266261991Sdim  /// this class having a VFPtr at offset zero.
267261991Sdim  bool hasExtendableVFPtr() const {
268261991Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
269261991Sdim    return CXXInfo->HasExtendableVFPtr;
270261991Sdim  }
271341825Sdim
272261991Sdim  /// hasOwnVBPtr - Does this class provide its own virtual-base
273261991Sdim  /// table pointer, rather than inheriting one from a primary base
274261991Sdim  /// class?
275261991Sdim  ///
276261991Sdim  /// This implies that the ABI has no primary base class, meaning
277261991Sdim  /// that it has no base classes that are suitable under the conditions
278261991Sdim  /// of the ABI.
279261991Sdim  bool hasOwnVBPtr() const {
280261991Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
281261991Sdim    return hasVBPtr() && !CXXInfo->BaseSharingVBPtr;
282261991Sdim  }
283261991Sdim
284261991Sdim  /// hasVBPtr - Does this class have a virtual function table pointer.
285261991Sdim  bool hasVBPtr() const {
286261991Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
287261991Sdim    return !CXXInfo->VBPtrOffset.isNegative();
288261991Sdim  }
289261991Sdim
290276479Sdim  CharUnits getRequiredAlignment() const {
291276479Sdim    return RequiredAlignment;
292276479Sdim  }
293276479Sdim
294309124Sdim  bool endsWithZeroSizedObject() const {
295309124Sdim    return CXXInfo && CXXInfo->EndsWithZeroSizedObject;
296276479Sdim  }
297276479Sdim
298276479Sdim  bool leadsWithZeroSizedBase() const {
299261991Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
300276479Sdim    return CXXInfo->LeadsWithZeroSizedBase;
301261991Sdim  }
302261991Sdim
303234353Sdim  /// getVBPtrOffset - Get the offset for virtual base table pointer.
304234353Sdim  /// This is only meaningful with the Microsoft ABI.
305226633Sdim  CharUnits getVBPtrOffset() const {
306234353Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
307226633Sdim    return CXXInfo->VBPtrOffset;
308226633Sdim  }
309239462Sdim
310261991Sdim  const CXXRecordDecl *getBaseSharingVBPtr() const {
311261991Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
312261991Sdim    return CXXInfo->BaseSharingVBPtr;
313261991Sdim  }
314261991Sdim
315239462Sdim  const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
316239462Sdim    assert(CXXInfo && "Record layout does not have C++ specific info!");
317239462Sdim    return CXXInfo->VBaseOffsets;
318239462Sdim  }
319193326Sed};
320193326Sed
321327952Sdim} // namespace clang
322193326Sed
323327952Sdim#endif // LLVM_CLANG_AST_RECORDLAYOUT_H
324