Tweak format string checking to work with %@ and ObjC toll-free bridging.  <rdar://problem/10814120>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149907 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 30bfe4b..1c911c4 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -336,9 +336,23 @@
       return argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
         argTy->isNullPtrType();
 
-    case ObjCPointerTy:
-      return argTy->getAs<ObjCObjectPointerType>() ||
-             argTy->getAs<BlockPointerType>();
+    case ObjCPointerTy: {
+      if (argTy->getAs<ObjCObjectPointerType>() ||
+          argTy->getAs<BlockPointerType>())
+        return true;
+      
+      // Handle implicit toll-free bridging.
+      if (const PointerType *PT = argTy->getAs<PointerType>()) {
+        // Things such as CFTypeRef are really just opaque pointers
+        // to C structs representing CF types that can often be bridged
+        // to Objective-C objects.  Since the compiler doesn't know which
+        // structs can be toll-free bridged, we just accept them all.
+        QualType pointee = PT->getPointeeType();
+        if (pointee->getAsStructureType() || pointee->isVoidType())
+          return true;
+      }
+      return false;      
+    }
   }
 
   llvm_unreachable("Invalid ArgTypeResult Kind!");
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
index a4d6eeb..675729c 100644
--- a/test/SemaObjC/format-strings-objc.m
+++ b/test/SemaObjC/format-strings-objc.m
@@ -146,3 +146,8 @@
   const wchar_t wchar_data = L'a';
   NSLog(@"%C", wchar_data);  // expected-warning{{format specifies type 'unsigned short' but the argument has type 'wchar_t'}}
 }
+
+// Test that %@ works with toll-free bridging (<rdar://problem/10814120>).
+void test_toll_free_bridging(CFStringRef x) {
+  NSLog(@"%@", x); // no-warning
+}