You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
651 lines
20 KiB
651 lines
20 KiB
//===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===// |
|
// |
|
// The LLVM Compiler Infrastructure |
|
// |
|
// This file is distributed under the University of Illinois Open Source |
|
// License. See LICENSE.TXT for details. |
|
// |
|
//===----------------------------------------------------------------------===// |
|
// |
|
// 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 "clang/Basic/Diagnostic.h" |
|
#include "llvm/ADT/SmallString.h" |
|
#include "llvm/Support/ErrorHandling.h" |
|
#include "llvm/Support/raw_ostream.h" |
|
using namespace clang; |
|
|
|
namespace { |
|
struct LVBase { |
|
llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd; |
|
CharUnits Offset; |
|
unsigned PathLength; |
|
unsigned CallIndex; |
|
}; |
|
} |
|
|
|
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(Uninitialized) { |
|
switch (RHS.getKind()) { |
|
case Uninitialized: |
|
break; |
|
case Int: |
|
MakeInt(); |
|
setInt(RHS.getInt()); |
|
break; |
|
case Float: |
|
MakeFloat(); |
|
setFloat(RHS.getFloat()); |
|
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.getLValueCallIndex()); |
|
else |
|
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(), |
|
RHS.getLValueCallIndex()); |
|
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 == 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 = Uninitialized; |
|
} |
|
|
|
bool APValue::needsCleanup() const { |
|
switch (getKind()) { |
|
case Uninitialized: |
|
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 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 Uninitialized: |
|
OS << "Uninitialized"; |
|
return; |
|
case Int: |
|
OS << "Int: " << getInt(); |
|
return; |
|
case Float: |
|
OS << "Float: " << GetApproxValue(getFloat()); |
|
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::Uninitialized: |
|
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::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: { |
|
LValueBase Base = getLValueBase(); |
|
if (!Base) { |
|
Out << "0"; |
|
return; |
|
} |
|
|
|
bool IsReference = Ty->isReferenceType(); |
|
QualType InnerTy |
|
= IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType(); |
|
if (InnerTy.isNull()) |
|
InnerTy = Ty; |
|
|
|
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 { |
|
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 { |
|
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 = |
|
BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).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].ArrayIndex << ']'; |
|
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; |
|
} |
|
|
|
const APValue::LValueBase APValue::getLValueBase() const { |
|
assert(isLValue() && "Invalid accessor"); |
|
return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getPointer(); |
|
} |
|
|
|
bool APValue::isLValueOnePastTheEnd() const { |
|
assert(isLValue() && "Invalid accessor"); |
|
return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getInt(); |
|
} |
|
|
|
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)->CallIndex; |
|
} |
|
|
|
void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, |
|
unsigned CallIndex) { |
|
assert(isLValue() && "Invalid accessor"); |
|
LV &LVal = *((LV*)(char*)Data.buffer); |
|
LVal.BaseAndIsOnePastTheEnd.setPointer(B); |
|
LVal.BaseAndIsOnePastTheEnd.setInt(false); |
|
LVal.Offset = O; |
|
LVal.CallIndex = CallIndex; |
|
LVal.resizePath((unsigned)-1); |
|
} |
|
|
|
void APValue::setLValue(LValueBase B, const CharUnits &O, |
|
ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd, |
|
unsigned CallIndex) { |
|
assert(isLValue() && "Invalid accessor"); |
|
LV &LVal = *((LV*)(char*)Data.buffer); |
|
LVal.BaseAndIsOnePastTheEnd.setPointer(B); |
|
LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd); |
|
LVal.Offset = O; |
|
LVal.CallIndex = CallIndex; |
|
LVal.resizePath(Path.size()); |
|
memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry)); |
|
} |
|
|
|
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(isUninit() && "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(isUninit() && "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(isUninit() && "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*)); |
|
}
|
|
|