objc arc: Diagnose block pointer type mismatch when
some arguments types are ns_consumed and some otherwise
matching types are not. This is objc side of
// rdar://10187884


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140729 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 458a8a4..8d2ebb3 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -1510,6 +1510,10 @@
                                      bool Unqualified = false);
   
   QualType mergeObjCGCQualifiers(QualType, QualType);
+    
+  bool FunctionTypesMatchOnNSConsumedAttrs(
+         const FunctionProtoType *FromFunctionType,
+         const FunctionProtoType *ToFunctionType);
 
   void ResetObjCLayout(const ObjCContainerDecl *CD) {
     ObjCLayouts[CD] = 0;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 98ce45f..4bafb2b 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -5570,6 +5570,10 @@
     if (lproto->getTypeQuals() != rproto->getTypeQuals())
       return QualType();
 
+    if (LangOpts.ObjCAutoRefCount &&
+        !FunctionTypesMatchOnNSConsumedAttrs(rproto, lproto))
+      return QualType();
+      
     // Check argument compatibility
     SmallVector<QualType, 10> types;
     for (unsigned i = 0; i < lproto_nargs; i++) {
@@ -5594,6 +5598,7 @@
       if (getCanonicalType(argtype) != getCanonicalType(rargtype))
         allRTypes = false;
     }
+      
     if (allLTypes) return lhs;
     if (allRTypes) return rhs;
 
@@ -5892,6 +5897,26 @@
   return QualType();
 }
 
+bool ASTContext::FunctionTypesMatchOnNSConsumedAttrs(
+                   const FunctionProtoType *FromFunctionType,
+                   const FunctionProtoType *ToFunctionType) {
+  if (FromFunctionType->hasAnyConsumedArgs() != 
+      ToFunctionType->hasAnyConsumedArgs())
+    return false;
+  FunctionProtoType::ExtProtoInfo FromEPI = 
+    FromFunctionType->getExtProtoInfo();
+  FunctionProtoType::ExtProtoInfo ToEPI = 
+    ToFunctionType->getExtProtoInfo();
+  if (FromEPI.ConsumedArguments && ToEPI.ConsumedArguments)
+    for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
+         ArgIdx != NumArgs; ++ArgIdx)  {
+      if (FromEPI.ConsumedArguments[ArgIdx] != 
+          ToEPI.ConsumedArguments[ArgIdx])
+        return false;
+    }
+  return true;
+}
+
 /// mergeObjCGCQualifiers - This routine merges ObjC's GC attribute of 'LHS' and
 /// 'RHS' attributes and returns the merged version; including for function
 /// return types.
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 63d4f5a..0c9083e 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -2074,22 +2074,10 @@
        // Argument types are too different. Abort.
        return false;
    }
-   if (LangOpts.ObjCAutoRefCount) {
-     if (FromFunctionType->hasAnyConsumedArgs() != 
-         ToFunctionType->hasAnyConsumedArgs())
-      return false;
-     FunctionProtoType::ExtProtoInfo FromEPI = 
-      FromFunctionType->getExtProtoInfo();
-     FunctionProtoType::ExtProtoInfo ToEPI = 
-      ToFunctionType->getExtProtoInfo();
-     if (FromEPI.ConsumedArguments && ToEPI.ConsumedArguments)
-       for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
-            ArgIdx != NumArgs; ++ArgIdx)  {
-         if (FromEPI.ConsumedArguments[ArgIdx] != 
-             ToEPI.ConsumedArguments[ArgIdx])
-           return false;
-       }
-   }
+   if (LangOpts.ObjCAutoRefCount && 
+       !Context.FunctionTypesMatchOnNSConsumedAttrs(FromFunctionType, 
+                                                    ToFunctionType))
+     return false;
    
    ConvertedType = ToType;
    return true;
diff --git a/test/SemaObjC/arc-nsconsumed-errors.m b/test/SemaObjC/arc-nsconsumed-errors.m
new file mode 100644
index 0000000..6e10fde
--- /dev/null
+++ b/test/SemaObjC/arc-nsconsumed-errors.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// rdar://10187884
+
+typedef void (^blk)(id arg1, __attribute((ns_consumed)) id arg2);
+typedef void (^blk1)(__attribute((ns_consumed))id arg1, __attribute((ns_consumed)) id arg2);
+blk a = ^void (__attribute((ns_consumed)) id arg1, __attribute((ns_consumed)) id arg2){}; // expected-error {{incompatible block pointer types initializing}}
+
+blk b = ^void (id arg1, __attribute((ns_consumed)) id arg2){};
+
+blk c = ^void (__attribute((ns_consumed)) id arg1, __attribute((ns_consumed)) id arg2){}; // expected-error {{incompatible block pointer types initializing}}
+
+blk d = ^void (id arg1, id arg2) {}; // expected-error {{incompatible block pointer types initializing}}
+
+blk1 a1 = ^void (__attribute((ns_consumed)) id arg1, id arg2){}; // expected-error {{incompatible block pointer types initializing}}
+
+blk1 b2 = ^void (id arg1, __attribute((ns_consumed)) id arg2){}; // expected-error {{incompatible block pointer types initializing}}
+
+blk1 c3 = ^void (__attribute((ns_consumed)) id arg1, __attribute((ns_consumed)) id arg2){};
+
+blk1 d4 = ^void (id arg1, id arg2) {}; // expected-error {{incompatible block pointer types initializing}}