<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi George,<div class=""><br class=""></div><div class="">After this commit we started to trap on the following case:</div><div class=""><div class=""><br class=""></div><div class=""><font face="Menlo" class="">#include <string.h></font></div><div class=""><font face="Menlo" class="">typedef struct {</font></div><div class=""><font face="Menlo" class=""> int n;</font></div><div class=""><font face="Menlo" class=""> char key[1];</font></div><div class=""><font face="Menlo" class="">} obj_t;</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">char *str = "hello";</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">int main() {</font></div><div class=""><font face="Menlo" class=""> obj_t* p = (obj_t*)malloc(strlen(str) + 1 + sizeof(int));</font></div><div class=""><font face="Menlo" class=""> strcpy(p->key, str);</font></div><div class=""><font face="Menlo" class=""> free(p);</font></div><div class=""><font face="Menlo" class=""> return 0;</font></div><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><br class=""></div><div class="">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?</div><div class=""><br class=""></div><div class="">Thanks,</div><div class="">Michael</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Sep 4, 2015, at 2:28 PM, George Burgess IV via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" class="">cfe-commits@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">Author: gbiv<br class="">Date: Fri Sep 4 16:28:13 2015<br class="">New Revision: 246877<br class=""><br class="">URL: <a href="http://llvm.org/viewvc/llvm-project?rev=246877&view=rev" class="">http://llvm.org/viewvc/llvm-project?rev=246877&view=rev</a><br class="">Log:<br class="">Increase accuracy of __builtin_object_size.<br class=""><br class="">Improvements:<br class=""><br class="">- For all types, we would give up in a case such as:<br class=""> __builtin_object_size((char*)&foo, N);<br class=""> even if we could provide an answer to<br class=""> __builtin_object_size(&foo, N);<br class=""> We now provide the same answer for both of the above examples in all<br class=""> cases.<br class=""><br class="">- For type=1|3, we now support subobjects with unknown bases, as long<br class=""> as the designator is valid.<br class=""><br class="">Thanks to Richard Smith for the review + design planning.<br class=""><br class="">Review: <a href="http://reviews.llvm.org/D12169" class="">http://reviews.llvm.org/D12169</a><br class=""><br class=""><br class="">Modified:<br class=""> cfe/trunk/lib/AST/ExprConstant.cpp<br class=""> cfe/trunk/test/CodeGen/object-size.c<br class=""><br class="">Modified: cfe/trunk/lib/AST/ExprConstant.cpp<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=246877&r1=246876&r2=246877&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=246877&r1=246876&r2=246877&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/lib/AST/ExprConstant.cpp (original)<br class="">+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Sep 4 16:28:13 2015<br class="">@@ -492,7 +492,11 @@ namespace {<br class=""> /// optimizer if we don't constant fold them here, but in an unevaluated<br class=""> /// context we try to fold them immediately since the optimizer never<br class=""> /// gets a chance to look at it.<br class="">- EM_PotentialConstantExpressionUnevaluated<br class="">+ EM_PotentialConstantExpressionUnevaluated,<br class="">+<br class="">+ /// Evaluate as a constant expression. Continue evaluating if we find a<br class="">+ /// MemberExpr with a base that can't be evaluated.<br class="">+ EM_DesignatorFold,<br class=""> } EvalMode;<br class=""><br class=""> /// Are we checking whether the expression is a potential constant<br class="">@@ -595,6 +599,7 @@ namespace {<br class=""> case EM_PotentialConstantExpression:<br class=""> case EM_ConstantExpressionUnevaluated:<br class=""> case EM_PotentialConstantExpressionUnevaluated:<br class="">+ case EM_DesignatorFold:<br class=""> HasActiveDiagnostic = false;<br class=""> return OptionalDiagnostic();<br class=""> }<br class="">@@ -674,6 +679,7 @@ namespace {<br class=""> case EM_ConstantExpression:<br class=""> case EM_ConstantExpressionUnevaluated:<br class=""> case EM_ConstantFold:<br class="">+ case EM_DesignatorFold:<br class=""> return false;<br class=""> }<br class=""> llvm_unreachable("Missed EvalMode case");<br class="">@@ -702,10 +708,15 @@ namespace {<br class=""> case EM_ConstantExpressionUnevaluated:<br class=""> case EM_ConstantFold:<br class=""> case EM_IgnoreSideEffects:<br class="">+ case EM_DesignatorFold:<br class=""> return false;<br class=""> }<br class=""> llvm_unreachable("Missed EvalMode case");<br class=""> }<br class="">+<br class="">+ bool allowInvalidBaseExpr() const {<br class="">+ return EvalMode == EM_DesignatorFold;<br class="">+ }<br class=""> };<br class=""><br class=""> /// Object used to treat all foldable expressions as constant expressions.<br class="">@@ -736,6 +747,21 @@ namespace {<br class=""> }<br class=""> };<br class=""><br class="">+ /// RAII object used to treat the current evaluation as the correct pointer<br class="">+ /// offset fold for the current EvalMode<br class="">+ struct FoldOffsetRAII {<br class="">+ EvalInfo &Info;<br class="">+ EvalInfo::EvaluationMode OldMode;<br class="">+ explicit FoldOffsetRAII(EvalInfo &Info, bool Subobject)<br class="">+ : Info(Info), OldMode(Info.EvalMode) {<br class="">+ if (!Info.checkingPotentialConstantExpression())<br class="">+ Info.EvalMode = Subobject ? EvalInfo::EM_DesignatorFold<br class="">+ : EvalInfo::EM_ConstantFold;<br class="">+ }<br class="">+<br class="">+ ~FoldOffsetRAII() { Info.EvalMode = OldMode; }<br class="">+ };<br class="">+<br class=""> /// RAII object used to suppress diagnostics and side-effects from a<br class=""> /// speculative evaluation.<br class=""> class SpeculativeEvaluationRAII {<br class="">@@ -917,7 +943,8 @@ namespace {<br class=""> struct LValue {<br class=""> APValue::LValueBase Base;<br class=""> CharUnits Offset;<br class="">- unsigned CallIndex;<br class="">+ bool InvalidBase : 1;<br class="">+ unsigned CallIndex : 31;<br class=""> SubobjectDesignator Designator;<br class=""><br class=""> const APValue::LValueBase getLValueBase() const { return Base; }<br class="">@@ -938,17 +965,23 @@ namespace {<br class=""> assert(V.isLValue());<br class=""> Base = V.getLValueBase();<br class=""> Offset = V.getLValueOffset();<br class="">+ InvalidBase = false;<br class=""> CallIndex = V.getLValueCallIndex();<br class=""> Designator = SubobjectDesignator(Ctx, V);<br class=""> }<br class=""><br class="">- void set(APValue::LValueBase B, unsigned I = 0) {<br class="">+ void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) {<br class=""> Base = B;<br class=""> Offset = CharUnits::Zero();<br class="">+ InvalidBase = BInvalid;<br class=""> CallIndex = I;<br class=""> Designator = SubobjectDesignator(getType(B));<br class=""> }<br class=""><br class="">+ void setInvalid(APValue::LValueBase B, unsigned I = 0) {<br class="">+ set(B, I, true);<br class="">+ }<br class="">+<br class=""> // Check that this LValue is not based on a null pointer. If it is, produce<br class=""> // a diagnostic and mark the designator as invalid.<br class=""> bool checkNullPointer(EvalInfo &Info, const Expr *E,<br class="">@@ -4368,20 +4401,23 @@ public:<br class=""> bool VisitMemberExpr(const MemberExpr *E) {<br class=""> // Handle non-static data members.<br class=""> QualType BaseTy;<br class="">+ bool EvalOK;<br class=""> if (E->isArrow()) {<br class="">- if (!EvaluatePointer(E->getBase(), Result, this->Info))<br class="">- return false;<br class="">+ EvalOK = EvaluatePointer(E->getBase(), Result, this->Info);<br class=""> BaseTy = E->getBase()->getType()->castAs<PointerType>()->getPointeeType();<br class=""> } else if (E->getBase()->isRValue()) {<br class=""> assert(E->getBase()->getType()->isRecordType());<br class="">- if (!EvaluateTemporary(E->getBase(), Result, this->Info))<br class="">- return false;<br class="">+ EvalOK = EvaluateTemporary(E->getBase(), Result, this->Info);<br class=""> BaseTy = E->getBase()->getType();<br class=""> } else {<br class="">- if (!this->Visit(E->getBase()))<br class="">- return false;<br class="">+ EvalOK = this->Visit(E->getBase());<br class=""> BaseTy = E->getBase()->getType();<br class=""> }<br class="">+ if (!EvalOK) {<br class="">+ if (!this->Info.allowInvalidBaseExpr())<br class="">+ return false;<br class="">+ Result.setInvalid(E->getBase());<br class="">+ }<br class=""><br class=""> const ValueDecl *MD = E->getMemberDecl();<br class=""> if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {<br class="">@@ -4793,7 +4829,7 @@ public:<br class=""> bool VisitObjCStringLiteral(const ObjCStringLiteral *E)<br class=""> { return Success(E); }<br class=""> bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E)<br class="">- { return Success(E); } <br class="">+ { return Success(E); }<br class=""> bool VisitAddrLabelExpr(const AddrLabelExpr *E)<br class=""> { return Success(E); }<br class=""> bool VisitCallExpr(const CallExpr *E);<br class="">@@ -4919,6 +4955,7 @@ bool PointerExprEvaluator::VisitCastExpr<br class=""> unsigned Size = Info.Ctx.getTypeSize(E->getType());<br class=""> uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();<br class=""> Result.Base = (Expr*)nullptr;<br class="">+ Result.InvalidBase = false;<br class=""> Result.Offset = CharUnits::fromQuantity(N);<br class=""> Result.CallIndex = 0;<br class=""> Result.Designator.setInvalid();<br class="">@@ -6211,6 +6248,26 @@ static QualType getObjectType(APValue::L<br class=""> return QualType();<br class=""> }<br class=""><br class="">+/// A more selective version of E->IgnoreParenCasts for<br class="">+/// TryEvaluateBuiltinObjectSize. This ignores casts/parens that serve only to<br class="">+/// change the type of E.<br class="">+/// Ex. For E = `(short*)((char*)(&foo))`, returns `&foo`<br class="">+///<br class="">+/// Always returns an RValue with a pointer representation.<br class="">+static const Expr *ignorePointerCastsAndParens(const Expr *E) {<br class="">+ assert(E->isRValue() && E->getType()->hasPointerRepresentation());<br class="">+<br class="">+ auto *NoParens = E->IgnoreParens();<br class="">+ auto *Cast = dyn_cast<CastExpr>(NoParens);<br class="">+ if (Cast == nullptr || Cast->getCastKind() == CK_DerivedToBase)<br class="">+ return NoParens;<br class="">+<br class="">+ auto *SubExpr = Cast->getSubExpr();<br class="">+ if (!SubExpr->getType()->hasPointerRepresentation() || !SubExpr->isRValue())<br class="">+ return NoParens;<br class="">+ return ignorePointerCastsAndParens(SubExpr);<br class="">+}<br class="">+<br class=""> bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E,<br class=""> unsigned Type) {<br class=""> // Determine the denoted object.<br class="">@@ -6220,23 +6277,35 @@ bool IntExprEvaluator::TryEvaluateBuilti<br class=""> // If there are any, but we can determine the pointed-to object anyway, then<br class=""> // ignore the side-effects.<br class=""> SpeculativeEvaluationRAII SpeculativeEval(Info);<br class="">- FoldConstant Fold(Info, true);<br class="">- if (!EvaluatePointer(E->getArg(0), Base, Info))<br class="">+ FoldOffsetRAII Fold(Info, Type & 1);<br class="">+ const Expr *Ptr = ignorePointerCastsAndParens(E->getArg(0));<br class="">+ if (!EvaluatePointer(Ptr, Base, Info))<br class=""> return false;<br class=""> }<br class=""><br class=""> CharUnits BaseOffset = Base.getLValueOffset();<br class="">-<br class="">- // If we point to before the start of the object, there are no<br class="">- // accessible bytes.<br class="">- if (BaseOffset < CharUnits::Zero())<br class="">+ // If we point to before the start of the object, there are no accessible<br class="">+ // bytes.<br class="">+ if (BaseOffset.isNegative())<br class=""> return Success(0, E);<br class=""><br class="">- // MostDerivedType is null if we're dealing with a literal such as nullptr or<br class="">- // (char*)0x100000. Lower it to LLVM in either case so it can figure out what<br class="">- // to do with it.<br class="">- // FIXME(gbiv): Try to do a better job with this in clang.<br class="">- if (Base.Designator.MostDerivedType.isNull())<br class="">+ // In the case where we're not dealing with a subobject, we discard the<br class="">+ // subobject bit.<br class="">+ if (!Base.Designator.Invalid && Base.Designator.Entries.empty())<br class="">+ Type = Type & ~1U;<br class="">+<br class="">+ // If Type & 1 is 0, we need to be able to statically guarantee that the bytes<br class="">+ // exist. If we can't verify the base, then we can't do that.<br class="">+ //<br class="">+ // As a special case, we produce a valid object size for an unknown object<br class="">+ // with a known designator if Type & 1 is 1. For instance:<br class="">+ //<br class="">+ // extern struct X { char buff[32]; int a, b, c; } *p;<br class="">+ // int a = __builtin_object_size(p->buff + 4, 3); // returns 28<br class="">+ // int b = __builtin_object_size(p->buff + 4, 2); // returns 0, not 40<br class="">+ //<br class="">+ // This matches GCC's behavior.<br class="">+ if ((Type & 1) == 0 && Base.InvalidBase)<br class=""> return Error(E);<br class=""><br class=""> // If Type & 1 is 0, the object in question is the complete object; reset to<br class="">@@ -6256,16 +6325,6 @@ bool IntExprEvaluator::TryEvaluateBuilti<br class=""> }<br class=""> }<br class=""><br class="">- // FIXME: We should produce a valid object size for an unknown object with a<br class="">- // known designator, if Type & 1 is 1. For instance:<br class="">- //<br class="">- // extern struct X { char buff[32]; int a, b, c; } *p;<br class="">- // int a = __builtin_object_size(p->buff + 4, 3); // returns 28<br class="">- // int b = __builtin_object_size(p->buff + 4, 2); // returns 0, not 40<br class="">- //<br class="">- // This is GCC's behavior. We currently don't do this, but (hopefully) will in<br class="">- // the near future.<br class="">-<br class=""> // If it is not possible to determine which objects ptr points to at compile<br class=""> // time, __builtin_object_size should return (size_t) -1 for type 0 or 1<br class=""> // and (size_t) 0 for type 2 or 3.<br class="">@@ -6280,14 +6339,15 @@ bool IntExprEvaluator::TryEvaluateBuilti<br class=""> End.Designator.Entries.size() == End.Designator.MostDerivedPathLength) {<br class=""> // We got a pointer to an array. Step to its end.<br class=""> AmountToAdd = End.Designator.MostDerivedArraySize -<br class="">- End.Designator.Entries.back().ArrayIndex;<br class="">- } else if (End.Designator.IsOnePastTheEnd) {<br class="">+ End.Designator.Entries.back().ArrayIndex;<br class="">+ } else if (End.Designator.isOnePastTheEnd()) {<br class=""> // We're already pointing at the end of the object.<br class=""> AmountToAdd = 0;<br class=""> }<br class=""><br class="">- if (End.Designator.MostDerivedType->isIncompleteType() ||<br class="">- End.Designator.MostDerivedType->isFunctionType())<br class="">+ QualType PointeeType = End.Designator.MostDerivedType;<br class="">+ assert(!PointeeType.isNull());<br class="">+ if (PointeeType->isIncompleteType() || PointeeType->isFunctionType())<br class=""> return Error(E);<br class=""><br class=""> if (!HandleLValueArrayAdjustment(Info, E, End, End.Designator.MostDerivedType,<br class="">@@ -6331,6 +6391,7 @@ bool IntExprEvaluator::VisitCallExpr(con<br class=""> case EvalInfo::EM_ConstantFold:<br class=""> case EvalInfo::EM_EvaluateForOverflow:<br class=""> case EvalInfo::EM_IgnoreSideEffects:<br class="">+ case EvalInfo::EM_DesignatorFold:<br class=""> // Leave it to IR generation.<br class=""> return Error(E);<br class=""> case EvalInfo::EM_ConstantExpressionUnevaluated:<br class=""><br class="">Modified: cfe/trunk/test/CodeGen/object-size.c<br class="">URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/object-size.c?rev=246877&r1=246876&r2=246877&view=diff" class="">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/object-size.c?rev=246877&r1=246876&r2=246877&view=diff</a><br class="">==============================================================================<br class="">--- cfe/trunk/test/CodeGen/object-size.c (original)<br class="">+++ cfe/trunk/test/CodeGen/object-size.c Fri Sep 4 16:28:13 2015<br class="">@@ -161,6 +161,15 @@ void test19() {<br class=""> gi = __builtin_object_size(&foo.a, 2);<br class=""> // CHECK: store i32 4<br class=""> gi = __builtin_object_size(&foo.a, 3);<br class="">+<br class="">+ // CHECK: store i32 4<br class="">+ gi = __builtin_object_size(&foo.b, 0);<br class="">+ // CHECK: store i32 4<br class="">+ gi = __builtin_object_size(&foo.b, 1);<br class="">+ // CHECK: store i32 4<br class="">+ gi = __builtin_object_size(&foo.b, 2);<br class="">+ // CHECK: store i32 4<br class="">+ gi = __builtin_object_size(&foo.b, 3);<br class=""> }<br class=""><br class=""> // CHECK: @test20<br class="">@@ -221,25 +230,59 @@ void test22() {<br class=""> gi = __builtin_object_size(&t[9].t[10], 2);<br class=""> // CHECK: store i32 0<br class=""> gi = __builtin_object_size(&t[9].t[10], 3);<br class="">+<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size((char*)&t[0] + sizeof(t), 0);<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size((char*)&t[0] + sizeof(t), 1);<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size((char*)&t[0] + sizeof(t), 2);<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size((char*)&t[0] + sizeof(t), 3);<br class="">+<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 0);<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 1);<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 2);<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 3);<br class=""> }<br class=""><br class="">-struct Test23Ty { int t[10]; };<br class="">+struct Test23Ty { int a; int t[10]; };<br class=""><br class=""> // CHECK: @test23<br class="">-void test23(struct Test22Ty *p) {<br class="">+void test23(struct Test23Ty *p) {<br class=""> // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)<br class=""> gi = __builtin_object_size(p, 0);<br class=""> // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)<br class=""> gi = __builtin_object_size(p, 1);<br class=""> // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)<br class=""> gi = __builtin_object_size(p, 2);<br class="">-<br class=""> // Note: this is currently fixed at 0 because LLVM doesn't have sufficient<br class=""> // data to correctly handle type=3<br class=""> // CHECK: store i32 0<br class=""> gi = __builtin_object_size(p, 3);<br class="">-}<br class=""><br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)<br class="">+ gi = __builtin_object_size(&p->a, 0);<br class="">+ // CHECK: store i32 4<br class="">+ gi = __builtin_object_size(&p->a, 1);<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)<br class="">+ gi = __builtin_object_size(&p->a, 2);<br class="">+ // CHECK: store i32 4<br class="">+ gi = __builtin_object_size(&p->a, 3);<br class="">+<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)<br class="">+ gi = __builtin_object_size(&p->t[5], 0);<br class="">+ // CHECK: store i32 20<br class="">+ gi = __builtin_object_size(&p->t[5], 1);<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)<br class="">+ gi = __builtin_object_size(&p->t[5], 2);<br class="">+ // CHECK: store i32 20<br class="">+ gi = __builtin_object_size(&p->t[5], 3);<br class="">+}<br class=""><br class=""> // PR24493 -- ICE if __builtin_object_size called with NULL and (Type & 1) != 0<br class=""> // CHECK: @test24<br class="">@@ -280,3 +323,71 @@ void test25() {<br class=""> // CHECK: store i32 0<br class=""> gi = __builtin_object_size((void*)0 + 0x1000, 3);<br class=""> }<br class="">+<br class="">+// CHECK: @test26<br class="">+void test26() {<br class="">+ struct { int v[10]; } t[10];<br class="">+<br class="">+ // CHECK: store i32 316<br class="">+ gi = __builtin_object_size(&t[1].v[11], 0);<br class="">+ // CHECK: store i32 312<br class="">+ gi = __builtin_object_size(&t[1].v[12], 1);<br class="">+ // CHECK: store i32 308<br class="">+ gi = __builtin_object_size(&t[1].v[13], 2);<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size(&t[1].v[14], 3);<br class="">+}<br class="">+<br class="">+struct Test27IncompleteTy;<br class="">+<br class="">+// CHECK: @test27<br class="">+void test27(struct Test27IncompleteTy *t) {<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)<br class="">+ gi = __builtin_object_size(t, 0);<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)<br class="">+ gi = __builtin_object_size(t, 1);<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)<br class="">+ gi = __builtin_object_size(t, 2);<br class="">+ // Note: this is currently fixed at 0 because LLVM doesn't have sufficient<br class="">+ // data to correctly handle type=3<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size(t, 3);<br class="">+<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)<br class="">+ gi = __builtin_object_size(&test27, 0);<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 false)<br class="">+ gi = __builtin_object_size(&test27, 1);<br class="">+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* {{.*}}, i1 true)<br class="">+ gi = __builtin_object_size(&test27, 2);<br class="">+ // Note: this is currently fixed at 0 because LLVM doesn't have sufficient<br class="">+ // data to correctly handle type=3<br class="">+ // CHECK: store i32 0<br class="">+ gi = __builtin_object_size(&test27, 3);<br class="">+}<br class="">+<br class="">+// The intent of this test is to ensure that __builtin_object_size treats `&foo`<br class="">+// and `(T*)&foo` identically, when used as the pointer argument.<br class="">+// CHECK: @test28<br class="">+void test28() {<br class="">+ struct { int v[10]; } t[10];<br class="">+<br class="">+#define addCasts(s) ((char*)((short*)(s)))<br class="">+ // CHECK: store i32 360<br class="">+ gi = __builtin_object_size(addCasts(&t[1]), 0);<br class="">+ // CHECK: store i32 360<br class="">+ gi = __builtin_object_size(addCasts(&t[1]), 1);<br class="">+ // CHECK: store i32 360<br class="">+ gi = __builtin_object_size(addCasts(&t[1]), 2);<br class="">+ // CHECK: store i32 360<br class="">+ gi = __builtin_object_size(addCasts(&t[1]), 3);<br class="">+<br class="">+ // CHECK: store i32 356<br class="">+ gi = __builtin_object_size(addCasts(&t[1].v[1]), 0);<br class="">+ // CHECK: store i32 36<br class="">+ gi = __builtin_object_size(addCasts(&t[1].v[1]), 1);<br class="">+ // CHECK: store i32 356<br class="">+ gi = __builtin_object_size(addCasts(&t[1].v[1]), 2);<br class="">+ // CHECK: store i32 36<br class="">+ gi = __builtin_object_size(addCasts(&t[1].v[1]), 3);<br class="">+#undef addCasts<br class="">+}<br class=""><br class=""><br class="">_______________________________________________<br class="">cfe-commits mailing list<br class=""><a href="mailto:cfe-commits@lists.llvm.org" class="">cfe-commits@lists.llvm.org</a><br class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits<br class=""></div></div></blockquote></div><br class=""></div></body></html>