llvm/clang/lib/AST/RecordLayoutBuilder.cpp

//=== RecordLayoutBuilder.cpp - Helper class for building record layouts ---==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"

usingnamespaceclang;

namespace {

/// BaseSubobjectInfo - Represents a single base subobject in a complete class.
/// For a class hierarchy like
///
/// class A { };
/// class B : A { };
/// class C : A, B { };
///
/// The BaseSubobjectInfo graph for C will have three BaseSubobjectInfo
/// instances, one for B and two for A.
///
/// If a base is virtual, it will only have one BaseSubobjectInfo allocated.
struct BaseSubobjectInfo {};

/// Externally provided layout. Typically used when the AST source, such
/// as DWARF, lacks all the information that was available at compile time, such
/// as alignment attributes on fields and pragmas in effect.
struct ExternalLayout {};

/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different
/// offsets while laying out a C++ class.
class EmptySubobjectMap {};

void EmptySubobjectMap::ComputeEmptySubobjectSizes() {}

bool
EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
                                             CharUnits Offset) const {}

void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
                                             CharUnits Offset) {}

bool
EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
                                                 CharUnits Offset) {}

void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
                                                  CharUnits Offset,
                                                  bool PlacingEmptyBase) {}

bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
                                             CharUnits Offset) {}

bool
EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
                                                  const CXXRecordDecl *Class,
                                                  CharUnits Offset) const {}

bool
EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
                                                  CharUnits Offset) const {}

bool
EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD,
                                         CharUnits Offset) {}

void EmptySubobjectMap::UpdateEmptyFieldSubobjects(
    const CXXRecordDecl *RD, const CXXRecordDecl *Class, CharUnits Offset,
    bool PlacingOverlappingField) {}

void EmptySubobjectMap::UpdateEmptyFieldSubobjects(
    const FieldDecl *FD, CharUnits Offset, bool PlacingOverlappingField) {}

ClassSetTy;

class ItaniumRecordLayoutBuilder {};
} // end anonymous namespace

void ItaniumRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {}

/// DeterminePrimaryBase - Determine the primary base of the given class.
void ItaniumRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {}

BaseSubobjectInfo *ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo(
    const CXXRecordDecl *RD, bool IsVirtual, BaseSubobjectInfo *Derived) {}

void ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo(
    const CXXRecordDecl *RD) {}

void ItaniumRecordLayoutBuilder::EnsureVTablePointerAlignment(
    CharUnits UnpackedBaseAlign) {}

void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases(
    const CXXRecordDecl *RD) {}

void ItaniumRecordLayoutBuilder::LayoutNonVirtualBase(
    const BaseSubobjectInfo *Base) {}

void ItaniumRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(
    const BaseSubobjectInfo *Info, CharUnits Offset) {}

void ItaniumRecordLayoutBuilder::LayoutVirtualBases(
    const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass) {}

void ItaniumRecordLayoutBuilder::LayoutVirtualBase(
    const BaseSubobjectInfo *Base) {}

CharUnits
ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {}

void ItaniumRecordLayoutBuilder::InitializeLayout(const Decl *D) {}

void ItaniumRecordLayoutBuilder::Layout(const RecordDecl *D) {}

void ItaniumRecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {}

void ItaniumRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {}

void ItaniumRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {}

// Rounds the specified size to have it a multiple of the char size.
static uint64_t
roundUpSizeToCharAlignment(uint64_t Size,
                           const ASTContext &Context) {}

void ItaniumRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
                                                    uint64_t StorageUnitSize,
                                                    bool FieldPacked,
                                                    const FieldDecl *D) {}

static bool isAIXLayout(const ASTContext &Context) {}

void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {}

void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
                                             bool InsertExtraPadding) {}

void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {}

void ItaniumRecordLayoutBuilder::UpdateAlignment(
    CharUnits NewAlignment, CharUnits UnpackedNewAlignment,
    CharUnits PreferredNewAlignment) {}

uint64_t
ItaniumRecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
                                                      uint64_t ComputedOffset) {}

/// Get diagnostic %select index for tag kind for
/// field padding diagnostic message.
/// WARNING: Indexes apply to particular diagnostics only!
///
/// \returns diagnostic %select index.
static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) {}

void ItaniumRecordLayoutBuilder::CheckFieldPadding(
    uint64_t Offset, uint64_t UnpaddedOffset, uint64_t UnpackedOffset,
    unsigned UnpackedAlign, bool isPacked, const FieldDecl *D) {}

static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
                                               const CXXRecordDecl *RD) {}

DiagnosticBuilder ItaniumRecordLayoutBuilder::Diag(SourceLocation Loc,
                                                   unsigned DiagID) {}

/// Does the target C++ ABI require us to skip over the tail-padding
/// of the given class (considering it as a base class) when allocating
/// objects?
static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {}

static bool isMsLayout(const ASTContext &Context) {}

// This section contains an implementation of struct layout that is, up to the
// included tests, compatible with cl.exe (2013).  The layout produced is
// significantly different than those produced by the Itanium ABI.  Here we note
// the most important differences.
//
// * The alignment of bitfields in unions is ignored when computing the
//   alignment of the union.
// * The existence of zero-width bitfield that occurs after anything other than
//   a non-zero length bitfield is ignored.
// * There is no explicit primary base for the purposes of layout.  All bases
//   with vfptrs are laid out first, followed by all bases without vfptrs.
// * The Itanium equivalent vtable pointers are split into a vfptr (virtual
//   function pointer) and a vbptr (virtual base pointer).  They can each be
//   shared with a, non-virtual bases. These bases need not be the same.  vfptrs
//   always occur at offset 0.  vbptrs can occur at an arbitrary offset and are
//   placed after the lexicographically last non-virtual base.  This placement
//   is always before fields but can be in the middle of the non-virtual bases
//   due to the two-pass layout scheme for non-virtual-bases.
// * Virtual bases sometimes require a 'vtordisp' field that is laid out before
//   the virtual base and is used in conjunction with virtual overrides during
//   construction and destruction.  This is always a 4 byte value and is used as
//   an alternative to constructor vtables.
// * vtordisps are allocated in a block of memory with size and alignment equal
//   to the alignment of the completed structure (before applying __declspec(
//   align())).  The vtordisp always occur at the end of the allocation block,
//   immediately prior to the virtual base.
// * vfptrs are injected after all bases and fields have been laid out.  In
//   order to guarantee proper alignment of all fields, the vfptr injection
//   pushes all bases and fields back by the alignment imposed by those bases
//   and fields.  This can potentially add a significant amount of padding.
//   vfptrs are always injected at offset 0.
// * vbptrs are injected after all bases and fields have been laid out.  In
//   order to guarantee proper alignment of all fields, the vfptr injection
//   pushes all bases and fields back by the alignment imposed by those bases
//   and fields.  This can potentially add a significant amount of padding.
//   vbptrs are injected immediately after the last non-virtual base as
//   lexicographically ordered in the code.  If this site isn't pointer aligned
//   the vbptr is placed at the next properly aligned location.  Enough padding
//   is added to guarantee a fit.
// * The last zero sized non-virtual base can be placed at the end of the
//   struct (potentially aliasing another object), or may alias with the first
//   field, even if they are of the same type.
// * The last zero size virtual base may be placed at the end of the struct
//   potentially aliasing another object.
// * The ABI attempts to avoid aliasing of zero sized bases by adding padding
//   between bases or vbases with specific properties.  The criteria for
//   additional padding between two bases is that the first base is zero sized
//   or ends with a zero sized subobject and the second base is zero sized or
//   trails with a zero sized base or field (sharing of vfptrs can reorder the
//   layout of the so the leading base is not always the first one declared).
//   This rule does take into account fields that are not records, so padding
//   will occur even if the last field is, e.g. an int. The padding added for
//   bases is 1 byte.  The padding added between vbases depends on the alignment
//   of the object but is at least 4 bytes (in both 32 and 64 bit modes).
// * There is no concept of non-virtual alignment, non-virtual alignment and
//   alignment are always identical.
// * There is a distinction between alignment and required alignment.
//   __declspec(align) changes the required alignment of a struct.  This
//   alignment is _always_ obeyed, even in the presence of #pragma pack. A
//   record inherits required alignment from all of its fields and bases.
// * __declspec(align) on bitfields has the effect of changing the bitfield's
//   alignment instead of its required alignment.  This is the only known way
//   to make the alignment of a struct bigger than 8.  Interestingly enough
//   this alignment is also immune to the effects of #pragma pack and can be
//   used to create structures with large alignment under #pragma pack.
//   However, because it does not impact required alignment, such a structure,
//   when used as a field or base, will not be aligned if #pragma pack is
//   still active at the time of use.
//
// Known incompatibilities:
// * all: #pragma pack between fields in a record
// * 2010 and back: If the last field in a record is a bitfield, every object
//   laid out after the record will have extra padding inserted before it.  The
//   extra padding will have size equal to the size of the storage class of the
//   bitfield.  0 sized bitfields don't exhibit this behavior and the extra
//   padding can be avoided by adding a 0 sized bitfield after the non-zero-
//   sized bitfield.
// * 2012 and back: In 64-bit mode, if the alignment of a record is 16 or
//   greater due to __declspec(align()) then a second layout phase occurs after
//   The locations of the vf and vb pointers are known.  This layout phase
//   suffers from the "last field is a bitfield" bug in 2010 and results in
//   _every_ field getting padding put in front of it, potentially including the
//   vfptr, leaving the vfprt at a non-zero location which results in a fault if
//   anything tries to read the vftbl.  The second layout phase also treats
//   bitfields as separate entities and gives them each storage rather than
//   packing them.  Additionally, because this phase appears to perform a
//   (an unstable) sort on the members before laying them out and because merged
//   bitfields have the same address, the bitfields end up in whatever order
//   the sort left them in, a behavior we could never hope to replicate.

namespace {
struct MicrosoftRecordLayoutBuilder {};
} // namespace

MicrosoftRecordLayoutBuilder::ElementInfo
MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
    const ASTRecordLayout &Layout) {}

MicrosoftRecordLayoutBuilder::ElementInfo
MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
    const FieldDecl *FD) {}

void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {}

void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {}

void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {}

void
MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {}

void
MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {}

static bool recordUsesEBO(const RecordDecl *RD) {}

void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
    const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl,
    const ASTRecordLayout &BaseLayout,
    const ASTRecordLayout *&PreviousBaseLayout) {}

void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {}

void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {}

void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {}

void
MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {}

void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {}

void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {}

void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {}

void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {}

// Recursively walks the non-virtual bases of a class and determines if any of
// them are in the bases with overridden methods set.
static bool
RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
                     BasesWithOverriddenMethods,
                 const CXXRecordDecl *RD) {}

void MicrosoftRecordLayoutBuilder::computeVtorDispSet(
    llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtordispSet,
    const CXXRecordDecl *RD) const {}

/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
const ASTRecordLayout &
ASTContext::getASTRecordLayout(const RecordDecl *D) const {}

const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) {}

void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) {}

static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) {}

uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const {}

uint64_t ASTContext::lookupFieldBitOffset(const ObjCInterfaceDecl *OID,
                                          const ObjCImplementationDecl *ID,
                                          const ObjCIvarDecl *Ivar) const {}

/// getObjCLayout - Get or compute information about the layout of the
/// given interface.
///
/// \param Impl - If given, also include the layout of the interface's
/// implementation. This may differ by including synthesized ivars.
const ASTRecordLayout &
ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
                          const ObjCImplementationDecl *Impl) const {}

static void PrintOffset(raw_ostream &OS,
                        CharUnits Offset, unsigned IndentLevel) {}

static void PrintBitFieldOffset(raw_ostream &OS, CharUnits Offset,
                                unsigned Begin, unsigned Width,
                                unsigned IndentLevel) {}

static void PrintIndentNoOffset(raw_ostream &OS, unsigned IndentLevel) {}

static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD,
                             const ASTContext &C,
                             CharUnits Offset,
                             unsigned IndentLevel,
                             const char* Description,
                             bool PrintSizeInfo,
                             bool IncludeVirtualBases) {}

void ASTContext::DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
                                  bool Simple) const {}