Add type checking for blocks.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55767 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 2acdfac..b84b958 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1767,6 +1767,52 @@
 //                        Type Compatibility Testing
 //===----------------------------------------------------------------------===//
 
+/// typesAreBlockCompatible - This routine is called when comparing two
+/// closure types. Types must be strictly compatible here.
+bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) {
+  if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers())
+    return false;
+  
+  QualType lcanon = getCanonicalType(lhs);
+  QualType rcanon = getCanonicalType(rhs);
+  
+  // If two types are identical, they are are compatible
+  if (lcanon == rcanon)
+    return true;
+  if (isa<FunctionType>(lcanon) && isa<FunctionType>(rcanon)) {
+    const FunctionType *lbase = cast<FunctionType>(lcanon);
+    const FunctionType *rbase = cast<FunctionType>(rcanon);
+    
+    // First check the return types.
+    if (!typesAreBlockCompatible(lbase->getResultType(),rbase->getResultType()))
+      return false;
+
+    // Return types matched, now check the argument types.
+    const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
+    const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
+        
+    if (lproto && rproto) { // two C99 style function prototypes
+      unsigned lproto_nargs = lproto->getNumArgs();
+      unsigned rproto_nargs = rproto->getNumArgs();
+      
+      if (lproto_nargs != rproto_nargs)
+        return false;
+      
+      if (lproto->isVariadic() || rproto->isVariadic())
+        return false;
+
+      // The use of ellipsis agree...now check the argument types.
+      for (unsigned i = 0; i < lproto_nargs; i++)
+        if (!typesAreBlockCompatible(lproto->getArgType(i), 
+                                     rproto->getArgType(i)))
+          return false;
+      return true;
+    }
+    return (!lproto && !rproto); // two K&R style function decls match.
+  }
+  return false;
+}
+
 /// areCompatVectorTypes - Return true if the two specified vector types are 
 /// compatible.
 static bool areCompatVectorTypes(const VectorType *LHS,