diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/APValue.cpp | 71 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 108 |
2 files changed, 133 insertions, 46 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; } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 6456376d48..8ec16217a7 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -46,6 +46,24 @@ namespace { struct CallStackFrame; struct EvalInfo; + /// Determine whether the described subobject is an array element. + static bool SubobjectIsArrayElement(QualType Base, + ArrayRef<APValue::LValuePathEntry> Path) { + bool IsArrayElement = false; + const Type *T = Base.getTypePtr(); + for (unsigned I = 0, N = Path.size(); I != N; ++I) { + IsArrayElement = T && T->isArrayType(); + if (IsArrayElement) + T = T->getBaseElementTypeUnsafe(); + else if (const FieldDecl *FD = dyn_cast<FieldDecl>(Path[I].BaseOrMember)) + T = FD->getType().getTypePtr(); + else + // Path[I] describes a base class. + T = 0; + } + return IsArrayElement; + } + /// A path from a glvalue to a subobject of that glvalue. struct SubobjectDesignator { /// True if the subobject was named in a manner not supported by C++11. Such @@ -59,20 +77,28 @@ namespace { /// Whether this designates 'one past the end' of the current subobject. bool OnePastTheEnd : 1; - union PathEntry { - /// If the current subobject is of class type, this indicates which - /// subobject of that type is accessed next. - const Decl *BaseOrMember; - /// If the current subobject is of array type, this indicates which index - /// within that array is accessed next. - uint64_t Index; - }; + typedef APValue::LValuePathEntry PathEntry; + /// The entries on the path from the glvalue to the designated subobject. SmallVector<PathEntry, 8> Entries; SubobjectDesignator() : Invalid(false), ArrayElement(false), OnePastTheEnd(false) {} + SubobjectDesignator(const APValue &V) : + Invalid(!V.isLValue() || !V.hasLValuePath()), ArrayElement(false), + OnePastTheEnd(false) { + if (!Invalid) { + ArrayRef<PathEntry> VEntries = V.getLValuePath(); + Entries.insert(Entries.end(), VEntries.begin(), VEntries.end()); + if (V.getLValueBase()) + ArrayElement = SubobjectIsArrayElement(V.getLValueBase()->getType(), + V.getLValuePath()); + else + assert(V.getLValuePath().empty() &&"Null pointer with nonempty path"); + } + } + void setInvalid() { Invalid = true; Entries.clear(); @@ -85,7 +111,7 @@ namespace { return; } PathEntry Entry; - Entry.Index = N; + Entry.ArrayIndex = N; Entries.push_back(Entry); ArrayElement = true; } @@ -106,7 +132,7 @@ namespace { void adjustIndex(uint64_t N) { if (Invalid) return; if (ArrayElement) { - Entries.back().Index += N; + Entries.back().ArrayIndex += N; return; } if (OnePastTheEnd && N == (uint64_t)-1) @@ -141,9 +167,9 @@ namespace { CCValue(const CCValue &V) : APValue(V), CallFrame(V.CallFrame) {} CCValue(const Expr *B, const CharUnits &O, CallStackFrame *F, const SubobjectDesignator &D) : - APValue(B, O), CallFrame(F), Designator(D) {} + APValue(B, O, APValue::NoLValuePath()), CallFrame(F), Designator(D) {} CCValue(const APValue &V, GlobalValue) : - APValue(V), CallFrame(0), Designator() {} + APValue(V), CallFrame(0), Designator(V) {} CallStackFrame *getLValueFrame() const { assert(getKind() == LValue); @@ -336,17 +362,39 @@ static bool IsGlobalLValue(const Expr* E) { return true; } -/// Check that this core constant expression value is a valid value for a -/// constant expression, and if it is, produce the corresponding constant value. -static bool CheckConstantExpression(const CCValue &CCValue, APValue &Value) { - if (CCValue.isLValue() && !IsGlobalLValue(CCValue.getLValueBase())) +/// Check that this reference or pointer core constant expression is a valid +/// value for a constant expression. Type T should be either LValue or CCValue. +template<typename T> +static bool CheckLValueConstantExpression(const T &LVal, APValue &Value) { + if (!IsGlobalLValue(LVal.getLValueBase())) return false; - // Slice off the extra bits. - Value = CCValue; + const SubobjectDesignator &Designator = LVal.getLValueDesignator(); + // A constant expression must refer to an object or be a null pointer. + if (Designator.Invalid || Designator.OnePastTheEnd || + (!LVal.getLValueBase() && !Designator.Entries.empty())) { + // FIXME: Check for out-of-bounds array indices. + // FIXME: This is not a constant expression. + Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(), + APValue::NoLValuePath()); + return true; + } + + Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(), + Designator.Entries); return true; } +/// Check that this core constant expression value is a valid value for a +/// constant expression, and if it is, produce the corresponding constant value. +static bool CheckConstantExpression(const CCValue &CCValue, APValue &Value) { + if (!CCValue.isLValue()) { + Value = CCValue; + return true; + } + return CheckLValueConstantExpression(CCValue, Value); +} + const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { if (!LVal.Base) return 0; @@ -595,7 +643,7 @@ bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type, return false; assert(Type->isIntegerType() && "string element not integer type"); - uint64_t Index = Designator.Entries[0].Index; + uint64_t Index = Designator.Entries[0].ArrayIndex; if (Index > S->getLength()) return false; APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), @@ -1954,7 +2002,7 @@ static bool HasSameBase(const LValue &A, const LValue &B) { if (!ADecl) return false; const Decl *BDecl = GetLValueBaseDecl(B); - if (ADecl != BDecl) + if (!BDecl || ADecl->getCanonicalDecl() != BDecl->getCanonicalDecl()) return false; } @@ -3293,24 +3341,8 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); LValue LV; - if (EvaluateLValue(this, LV, Info) && !Result.HasSideEffects && - IsGlobalLValue(LV.Base)) { - Result.Val = APValue(LV.Base, LV.Offset); - return true; - } - return false; -} - -bool Expr::EvaluateAsAnyLValue(EvalResult &Result, - const ASTContext &Ctx) const { - EvalInfo Info(Ctx, Result); - - LValue LV; - if (EvaluateLValue(this, LV, Info)) { - Result.Val = APValue(LV.Base, LV.Offset); - return true; - } - return false; + return EvaluateLValue(this, LV, Info) && !Result.HasSideEffects && + CheckLValueConstantExpression(LV, Result.Val); } /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be |