aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/APValue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/APValue.cpp')
-rw-r--r--lib/AST/APValue.cpp121
1 files changed, 105 insertions, 16 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 146ebad055..b99a66267c 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -21,7 +21,7 @@ using namespace clang;
namespace {
struct LVBase {
- APValue::LValueBase Base;
+ llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd;
CharUnits Offset;
unsigned PathLength;
};
@@ -40,12 +40,17 @@ struct APValue::LV : LVBase {
};
LV() { PathLength = (unsigned)-1; }
- ~LV() { if (hasPathPtr()) delete [] PathPtr; }
+ ~LV() { resizePath(0); }
- void allocPath() {
- if (hasPathPtr()) PathPtr = new LValuePathEntry[PathLength];
+ void resizePath(unsigned Length) {
+ if (Length == PathLength)
+ return;
+ if (hasPathPtr())
+ delete [] PathPtr;
+ PathLength = Length;
+ if (hasPathPtr())
+ PathPtr = new LValuePathEntry[Length];
}
- void freePath() { if (hasPathPtr()) delete [] PathPtr; }
bool hasPath() const { return PathLength != (unsigned)-1; }
bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
@@ -56,6 +61,43 @@ struct APValue::LV : LVBase {
}
};
+namespace {
+ struct MemberPointerBase {
+ llvm::PointerIntPair<const ValueDecl*, 1, bool> MemberAndIsDerivedMember;
+ unsigned PathLength;
+ };
+}
+
+struct APValue::MemberPointerData : MemberPointerBase {
+ static const unsigned InlinePathSpace =
+ (MaxSize - 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) :
@@ -78,7 +120,8 @@ APValue::UnionData::~UnionData () {
const APValue &APValue::operator=(const APValue &RHS) {
if (this == &RHS)
return *this;
- if (Kind != RHS.Kind || Kind == Array || Kind == Struct) {
+ if (Kind != RHS.Kind || Kind == Array || Kind == Struct ||
+ Kind == MemberPointer) {
MakeUninit();
if (RHS.isInt())
MakeInt();
@@ -98,6 +141,10 @@ const APValue &APValue::operator=(const APValue &RHS) {
MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
else if (RHS.isUnion())
MakeUnion();
+ else if (RHS.isMemberPointer())
+ MakeMemberPointer(RHS.getMemberPointerDecl(),
+ RHS.isMemberPointerToDerivedMember(),
+ RHS.getMemberPointerPath());
}
if (isInt())
setInt(RHS.getInt());
@@ -112,7 +159,8 @@ const APValue &APValue::operator=(const APValue &RHS) {
setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
else if (isLValue()) {
if (RHS.hasLValuePath())
- setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath());
+ setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
+ RHS.isLValueOnePastTheEnd());
else
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath());
} else if (isArray()) {
@@ -149,6 +197,8 @@ void APValue::MakeUninit() {
((StructData*)(char*)Data)->~StructData();
else if (Kind == Union)
((UnionData*)(char*)Data)->~UnionData();
+ else if (Kind == MemberPointer)
+ ((MemberPointerData*)(char*)Data)->~MemberPointerData();
Kind = Uninitialized;
}
@@ -217,6 +267,9 @@ void APValue::print(raw_ostream &OS) const {
case Union:
OS << "Union: " << getUnionValue();
return;
+ case MemberPointer:
+ OS << "MemberPointer: <todo>";
+ return;
}
llvm_unreachable("Unknown APValue kind!");
}
@@ -280,6 +333,9 @@ static void WriteShortAPValueToStream(raw_ostream& Out,
case APValue::Union:
Out << '{' << V.getUnionValue() << '}';
return;
+ case APValue::MemberPointer:
+ Out << "MemberPointer: <todo>";
+ return;
}
llvm_unreachable("Unknown APValue kind!");
}
@@ -294,7 +350,12 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
const APValue::LValueBase APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data)->Base;
+ return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getPointer();
+}
+
+bool APValue::isLValueOnePastTheEnd() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getInt();
}
CharUnits &APValue::getLValueOffset() {
@@ -316,24 +377,41 @@ ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data);
- LVal.freePath();
- LVal.Base = B;
+ LVal.BaseAndIsOnePastTheEnd.setPointer(B);
+ LVal.BaseAndIsOnePastTheEnd.setInt(false);
LVal.Offset = O;
- LVal.PathLength = (unsigned)-1;
+ LVal.resizePath((unsigned)-1);
}
void APValue::setLValue(LValueBase B, const CharUnits &O,
- ArrayRef<LValuePathEntry> Path) {
+ ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data);
- LVal.freePath();
- LVal.Base = B;
+ LVal.BaseAndIsOnePastTheEnd.setPointer(B);
+ LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd);
LVal.Offset = O;
- LVal.PathLength = Path.size();
- LVal.allocPath();
+ 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);
+ return MPD.MemberAndIsDerivedMember.getPointer();
+}
+
+bool APValue::isMemberPointerToDerivedMember() const {
+ assert(isMemberPointer() && "Invalid accessor");
+ const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ return MPD.MemberAndIsDerivedMember.getInt();
+}
+
+ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
+ assert(isMemberPointer() && "Invalid accessor");
+ const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ return ArrayRef<const CXXRecordDecl*>(MPD.getPath(), MPD.PathLength);
+}
+
void APValue::MakeLValue() {
assert(isUninit() && "Bad state change");
assert(sizeof(LV) <= MaxSize && "LV too big");
@@ -346,3 +424,14 @@ void APValue::MakeArray(unsigned InitElts, unsigned Size) {
new ((void*)(char*)Data) 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) 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*));
+}