Revert r245323, it caused PR24493.

llvm-svn: 245342
This commit is contained in:
Nico Weber 2015-08-18 20:32:55 +00:00
parent a364173219
commit 19999b4816
3 changed files with 48 additions and 175 deletions

View File

@ -967,6 +967,10 @@ namespace {
// Check this LValue refers to an object. If not, set the designator to be
// invalid and emit a diagnostic.
bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
// Outside C++11, do not build a designator referring to a subobject of
// any object: we won't use such a designator for anything.
if (!Info.getLangOpts().CPlusPlus11)
Designator.setInvalid();
return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
Designator.checkSubobject(Info, E, CSK);
}
@ -2709,7 +2713,8 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
// Check for special cases where there is no existing APValue to look at.
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
if (Base && !LVal.CallIndex && !Type.isVolatileQualified()) {
if (!LVal.Designator.Invalid && Base && !LVal.CallIndex &&
!Type.isVolatileQualified()) {
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
// In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
// initializer until now for such expressions. Such an expression can't be
@ -5993,7 +5998,8 @@ public:
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
private:
bool TryEvaluateBuiltinObjectSize(const CallExpr *E, unsigned Type);
static QualType GetObjectType(APValue::LValueBase B);
bool TryEvaluateBuiltinObjectSize(const CallExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
@ -6165,7 +6171,7 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
/// Retrieves the "underlying object type" of the given expression,
/// as used by __builtin_object_size.
static QualType getObjectType(APValue::LValueBase B) {
QualType IntExprEvaluator::GetObjectType(APValue::LValueBase B) {
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getType();
@ -6177,87 +6183,49 @@ static QualType getObjectType(APValue::LValueBase B) {
return QualType();
}
bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
unsigned Type) {
// Determine the denoted object.
bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) {
LValue Base;
{
// The operand of __builtin_object_size is never evaluated for side-effects.
// If there are any, but we can determine the pointed-to object anyway, then
// ignore the side-effects.
SpeculativeEvaluationRAII SpeculativeEval(Info);
FoldConstant Fold(Info, true);
if (!EvaluatePointer(E->getArg(0), Base, Info))
return false;
}
CharUnits BaseOffset = Base.getLValueOffset();
// If we point to before the start of the object, there are no
// accessible bytes.
if (BaseOffset < CharUnits::Zero())
return Success(0, E);
// If Type & 1 is 0, the object in question is the complete object; reset to
// a complete object designator in that case.
//
// If Type is 1 and we've lost track of the subobject, just find the complete
// object instead. (If Type is 3, that's not correct behavior and we should
// return 0 instead.)
LValue End = Base;
if (((Type & 1) == 0) || (End.Designator.Invalid && Type == 1)) {
QualType T = getObjectType(End.getLValueBase());
if (T.isNull())
End.Designator.setInvalid();
else {
End.Designator = SubobjectDesignator(T);
End.Offset = CharUnits::Zero();
}
if (!Base.getLValueBase()) {
// It is not possible to determine which objects ptr points to at compile time,
// __builtin_object_size should return (size_t) -1 for type 0 or 1
// and (size_t) 0 for type 2 or 3.
llvm::APSInt TypeIntVaue;
const Expr *ExprType = E->getArg(1);
if (!ExprType->EvaluateAsInt(TypeIntVaue, Info.Ctx))
return false;
if (TypeIntVaue == 0 || TypeIntVaue == 1)
return Success(-1, E);
if (TypeIntVaue == 2 || TypeIntVaue == 3)
return Success(0, E);
return Error(E);
}
// FIXME: We should produce a valid object size for an unknown object with a
// known designator, if Type & 1 is 1. For instance:
//
// extern struct X { char buff[32]; int a, b, c; } *p;
// int a = __builtin_object_size(p->buff + 4, 3); // returns 28
// int b = __builtin_object_size(p->buff + 4, 2); // returns 0, not 40
//
// This is GCC's behavior. We currently don't do this, but (hopefully) will in
// the near future.
// If it is not possible to determine which objects ptr points to at compile
// time, __builtin_object_size should return (size_t) -1 for type 0 or 1
// and (size_t) 0 for type 2 or 3.
if (End.Designator.Invalid)
return false;
// According to the GCC documentation, we want the size of the subobject
// denoted by the pointer. But that's not quite right -- what we actually
// want is the size of the immediately-enclosing array, if there is one.
int64_t AmountToAdd = 1;
if (End.Designator.MostDerivedArraySize &&
End.Designator.Entries.size() == End.Designator.MostDerivedPathLength) {
// We got a pointer to an array. Step to its end.
AmountToAdd = End.Designator.MostDerivedArraySize -
End.Designator.Entries.back().ArrayIndex;
} else if (End.Designator.IsOnePastTheEnd) {
// We're already pointing at the end of the object.
AmountToAdd = 0;
}
if (End.Designator.MostDerivedType->isIncompleteType() ||
End.Designator.MostDerivedType->isFunctionType())
QualType T = GetObjectType(Base.getLValueBase());
if (T.isNull() ||
T->isIncompleteType() ||
T->isFunctionType() ||
T->isVariablyModifiedType() ||
T->isDependentType())
return Error(E);
if (!HandleLValueArrayAdjustment(Info, E, End, End.Designator.MostDerivedType,
AmountToAdd))
return false;
CharUnits Size = Info.Ctx.getTypeSizeInChars(T);
CharUnits Offset = Base.getLValueOffset();
auto EndOffset = End.getLValueOffset();
if (BaseOffset > EndOffset)
return Success(0, E);
return Success(EndOffset - BaseOffset, E);
if (!Offset.isNegative() && Offset <= Size)
Size -= Offset;
else
Size = CharUnits::Zero();
return Success(Size, E);
}
bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
@ -6266,21 +6234,17 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
return ExprEvaluatorBaseTy::VisitCallExpr(E);
case Builtin::BI__builtin_object_size: {
// The type was checked when we built the expression.
unsigned Type =
E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue();
assert(Type <= 3 && "unexpected type");
if (TryEvaluateBuiltinObjectSize(E, Type))
if (TryEvaluateBuiltinObjectSize(E))
return true;
// If evaluating the argument has side-effects, we can't determine the size
// of the object, and so we lower it to unknown now. CodeGen relies on us to
// handle all cases where the expression has side-effects.
// Likewise, if Type is 3, we must handle this because CodeGen cannot give a
// conservatively correct answer in that case.
if (E->getArg(0)->HasSideEffects(Info.Ctx) || Type == 3)
return Success((Type & 2) ? 0 : -1, E);
if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
if (E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue() <= 1)
return Success(-1ULL, E);
return Success(0, E);
}
// Expression had no side effects, but we couldn't statically determine the
// size of the referenced object.
@ -6290,12 +6254,10 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case EvalInfo::EM_ConstantFold:
case EvalInfo::EM_EvaluateForOverflow:
case EvalInfo::EM_IgnoreSideEffects:
// Leave it to IR generation.
return Error(E);
case EvalInfo::EM_ConstantExpressionUnevaluated:
case EvalInfo::EM_PotentialConstantExpressionUnevaluated:
// Reduce it to a constant now.
return Success((Type & 2) ? 0 : -1, E);
return Success(-1ULL, E);
}
}

View File

@ -146,96 +146,3 @@ unsigned test18(int cond) {
// CHECK: call i64 @llvm.objectsize.i64
return __builtin_object_size(cond ? a : b, 0);
}
// CHECK: @test19
void test19() {
struct {
int a, b;
} foo;
// CHECK: store i32 8
gi = __builtin_object_size(&foo.a, 0);
// CHECK: store i32 4
gi = __builtin_object_size(&foo.a, 1);
// CHECK: store i32 8
gi = __builtin_object_size(&foo.a, 2);
// CHECK: store i32 4
gi = __builtin_object_size(&foo.a, 3);
}
// CHECK: @test20
void test20() {
struct { int t[10]; } t[10];
// CHECK: store i32 380
gi = __builtin_object_size(&t[0].t[5], 0);
// CHECK: store i32 20
gi = __builtin_object_size(&t[0].t[5], 1);
// CHECK: store i32 380
gi = __builtin_object_size(&t[0].t[5], 2);
// CHECK: store i32 20
gi = __builtin_object_size(&t[0].t[5], 3);
}
// CHECK: @test21
void test21() {
struct { int t; } t;
// CHECK: store i32 0
gi = __builtin_object_size(&t + 1, 0);
// CHECK: store i32 0
gi = __builtin_object_size(&t + 1, 1);
// CHECK: store i32 0
gi = __builtin_object_size(&t + 1, 2);
// CHECK: store i32 0
gi = __builtin_object_size(&t + 1, 3);
// CHECK: store i32 0
gi = __builtin_object_size(&t.t + 1, 0);
// CHECK: store i32 0
gi = __builtin_object_size(&t.t + 1, 1);
// CHECK: store i32 0
gi = __builtin_object_size(&t.t + 1, 2);
// CHECK: store i32 0
gi = __builtin_object_size(&t.t + 1, 3);
}
// CHECK: @test22
void test22() {
struct { int t[10]; } t[10];
// CHECK: store i32 0
gi = __builtin_object_size(&t[10], 0);
// CHECK: store i32 0
gi = __builtin_object_size(&t[10], 1);
// CHECK: store i32 0
gi = __builtin_object_size(&t[10], 2);
// CHECK: store i32 0
gi = __builtin_object_size(&t[10], 3);
// CHECK: store i32 0
gi = __builtin_object_size(&t[9].t[10], 0);
// CHECK: store i32 0
gi = __builtin_object_size(&t[9].t[10], 1);
// CHECK: store i32 0
gi = __builtin_object_size(&t[9].t[10], 2);
// CHECK: store i32 0
gi = __builtin_object_size(&t[9].t[10], 3);
}
struct Test23Ty { int t[10]; };
// CHECK: @test23
void test23(struct Test22Ty *p) {
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(p, 0);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(p, 1);
// CHECK:= call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
gi = __builtin_object_size(p, 2);
// Note: this is currently fixed at 0 because LLVM doesn't have sufficient
// data to correctly handle type=3
// CHECK: store i32 0
gi = __builtin_object_size(p, 3);
}

View File

@ -118,6 +118,10 @@ float varfloat;
const float constfloat = 0;
EVAL_EXPR(43, varfloat && constfloat) // expected-error {{must have a constant size}}
// <rdar://problem/11205586>
// (Make sure we continue to reject this.)
EVAL_EXPR(44, "x"[0]); // expected-error {{variable length array}}
// <rdar://problem/10962435>
EVAL_EXPR(45, ((char*)-1) + 1 == 0 ? 1 : -1)
EVAL_EXPR(46, ((char*)-1) + 1 < (char*) -1 ? 1 : -1)