Allow reference binding of a reference of Objective-C object type to
an lvalue of another, compatible Objective-C object type (e.g., a
subclass). Introduce a new initialization sequence step kind to
describe this binding, along with a new cast kind. Fixes PR7741.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110513 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 22e1ebf..2c16c07 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -4560,6 +4560,12 @@
          canAssignObjCInterfaces(RHSOPT, LHSOPT);
 }
 
+bool ASTContext::canBindObjCObjectType(QualType To, QualType From) {
+  return canAssignObjCInterfaces(
+                getObjCObjectPointerType(To)->getAs<ObjCObjectPointerType>(),
+                getObjCObjectPointerType(From)->getAs<ObjCObjectPointerType>());
+}
+
 /// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
 /// both shall have the identically qualified version of a compatible type.
 /// C99 6.2.7p1: Two types have compatible types if their types are the
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index d85162a..e40fc79 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -717,6 +717,8 @@
     return "AnyPointerToObjCPointerCast";
   case CastExpr::CK_AnyPointerToBlockPointerCast:
     return "AnyPointerToBlockPointerCast";
+  case CastExpr::CK_ObjCObjectLValueCast:
+    return "ObjCObjectLValueCast";
   }
 
   assert(0 && "Unhandled cast kind!");
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index ccb836f..4c1838f 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -2514,7 +2514,8 @@
   case CastExpr::CK_AnyPointerToObjCPointerCast:
   case CastExpr::CK_AnyPointerToBlockPointerCast:
   case CastExpr::CK_DerivedToBase:
-  case CastExpr::CK_UncheckedDerivedToBase: {
+  case CastExpr::CK_UncheckedDerivedToBase:
+  case CastExpr::CK_ObjCObjectLValueCast: {
     // Delegate to SValuator to process.
     for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
       ExplodedNode* N = *I;
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 9424776..e2ccf55 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -1851,6 +1851,13 @@
                                            ConvertType(CE->getTypeAsWritten()));
     return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
   }
+  case CastExpr::CK_ObjCObjectLValueCast: {
+    LValue LV = EmitLValue(E->getSubExpr());
+    QualType ToType = getContext().getLValueReferenceType(E->getType());
+    llvm::Value *V = Builder.CreateBitCast(LV.getAddress(), 
+                                           ConvertType(ToType));
+    return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+  }
   }
   
   llvm_unreachable("Unhandled lvalue cast kind?");
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index dbafd2b..c9e4dbd 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -925,7 +925,8 @@
     //assert(0 && "Unknown cast kind!");
     break;
 
-  case CastExpr::CK_LValueBitCast: {
+  case CastExpr::CK_LValueBitCast: 
+  case CastExpr::CK_ObjCObjectLValueCast: {
     Value *V = EmitLValue(E).getAddress();
     V = Builder.CreateBitCast(V, 
                           ConvertType(CGF.getContext().getPointerType(DestTy)));
@@ -1044,7 +1045,10 @@
     return Builder.CreatePtrToInt(Src, ConvertType(DestTy));
   }
   case CastExpr::CK_ToVoid: {
-    CGF.EmitAnyExpr(E, 0, false, true);
+    if (E->Classify(CGF.getContext()).isGLValue())
+      CGF.EmitLValue(E);
+    else
+      CGF.EmitAnyExpr(E, 0, false, true);
     return 0;
   }
   case CastExpr::CK_VectorSplat: {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3570a77..d22714a 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -4517,7 +4517,8 @@
 
   ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc,
                                                       QualType T1, QualType T2,
-                                                      bool& DerivedToBase);
+                                                      bool &DerivedToBase,
+                                                      bool &ObjCConversion);
 
   /// CheckCastTypes - Check type constraints for casting between types under
   /// C semantics, or forward to CXXCheckCStyleCast in C++.
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index 5335266..4ee20a1 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -646,9 +646,10 @@
   // this is the only cast possibility, so we issue an error if we fail now.
   // FIXME: Should allow casting away constness if CStyle.
   bool DerivedToBase;
+  bool ObjCConversion;
   if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),
                                         SrcExpr->getType(), R->getPointeeType(),
-                                        DerivedToBase) <
+                                        DerivedToBase, ObjCConversion) <
         Sema::Ref_Compatible_With_Added_Qualification) {
     msg = diag::err_bad_lvalue_to_rvalue_cast;
     return TC_Failed;
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 5ffb648..98a3a03 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2035,6 +2035,7 @@
   case SK_ZeroInitialization:
   case SK_CAssignment:
   case SK_StringInit:
+  case SK_ObjCObjectConversion:
     break;
     
   case SK_ConversionSequence:
@@ -2201,6 +2202,13 @@
   Steps.push_back(S);
 }
 
+void InitializationSequence::AddObjCObjectConversionStep(QualType T) {
+  Step S;
+  S.Kind = SK_ObjCObjectConversion;
+  S.Type = T;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::SetOverloadFailure(FailureKind Failure, 
                                                 OverloadingResult Result) {
   SequenceKind = FailedSequence;
@@ -2275,10 +2283,13 @@
   QualType T2 = cv2T2.getUnqualifiedType();
 
   bool DerivedToBase;
+  bool ObjCConversion;
   assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), 
-                                         T1, T2, DerivedToBase) &&
+                                         T1, T2, DerivedToBase,
+                                         ObjCConversion) &&
          "Must have incompatible references when binding via conversion");
   (void)DerivedToBase;
+  (void)ObjCConversion;
 
   // Build the candidate set directly in the initialization sequence
   // structure, so that it will persist if we fail.
@@ -2400,10 +2411,11 @@
         ImplicitCastExpr::LValue : ImplicitCastExpr::XValue;
 
   bool NewDerivedToBase = false;
+  bool NewObjCConversion = false;
   Sema::ReferenceCompareResult NewRefRelationship
     = S.CompareReferenceRelationship(DeclLoc, T1, 
                                      T2.getNonLValueExprType(S.Context),
-                                     NewDerivedToBase);
+                                     NewDerivedToBase, NewObjCConversion);
   if (NewRefRelationship == Sema::Ref_Incompatible) {
     // If the type we've converted to is not reference-related to the
     // type we're looking for, then there is another conversion step
@@ -2418,8 +2430,12 @@
     Sequence.AddDerivedToBaseCastStep(
                                 S.Context.getQualifiedType(T1,
                                   T2.getNonReferenceType().getQualifiers()), 
-                                  Category);
-  
+                                      Category);
+  else if (NewObjCConversion)
+    Sequence.AddObjCObjectConversionStep(
+                                S.Context.getQualifiedType(T1,
+                                  T2.getNonReferenceType().getQualifiers()));
+
   if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers())
     Sequence.AddQualificationConversionStep(cv1T1, Category);
   
@@ -2467,9 +2483,11 @@
   bool isLValueRef = DestType->isLValueReferenceType();
   bool isRValueRef = !isLValueRef;
   bool DerivedToBase = false;
+  bool ObjCConversion = false;
   Expr::Classification InitCategory = Initializer->Classify(S.Context);
   Sema::ReferenceCompareResult RefRelationship
-    = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase);
+    = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
+                                     ObjCConversion);
 
   // C++0x [dcl.init.ref]p5:
   //   A reference to type "cv1 T1" is initialized by an expression of type 
@@ -2497,6 +2515,10 @@
         Sequence.AddDerivedToBaseCastStep(
                          S.Context.getQualifiedType(T1, T2Quals), 
                          ImplicitCastExpr::LValue);
+      else if (ObjCConversion)
+        Sequence.AddObjCObjectConversionStep(
+                                     S.Context.getQualifiedType(T1, T2Quals));
+
       if (T1Quals != T2Quals)
         Sequence.AddQualificationConversionStep(cv1T1,ImplicitCastExpr::LValue);
       bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() &&
@@ -2577,6 +2599,10 @@
                          S.Context.getQualifiedType(T1, T2Quals), 
                          isXValue ? ImplicitCastExpr::XValue
                                   : ImplicitCastExpr::RValue);
+      else if (ObjCConversion)
+        Sequence.AddObjCObjectConversionStep(
+                                     S.Context.getQualifiedType(T1, T2Quals));
+
       if (T1Quals != T2Quals)
         Sequence.AddQualificationConversionStep(cv1T1,
                      isXValue ? ImplicitCastExpr::XValue
@@ -3546,6 +3572,7 @@
   case SK_ListInitialization:
   case SK_CAssignment:
   case SK_StringInit:
+  case SK_ObjCObjectConversion:
     assert(Args.size() == 1);
     CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain());
     if (CurInit.isInvalid())
@@ -3926,6 +3953,14 @@
       CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, S);
       break;
     }
+
+    case SK_ObjCObjectConversion:
+      S.ImpCastExprToType(CurInitExpr, Step->Type, 
+                          CastExpr::CK_ObjCObjectLValueCast,
+                          S.CastCategory(CurInitExpr));
+      CurInit.release();
+      CurInit = S.Owned(CurInitExpr);
+      break;
     }
   }
   
@@ -4392,6 +4427,10 @@
     case SK_StringInit:
       OS << "string initialization";
       break;
+
+    case SK_ObjCObjectConversion:
+      OS << "Objective-C object conversion";
+      break;
     }
   }
 }
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 52481bb..db0b7c3 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -479,7 +479,10 @@
     /// \brief C assignment
     SK_CAssignment,
     /// \brief Initialization by string
-    SK_StringInit
+    SK_StringInit,
+    /// \brief An initialization that "converts" an Objective-C object
+    /// (not a point to an object) to another Objective-C object type.
+    SK_ObjCObjectConversion
   };
   
   /// \brief A single step in the initialization sequence.
@@ -737,6 +740,10 @@
   /// \brief Add a string init step.
   void AddStringInitStep(QualType T);
 
+  /// \brief Add an Objective-C object conversion step, which is
+  /// always a no-op.
+  void AddObjCObjectConversionStep(QualType T);
+
   /// \brief Note that this initialization sequence failed.
   void SetFailed(FailureKind Failure) {
     SequenceKind = FailedSequence;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 27e6c2c..d3855a5 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -2575,7 +2575,8 @@
 Sema::ReferenceCompareResult
 Sema::CompareReferenceRelationship(SourceLocation Loc,
                                    QualType OrigT1, QualType OrigT2,
-                                   bool& DerivedToBase) {
+                                   bool &DerivedToBase,
+                                   bool &ObjCConversion) {
   assert(!OrigT1->isReferenceType() &&
     "T1 must be the pointee type of the reference type");
   assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -2590,11 +2591,17 @@
   //   Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
   //   reference-related to "cv2 T2" if T1 is the same type as T2, or
   //   T1 is a base class of T2.
-  if (UnqualT1 == UnqualT2)
-    DerivedToBase = false;
-  else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
+  DerivedToBase = false;
+  ObjCConversion = false;
+  if (UnqualT1 == UnqualT2) {
+    // Nothing to do.
+  } else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
            IsDerivedFrom(UnqualT2, UnqualT1))
     DerivedToBase = true;
+  else if (UnqualT1->isObjCObjectOrInterfaceType() &&
+           UnqualT2->isObjCObjectOrInterfaceType() &&
+           Context.canBindObjCObjectType(UnqualT1, UnqualT2))
+    ObjCConversion = true;
   else
     return Ref_Incompatible;
 
@@ -2741,9 +2748,11 @@
   // Compute some basic properties of the types and the initializer.
   bool isRValRef = DeclType->isRValueReferenceType();
   bool DerivedToBase = false;
+  bool ObjCConversion = false;
   Expr::Classification InitCategory = Init->Classify(S.Context);
   Sema::ReferenceCompareResult RefRelationship
-    = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
+    = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase,
+                                     ObjCConversion);
 
 
   // C++0x [dcl.init.ref]p5:
@@ -2769,7 +2778,9 @@
       //   derived-to-base Conversion (13.3.3.1).
       ICS.setStandard();
       ICS.Standard.First = ICK_Identity;
-      ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+      ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
+                         : ObjCConversion? ICK_Compatible_Conversion
+                         : ICK_Identity;
       ICS.Standard.Third = ICK_Identity;
       ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
       ICS.Standard.setToType(0, T2);
@@ -2857,7 +2868,9 @@
       RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
     ICS.setStandard();
     ICS.Standard.First = ICK_Identity;
-    ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+    ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base 
+                        : ObjCConversion? ICK_Compatible_Conversion
+                        : ICK_Identity;
     ICS.Standard.Third = ICK_Identity;
     ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
     ICS.Standard.setToType(0, T2);