Commit 77a08a40 authored by Hans Wennborg's avatar Hans Wennborg
Browse files

Merging r294800:

------------------------------------------------------------------------
r294800 | gbiv | 2017-02-10 14:52:29 -0800 (Fri, 10 Feb 2017) | 10 lines

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/branches/release_40@295087 91177308-0d34-0410-b5e6-96231b3b80d8
parent bf0d36c6
......@@ -604,10 +604,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
......@@ -890,10 +892,6 @@ namespace {
return KeepGoing;
}
bool allowInvalidBaseExpr() const {
return EvalMode == EM_OffsetFold;
}
class ArrayInitLoopIndex {
EvalInfo &Info;
uint64_t OuterIndex;
......@@ -1394,8 +1392,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);
......@@ -4803,6 +4803,7 @@ class LValueExprEvaluatorBase
: public ExprEvaluatorBase<Derived> {
protected:
LValue &Result;
bool InvalidBaseOK;
typedef LValueExprEvaluatorBase LValueExprEvaluatorBaseTy;
typedef ExprEvaluatorBase<Derived> ExprEvaluatorBaseTy;
......@@ -4811,9 +4812,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);
......@@ -4825,7 +4831,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());
......@@ -4836,7 +4842,7 @@ public:
BaseTy = E->getBase()->getType();
}
if (!EvalOK) {
if (!this->Info.allowInvalidBaseExpr())
if (!InvalidBaseOK)
return false;
Result.setInvalid(E);
return true;
......@@ -4930,8 +4936,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);
......@@ -4984,10 +4990,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) {
......@@ -5148,7 +5155,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;
......@@ -5160,7 +5167,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) {
......@@ -5308,7 +5315,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.
......@@ -5342,17 +5349,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);
......@@ -5399,9 +5416,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) {
......@@ -5414,7 +5432,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;
......@@ -5432,7 +5450,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) {
......@@ -5466,7 +5484,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;
......@@ -5513,7 +5531,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);
......@@ -5530,18 +5548,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);
}
}
......@@ -5586,7 +5605,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);
......@@ -5609,12 +5628,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);
......@@ -6255,7 +6274,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) {
......@@ -7358,7 +7377,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;
}
......
......@@ -549,3 +549,22 @@ int incomplete_and_function_types() {
// CHECK: store i32 0
gi = __builtin_object_size(incomplete_char_array, 3);
}
// Flips between the pointer and lvalue evaluator a lot.
void deeply_nested() {
struct {
struct {
struct {
struct {
int e[2];
char f; // Inhibit our writing-off-the-end check
} d[2];
} c[2];
} b[2];
} *a;
// CHECK: store i32 4
gi = __builtin_object_size(&a->b[1].c[1].d[1].e[1], 1);
// CHECK: store i32 4
gi = __builtin_object_size(&a->b[1].c[1].d[1].e[1], 3);
}
......@@ -76,3 +76,18 @@ int pr28314(void) {
a += __builtin_object_size(p3->b, 0);
return a;
}
int pr31843() {
int n = 0;
struct { int f; } a;
int b;
n += __builtin_object_size(({&(b ? &a : &a)->f; pr31843;}), 0); // expected-warning{{expression result unused}}
struct statfs { char f_mntonname[1024];};
struct statfs *outStatFSBuf;
n += __builtin_object_size(outStatFSBuf->f_mntonname ? "" : "", 1); // expected-warning{{address of array}}
n += __builtin_object_size(outStatFSBuf->f_mntonname ?: "", 1);
return n;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment