[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