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