Add static analyzer transfer function support for __builtin_offsetof.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81820 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 8214199..0e08cd2 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -2430,10 +2430,15 @@
       return;
     }
 
-      // FIXME: Just report "Unknown" for OffsetOf.
-    case UnaryOperator::OffsetOf:
-      Dst.Add(Pred);
+    case UnaryOperator::OffsetOf: {
+      const APSInt &IV = U->EvaluateAsInt(getContext());
+      assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
+      assert(U->getType()->isIntegerType());
+      assert(IV.isSigned() == U->getType()->isSignedIntegerType());
+      SVal X = ValMgr.makeIntVal(IV);      
+      MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
       return;
+    }
 
     case UnaryOperator::Plus: assert (!asLValue);  // FALL-THROUGH.
     case UnaryOperator::Extension: {
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index 34a0953..189fc44 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -567,3 +567,45 @@
   return self;
 }
 @end
+
+// Test reasoning of __builtin_offsetof;
+struct test_offsetof_A {
+  int x;
+  int y;
+};
+struct test_offsetof_B {
+  int w;
+  int z;
+};
+void test_offsetof_1() {
+  if (__builtin_offsetof(struct test_offsetof_A, x) ==
+      __builtin_offsetof(struct test_offsetof_B, w))
+    return;
+  int *p = 0;
+  *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_2() {
+  if (__builtin_offsetof(struct test_offsetof_A, y) ==
+      __builtin_offsetof(struct test_offsetof_B, z))
+    return;
+  int *p = 0;
+  *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_3() {
+  if (__builtin_offsetof(struct test_offsetof_A, y) -
+      __builtin_offsetof(struct test_offsetof_A, x)
+      ==
+      __builtin_offsetof(struct test_offsetof_B, z) -
+      __builtin_offsetof(struct test_offsetof_B, w))
+    return;
+  int *p = 0;
+  *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_4() {
+  if (__builtin_offsetof(struct test_offsetof_A, y) ==
+      __builtin_offsetof(struct test_offsetof_B, w))
+    return;
+  int *p = 0;
+  *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}}
+}
+
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 9625514..397464a 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1028,3 +1028,39 @@
 }
 @end
 
+//===----------------------------------------------------------------------===//
+// Test that leaks post-dominated by "panic" functions are not reported.
+//
+// <rdar://problem/5905851> do not report a leak when post-dominated by a call
+// to a noreturn or panic function
+//===----------------------------------------------------------------------===//
+
+void panic() __attribute__((noreturn));
+
+void test_panic_negative() {
+  signed z = 1;
+  CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z);  // expected-warning{{leak}}
+}
+
+void test_panic_positive() {
+  signed z = 1;
+  CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+  panic();
+}
+
+void test_panic_neg_2(int x) {
+  signed z = 1;
+  CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+  if (x)
+    panic();
+}
+
+void test_panic_pos_2(int x) {
+  signed z = 1;
+  CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+  if (x)
+    panic();  
+  if (!x)
+    panic();
+}
+