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/ExprConstant.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/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 108 |
1 files changed, 70 insertions, 38 deletions
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 |