[cfe-commits] r61246 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaObjCXX/overload.mm

Douglas Gregor dgregor at apple.com
Fri Dec 19 09:40:10 PST 2008


Author: dgregor
Date: Fri Dec 19 11:40:08 2008
New Revision: 61246

URL: http://llvm.org/viewvc/llvm-project?rev=61246&view=rev
Log:
Allow downcasts of pointers to Objective-C interfaces, with a
warning. This matches GCC's behavior and addresses
<rdar://problem/6458293>.


Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaOverload.h
    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=61246&r1=61245&r2=61246&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Dec 19 11:40:08 2008
@@ -382,7 +382,7 @@
   bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
   bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
   bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
-                           QualType& ConvertedType);
+                           QualType& ConvertedType, bool &IncompatibleObjC);
   bool CheckPointerConversion(Expr *From, QualType ToType);
   bool IsQualificationConversion(QualType FromType, QualType ToType);
   bool IsUserDefinedConversion(Expr *From, QualType ToType, 
@@ -1260,9 +1260,11 @@
 
   bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);
 
-  bool PerformImplicitConversion(Expr *&From, QualType ToType);
+  bool PerformImplicitConversion(Expr *&From, QualType ToType, 
+                                 const char *Flavor);
   bool PerformImplicitConversion(Expr *&From, QualType ToType,
-                                 const StandardConversionSequence& SCS);
+                                 const StandardConversionSequence& SCS,
+                                 const char *Flavor);
   
   /// the following "Check" methods will return a valid/converted QualType
   /// or a null QualType (indicating an error diagnostic was issued).

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Dec 19 11:40:08 2008
@@ -744,7 +744,10 @@
   // Get the type before calling CheckSingleAssignmentConstraints(), since
   // it can promote the expression.
   QualType InitType = Init->getType(); 
-  
+
+  if (getLangOptions().CPlusPlus)
+    return PerformCopyInitialization(Init, DeclType, "initializing");
+
   AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init);
   return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
                                   InitType, Init, "initializing");
@@ -843,7 +846,7 @@
       //      destination type.
       // FIXME: We're pretending to do copy elision here; return to
       // this when we have ASTs for such things.
-      if (!PerformImplicitConversion(Init, DeclType))
+      if (!PerformImplicitConversion(Init, DeclType, "initializing"))
         return false;
       
       return Diag(InitLoc, diag::err_typecheck_convert_incompatible)

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Dec 19 11:40:08 2008
@@ -1838,7 +1838,7 @@
     *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions);
     return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
   } else {
-    return PerformImplicitConversion(Init, T1);
+    return PerformImplicitConversion(Init, T1, "initializing");
   }
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Dec 19 11:40:08 2008
@@ -2138,7 +2138,8 @@
       // C++ 5.17p3: If the left operand is not of class type, the
       // expression is implicitly converted (C++ 4) to the
       // cv-unqualified type of the left operand.
-      if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType()))
+      if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(),
+                                    "assigning"))
         return Incompatible;
       else
         return Compatible;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Dec 19 11:40:08 2008
@@ -708,14 +708,16 @@
 /// PerformImplicitConversion - Perform an implicit conversion of the
 /// expression From to the type ToType. Returns true if there was an
 /// error, false otherwise. The expression From is replaced with the
-/// converted expression.
+/// converted expression. Flavor is the kind of conversion we're
+/// performing, used in the error message.
 bool 
-Sema::PerformImplicitConversion(Expr *&From, QualType ToType)
+Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
+                                const char *Flavor)
 {
   ImplicitConversionSequence ICS = TryImplicitConversion(From, ToType);
   switch (ICS.ConversionKind) {
   case ImplicitConversionSequence::StandardConversion:
-    if (PerformImplicitConversion(From, ToType, ICS.Standard))
+    if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor))
       return true;
     break;
 
@@ -742,10 +744,12 @@
 /// expression From to the type ToType by following the standard
 /// conversion sequence SCS. Returns true if there was an error, false
 /// otherwise. The expression From is replaced with the converted
-/// expression.
+/// expression. Flavor is the context in which we're performing this
+/// conversion, for use in error messages.
 bool 
 Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
-                                const StandardConversionSequence& SCS)
+                                const StandardConversionSequence& SCS,
+                                const char *Flavor)
 {
   // Overall FIXME: we are recomputing too many types here and doing
   // far too much extra work. What this means is that we need to keep
@@ -808,6 +812,14 @@
     break;
 
   case ICK_Pointer_Conversion:
+    if (SCS.IncompatibleObjC) {
+      // Diagnose incompatible Objective-C conversions
+      Diag(From->getSourceRange().getBegin(), 
+           diag::ext_typecheck_convert_incompatible_pointer)
+        << From->getType() << ToType << Flavor
+        << From->getSourceRange();
+    }
+
     if (CheckPointerConversion(From, ToType))
       return true;
     ImpCastExprToType(From, ToType);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Dec 19 11:40:08 2008
@@ -419,6 +419,7 @@
   // Standard conversions (C++ [conv])
   SCS.setAsIdentityConversion();
   SCS.Deprecated = false;
+  SCS.IncompatibleObjC = false;
   SCS.FromTypePtr = FromType.getAsOpaquePtr();
   SCS.CopyConstructor = 0;
 
@@ -494,6 +495,7 @@
   // point promotion, integral conversion, floating point conversion,
   // floating-integral conversion, pointer conversion,
   // pointer-to-member conversion, or boolean conversion (C++ 4p1).
+  bool IncompatibleObjC = false;
   if (Context.getCanonicalType(FromType).getUnqualifiedType() ==
       Context.getCanonicalType(ToType).getUnqualifiedType()) {
     // The unqualified versions of the types are the same: there's no
@@ -533,8 +535,10 @@
     FromType = ToType.getUnqualifiedType();
   }
   // Pointer conversions (C++ 4.10).
-  else if (IsPointerConversion(From, FromType, ToType, FromType)) {
+  else if (IsPointerConversion(From, FromType, ToType, FromType, 
+                               IncompatibleObjC)) {
     SCS.Second = ICK_Pointer_Conversion;
+    SCS.IncompatibleObjC = IncompatibleObjC;
   }
   // FIXME: Pointer to member conversions (4.11).
   // Boolean conversions (C++ 4.12).
@@ -751,10 +755,15 @@
 /// appropriate overloading rules for Objective-C, we may want to
 /// split the Objective-C checks into a different routine; however,
 /// GCC seems to consider all of these conversions to be pointer
-/// conversions, so for now they live here.
+/// conversions, so for now they live here. IncompatibleObjC will be
+/// set if the conversion is an allowed Objective-C conversion that
+/// should result in a warning.
 bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
-                               QualType& ConvertedType)
+                               QualType& ConvertedType,
+                               bool &IncompatibleObjC)
 {
+  IncompatibleObjC = false;
+
   // Blocks: Block pointers can be converted to void*.
   if (FromType->isBlockPointerType() && ToType->isPointerType() &&
       ToType->getAsPointerType()->getPointeeType()->isVoidType()) {
@@ -836,6 +845,18 @@
     return true;
   }
 
+  if (FromIface && ToIface && 
+      Context.canAssignObjCInterfaces(FromIface, ToIface)) {
+    // Okay: this is some kind of implicit downcast of Objective-C
+    // interfaces, which is permitted. However, we're going to
+    // complain about it.
+    IncompatibleObjC = true;
+    ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, 
+                                                       ToPointeeType,
+                                                       ToType, Context);
+    return true;
+  }
+
   // Objective C++: We're able to convert between "id" and a pointer
   // to any interface (in both directions).
   if ((FromIface && Context.isObjCIdType(ToPointeeType))
@@ -1533,7 +1554,7 @@
   if (ToType->isReferenceType())
     return CheckReferenceInit(From, ToType);
 
-  if (!PerformImplicitConversion(From, ToType))
+  if (!PerformImplicitConversion(From, ToType, Flavor))
     return false;
   
   return Diag(From->getSourceRange().getBegin(),

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Fri Dec 19 11:40:08 2008
@@ -98,6 +98,10 @@
     /// (C++ 4.2p2).
     bool Deprecated : 1;
 
+    /// IncompatibleObjC - Whether this is an Objective-C conversion
+    /// that we should warn about (if we actually use it).
+    bool IncompatibleObjC : 1;
+
     /// ReferenceBinding - True when this is a reference binding 
     /// (C++ [over.ics.ref]).
     bool ReferenceBinding : 1;

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

==============================================================================
--- cfe/trunk/test/SemaObjCXX/overload.mm (original)
+++ cfe/trunk/test/SemaObjCXX/overload.mm Fri Dec 19 11:40:08 2008
@@ -45,6 +45,11 @@
   //  int& i3 = h(b); FIXME: we match GCC here, but shouldn't this work?
 }
 
+void downcast_test(A* a) {
+  B* b = a; // expected-warning{{incompatible pointer types initializing 'B *', expected 'A *'}}
+  b = a;  // expected-warning{{incompatible pointer types assigning 'B *', expected 'A *'}}
+}
+
 int& cv(A*);
 float& cv(const A*);
 int& cv2(void*);





More information about the cfe-commits mailing list