summaryrefslogtreecommitdiffstats
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorGeorge Burgess IV <george.burgess.iv@gmail.com>2017-02-10 22:52:29 +0000
committerGeorge Burgess IV <george.burgess.iv@gmail.com>2017-02-10 22:52:29 +0000
commitfbe18a269deb1a11c16eb2d2419b3c9ef9be8d3b (patch)
tree101c7ab0c616b1ff0ca0a8c351ac55b10ce7cd8c /lib/AST/ExprConstant.cpp
parent8fc981f3af745890158e2b6009eede292605b098 (diff)
Don't let EvaluationModes dictate whether an invalid base is OK
What we want to actually control this behavior is something more local than an EvalutationMode. Please see the linked revision for more discussion on why/etc. This fixes PR31843. Differential Revision: https://reviews.llvm.org/D29469 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@294800 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r--lib/AST/ExprConstant.cpp94
1 files changed, 57 insertions, 37 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index fafd91dc71..dff126db0c 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -616,10 +616,12 @@ namespace {
/// gets a chance to look at it.
EM_PotentialConstantExpressionUnevaluated,
- /// Evaluate as a constant expression. Continue evaluating if either:
- /// - We find a MemberExpr with a base that can't be evaluated.
- /// - We find a variable initialized with a call to a function that has
- /// the alloc_size attribute on it.
+ /// Evaluate as a constant expression. In certain scenarios, if:
+ /// - we find a MemberExpr with a base that can't be evaluated, or
+ /// - we find a variable initialized with a call to a function that has
+ /// the alloc_size attribute on it
+ /// then we may consider evaluation to have succeeded.
+ ///
/// In either case, the LValue returned shall have an invalid base; in the
/// former, the base will be the invalid MemberExpr, in the latter, the
/// base will be either the alloc_size CallExpr or a CastExpr wrapping
@@ -902,10 +904,6 @@ namespace {
return KeepGoing;
}
- bool allowInvalidBaseExpr() const {
- return EvalMode == EM_OffsetFold;
- }
-
class ArrayInitLoopIndex {
EvalInfo &Info;
uint64_t OuterIndex;
@@ -1416,8 +1414,10 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
const LValue &This, const Expr *E,
bool AllowNonLiteralTypes = false);
-static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
-static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
+static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
+ bool InvalidBaseOK = false);
+static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
+ bool InvalidBaseOK = false);
static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
EvalInfo &Info);
static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info);
@@ -4835,6 +4835,7 @@ class LValueExprEvaluatorBase
: public ExprEvaluatorBase<Derived> {
protected:
LValue &Result;
+ bool InvalidBaseOK;
typedef LValueExprEvaluatorBase LValueExprEvaluatorBaseTy;
typedef ExprEvaluatorBase<Derived> ExprEvaluatorBaseTy;
@@ -4843,9 +4844,14 @@ protected:
return true;
}
+ bool evaluatePointer(const Expr *E, LValue &Result) {
+ return EvaluatePointer(E, Result, this->Info, InvalidBaseOK);
+ }
+
public:
- LValueExprEvaluatorBase(EvalInfo &Info, LValue &Result) :
- ExprEvaluatorBaseTy(Info), Result(Result) {}
+ LValueExprEvaluatorBase(EvalInfo &Info, LValue &Result, bool InvalidBaseOK)
+ : ExprEvaluatorBaseTy(Info), Result(Result),
+ InvalidBaseOK(InvalidBaseOK) {}
bool Success(const APValue &V, const Expr *E) {
Result.setFrom(this->Info.Ctx, V);
@@ -4857,7 +4863,7 @@ public:
QualType BaseTy;
bool EvalOK;
if (E->isArrow()) {
- EvalOK = EvaluatePointer(E->getBase(), Result, this->Info);
+ EvalOK = evaluatePointer(E->getBase(), Result);
BaseTy = E->getBase()->getType()->castAs<PointerType>()->getPointeeType();
} else if (E->getBase()->isRValue()) {
assert(E->getBase()->getType()->isRecordType());
@@ -4868,7 +4874,7 @@ public:
BaseTy = E->getBase()->getType();
}
if (!EvalOK) {
- if (!this->Info.allowInvalidBaseExpr())
+ if (!InvalidBaseOK)
return false;
Result.setInvalid(E);
return true;
@@ -4962,8 +4968,8 @@ namespace {
class LValueExprEvaluator
: public LValueExprEvaluatorBase<LValueExprEvaluator> {
public:
- LValueExprEvaluator(EvalInfo &Info, LValue &Result) :
- LValueExprEvaluatorBaseTy(Info, Result) {}
+ LValueExprEvaluator(EvalInfo &Info, LValue &Result, bool InvalidBaseOK) :
+ LValueExprEvaluatorBaseTy(Info, Result, InvalidBaseOK) {}
bool VisitVarDecl(const Expr *E, const VarDecl *VD);
bool VisitUnaryPreIncDec(const UnaryOperator *UO);
@@ -5016,10 +5022,11 @@ public:
/// * function designators in C, and
/// * "extern void" objects
/// * @selector() expressions in Objective-C
-static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info) {
+static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
+ bool InvalidBaseOK) {
assert(E->isGLValue() || E->getType()->isFunctionType() ||
E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E));
- return LValueExprEvaluator(Info, Result).Visit(E);
+ return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E);
}
bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
@@ -5180,7 +5187,7 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
if (E->getBase()->getType()->isVectorType())
return Error(E);
- if (!EvaluatePointer(E->getBase(), Result, Info))
+ if (!evaluatePointer(E->getBase(), Result))
return false;
APSInt Index;
@@ -5191,7 +5198,7 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
- return EvaluatePointer(E->getSubExpr(), Result, Info);
+ return evaluatePointer(E->getSubExpr(), Result);
}
bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -5339,7 +5346,7 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
/// and mark Result's Base as invalid.
static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base,
LValue &Result) {
- if (!Info.allowInvalidBaseExpr() || Base.isNull())
+ if (Base.isNull())
return false;
// Because we do no form of static analysis, we only support const variables.
@@ -5373,17 +5380,27 @@ namespace {
class PointerExprEvaluator
: public ExprEvaluatorBase<PointerExprEvaluator> {
LValue &Result;
+ bool InvalidBaseOK;
bool Success(const Expr *E) {
Result.set(E);
return true;
}
+ bool evaluateLValue(const Expr *E, LValue &Result) {
+ return EvaluateLValue(E, Result, Info, InvalidBaseOK);
+ }
+
+ bool evaluatePointer(const Expr *E, LValue &Result) {
+ return EvaluatePointer(E, Result, Info, InvalidBaseOK);
+ }
+
bool visitNonBuiltinCallExpr(const CallExpr *E);
public:
- PointerExprEvaluator(EvalInfo &info, LValue &Result)
- : ExprEvaluatorBaseTy(info), Result(Result) {}
+ PointerExprEvaluator(EvalInfo &info, LValue &Result, bool InvalidBaseOK)
+ : ExprEvaluatorBaseTy(info), Result(Result),
+ InvalidBaseOK(InvalidBaseOK) {}
bool Success(const APValue &V, const Expr *E) {
Result.setFrom(Info.Ctx, V);
@@ -5430,9 +5447,10 @@ public:
};
} // end anonymous namespace
-static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) {
+static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info,
+ bool InvalidBaseOK) {
assert(E->isRValue() && E->getType()->hasPointerRepresentation());
- return PointerExprEvaluator(Info, Result).Visit(E);
+ return PointerExprEvaluator(Info, Result, InvalidBaseOK).Visit(E);
}
bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
@@ -5445,7 +5463,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (IExp->getType()->isPointerType())
std::swap(PExp, IExp);
- bool EvalPtrOK = EvaluatePointer(PExp, Result, Info);
+ bool EvalPtrOK = evaluatePointer(PExp, Result);
if (!EvalPtrOK && !Info.noteFailure())
return false;
@@ -5461,7 +5479,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
}
bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
- return EvaluateLValue(E->getSubExpr(), Result, Info);
+ return evaluateLValue(E->getSubExpr(), Result);
}
bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
@@ -5495,7 +5513,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
- if (!EvaluatePointer(E->getSubExpr(), Result, Info))
+ if (!evaluatePointer(E->getSubExpr(), Result))
return false;
if (!Result.Base && Result.Offset.isZero())
return true;
@@ -5542,7 +5560,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
}
case CK_ArrayToPointerDecay:
if (SubExpr->isGLValue()) {
- if (!EvaluateLValue(SubExpr, Result, Info))
+ if (!evaluateLValue(SubExpr, Result))
return false;
} else {
Result.set(SubExpr, Info.CurrentCall->Index);
@@ -5559,18 +5577,19 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return true;
case CK_FunctionToPointerDecay:
- return EvaluateLValue(SubExpr, Result, Info);
+ return evaluateLValue(SubExpr, Result);
case CK_LValueToRValue: {
LValue LVal;
- if (!EvaluateLValue(E->getSubExpr(), LVal, Info))
+ if (!evaluateLValue(E->getSubExpr(), LVal))
return false;
APValue RVal;
// Note, we use the subexpression's type in order to retain cv-qualifiers.
if (!handleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(),
LVal, RVal))
- return evaluateLValueAsAllocSize(Info, LVal.Base, Result);
+ return InvalidBaseOK &&
+ evaluateLValueAsAllocSize(Info, LVal.Base, Result);
return Success(RVal, E);
}
}
@@ -5615,7 +5634,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
if (ExprEvaluatorBaseTy::VisitCallExpr(E))
return true;
- if (!(Info.allowInvalidBaseExpr() && getAllocSizeAttr(E)))
+ if (!(InvalidBaseOK && getAllocSizeAttr(E)))
return false;
Result.setInvalid(E);
@@ -5638,12 +5657,12 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
switch (BuiltinOp) {
case Builtin::BI__builtin_addressof:
- return EvaluateLValue(E->getArg(0), Result, Info);
+ return evaluateLValue(E->getArg(0), Result);
case Builtin::BI__builtin_assume_aligned: {
// We need to be very careful here because: if the pointer does not have the
// asserted alignment, then the behavior is undefined, and undefined
// behavior is non-constant.
- if (!EvaluatePointer(E->getArg(0), Result, Info))
+ if (!evaluatePointer(E->getArg(0), Result))
return false;
LValue OffsetResult(Result);
@@ -6279,7 +6298,7 @@ class TemporaryExprEvaluator
: public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
public:
TemporaryExprEvaluator(EvalInfo &Info, LValue &Result) :
- LValueExprEvaluatorBaseTy(Info, Result) {}
+ LValueExprEvaluatorBaseTy(Info, Result, false) {}
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
@@ -7383,7 +7402,8 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
if (!EvaluateAsRValue(Info, E, RVal))
return false;
LVal.setFrom(Info.Ctx, RVal);
- } else if (!EvaluatePointer(ignorePointerCastsAndParens(E), LVal, Info))
+ } else if (!EvaluatePointer(ignorePointerCastsAndParens(E), LVal, Info,
+ /*InvalidBaseOK=*/true))
return false;
}