Implement the Objective-C 'instancetype' type, which is an alias of
'id' that can be used (only!) via a contextual keyword as the result
type of an Objective-C message send. 'instancetype' then gives the
method a related result type, which we have already been inferring for
a variety of methods (new, alloc, init, self, retain). Addresses
<rdar://problem/9267640>.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139275 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 3e657c7..8dfdeb4 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -148,8 +148,13 @@
         << ResultTypeRange;
     }
     
-    Diag(Overridden->getLocation(), diag::note_related_result_type_overridden)
-      << Overridden->getMethodFamily();
+    if (ObjCMethodFamily Family = Overridden->getMethodFamily())
+      Diag(Overridden->getLocation(), 
+           diag::note_related_result_type_overridden_family)
+        << Family;
+    else
+      Diag(Overridden->getLocation(), 
+           diag::note_related_result_type_overridden);
   }
   
   return false;
@@ -2261,16 +2266,22 @@
   return false;
 }
 
+namespace  {
+  /// \brief Describes the compatibility of a result type with its method.
+  enum ResultTypeCompatibilityKind {
+    RTC_Compatible,
+    RTC_Incompatible,
+    RTC_Unknown
+  };
+}
+
 /// \brief Check whether the declared result type of the given Objective-C
 /// method declaration is compatible with the method's class.
 ///
-static bool 
+static ResultTypeCompatibilityKind 
 CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
                                     ObjCInterfaceDecl *CurrentClass) {
   QualType ResultType = Method->getResultType();
-  SourceRange ResultTypeRange;
-  if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo())
-    ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
   
   // If an Objective-C method inherits its related result type, then its 
   // declared result type must be compatible with its own class type. The
@@ -2280,23 +2291,27 @@
     //   - it is id or qualified id, or
     if (ResultObjectType->isObjCIdType() ||
         ResultObjectType->isObjCQualifiedIdType())
-      return false;
+      return RTC_Compatible;
   
     if (CurrentClass) {
       if (ObjCInterfaceDecl *ResultClass 
                                       = ResultObjectType->getInterfaceDecl()) {
         //   - it is the same as the method's class type, or
         if (CurrentClass == ResultClass)
-          return false;
+          return RTC_Compatible;
         
         //   - it is a superclass of the method's class type
         if (ResultClass->isSuperClassOf(CurrentClass))
-          return false;
+          return RTC_Compatible;
       }      
+    } else {
+      // Any Objective-C pointer type might be acceptable for a protocol
+      // method; we just don't know.
+      return RTC_Unknown;
     }
   }
   
-  return true;
+  return RTC_Incompatible;
 }
 
 namespace {
@@ -2457,6 +2472,7 @@
   Decl *ClassDecl = cast<Decl>(OCD); 
   QualType resultDeclType;
 
+  bool HasRelatedResultType = false;
   TypeSourceInfo *ResultTInfo = 0;
   if (ReturnType) {
     resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo);
@@ -2468,6 +2484,8 @@
         << 0 << resultDeclType;
       return 0;
     }    
+    
+    HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType());
   } else { // get the type for "id".
     resultDeclType = Context.getObjCIdType();
     Diag(MethodLoc, diag::warn_missing_method_return_type)
@@ -2484,7 +2502,7 @@
                            MethodDeclKind == tok::objc_optional 
                              ? ObjCMethodDecl::Optional
                              : ObjCMethodDecl::Required,
-                           false);
+                           HasRelatedResultType);
 
   SmallVector<ParmVarDecl*, 16> Params;
 
@@ -2604,9 +2622,8 @@
       CurrentClass = CatImpl->getClassInterface();
   }
 
-  bool isRelatedResultTypeCompatible =
-    (getLangOptions().ObjCInferRelatedResultType &&
-     !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass));
+  ResultTypeCompatibilityKind RTC
+    = CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass);
 
   // Search for overridden methods and merge information down from them.
   OverrideSearch overrides(*this, ObjCMethod);
@@ -2615,7 +2632,7 @@
     ObjCMethodDecl *overridden = *i;
 
     // Propagate down the 'related result type' bit from overridden methods.
-    if (isRelatedResultTypeCompatible && overridden->hasRelatedResultType())
+    if (RTC != RTC_Incompatible && overridden->hasRelatedResultType())
       ObjCMethod->SetRelatedResultType();
 
     // Then merge the declarations.
@@ -2633,8 +2650,10 @@
   if (getLangOptions().ObjCAutoRefCount)
     ARCError = CheckARCMethodDecl(*this, ObjCMethod);
 
-  if (!ARCError && isRelatedResultTypeCompatible &&
-      !ObjCMethod->hasRelatedResultType()) {
+  // Infer the related result type when possible.
+  if (!ARCError && RTC == RTC_Compatible &&
+      !ObjCMethod->hasRelatedResultType() &&
+      LangOpts.ObjCInferRelatedResultType) {
     bool InferRelatedResultType = false;
     switch (ObjCMethod->getMethodFamily()) {
     case OMF_None: