<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>