[arcmt] In GC, error out when there is a call that returns a pointer to
GC managed non-objc object memory.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143747 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp
index 8042c6c..94e965d 100644
--- a/lib/ARCMigrate/TransGCCalls.cpp
+++ b/lib/ARCMigrate/TransGCCalls.cpp
@@ -35,6 +35,13 @@
   bool VisitCallExpr(CallExpr *E) {
     TransformActions &TA = MigrateCtx.getPass().TA;
 
+    if (MigrateCtx.isGCOwnedNonObjC(E->getType())) {
+      TA.reportError("call returns pointer to GC managed memory; "
+                     "it will become unmanaged in ARC",
+                     E->getLocStart(), E->getSourceRange());
+      return true;
+    }
+
     Expr *CEE = E->getCallee()->IgnoreParenImpCasts();
     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
       if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl())) {
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index ec676e9..7ad9b60 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -122,6 +122,8 @@
                        ASTContext &ctx, Preprocessor &PP)
     : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { }
 
+  ASTContext &getASTContext() { return Ctx; }
+
   void startTransaction();
   bool commitTransaction();
   void abortTransaction();
@@ -674,6 +676,12 @@
                                    SourceRange range) {
   assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
          "Errors should be emitted out of a transaction");
+
+  SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)->
+                                             getASTContext().getSourceManager();
+  if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
+    return;
+
   // FIXME: Use a custom category name to distinguish rewriter errors.
   std::string rewriteErr = "[rewriter] ";
   rewriteErr += error;
@@ -688,6 +696,12 @@
                                   SourceRange range) {
   assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
          "Errors should be emitted out of a transaction");
+
+  SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)->
+                                             getASTContext().getSourceManager();
+  if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
+    return;
+
   // FIXME: Use a custom category name to distinguish rewriter errors.
   std::string rewriteNote = "[rewriter] ";
   rewriteNote += note;
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 0decdd6..d0c9bc6 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -324,6 +324,26 @@
     delete *I;
 }
 
+bool MigrationContext::isGCOwnedNonObjC(QualType T) {
+  while (!T.isNull()) {
+    if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
+      if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
+        return !AttrT->getModifiedType()->isObjCRetainableType();
+    }
+
+    if (T->isArrayType())
+      T = Pass.Ctx.getBaseElementType(T);
+    else if (const PointerType *PT = T->getAs<PointerType>())
+      T = PT->getPointeeType();
+    else if (const ReferenceType *RT = T->getAs<ReferenceType>())
+      T = RT->getPointeeType();
+    else
+      break;
+  }
+
+  return false;
+}
+
 void MigrationContext::traverse(TranslationUnitDecl *TU) {
   ASTTransform(*this).TraverseDecl(TU);
 }
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index d935e86..5158446 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -82,6 +82,8 @@
     Traversers.push_back(traverser);
   }
 
+  bool isGCOwnedNonObjC(QualType T);
+
   void traverse(TranslationUnitDecl *TU);
 };