#ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
#define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
#include "PrimType.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
namespace clang {
namespace interp {
class Block;
class Record;
struct InitMap;
struct Descriptor;
enum PrimType : unsigned;
using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>;
using BlockCtorFn = void (*)(Block *Storage, std::byte *FieldPtr, bool IsConst,
bool IsMutable, bool IsActive,
const Descriptor *FieldDesc);
using BlockDtorFn = void (*)(Block *Storage, std::byte *FieldPtr,
const Descriptor *FieldDesc);
using BlockMoveFn = void (*)(Block *Storage, const std::byte *SrcFieldPtr,
std::byte *DstFieldPtr,
const Descriptor *FieldDesc);
enum class GlobalInitState {
Initialized,
NoInitializer,
InitializerFailed,
};
struct alignas(void *) GlobalInlineDescriptor {
GlobalInitState InitState = GlobalInitState::InitializerFailed;
};
static_assert(sizeof(GlobalInlineDescriptor) == sizeof(void *), "");
struct InlineDescriptor {
unsigned Offset;
LLVM_PREFERRED_TYPE(bool)
unsigned IsConst : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsInitialized : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsBase : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsVirtualBase : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsActive : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsFieldMutable : 1;
const Descriptor *Desc;
InlineDescriptor(const Descriptor *D)
: Offset(sizeof(InlineDescriptor)), IsConst(false), IsInitialized(false),
IsBase(false), IsActive(false), IsFieldMutable(false), Desc(D) {}
void dump() const { dump(llvm::errs()); }
void dump(llvm::raw_ostream &OS) const;
};
static_assert(sizeof(GlobalInlineDescriptor) != sizeof(InlineDescriptor), "");
struct Descriptor final {
private:
const DeclTy Source;
const unsigned ElemSize;
const unsigned Size;
const unsigned MDSize;
const unsigned AllocSize;
static constexpr unsigned UnknownSizeMark = (unsigned)-1;
public:
struct UnknownSize {};
using MetadataSize = std::optional<unsigned>;
static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor);
static constexpr MetadataSize GlobalMD = sizeof(GlobalInlineDescriptor);
static constexpr unsigned MaxArrayElemBytes =
std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMapPtr) -
align(std::max(*InlineDescMD, *GlobalMD));
const Record *const ElemRecord = nullptr;
const Descriptor *const ElemDesc = nullptr;
const std::optional<PrimType> PrimT = std::nullopt;
const bool IsConst = false;
const bool IsMutable = false;
const bool IsTemporary = false;
const bool IsArray = false;
bool IsDummy = false;
const BlockCtorFn CtorFn = nullptr;
const BlockDtorFn DtorFn = nullptr;
const BlockMoveFn MoveFn = nullptr;
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsConst,
bool IsTemporary, bool IsMutable);
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, size_t NumElems,
bool IsConst, bool IsTemporary, bool IsMutable);
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MDSize,
bool IsTemporary, UnknownSize);
Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable);
Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
bool IsTemporary, UnknownSize);
Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst,
bool IsTemporary, bool IsMutable);
Descriptor(const DeclTy &D);
void makeDummy() { IsDummy = true; }
QualType getType() const;
QualType getElemQualType() const;
SourceLocation getLocation() const;
const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
const DeclTy &getSource() const { return Source; }
const ValueDecl *asValueDecl() const {
return dyn_cast_if_present<ValueDecl>(asDecl());
}
const VarDecl *asVarDecl() const {
return dyn_cast_if_present<VarDecl>(asDecl());
}
const FieldDecl *asFieldDecl() const {
return dyn_cast_if_present<FieldDecl>(asDecl());
}
const RecordDecl *asRecordDecl() const {
return dyn_cast_if_present<RecordDecl>(asDecl());
}
unsigned getSize() const {
assert(!isUnknownSizeArray() && "Array of unknown size");
return Size;
}
PrimType getPrimType() const {
assert(isPrimitiveArray() || isPrimitive());
return *PrimT;
}
unsigned getAllocSize() const { return AllocSize; }
unsigned getElemSize() const { return ElemSize; }
unsigned getMetadataSize() const { return MDSize; }
unsigned getNumElems() const {
return Size == UnknownSizeMark ? 0 : (getSize() / getElemSize());
}
bool isPrimitiveArray() const { return IsArray && !ElemDesc; }
bool isCompositeArray() const { return IsArray && ElemDesc; }
bool isZeroSizeArray() const { return Size == 0; }
bool isUnknownSizeArray() const { return Size == UnknownSizeMark; }
bool isPrimitive() const { return !IsArray && !ElemRecord; }
bool isArray() const { return IsArray; }
bool isRecord() const { return !IsArray && ElemRecord; }
bool isDummy() const { return IsDummy; }
void dump() const;
void dump(llvm::raw_ostream &OS) const;
};
struct InitMap final {
private:
using T = uint64_t;
static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT;
public:
explicit InitMap(unsigned N);
private:
friend class Pointer;
T *data() { return Data.get(); }
const T *data() const { return Data.get(); }
bool initializeElement(unsigned I);
bool isElementInitialized(unsigned I) const;
static constexpr size_t numFields(unsigned N) {
return (N + PER_FIELD - 1) / PER_FIELD;
}
unsigned UninitFields;
std::unique_ptr<T[]> Data;
};
}
}
#endif