objc-arc: Add support for unbridged cast of 
__builtin___CFStringMakeConstantString and CF typed function calls 
with explicit cf_returns_retained/cf_returns_not_retained attributes.
// rdar://9544832


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133535 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index ff3f837..83b01f2 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1552,36 +1552,56 @@
 
 bool
 Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) {
-  Expr *NewExp = Exp->IgnoreParenImpCasts();
+  Expr *NewExp = Exp->IgnoreParenCasts();
   
-  if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp))
+  if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp)
+      && !isa<CallExpr>(NewExp))
     return false;
   ObjCMethodDecl *method = 0;
+  bool MethodReturnsPlusOne = false;
+  
   if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) {
     method = PRE->getExplicitProperty()->getGetterMethodDecl();
   }
-  else {
-    ObjCMessageExpr *ME = cast<ObjCMessageExpr>(NewExp);
+  else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(NewExp))
     method = ME->getMethodDecl();
-  }
-  if (!method)
-    return false;
-  if (method->hasAttr<CFReturnsNotRetainedAttr>())
-    return true;
-  bool MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>();
-  if (!MethodReturnsPlusOne) {
-    ObjCMethodFamily family = method->getSelector().getMethodFamily();
-    switch (family) {
-      case OMF_alloc:
-      case OMF_copy:
-      case OMF_mutableCopy:
-      case OMF_new:
-        MethodReturnsPlusOne = true;
-        break;
-      default:
-        break;
+  else {
+    CallExpr *CE = cast<CallExpr>(NewExp);
+    Decl *CallDecl = CE->getCalleeDecl();
+    if (!CallDecl)
+      return false;
+    if (CallDecl->hasAttr<CFReturnsNotRetainedAttr>())
+      return true;
+    MethodReturnsPlusOne = CallDecl->hasAttr<CFReturnsRetainedAttr>();
+    if (!MethodReturnsPlusOne) {
+      if (NamedDecl *ND = dyn_cast<NamedDecl>(CallDecl))
+        if (const IdentifierInfo *Id = ND->getIdentifier())
+          if (Id->isStr("__builtin___CFStringMakeConstantString"))
+            return true;
     }
   }
+  
+  if (!MethodReturnsPlusOne) {
+    if (!method)
+      return false;
+    if (method->hasAttr<CFReturnsNotRetainedAttr>())
+      return true;
+    MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>();
+    if (!MethodReturnsPlusOne) {
+      ObjCMethodFamily family = method->getSelector().getMethodFamily();
+      switch (family) {
+        case OMF_alloc:
+        case OMF_copy:
+        case OMF_mutableCopy:
+        case OMF_new:
+          MethodReturnsPlusOne = true;
+          break;
+        default:
+          break;
+      }
+    }
+  }
+  
   if (MethodReturnsPlusOne) {
     TypeSourceInfo *TSInfo = 
       Context.getTrivialTypeSourceInfo(castType, SourceLocation());
diff --git a/test/CodeGenObjC/arc-unbridged-cast.m b/test/CodeGenObjC/arc-unbridged-cast.m
index 5c560e9..0f3db09 100644
--- a/test/CodeGenObjC/arc-unbridged-cast.m
+++ b/test/CodeGenObjC/arc-unbridged-cast.m
@@ -24,4 +24,14 @@
 - (void) setP : (CFStringRef)arg {}
 @end
 
+// rdar://9544832
+CFStringRef SomeOtherFunc() __attribute__((cf_returns_retained));
+id MMM()
+{
+  id obj = (id)((CFStringRef) __builtin___CFStringMakeConstantString ("" "Some CF String" ""));
+  if (obj)
+    return (id) SomeOtherFunc();
+  return 0;
+}
+
 // CHECK-NOT: call i8* @objc_retainAutoreleasedReturnValue