diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-11-07 05:07:52 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-11-07 05:07:52 +0000 |
commit | 9a17a680c74ef661bf3d864029adf7e74d9cb5b8 (patch) | |
tree | 7446ea85d9828775a776b0b4e214303c2f5710c0 /lib/AST/APValue.cpp | |
parent | db45806b991013280a03057025c9538de64d5dfb (diff) |
Constant expression evaluation: preserve subobject designator when flattening a
core constant value down to an APValue.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143909 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/APValue.cpp')
-rw-r--r-- | lib/AST/APValue.cpp | 71 |
1 files changed, 63 insertions, 8 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 0f315bbccd..12420fd809 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -20,14 +20,41 @@ using namespace clang; namespace { - struct LV { - const Expr* Base; + struct LVBase { + const Expr *Base; CharUnits Offset; + unsigned PathLength; }; } +struct APValue::LV : LVBase { + static const unsigned InlinePathSpace = + (MaxSize - 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() { if (hasPathPtr()) delete [] PathPtr; } + + void allocPath() { + if (hasPathPtr()) PathPtr = new LValuePathEntry[PathLength]; + } + + bool hasPath() const { return PathLength != (unsigned)-1; } + bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; } + + LValuePathEntry *getPath() { return hasPathPtr() ? PathPtr : Path; } +}; + APValue::APValue(const Expr* B) : Kind(Uninitialized) { - MakeLValue(); setLValue(B, CharUnits::Zero()); + MakeLValue(); + setLValue(B, CharUnits::Zero(), ArrayRef<LValuePathEntry>()); } const APValue &APValue::operator=(const APValue &RHS) { @@ -57,8 +84,12 @@ const APValue &APValue::operator=(const APValue &RHS) { setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag()); else if (isComplexFloat()) setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag()); - else if (isLValue()) - setLValue(RHS.getLValueBase(), RHS.getLValueOffset()); + else if (isLValue()) { + if (RHS.hasLValuePath()) + setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath()); + else + setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath()); + } return *this; } @@ -174,14 +205,38 @@ CharUnits &APValue::getLValueOffset() { return ((LV*)(void*)Data)->Offset; } -void APValue::setLValue(const Expr *B, const CharUnits &O) { +bool APValue::hasLValuePath() const { + assert(isLValue() && "Invalid accessor"); + return ((LV*)(char*)Data)->hasPath(); +} + +ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const { + assert(isLValue() && hasLValuePath() && "Invalid accessor"); + LV &LVal = *((LV*)(char*)Data); + return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength); +} + +void APValue::setLValue(const Expr *B, const CharUnits &O, NoLValuePath) { + assert(isLValue() && "Invalid accessor"); + LV &LVal = *((LV*)(char*)Data); + LVal.Base = B; + LVal.Offset = O; + LVal.PathLength = (unsigned)-1; +} + +void APValue::setLValue(const Expr *B, const CharUnits &O, + ArrayRef<LValuePathEntry> Path) { assert(isLValue() && "Invalid accessor"); - ((LV*)(char*)Data)->Base = B; - ((LV*)(char*)Data)->Offset = O; + LV &LVal = *((LV*)(char*)Data); + LVal.Base = B; + LVal.Offset = O; + LVal.PathLength = Path.size(); + memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry)); } void APValue::MakeLValue() { assert(isUninit() && "Bad state change"); + assert(sizeof(LV) <= MaxSize && "LV too big"); new ((void*)(char*)Data) LV(); Kind = LValue; } |