[cfe-commits] r125445 - in /cfe/trunk: include/clang/Sema/Overload.h include/clang/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp test/CodeGenObjCXX/blocks.mm test/SemaCXX/block-call.cpp test/SemaObjCXX/blocks.mm

Fariborz Jahanian fjahanian at apple.com
Sat Feb 12 11:07:46 PST 2011


Author: fjahanian
Date: Sat Feb 12 13:07:46 2011
New Revision: 125445

URL: http://llvm.org/viewvc/llvm-project?rev=125445&view=rev
Log:
Implement objective-c++'s block pointer type matching involving
types which are contravariance in argument types and covariance
in return types. // rdar://8979379.

Added:
    cfe/trunk/test/CodeGenObjCXX/blocks.mm
    cfe/trunk/test/SemaCXX/block-call.cpp
Modified:
    cfe/trunk/include/clang/Sema/Overload.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaObjCXX/blocks.mm

Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=125445&r1=125444&r2=125445&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Sat Feb 12 13:07:46 2011
@@ -75,6 +75,7 @@
     ICK_Vector_Conversion,     ///< Vector conversions
     ICK_Vector_Splat,          ///< A vector splat from an arithmetic type
     ICK_Complex_Real,          ///< Complex-real conversions (C99 6.3.1.7)
+    ICK_Block_Pointer_Conversion,    ///< Block Pointer conversions 
     ICK_Num_Conversion_Kinds   ///< The number of conversion kinds
   };
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=125445&r1=125444&r2=125445&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Feb 12 13:07:46 2011
@@ -1019,6 +1019,8 @@
                            QualType& ConvertedType, bool &IncompatibleObjC);
   bool isObjCPointerConversion(QualType FromType, QualType ToType,
                                QualType& ConvertedType, bool &IncompatibleObjC);
+  bool IsBlockPointerConversion(QualType FromType, QualType ToType,
+                                QualType& ConvertedType);
   bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType, 
                                 const FunctionProtoType *NewType);
   

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=125445&r1=125444&r2=125445&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sat Feb 12 13:07:46 2011
@@ -2199,7 +2199,12 @@
       }
     }
     break;
-
+  
+  case ICK_Block_Pointer_Conversion: {
+      ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue);
+      break;
+    }
+      
   case ICK_Lvalue_To_Rvalue:
   case ICK_Array_To_Pointer:
   case ICK_Function_To_Pointer:

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=125445&r1=125444&r2=125445&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Feb 12 13:07:46 2011
@@ -1166,6 +1166,8 @@
     // Floating-integral conversions (C++ 4.9).
     SCS.Second = ICK_Floating_Integral;
     FromType = ToType.getUnqualifiedType();
+  } else if (S.IsBlockPointerConversion(FromType, ToType, FromType)) {
+               SCS.Second = ICK_Block_Pointer_Conversion;
   } else if (S.IsPointerConversion(From, FromType, ToType, InOverloadResolution,
                                    FromType, IncompatibleObjC)) {
     // Pointer conversions (C++ 4.10).
@@ -1782,6 +1784,92 @@
   return false;
 }
 
+bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
+                                    QualType& ConvertedType) {
+  QualType ToPointeeType;
+  if (const BlockPointerType *ToBlockPtr =
+        ToType->getAs<BlockPointerType>())
+    ToPointeeType = ToBlockPtr->getPointeeType();
+  else
+    return false;
+  
+  QualType FromPointeeType;
+  if (const BlockPointerType *FromBlockPtr =
+      FromType->getAs<BlockPointerType>())
+    FromPointeeType = FromBlockPtr->getPointeeType();
+  else
+    return false;
+  // We have pointer to blocks, check whether the only
+  // differences in the argument and result types are in Objective-C
+  // pointer conversions. If so, we permit the conversion.
+  
+  const FunctionProtoType *FromFunctionType
+    = FromPointeeType->getAs<FunctionProtoType>();
+  const FunctionProtoType *ToFunctionType
+    = ToPointeeType->getAs<FunctionProtoType>();
+  
+  if (FromFunctionType && ToFunctionType) {
+    if (Context.getCanonicalType(FromPointeeType)
+          == Context.getCanonicalType(ToPointeeType))
+      return true;
+    
+    // Perform the quick checks that will tell us whether these
+    // function types are obviously different.
+    if (FromFunctionType->getNumArgs() != ToFunctionType->getNumArgs() ||
+        FromFunctionType->isVariadic() != ToFunctionType->isVariadic() ||
+        FromFunctionType->getTypeQuals() != ToFunctionType->getTypeQuals())
+      return false;
+    
+    bool IncompatibleObjC = false;
+    if (Context.getCanonicalType(FromFunctionType->getResultType())
+          == Context.getCanonicalType(ToFunctionType->getResultType())) {
+      // Okay, the types match exactly. Nothing to do.
+    } else {
+      QualType RHS = FromFunctionType->getResultType();
+      QualType CanRHS = Context.getCanonicalType(RHS);
+      QualType LHS = ToFunctionType->getResultType();
+      QualType CanLHS = Context.getCanonicalType(LHS);
+      if (!CanRHS->isRecordType() &&
+          !CanRHS.hasQualifiers() && CanLHS.hasQualifiers())
+        CanLHS = CanLHS.getUnqualifiedType();
+
+      if (Context.getCanonicalType(CanRHS)
+          == Context.getCanonicalType(CanLHS)) {
+        // OK exact match.
+      } else if (isObjCPointerConversion(CanRHS, CanLHS,
+                                  ConvertedType, IncompatibleObjC)) {
+      if (IncompatibleObjC)
+        return false;
+      // Okay, we have an Objective-C pointer conversion.
+      }
+      else
+        return false;
+    }
+    
+    // Check argument types.
+    for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
+         ArgIdx != NumArgs; ++ArgIdx) {
+      IncompatibleObjC = false;
+      QualType FromArgType = FromFunctionType->getArgType(ArgIdx);
+      QualType ToArgType = ToFunctionType->getArgType(ArgIdx);
+      if (Context.getCanonicalType(FromArgType)
+            == Context.getCanonicalType(ToArgType)) {
+        // Okay, the types match exactly. Nothing to do.
+      } else if (isObjCPointerConversion(ToArgType, FromArgType,
+                                         ConvertedType, IncompatibleObjC)) {
+        if (IncompatibleObjC)
+          return false;
+        // Okay, we have an Objective-C pointer conversion.
+      } else
+        // Argument types are too different. Abort.
+        return false;
+    }
+    ConvertedType = ToType;
+    return true;
+  }
+  return false;
+}
+
 /// FunctionArgTypesAreEqual - This routine checks two function proto types
 /// for equlity of their argument types. Caller has already checked that
 /// they have same number of arguments. This routine assumes that Objective-C

Added: cfe/trunk/test/CodeGenObjCXX/blocks.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/blocks.mm?rev=125445&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/blocks.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/blocks.mm Sat Feb 12 13:07:46 2011
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin %s
+// rdar://8979379
+
+ at interface A
+ at end
+
+ at interface B : A
+ at end
+
+void f(int (^bl)(B* b));
+
+// Test1
+void g() {
+  f(^(A* a) { return 0; });
+}
+
+// Test2
+void g1() {
+  int (^bl)(B* b) = ^(A* a) { return 0; };
+}
+
+// Test3
+ at protocol NSObject;
+
+void bar(id(^)(void));
+
+void foo(id <NSObject>(^objectCreationBlock)(void)) {
+    return bar(objectCreationBlock);
+}
+

Added: cfe/trunk/test/SemaCXX/block-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/block-call.cpp?rev=125445&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/block-call.cpp (added)
+++ cfe/trunk/test/SemaCXX/block-call.cpp Sat Feb 12 13:07:46 2011
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s -fblocks
+
+int (*FP)();
+int (^IFP) ();
+int (^II) (int);
+int main() {
+  int (*FPL) (int) = FP; // expected-error {{cannot initialize a variable of type 'int (*)(int)' with an lvalue of type 'int (*)()'}} 
+
+  // For Blocks, the ASTContext::typesAreBlockCompatible() makes sure this is an error.
+  int (^PFR) (int) = IFP; // expected-error {{cannot initialize a variable of type 'int (^)(int)' with an lvalue of type 'int (^)()'}}
+  PFR = II;       // OK
+
+  int (^IFP) () = PFR; // OK
+
+
+  const int (^CIC) () = IFP; // OK -  initializing 'const int (^)()' with an expression of type 'int (^)()'}}
+
+  const int (^CICC) () = CIC;
+
+
+  int * const (^IPCC) () = 0;
+
+  int * const (^IPCC1) () = IPCC;
+
+  int * (^IPCC2) () = IPCC;       // expected-error  {{cannot initialize a variable of type 'int *(^)()' with an lvalue of type 'int *const (^)()'}}
+
+  int (^IPCC3) (const int) = PFR;
+
+  int (^IPCC4) (int, char (^CArg) (double));
+
+  int (^IPCC5) (int, char (^CArg) (double)) = IPCC4;
+
+  int (^IPCC6) (int, char (^CArg) (float))  = IPCC4; // expected-error {{cannot initialize a variable of type 'int (^)(int, char (^)(float))' with an lvalue of type}}
+
+  IPCC2 = 0;
+  IPCC2 = 1; 
+  int (^x)() = 0;
+  int (^y)() = 3;   // expected-error {{cannot initialize a variable of type 'int (^)()' with an rvalue of type 'int'}}
+  int a = 1;
+  int (^z)() = a+4;   // expected-error {{cannot initialize a variable of type 'int (^)()' with an rvalue of type 'int'}}
+}
+
+int blah() {
+  int (^IFP) (float);
+  char (^PCP)(double, double, char);
+
+  IFP(1.0);
+  IFP (1.0, 2.0); // expected-error {{too many arguments to block call}}
+
+  char ch = PCP(1.0, 2.0, 'a');
+  return PCP(1.0, 2.0);   // expected-error {{too few arguments to block}}
+}

Modified: cfe/trunk/test/SemaObjCXX/blocks.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/blocks.mm?rev=125445&r1=125444&r2=125445&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/blocks.mm (original)
+++ cfe/trunk/test/SemaObjCXX/blocks.mm Sat Feb 12 13:07:46 2011
@@ -3,7 +3,7 @@
 
 void bar(id(^)(void));
 void foo(id <NSObject>(^objectCreationBlock)(void)) {
-    return bar(objectCreationBlock); // expected-warning{{incompatible pointer types passing 'id<NSObject> (^)()' to parameter of type 'id (^)()'}}
+    return bar(objectCreationBlock); // OK
 }
 
 void bar2(id(*)(void));
@@ -104,3 +104,17 @@
     X<N> xN = ^() { return X<N>(); }();
   }
 }
+
+// rdar://8979379
+
+ at interface A
+ at end
+
+ at interface B : A
+ at end
+
+void f(int (^bl)(A* a)); // expected-note {{candidate function not viable: no known conversion from 'int (^)(B *)' to 'int (^)(A *)' for 1st argument}}
+
+void g() {
+  f(^(B* b) { return 0; }); // expected-error {{no matching function for call to 'f'}}
+}





More information about the cfe-commits mailing list