[cfe-commits] r61255 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaOverload.cpp test/SemaObjCXX/overload.mm

Douglas Gregor dgregor at apple.com
Fri Dec 19 11:13:17 PST 2008


Author: dgregor
Date: Fri Dec 19 13:13:09 2008
New Revision: 61255

URL: http://llvm.org/viewvc/llvm-project?rev=61255&view=rev
Log:
Support more implicit conversions for Objective-C types. Addresses <rdar://problem/6458293>.

Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaObjCXX/overload.mm

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61255&r1=61254&r2=61255&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Dec 19 13:13:09 2008
@@ -383,6 +383,8 @@
   bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
   bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
                            QualType& ConvertedType, bool &IncompatibleObjC);
+  bool isObjCPointerConversion(QualType FromType, QualType ToType,
+                               QualType& ConvertedType, bool &IncompatibleObjC);
   bool CheckPointerConversion(Expr *From, QualType ToType);
   bool IsQualificationConversion(QualType FromType, QualType ToType);
   bool IsUserDefinedConversion(Expr *From, QualType ToType, 

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=61255&r1=61254&r2=61255&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Dec 19 13:13:09 2008
@@ -763,6 +763,8 @@
                                bool &IncompatibleObjC)
 {
   IncompatibleObjC = false;
+  if (isObjCPointerConversion(FromType, ToType, ConvertedType, IncompatibleObjC))
+    return true;
 
   // Blocks: Block pointers can be converted to void*.
   if (FromType->isBlockPointerType() && ToType->isPointerType() &&
@@ -777,13 +779,6 @@
     return true;
   }
 
-  // Conversions with Objective-C's id<...>.
-  if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) &&
-      ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
-    ConvertedType = ToType;
-    return true;
-  }
-
   const PointerType* ToTypePtr = ToType->getAsPointerType();
   if (!ToTypePtr)
     return false;
@@ -805,7 +800,8 @@
   // An rvalue of type "pointer to cv T," where T is an object type,
   // can be converted to an rvalue of type "pointer to cv void" (C++
   // 4.10p2).
-  if (FromPointeeType->isIncompleteOrObjectType() && ToPointeeType->isVoidType()) {
+  if (FromPointeeType->isIncompleteOrObjectType() && 
+      ToPointeeType->isVoidType()) {
     ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, 
                                                        ToPointeeType,
                                                        ToType, Context);
@@ -833,6 +829,37 @@
     return true;
   }
 
+  return false;
+}
+
+/// isObjCPointerConversion - Determines whether this is an
+/// Objective-C pointer conversion. Subroutine of IsPointerConversion,
+/// with the same arguments and return values.
+bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, 
+                                   QualType& ConvertedType,
+                                   bool &IncompatibleObjC) {
+  if (!getLangOptions().ObjC1)
+    return false;
+
+  // Conversions with Objective-C's id<...>.
+  if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) &&
+      ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
+    ConvertedType = ToType;
+    return true;
+  }
+
+  const PointerType* ToTypePtr = ToType->getAsPointerType();
+  if (!ToTypePtr)
+    return false;
+
+  // Beyond this point, both types need to be pointers.
+  const PointerType *FromTypePtr = FromType->getAsPointerType();
+  if (!FromTypePtr)
+    return false;
+
+  QualType FromPointeeType = FromTypePtr->getPointeeType();
+  QualType ToPointeeType = ToTypePtr->getPointeeType();
+
   // Objective C++: We're able to convert from a pointer to an
   // interface to a pointer to a different interface.
   const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType();
@@ -877,7 +904,81 @@
     return true;
   }
 
-  return false;
+  // If we have pointers to pointers, recursively check whether this
+  // is an Objective-C conversion.
+  if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() &&
+      isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
+                              IncompatibleObjC)) {
+    // We always complain about this conversion.
+    IncompatibleObjC = true;
+    ConvertedType = ToType;
+    return true;
+  }
+
+  // If we have pointers to functions, check whether the only
+  // differences in the argument and result types are in Objective-C
+  // pointer conversions. If so, we permit the conversion (but
+  // complain about it).
+  const FunctionTypeProto *FromFunctionType 
+    = FromPointeeType->getAsFunctionTypeProto();
+  const FunctionTypeProto *ToFunctionType
+    = ToPointeeType->getAsFunctionTypeProto();
+  if (FromFunctionType && ToFunctionType) {
+    // If the function types are exactly the same, this isn't an
+    // Objective-C pointer conversion.
+    if (Context.getCanonicalType(FromPointeeType)
+          == Context.getCanonicalType(ToPointeeType))
+      return false;
+
+    // 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 HasObjCConversion = false;
+    if (Context.getCanonicalType(FromFunctionType->getResultType())
+          == Context.getCanonicalType(ToFunctionType->getResultType())) {
+      // Okay, the types match exactly. Nothing to do.
+    } else if (isObjCPointerConversion(FromFunctionType->getResultType(),
+                                       ToFunctionType->getResultType(),
+                                       ConvertedType, IncompatibleObjC)) {
+      // Okay, we have an Objective-C pointer conversion.
+      HasObjCConversion = true;
+    } else {
+      // Function types are too different. Abort.
+      return false;
+    }
+     
+    // Check argument types.
+    for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
+         ArgIdx != NumArgs; ++ArgIdx) {
+      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(FromArgType, ToArgType,
+                                         ConvertedType, IncompatibleObjC)) {
+        // Okay, we have an Objective-C pointer conversion.
+        HasObjCConversion = true;
+      } else {
+        // Argument types are too different. Abort.
+        return false;
+      }
+    }
+
+    if (HasObjCConversion) {
+      // We had an Objective-C conversion. Allow this pointer
+      // conversion, but complain about it.
+      ConvertedType = ToType;
+      IncompatibleObjC = true;
+      return true;
+    }
+  }
+
+  return false;  
 }
 
 /// CheckPointerConversion - Check the pointer conversion from the

Modified: cfe/trunk/test/SemaObjCXX/overload.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/overload.mm?rev=61255&r1=61254&r2=61255&view=diff

==============================================================================
--- cfe/trunk/test/SemaObjCXX/overload.mm (original)
+++ cfe/trunk/test/SemaObjCXX/overload.mm Fri Dec 19 13:13:09 2008
@@ -45,9 +45,12 @@
   //  int& i3 = h(b); FIXME: we match GCC here, but shouldn't this work?
 }
 
-void downcast_test(A* a) {
+void downcast_test(A* a, A** ap) {
   B* b = a; // expected-warning{{incompatible pointer types initializing 'B *', expected 'A *'}}
   b = a;  // expected-warning{{incompatible pointer types assigning 'B *', expected 'A *'}}
+
+  B** bp = ap; // expected-warning{{incompatible pointer types initializing 'B **', expected 'A **'}}
+  bp = ap; // expected-warning{{incompatible pointer types assigning 'B **', expected 'A **'}}
 }
 
 int& cv(A*);
@@ -73,3 +76,15 @@
   int& i2 = qualid(b);
   float& f1 = qualid(c);
 }
+
+
+ at class NSException;
+typedef struct {
+    void (*throw_exc)(id);
+}
+objc_exception_functions_t;
+
+void (*_NSExceptionRaiser(void))(NSException *) {
+    objc_exception_functions_t exc_funcs;
+    return exc_funcs.throw_exc; // expected-warning{{incompatible pointer types returning 'void (*)(NSException *)', expected 'void (*)(id)'}}
+}





More information about the cfe-commits mailing list