llvm-project/clang/lib/AST/APValue.cpp
Richard Smith e637cbe4e4 Refactor: split Uninitialized state on APValue into an "Absent" state
representing no such object, and an "Indeterminate" state representing
an uninitialized object. The latter is not yet used, but soon will be.

llvm-svn: 361328
2019-05-21 23:15:18 +00:00

815 lines
24 KiB
C++

//===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file implements the APValue class.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
/// The identity of a type_info object depends on the canonical unqualified
/// type only.
TypeInfoLValue::TypeInfoLValue(const Type *T)
: T(T->getCanonicalTypeUnqualified().getTypePtr()) {}
void TypeInfoLValue::print(llvm::raw_ostream &Out,
const PrintingPolicy &Policy) const {
Out << "typeid(";
QualType(getType(), 0).print(Out, Policy);
Out << ")";
}
static_assert(
1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <=
alignof(Type),
"Type is insufficiently aligned");
APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V)
: Ptr(P), Local{I, V} {}
APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V)
: Ptr(P), Local{I, V} {}
APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
QualType TypeInfo) {
LValueBase Base;
Base.Ptr = LV;
Base.TypeInfoType = TypeInfo.getAsOpaquePtr();
return Base;
}
unsigned APValue::LValueBase::getCallIndex() const {
return is<TypeInfoLValue>() ? 0 : Local.CallIndex;
}
unsigned APValue::LValueBase::getVersion() const {
return is<TypeInfoLValue>() ? 0 : Local.Version;
}
QualType APValue::LValueBase::getTypeInfoType() const {
assert(is<TypeInfoLValue>() && "not a type_info lvalue");
return QualType::getFromOpaquePtr(TypeInfoType);
}
namespace clang {
bool operator==(const APValue::LValueBase &LHS,
const APValue::LValueBase &RHS) {
if (LHS.Ptr != RHS.Ptr)
return false;
if (LHS.is<TypeInfoLValue>())
return true;
return LHS.Local.CallIndex == RHS.Local.CallIndex &&
LHS.Local.Version == RHS.Local.Version;
}
}
namespace {
struct LVBase {
APValue::LValueBase Base;
CharUnits Offset;
unsigned PathLength;
bool IsNullPtr : 1;
bool IsOnePastTheEnd : 1;
};
}
void *APValue::LValueBase::getOpaqueValue() const {
return Ptr.getOpaqueValue();
}
bool APValue::LValueBase::isNull() const {
return Ptr.isNull();
}
APValue::LValueBase::operator bool () const {
return static_cast<bool>(Ptr);
}
clang::APValue::LValueBase
llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() {
return clang::APValue::LValueBase(
DenseMapInfo<const ValueDecl*>::getEmptyKey());
}
clang::APValue::LValueBase
llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
return clang::APValue::LValueBase(
DenseMapInfo<const ValueDecl*>::getTombstoneKey());
}
namespace clang {
llvm::hash_code hash_value(const APValue::LValueBase &Base) {
if (Base.is<TypeInfoLValue>())
return llvm::hash_value(Base.getOpaqueValue());
return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
Base.getVersion());
}
}
unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue(
const clang::APValue::LValueBase &Base) {
return hash_value(Base);
}
bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual(
const clang::APValue::LValueBase &LHS,
const clang::APValue::LValueBase &RHS) {
return LHS == RHS;
}
struct APValue::LV : LVBase {
static const unsigned InlinePathSpace =
(DataSize - sizeof(LVBase)) / sizeof(LValuePathEntry);
/// Path - The sequence of base classes, fields and array indices to follow to
/// walk from Base to the subobject. When performing GCC-style folding, there
/// may not be such a path.
union {
LValuePathEntry Path[InlinePathSpace];
LValuePathEntry *PathPtr;
};
LV() { PathLength = (unsigned)-1; }
~LV() { resizePath(0); }
void resizePath(unsigned Length) {
if (Length == PathLength)
return;
if (hasPathPtr())
delete [] PathPtr;
PathLength = Length;
if (hasPathPtr())
PathPtr = new LValuePathEntry[Length];
}
bool hasPath() const { return PathLength != (unsigned)-1; }
bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
LValuePathEntry *getPath() { return hasPathPtr() ? PathPtr : Path; }
const LValuePathEntry *getPath() const {
return hasPathPtr() ? PathPtr : Path;
}
};
namespace {
struct MemberPointerBase {
llvm::PointerIntPair<const ValueDecl*, 1, bool> MemberAndIsDerivedMember;
unsigned PathLength;
};
}
struct APValue::MemberPointerData : MemberPointerBase {
static const unsigned InlinePathSpace =
(DataSize - sizeof(MemberPointerBase)) / sizeof(const CXXRecordDecl*);
typedef const CXXRecordDecl *PathElem;
union {
PathElem Path[InlinePathSpace];
PathElem *PathPtr;
};
MemberPointerData() { PathLength = 0; }
~MemberPointerData() { resizePath(0); }
void resizePath(unsigned Length) {
if (Length == PathLength)
return;
if (hasPathPtr())
delete [] PathPtr;
PathLength = Length;
if (hasPathPtr())
PathPtr = new PathElem[Length];
}
bool hasPathPtr() const { return PathLength > InlinePathSpace; }
PathElem *getPath() { return hasPathPtr() ? PathPtr : Path; }
const PathElem *getPath() const {
return hasPathPtr() ? PathPtr : Path;
}
};
// FIXME: Reduce the malloc traffic here.
APValue::Arr::Arr(unsigned NumElts, unsigned Size) :
Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]),
NumElts(NumElts), ArrSize(Size) {}
APValue::Arr::~Arr() { delete [] Elts; }
APValue::StructData::StructData(unsigned NumBases, unsigned NumFields) :
Elts(new APValue[NumBases+NumFields]),
NumBases(NumBases), NumFields(NumFields) {}
APValue::StructData::~StructData() {
delete [] Elts;
}
APValue::UnionData::UnionData() : Field(nullptr), Value(new APValue) {}
APValue::UnionData::~UnionData () {
delete Value;
}
APValue::APValue(const APValue &RHS) : Kind(None) {
switch (RHS.getKind()) {
case None:
case Indeterminate:
Kind = RHS.getKind();
break;
case Int:
MakeInt();
setInt(RHS.getInt());
break;
case Float:
MakeFloat();
setFloat(RHS.getFloat());
break;
case FixedPoint: {
APFixedPoint FXCopy = RHS.getFixedPoint();
MakeFixedPoint(std::move(FXCopy));
break;
}
case Vector:
MakeVector();
setVector(((const Vec *)(const char *)RHS.Data.buffer)->Elts,
RHS.getVectorLength());
break;
case ComplexInt:
MakeComplexInt();
setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
break;
case ComplexFloat:
MakeComplexFloat();
setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
break;
case LValue:
MakeLValue();
if (RHS.hasLValuePath())
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
RHS.isLValueOnePastTheEnd(), RHS.isNullPointer());
else
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(),
RHS.isNullPointer());
break;
case Array:
MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I)
getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
if (RHS.hasArrayFiller())
getArrayFiller() = RHS.getArrayFiller();
break;
case Struct:
MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
for (unsigned I = 0, N = RHS.getStructNumBases(); I != N; ++I)
getStructBase(I) = RHS.getStructBase(I);
for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I)
getStructField(I) = RHS.getStructField(I);
break;
case Union:
MakeUnion();
setUnion(RHS.getUnionField(), RHS.getUnionValue());
break;
case MemberPointer:
MakeMemberPointer(RHS.getMemberPointerDecl(),
RHS.isMemberPointerToDerivedMember(),
RHS.getMemberPointerPath());
break;
case AddrLabelDiff:
MakeAddrLabelDiff();
setAddrLabelDiff(RHS.getAddrLabelDiffLHS(), RHS.getAddrLabelDiffRHS());
break;
}
}
void APValue::DestroyDataAndMakeUninit() {
if (Kind == Int)
((APSInt*)(char*)Data.buffer)->~APSInt();
else if (Kind == Float)
((APFloat*)(char*)Data.buffer)->~APFloat();
else if (Kind == FixedPoint)
((APFixedPoint *)(char *)Data.buffer)->~APFixedPoint();
else if (Kind == Vector)
((Vec*)(char*)Data.buffer)->~Vec();
else if (Kind == ComplexInt)
((ComplexAPSInt*)(char*)Data.buffer)->~ComplexAPSInt();
else if (Kind == ComplexFloat)
((ComplexAPFloat*)(char*)Data.buffer)->~ComplexAPFloat();
else if (Kind == LValue)
((LV*)(char*)Data.buffer)->~LV();
else if (Kind == Array)
((Arr*)(char*)Data.buffer)->~Arr();
else if (Kind == Struct)
((StructData*)(char*)Data.buffer)->~StructData();
else if (Kind == Union)
((UnionData*)(char*)Data.buffer)->~UnionData();
else if (Kind == MemberPointer)
((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData();
else if (Kind == AddrLabelDiff)
((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData();
Kind = None;
}
bool APValue::needsCleanup() const {
switch (getKind()) {
case None:
case Indeterminate:
case AddrLabelDiff:
return false;
case Struct:
case Union:
case Array:
case Vector:
return true;
case Int:
return getInt().needsCleanup();
case Float:
return getFloat().needsCleanup();
case FixedPoint:
return getFixedPoint().getValue().needsCleanup();
case ComplexFloat:
assert(getComplexFloatImag().needsCleanup() ==
getComplexFloatReal().needsCleanup() &&
"In _Complex float types, real and imaginary values always have the "
"same size.");
return getComplexFloatReal().needsCleanup();
case ComplexInt:
assert(getComplexIntImag().needsCleanup() ==
getComplexIntReal().needsCleanup() &&
"In _Complex int types, real and imaginary values must have the "
"same size.");
return getComplexIntReal().needsCleanup();
case LValue:
return reinterpret_cast<const LV *>(Data.buffer)->hasPathPtr();
case MemberPointer:
return reinterpret_cast<const MemberPointerData *>(Data.buffer)
->hasPathPtr();
}
llvm_unreachable("Unknown APValue kind!");
}
void APValue::swap(APValue &RHS) {
std::swap(Kind, RHS.Kind);
char TmpData[DataSize];
memcpy(TmpData, Data.buffer, DataSize);
memcpy(Data.buffer, RHS.Data.buffer, DataSize);
memcpy(RHS.Data.buffer, TmpData, DataSize);
}
LLVM_DUMP_METHOD void APValue::dump() const {
dump(llvm::errs());
llvm::errs() << '\n';
}
static double GetApproxValue(const llvm::APFloat &F) {
llvm::APFloat V = F;
bool ignored;
V.convert(llvm::APFloat::IEEEdouble(), llvm::APFloat::rmNearestTiesToEven,
&ignored);
return V.convertToDouble();
}
void APValue::dump(raw_ostream &OS) const {
switch (getKind()) {
case None:
OS << "None";
return;
case Indeterminate:
OS << "Indeterminate";
return;
case Int:
OS << "Int: " << getInt();
return;
case Float:
OS << "Float: " << GetApproxValue(getFloat());
return;
case FixedPoint:
OS << "FixedPoint : " << getFixedPoint();
return;
case Vector:
OS << "Vector: ";
getVectorElt(0).dump(OS);
for (unsigned i = 1; i != getVectorLength(); ++i) {
OS << ", ";
getVectorElt(i).dump(OS);
}
return;
case ComplexInt:
OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag();
return;
case ComplexFloat:
OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal())
<< ", " << GetApproxValue(getComplexFloatImag());
return;
case LValue:
OS << "LValue: <todo>";
return;
case Array:
OS << "Array: ";
for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) {
getArrayInitializedElt(I).dump(OS);
if (I != getArraySize() - 1) OS << ", ";
}
if (hasArrayFiller()) {
OS << getArraySize() - getArrayInitializedElts() << " x ";
getArrayFiller().dump(OS);
}
return;
case Struct:
OS << "Struct ";
if (unsigned N = getStructNumBases()) {
OS << " bases: ";
getStructBase(0).dump(OS);
for (unsigned I = 1; I != N; ++I) {
OS << ", ";
getStructBase(I).dump(OS);
}
}
if (unsigned N = getStructNumFields()) {
OS << " fields: ";
getStructField(0).dump(OS);
for (unsigned I = 1; I != N; ++I) {
OS << ", ";
getStructField(I).dump(OS);
}
}
return;
case Union:
OS << "Union: ";
getUnionValue().dump(OS);
return;
case MemberPointer:
OS << "MemberPointer: <todo>";
return;
case AddrLabelDiff:
OS << "AddrLabelDiff: <todo>";
return;
}
llvm_unreachable("Unknown APValue kind!");
}
void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
switch (getKind()) {
case APValue::None:
Out << "<out of lifetime>";
return;
case APValue::Indeterminate:
Out << "<uninitialized>";
return;
case APValue::Int:
if (Ty->isBooleanType())
Out << (getInt().getBoolValue() ? "true" : "false");
else
Out << getInt();
return;
case APValue::Float:
Out << GetApproxValue(getFloat());
return;
case APValue::FixedPoint:
Out << getFixedPoint();
return;
case APValue::Vector: {
Out << '{';
QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
getVectorElt(0).printPretty(Out, Ctx, ElemTy);
for (unsigned i = 1; i != getVectorLength(); ++i) {
Out << ", ";
getVectorElt(i).printPretty(Out, Ctx, ElemTy);
}
Out << '}';
return;
}
case APValue::ComplexInt:
Out << getComplexIntReal() << "+" << getComplexIntImag() << "i";
return;
case APValue::ComplexFloat:
Out << GetApproxValue(getComplexFloatReal()) << "+"
<< GetApproxValue(getComplexFloatImag()) << "i";
return;
case APValue::LValue: {
bool IsReference = Ty->isReferenceType();
QualType InnerTy
= IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType();
if (InnerTy.isNull())
InnerTy = Ty;
LValueBase Base = getLValueBase();
if (!Base) {
if (isNullPointer()) {
Out << (Ctx.getLangOpts().CPlusPlus11 ? "nullptr" : "0");
} else if (IsReference) {
Out << "*(" << InnerTy.stream(Ctx.getPrintingPolicy()) << "*)"
<< getLValueOffset().getQuantity();
} else {
Out << "(" << Ty.stream(Ctx.getPrintingPolicy()) << ")"
<< getLValueOffset().getQuantity();
}
return;
}
if (!hasLValuePath()) {
// No lvalue path: just print the offset.
CharUnits O = getLValueOffset();
CharUnits S = Ctx.getTypeSizeInChars(InnerTy);
if (!O.isZero()) {
if (IsReference)
Out << "*(";
if (O % S) {
Out << "(char*)";
S = CharUnits::One();
}
Out << '&';
} else if (!IsReference)
Out << '&';
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
Out << *VD;
else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
TI.print(Out, Ctx.getPrintingPolicy());
} else {
assert(Base.get<const Expr *>() != nullptr &&
"Expecting non-null Expr");
Base.get<const Expr*>()->printPretty(Out, nullptr,
Ctx.getPrintingPolicy());
}
if (!O.isZero()) {
Out << " + " << (O / S);
if (IsReference)
Out << ')';
}
return;
}
// We have an lvalue path. Print it out nicely.
if (!IsReference)
Out << '&';
else if (isLValueOnePastTheEnd())
Out << "*(&";
QualType ElemTy;
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
Out << *VD;
ElemTy = VD->getType();
} else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
TI.print(Out, Ctx.getPrintingPolicy());
ElemTy = Base.getTypeInfoType();
} else {
const Expr *E = Base.get<const Expr*>();
assert(E != nullptr && "Expecting non-null Expr");
E->printPretty(Out, nullptr, Ctx.getPrintingPolicy());
ElemTy = E->getType();
}
ArrayRef<LValuePathEntry> Path = getLValuePath();
const CXXRecordDecl *CastToBase = nullptr;
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
if (ElemTy->getAs<RecordType>()) {
// The lvalue refers to a class type, so the next path entry is a base
// or member.
const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer();
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
CastToBase = RD;
ElemTy = Ctx.getRecordType(RD);
} else {
const ValueDecl *VD = cast<ValueDecl>(BaseOrMember);
Out << ".";
if (CastToBase)
Out << *CastToBase << "::";
Out << *VD;
ElemTy = VD->getType();
}
} else {
// The lvalue must refer to an array.
Out << '[' << Path[I].getAsArrayIndex() << ']';
ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType();
}
}
// Handle formatting of one-past-the-end lvalues.
if (isLValueOnePastTheEnd()) {
// FIXME: If CastToBase is non-0, we should prefix the output with
// "(CastToBase*)".
Out << " + 1";
if (IsReference)
Out << ')';
}
return;
}
case APValue::Array: {
const ArrayType *AT = Ctx.getAsArrayType(Ty);
QualType ElemTy = AT->getElementType();
Out << '{';
if (unsigned N = getArrayInitializedElts()) {
getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy);
for (unsigned I = 1; I != N; ++I) {
Out << ", ";
if (I == 10) {
// Avoid printing out the entire contents of large arrays.
Out << "...";
break;
}
getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy);
}
}
Out << '}';
return;
}
case APValue::Struct: {
Out << '{';
const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
bool First = true;
if (unsigned N = getStructNumBases()) {
const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD);
CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin();
for (unsigned I = 0; I != N; ++I, ++BI) {
assert(BI != CD->bases_end());
if (!First)
Out << ", ";
getStructBase(I).printPretty(Out, Ctx, BI->getType());
First = false;
}
}
for (const auto *FI : RD->fields()) {
if (!First)
Out << ", ";
if (FI->isUnnamedBitfield()) continue;
getStructField(FI->getFieldIndex()).
printPretty(Out, Ctx, FI->getType());
First = false;
}
Out << '}';
return;
}
case APValue::Union:
Out << '{';
if (const FieldDecl *FD = getUnionField()) {
Out << "." << *FD << " = ";
getUnionValue().printPretty(Out, Ctx, FD->getType());
}
Out << '}';
return;
case APValue::MemberPointer:
// FIXME: This is not enough to unambiguously identify the member in a
// multiple-inheritance scenario.
if (const ValueDecl *VD = getMemberPointerDecl()) {
Out << '&' << *cast<CXXRecordDecl>(VD->getDeclContext()) << "::" << *VD;
return;
}
Out << "0";
return;
case APValue::AddrLabelDiff:
Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName();
Out << " - ";
Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName();
return;
}
llvm_unreachable("Unknown APValue kind!");
}
std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
std::string Result;
llvm::raw_string_ostream Out(Result);
printPretty(Out, Ctx, Ty);
Out.flush();
return Result;
}
bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy,
const ASTContext &Ctx) const {
if (isInt()) {
Result = getInt();
return true;
}
if (isLValue() && isNullPointer()) {
Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy);
return true;
}
if (isLValue() && !getLValueBase()) {
Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy);
return true;
}
return false;
}
const APValue::LValueBase APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const void*)Data.buffer)->Base;
}
bool APValue::isLValueOnePastTheEnd() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const void*)Data.buffer)->IsOnePastTheEnd;
}
CharUnits &APValue::getLValueOffset() {
assert(isLValue() && "Invalid accessor");
return ((LV*)(void*)Data.buffer)->Offset;
}
bool APValue::hasLValuePath() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const char*)Data.buffer)->hasPath();
}
ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
assert(isLValue() && hasLValuePath() && "Invalid accessor");
const LV &LVal = *((const LV*)(const char*)Data.buffer);
return llvm::makeArrayRef(LVal.getPath(), LVal.PathLength);
}
unsigned APValue::getLValueCallIndex() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const char*)Data.buffer)->Base.getCallIndex();
}
unsigned APValue::getLValueVersion() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const char*)Data.buffer)->Base.getVersion();
}
bool APValue::isNullPointer() const {
assert(isLValue() && "Invalid usage");
return ((const LV*)(const char*)Data.buffer)->IsNullPtr;
}
void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
bool IsNullPtr) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data.buffer);
LVal.Base = B;
LVal.IsOnePastTheEnd = false;
LVal.Offset = O;
LVal.resizePath((unsigned)-1);
LVal.IsNullPtr = IsNullPtr;
}
void APValue::setLValue(LValueBase B, const CharUnits &O,
ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,
bool IsNullPtr) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data.buffer);
LVal.Base = B;
LVal.IsOnePastTheEnd = IsOnePastTheEnd;
LVal.Offset = O;
LVal.resizePath(Path.size());
memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
LVal.IsNullPtr = IsNullPtr;
}
const ValueDecl *APValue::getMemberPointerDecl() const {
assert(isMemberPointer() && "Invalid accessor");
const MemberPointerData &MPD =
*((const MemberPointerData *)(const char *)Data.buffer);
return MPD.MemberAndIsDerivedMember.getPointer();
}
bool APValue::isMemberPointerToDerivedMember() const {
assert(isMemberPointer() && "Invalid accessor");
const MemberPointerData &MPD =
*((const MemberPointerData *)(const char *)Data.buffer);
return MPD.MemberAndIsDerivedMember.getInt();
}
ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
assert(isMemberPointer() && "Invalid accessor");
const MemberPointerData &MPD =
*((const MemberPointerData *)(const char *)Data.buffer);
return llvm::makeArrayRef(MPD.getPath(), MPD.PathLength);
}
void APValue::MakeLValue() {
assert(isAbsent() && "Bad state change");
static_assert(sizeof(LV) <= DataSize, "LV too big");
new ((void*)(char*)Data.buffer) LV();
Kind = LValue;
}
void APValue::MakeArray(unsigned InitElts, unsigned Size) {
assert(isAbsent() && "Bad state change");
new ((void*)(char*)Data.buffer) Arr(InitElts, Size);
Kind = Array;
}
void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
ArrayRef<const CXXRecordDecl*> Path) {
assert(isAbsent() && "Bad state change");
MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData;
Kind = MemberPointer;
MPD->MemberAndIsDerivedMember.setPointer(Member);
MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember);
MPD->resizePath(Path.size());
memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*));
}