r246877 - Increase accuracy of __builtin_object_size.
George Burgess IV via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 16:30:40 PDT 2015
Proposed fix: http://reviews.llvm.org/D12821
On Fri, Sep 11, 2015 at 1:44 PM, George Burgess IV <
george.burgess.iv at gmail.com> wrote:
> > It might be reasonable for __builtin_object_size(..., 2) to give up if
> [...]
>
> That sounds like the best overall solution to me, as well. Working on a
> fix now.
>
> On Fri, Sep 11, 2015 at 1:22 PM, Richard Smith <richard at metafoo.co.uk>
> wrote:
>
>> On Fri, Sep 11, 2015 at 12:15 PM, Mikhail Zolotukhin via cfe-commits <
>> cfe-commits at lists.llvm.org> wrote:
>>
>>> Hi George,
>>>
>>> After this commit we started to trap on the following case:
>>>
>>> #include <string.h>
>>> typedef struct {
>>> int n;
>>> char key[1];
>>> } obj_t;
>>>
>>> char *str = "hello";
>>>
>>> int main() {
>>> obj_t* p = (obj_t*)malloc(strlen(str) + 1 + sizeof(int));
>>> strcpy(p->key, str);
>>> free(p);
>>> return 0;
>>> }
>>>
>>> As far as I understand, this might be a common pattern in pre-C99
>>> codebase, and it fails when compiled with -D_FORTIFY_SOURCE=2. Is there a
>>> way we could fix it in clang, or the only fix is to use less strict
>>> FORTIFY_SOURCE level?
>>>
>>
>> It might be reasonable for __builtin_object_size(..., 2) to give up if:
>>
>> 1) we lost track of the complete object, and
>> 2) the designator refers to the final subobject of the currently-known
>> complete object, and
>> 3) that subobject is either a flexible array member or an array of bound
>> 0 or 1.
>>
>> Then we'd leave it to IR generation to do the llvm.object.size(..., i1
>> false) dance, and in this case to grab the size of the malloc (minus the
>> offset of 'key').
>>
>> Thanks,
>>> Michael
>>>
>>> On Sep 4, 2015, at 2:28 PM, George Burgess IV via cfe-commits <
>>> cfe-commits at lists.llvm.org> wrote:
>>>
>>> Author: gbiv
>>> Date: Fri Sep 4 16:28:13 2015
>>> New Revision: 246877
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=246877&view=rev
>>> Log:
>>> Increase accuracy of __builtin_object_size.
>>>
>>> Improvements:
>>>
>>> - For all types, we would give up in a case such as:
>>> __builtin_object_size((char*)&foo, N);
>>> even if we could provide an answer to
>>> __builtin_object_size(&foo, N);
>>> We now provide the same answer for both of the above examples in all
>>> cases.
>>>
>>> - For type=1|3, we now support subobjects with unknown bases, as long
>>> as the designator is valid.
>>>
>>> Thanks to Richard Smith for the review + design planning.
>>>
>>> Review: http://reviews.llvm.org/D12169
>>>
>>>
>>> Modified:
>>> cfe/trunk/lib/AST/ExprConstant.cpp
>>> cfe/trunk/test/CodeGen/object-size.c
>>>
>>> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=246877&r1=246876&r2=246877&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
>>> +++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Sep 4 16:28:13 2015
>>> @@ -492,7 +492,11 @@ namespace {
>>> /// optimizer if we don't constant fold them here, but in an
>>> unevaluated
>>> /// context we try to fold them immediately since the optimizer
>>> never
>>> /// gets a chance to look at it.
>>> - EM_PotentialConstantExpressionUnevaluated
>>> + EM_PotentialConstantExpressionUnevaluated,
>>> +
>>> + /// Evaluate as a constant expression. Continue evaluating if we
>>> find a
>>> + /// MemberExpr with a base that can't be evaluated.
>>> + EM_DesignatorFold,
>>> } EvalMode;
>>>
>>> /// Are we checking whether the expression is a potential constant
>>> @@ -595,6 +599,7 @@ namespace {
>>> case EM_PotentialConstantExpression:
>>> case EM_ConstantExpressionUnevaluated:
>>> case EM_PotentialConstantExpressionUnevaluated:
>>> + case EM_DesignatorFold:
>>> HasActiveDiagnostic = false;
>>> return OptionalDiagnostic();
>>> }
>>> @@ -674,6 +679,7 @@ namespace {
>>> case EM_ConstantExpression:
>>> case EM_ConstantExpressionUnevaluated:
>>> case EM_ConstantFold:
>>> + case EM_DesignatorFold:
>>> return false;
>>> }
>>> llvm_unreachable("Missed EvalMode case");
>>> @@ -702,10 +708,15 @@ namespace {
>>> case EM_ConstantExpressionUnevaluated:
>>> case EM_ConstantFold:
>>> case EM_IgnoreSideEffects:
>>> + case EM_DesignatorFold:
>>> return false;
>>> }
>>> llvm_unreachable("Missed EvalMode case");
>>> }
>>> +
>>> + bool allowInvalidBaseExpr() const {
>>> + return EvalMode == EM_DesignatorFold;
>>> + }
>>> };
>>>
>>> /// Object used to treat all foldable expressions as constant
>>> expressions.
>>> @@ -736,6 +747,21 @@ namespace {
>>> }
>>> };
>>>
>>> + /// RAII object used to treat the current evaluation as the correct
>>> pointer
>>> + /// offset fold for the current EvalMode
>>> + struct FoldOffsetRAII {
>>> + EvalInfo &Info;
>>> + EvalInfo::EvaluationMode OldMode;
>>> + explicit FoldOffsetRAII(EvalInfo &Info, bool Subobject)
>>> + : Info(Info), OldMode(Info.EvalMode) {
>>> + if (!Info.checkingPotentialConstantExpression())
>>> + Info.EvalMode = Subobject ? EvalInfo::EM_DesignatorFold
>>> + : EvalInfo::EM_ConstantFold;
>>> + }
>>> +
>>> + ~FoldOffsetRAII() { Info.EvalMode = OldMode; }
>>> + };
>>> +
>>> /// RAII object used to suppress diagnostics and side-effects from a
>>> /// speculative evaluation.
>>> class SpeculativeEvaluationRAII {
>>> @@ -917,7 +943,8 @@ namespace {
>>> struct LValue {
>>> APValue::LValueBase Base;
>>> CharUnits Offset;
>>> - unsigned CallIndex;
>>> + bool InvalidBase : 1;
>>> + unsigned CallIndex : 31;
>>> SubobjectDesignator Designator;
>>>
>>> const APValue::LValueBase getLValueBase() const { return Base; }
>>> @@ -938,17 +965,23 @@ namespace {
>>> assert(V.isLValue());
>>> Base = V.getLValueBase();
>>> Offset = V.getLValueOffset();
>>> + InvalidBase = false;
>>> CallIndex = V.getLValueCallIndex();
>>> Designator = SubobjectDesignator(Ctx, V);
>>> }
>>>
>>> - void set(APValue::LValueBase B, unsigned I = 0) {
>>> + void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid =
>>> false) {
>>> Base = B;
>>> Offset = CharUnits::Zero();
>>> + InvalidBase = BInvalid;
>>> CallIndex = I;
>>> Designator = SubobjectDesignator(getType(B));
>>> }
>>>
>>> + void setInvalid(APValue::LValueBase B, unsigned I = 0) {
>>> + set(B, I, true);
>>> + }
>>> +
>>> // Check that this LValue is not based on a null pointer. If it is,
>>> produce
>>> // a diagnostic and mark the designator as invalid.
>>> bool checkNullPointer(EvalInfo &Info, const Expr *E,
>>> @@ -4368,20 +4401,23 @@ public:
>>> bool VisitMemberExpr(const MemberExpr *E) {
>>> // Handle non-static data members.
>>> QualType BaseTy;
>>> + bool EvalOK;
>>> if (E->isArrow()) {
>>> - if (!EvaluatePointer(E->getBase(), Result, this->Info))
>>> - return false;
>>> + EvalOK = EvaluatePointer(E->getBase(), Result, this->Info);
>>> BaseTy =
>>> E->getBase()->getType()->castAs<PointerType>()->getPointeeType();
>>> } else if (E->getBase()->isRValue()) {
>>> assert(E->getBase()->getType()->isRecordType());
>>> - if (!EvaluateTemporary(E->getBase(), Result, this->Info))
>>> - return false;
>>> + EvalOK = EvaluateTemporary(E->getBase(), Result, this->Info);
>>> BaseTy = E->getBase()->getType();
>>> } else {
>>> - if (!this->Visit(E->getBase()))
>>> - return false;
>>> + EvalOK = this->Visit(E->getBase());
>>> BaseTy = E->getBase()->getType();
>>> }
>>> + if (!EvalOK) {
>>> + if (!this->Info.allowInvalidBaseExpr())
>>> + return false;
>>> + Result.setInvalid(E->getBase());
>>> + }
>>>
>>> const ValueDecl *MD = E->getMemberDecl();
>>> if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
>>> @@ -4793,7 +4829,7 @@ public:
>>> bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
>>> { return Success(E); }
>>> bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E)
>>> - { return Success(E); }
>>> + { return Success(E); }
>>> bool VisitAddrLabelExpr(const AddrLabelExpr *E)
>>> { return Success(E); }
>>> bool VisitCallExpr(const CallExpr *E);
>>> @@ -4919,6 +4955,7 @@ bool PointerExprEvaluator::VisitCastExpr
>>> unsigned Size = Info.Ctx.getTypeSize(E->getType());
>>> uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
>>> Result.Base = (Expr*)nullptr;
>>> + Result.InvalidBase = false;
>>> Result.Offset = CharUnits::fromQuantity(N);
>>> Result.CallIndex = 0;
>>> Result.Designator.setInvalid();
>>> @@ -6211,6 +6248,26 @@ static QualType getObjectType(APValue::L
>>> return QualType();
>>> }
>>>
>>> +/// A more selective version of E->IgnoreParenCasts for
>>> +/// TryEvaluateBuiltinObjectSize. This ignores casts/parens that serve
>>> only to
>>> +/// change the type of E.
>>> +/// Ex. For E = `(short*)((char*)(&foo))`, returns `&foo`
>>> +///
>>> +/// Always returns an RValue with a pointer representation.
>>> +static const Expr *ignorePointerCastsAndParens(const Expr *E) {
>>> + assert(E->isRValue() && E->getType()->hasPointerRepresentation());
>>> +
>>> + auto *NoParens = E->IgnoreParens();
>>> + auto *Cast = dyn_cast<CastExpr>(NoParens);
>>> + if (Cast == nullptr || Cast->getCastKind() == CK_DerivedToBase)
>>> + return NoParens;
>>> +
>>> + auto *SubExpr = Cast->getSubExpr();
>>> + if (!SubExpr->getType()->hasPointerRepresentation() ||
>>> !SubExpr->isRValue())
>>> + return NoParens;
>>> + return ignorePointerCastsAndParens(SubExpr);
>>> +}
>>> +
>>> bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,
>>> unsigned Type) {
>>> // Determine the denoted object.
>>> @@ -6220,23 +6277,35 @@ bool IntExprEvaluator::TryEvaluateBuilti
>>> // 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))
>>> + FoldOffsetRAII Fold(Info, Type & 1);
>>> + const Expr *Ptr = ignorePointerCastsAndParens(E->getArg(0));
>>> + if (!EvaluatePointer(Ptr, 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())
>>> + // If we point to before the start of the object, there are no
>>> accessible
>>> + // bytes.
>>> + if (BaseOffset.isNegative())
>>> return Success(0, E);
>>>
>>> - // MostDerivedType is null if we're dealing with a literal such as
>>> nullptr or
>>> - // (char*)0x100000. Lower it to LLVM in either case so it can figure
>>> out what
>>> - // to do with it.
>>> - // FIXME(gbiv): Try to do a better job with this in clang.
>>> - if (Base.Designator.MostDerivedType.isNull())
>>> + // In the case where we're not dealing with a subobject, we discard
>>> the
>>> + // subobject bit.
>>> + if (!Base.Designator.Invalid && Base.Designator.Entries.empty())
>>> + Type = Type & ~1U;
>>> +
>>> + // If Type & 1 is 0, we need to be able to statically guarantee that
>>> the bytes
>>> + // exist. If we can't verify the base, then we can't do that.
>>> + //
>>> + // As a special case, we 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 matches GCC's behavior.
>>> + if ((Type & 1) == 0 && Base.InvalidBase)
>>> return Error(E);
>>>
>>> // If Type & 1 is 0, the object in question is the complete object;
>>> reset to
>>> @@ -6256,16 +6325,6 @@ bool IntExprEvaluator::TryEvaluateBuilti
>>> }
>>> }
>>>
>>> - // 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.
>>> @@ -6280,14 +6339,15 @@ bool IntExprEvaluator::TryEvaluateBuilti
>>> 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) {
>>> + 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 PointeeType = End.Designator.MostDerivedType;
>>> + assert(!PointeeType.isNull());
>>> + if (PointeeType->isIncompleteType() || PointeeType->isFunctionType())
>>> return Error(E);
>>>
>>> if (!HandleLValueArrayAdjustment(Info, E, End,
>>> End.Designator.MostDerivedType,
>>> @@ -6331,6 +6391,7 @@ bool IntExprEvaluator::VisitCallExpr(con
>>> case EvalInfo::EM_ConstantFold:
>>> case EvalInfo::EM_EvaluateForOverflow:
>>> case EvalInfo::EM_IgnoreSideEffects:
>>> + case EvalInfo::EM_DesignatorFold:
>>> // Leave it to IR generation.
>>> return Error(E);
>>> case EvalInfo::EM_ConstantExpressionUnevaluated:
>>>
>>> Modified: cfe/trunk/test/CodeGen/object-size.c
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/object-size.c?rev=246877&r1=246876&r2=246877&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/CodeGen/object-size.c (original)
>>> +++ cfe/trunk/test/CodeGen/object-size.c Fri Sep 4 16:28:13 2015
>>> @@ -161,6 +161,15 @@ void test19() {
>>> gi = __builtin_object_size(&foo.a, 2);
>>> // CHECK: store i32 4
>>> gi = __builtin_object_size(&foo.a, 3);
>>> +
>>> + // CHECK: store i32 4
>>> + gi = __builtin_object_size(&foo.b, 0);
>>> + // CHECK: store i32 4
>>> + gi = __builtin_object_size(&foo.b, 1);
>>> + // CHECK: store i32 4
>>> + gi = __builtin_object_size(&foo.b, 2);
>>> + // CHECK: store i32 4
>>> + gi = __builtin_object_size(&foo.b, 3);
>>> }
>>>
>>> // CHECK: @test20
>>> @@ -221,25 +230,59 @@ void test22() {
>>> gi = __builtin_object_size(&t[9].t[10], 2);
>>> // CHECK: store i32 0
>>> gi = __builtin_object_size(&t[9].t[10], 3);
>>> +
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 0);
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 1);
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 2);
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 3);
>>> +
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 0);
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 1);
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 2);
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 3);
>>> }
>>>
>>> -struct Test23Ty { int t[10]; };
>>> +struct Test23Ty { int a; int t[10]; };
>>>
>>> // CHECK: @test23
>>> -void test23(struct Test22Ty *p) {
>>> +void test23(struct Test23Ty *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);
>>> -}
>>>
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
>>> + gi = __builtin_object_size(&p->a, 0);
>>> + // CHECK: store i32 4
>>> + gi = __builtin_object_size(&p->a, 1);
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
>>> + gi = __builtin_object_size(&p->a, 2);
>>> + // CHECK: store i32 4
>>> + gi = __builtin_object_size(&p->a, 3);
>>> +
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
>>> + gi = __builtin_object_size(&p->t[5], 0);
>>> + // CHECK: store i32 20
>>> + gi = __builtin_object_size(&p->t[5], 1);
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
>>> + gi = __builtin_object_size(&p->t[5], 2);
>>> + // CHECK: store i32 20
>>> + gi = __builtin_object_size(&p->t[5], 3);
>>> +}
>>>
>>> // PR24493 -- ICE if __builtin_object_size called with NULL and (Type &
>>> 1) != 0
>>> // CHECK: @test24
>>> @@ -280,3 +323,71 @@ void test25() {
>>> // CHECK: store i32 0
>>> gi = __builtin_object_size((void*)0 + 0x1000, 3);
>>> }
>>> +
>>> +// CHECK: @test26
>>> +void test26() {
>>> + struct { int v[10]; } t[10];
>>> +
>>> + // CHECK: store i32 316
>>> + gi = __builtin_object_size(&t[1].v[11], 0);
>>> + // CHECK: store i32 312
>>> + gi = __builtin_object_size(&t[1].v[12], 1);
>>> + // CHECK: store i32 308
>>> + gi = __builtin_object_size(&t[1].v[13], 2);
>>> + // CHECK: store i32 0
>>> + gi = __builtin_object_size(&t[1].v[14], 3);
>>> +}
>>> +
>>> +struct Test27IncompleteTy;
>>> +
>>> +// CHECK: @test27
>>> +void test27(struct Test27IncompleteTy *t) {
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
>>> + gi = __builtin_object_size(t, 0);
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
>>> + gi = __builtin_object_size(t, 1);
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
>>> + gi = __builtin_object_size(t, 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(t, 3);
>>> +
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
>>> + gi = __builtin_object_size(&test27, 0);
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)
>>> + gi = __builtin_object_size(&test27, 1);
>>> + // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true)
>>> + gi = __builtin_object_size(&test27, 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(&test27, 3);
>>> +}
>>> +
>>> +// The intent of this test is to ensure that __builtin_object_size
>>> treats `&foo`
>>> +// and `(T*)&foo` identically, when used as the pointer argument.
>>> +// CHECK: @test28
>>> +void test28() {
>>> + struct { int v[10]; } t[10];
>>> +
>>> +#define addCasts(s) ((char*)((short*)(s)))
>>> + // CHECK: store i32 360
>>> + gi = __builtin_object_size(addCasts(&t[1]), 0);
>>> + // CHECK: store i32 360
>>> + gi = __builtin_object_size(addCasts(&t[1]), 1);
>>> + // CHECK: store i32 360
>>> + gi = __builtin_object_size(addCasts(&t[1]), 2);
>>> + // CHECK: store i32 360
>>> + gi = __builtin_object_size(addCasts(&t[1]), 3);
>>> +
>>> + // CHECK: store i32 356
>>> + gi = __builtin_object_size(addCasts(&t[1].v[1]), 0);
>>> + // CHECK: store i32 36
>>> + gi = __builtin_object_size(addCasts(&t[1].v[1]), 1);
>>> + // CHECK: store i32 356
>>> + gi = __builtin_object_size(addCasts(&t[1].v[1]), 2);
>>> + // CHECK: store i32 36
>>> + gi = __builtin_object_size(addCasts(&t[1].v[1]), 3);
>>> +#undef addCasts
>>> +}
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150911/d5050e0d/attachment-0001.html>
More information about the cfe-commits
mailing list