Automatic Reference Counting.

Language-design credit goes to a lot of people, but I particularly want
to single out Blaine Garst and Patrick Beard for their contributions.

Compiler implementation credit goes to Argyrios, Doug, Fariborz, and myself,
in no particular order.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133103 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index bfa2ef4..563de6f 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -16,14 +16,96 @@
 #include "clang/Sema/ExternalSemaSource.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "clang/AST/ASTConsumer.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
 #include "clang/Sema/DeclSpec.h"
 #include "llvm/ADT/DenseSet.h"
 
 using namespace clang;
 
+/// Check whether the given method, which must be in the 'init'
+/// family, is a valid member of that family.
+///
+/// \param receiverTypeIfCall - if null, check this as if declaring it;
+///   if non-null, check this as if making a call to it with the given
+///   receiver type
+///
+/// \return true to indicate that there was an error and appropriate
+///   actions were taken
+bool Sema::checkInitMethod(ObjCMethodDecl *method,
+                           QualType receiverTypeIfCall) {
+  if (method->isInvalidDecl()) return true;
+
+  // This castAs is safe: methods that don't return an object
+  // pointer won't be inferred as inits and will reject an explicit
+  // objc_method_family(init).
+
+  // We ignore protocols here.  Should we?  What about Class?
+
+  const ObjCObjectType *result = method->getResultType()
+    ->castAs<ObjCObjectPointerType>()->getObjectType();
+
+  if (result->isObjCId()) {
+    return false;
+  } else if (result->isObjCClass()) {
+    // fall through: always an error
+  } else {
+    ObjCInterfaceDecl *resultClass = result->getInterface();
+    assert(resultClass && "unexpected object type!");
+
+    // It's okay for the result type to still be a forward declaration
+    // if we're checking an interface declaration.
+    if (resultClass->isForwardDecl()) {
+      if (receiverTypeIfCall.isNull() &&
+          !isa<ObjCImplementationDecl>(method->getDeclContext()))
+        return false;
+
+    // Otherwise, we try to compare class types.
+    } else {
+      // If this method was declared in a protocol, we can't check
+      // anything unless we have a receiver type that's an interface.
+      const ObjCInterfaceDecl *receiverClass = 0;
+      if (isa<ObjCProtocolDecl>(method->getDeclContext())) {
+        if (receiverTypeIfCall.isNull())
+          return false;
+
+        receiverClass = receiverTypeIfCall->castAs<ObjCObjectPointerType>()
+          ->getInterfaceDecl();
+
+        // This can be null for calls to e.g. id<Foo>.
+        if (!receiverClass) return false;
+      } else {
+        receiverClass = method->getClassInterface();
+        assert(receiverClass && "method not associated with a class!");
+      }
+
+      // If either class is a subclass of the other, it's fine.
+      if (receiverClass->isSuperClassOf(resultClass) ||
+          resultClass->isSuperClassOf(receiverClass))
+        return false;
+    }
+  }
+
+  SourceLocation loc = method->getLocation();
+
+  // If we're in a system header, and this is not a call, just make
+  // the method unusable.
+  if (receiverTypeIfCall.isNull() && getSourceManager().isInSystemHeader(loc)) {
+    method->addAttr(new (Context) UnavailableAttr(loc, Context,
+                "init method returns a type unrelated to its receiver type"));
+    return true;
+  }
+
+  // Otherwise, it's an error.
+  Diag(loc, diag::err_arc_init_method_unrelated_result_type);
+  method->setInvalidDecl();
+  return true;
+}
+
 bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, 
                                    const ObjCMethodDecl *Overridden,
                                    bool IsImplementation) {
@@ -36,7 +118,7 @@
     QualType ResultType = NewMethod->getResultType();
     SourceRange ResultTypeRange;
     if (const TypeSourceInfo *ResultTypeInfo 
-        = NewMethod->getResultTypeSourceInfo())
+                                        = NewMethod->getResultTypeSourceInfo())
       ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
     
     // Figure out which class this method is part of, if any.
@@ -107,10 +189,10 @@
       if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
         return true;
     }
-    
+
     // Look through protocols.
     for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
-         IEnd = Class->protocol_end();
+                                           IEnd = Class->protocol_end();
          I != IEnd; ++I)
       if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
         return true;
@@ -123,7 +205,7 @@
   if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
     // Look through protocols.
     for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
-         IEnd = Category->protocol_end();
+                                           IEnd = Category->protocol_end();
          I != IEnd; ++I)
       if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
         return true;
@@ -134,7 +216,7 @@
   if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
     // Look through protocols.
     for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
-         IEnd = Protocol->protocol_end();
+                                           IEnd = Protocol->protocol_end();
          I != IEnd; ++I)
       if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
         return true;
@@ -149,13 +231,13 @@
                                     DeclContext *DC) {
   if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
     return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
-  
+
   if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
     return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
-  
+
   if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
     return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
-  
+
   if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
     return ::CheckObjCMethodOverrides(*this, NewMethod, 
                                       Impl->getClassInterface());
@@ -167,6 +249,50 @@
   return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
 }
 
+/// \brief Check a method declaration for compatibility with the Objective-C
+/// ARC conventions.
+static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
+  ObjCMethodFamily family = method->getMethodFamily();
+  switch (family) {
+  case OMF_None:
+  case OMF_dealloc:
+  case OMF_retain:
+  case OMF_release:
+  case OMF_autorelease:
+  case OMF_retainCount:
+  case OMF_self:
+    return false;
+
+  case OMF_init:
+    // If the method doesn't obey the init rules, don't bother annotating it.
+    if (S.checkInitMethod(method, QualType()))
+      return true;
+
+    method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(),
+                                                       S.Context));
+
+    // Don't add a second copy of this attribute, but otherwise don't
+    // let it be suppressed.
+    if (method->hasAttr<NSReturnsRetainedAttr>())
+      return false;
+    break;
+
+  case OMF_alloc:
+  case OMF_copy:
+  case OMF_mutableCopy:
+  case OMF_new:
+    if (method->hasAttr<NSReturnsRetainedAttr>() ||
+        method->hasAttr<NSReturnsNotRetainedAttr>() ||
+        method->hasAttr<NSReturnsAutoreleasedAttr>())
+      return false;
+    break;
+  }
+
+  method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
+                                                        S.Context));
+  return false;
+}
+
 static void DiagnoseObjCImplementedDeprecations(Sema &S,
                                                 NamedDecl *ND,
                                                 SourceLocation ImplLoc,
@@ -220,6 +346,30 @@
     if ((*PI)->getIdentifier())
       PushOnScopeChains(*PI, FnBodyScope);
   }
+
+  // In ARC, disallow definition of retain/release/autorelease/retainCount
+  if (getLangOptions().ObjCAutoRefCount) {
+    switch (MDecl->getMethodFamily()) {
+    case OMF_retain:
+    case OMF_retainCount:
+    case OMF_release:
+    case OMF_autorelease:
+      Diag(MDecl->getLocation(), diag::err_arc_illegal_method_def)
+        << MDecl->getSelector();
+      break;
+
+    case OMF_None:
+    case OMF_dealloc:
+    case OMF_alloc:
+    case OMF_init:
+    case OMF_mutableCopy:
+    case OMF_copy:
+    case OMF_new:
+    case OMF_self:
+      break;
+    }
+  }
+
   // Warn on implementating deprecated methods under 
   // -Wdeprecated-implementations flag.
   if (ObjCInterfaceDecl *IC = MDecl->getClassInterface())
@@ -1099,11 +1249,83 @@
   S.Diag(IfaceVar->getLocation(), diag::note_previous_definition)
     << getTypeRange(IfaceVar->getTypeSourceInfo());
 }
-                                     
+
+/// In ARC, check whether the conventional meanings of the two methods
+/// match.  If they don't, it's a hard error.
+static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
+                                      ObjCMethodDecl *decl) {
+  ObjCMethodFamily implFamily = impl->getMethodFamily();
+  ObjCMethodFamily declFamily = decl->getMethodFamily();
+  if (implFamily == declFamily) return false;
+
+  // Since conventions are sorted by selector, the only possibility is
+  // that the types differ enough to cause one selector or the other
+  // to fall out of the family.
+  assert(implFamily == OMF_None || declFamily == OMF_None);
+
+  // No further diagnostics required on invalid declarations.
+  if (impl->isInvalidDecl() || decl->isInvalidDecl()) return true;
+
+  const ObjCMethodDecl *unmatched = impl;
+  ObjCMethodFamily family = declFamily;
+  unsigned errorID = diag::err_arc_lost_method_convention;
+  unsigned noteID = diag::note_arc_lost_method_convention;
+  if (declFamily == OMF_None) {
+    unmatched = decl;
+    family = implFamily;
+    errorID = diag::err_arc_gained_method_convention;
+    noteID = diag::note_arc_gained_method_convention;
+  }
+
+  // Indexes into a %select clause in the diagnostic.
+  enum FamilySelector {
+    F_alloc, F_copy, F_mutableCopy = F_copy, F_init, F_new
+  };
+  FamilySelector familySelector = FamilySelector();
+
+  switch (family) {
+  case OMF_None: llvm_unreachable("logic error, no method convention");
+  case OMF_retain:
+  case OMF_release:
+  case OMF_autorelease:
+  case OMF_dealloc:
+  case OMF_retainCount:
+  case OMF_self:
+    // Mismatches for these methods don't change ownership
+    // conventions, so we don't care.
+    return false;
+
+  case OMF_init: familySelector = F_init; break;
+  case OMF_alloc: familySelector = F_alloc; break;
+  case OMF_copy: familySelector = F_copy; break;
+  case OMF_mutableCopy: familySelector = F_mutableCopy; break;
+  case OMF_new: familySelector = F_new; break;
+  }
+
+  enum ReasonSelector { R_NonObjectReturn, R_UnrelatedReturn };
+  ReasonSelector reasonSelector;
+
+  // The only reason these methods don't fall within their families is
+  // due to unusual result types.
+  if (unmatched->getResultType()->isObjCObjectPointerType()) {
+    reasonSelector = R_UnrelatedReturn;
+  } else {
+    reasonSelector = R_NonObjectReturn;
+  }
+
+  S.Diag(impl->getLocation(), errorID) << familySelector << reasonSelector;
+  S.Diag(decl->getLocation(), noteID) << familySelector << reasonSelector;
+
+  return true;
+}
 
 void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
                                        ObjCMethodDecl *MethodDecl,
                                        bool IsProtocolMethodDecl) {
+  if (getLangOptions().ObjCAutoRefCount &&
+      checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl))
+    return;
+
   CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, 
                             IsProtocolMethodDecl);
 
@@ -1430,48 +1652,82 @@
   return CDecl;
 }
 
+static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy,
+                       QualType leftQT, QualType rightQT) {
+  const Type *left =
+    Context.getCanonicalType(leftQT).getUnqualifiedType().getTypePtr();
+  const Type *right =
+    Context.getCanonicalType(rightQT).getUnqualifiedType().getTypePtr();
+
+  if (left == right) return true;
+
+  // If we're doing a strict match, the types have to match exactly.
+  if (strategy == Sema::MMS_strict) return false;
+
+  if (left->isIncompleteType() || right->isIncompleteType()) return false;
+
+  // Otherwise, use this absurdly complicated algorithm to try to
+  // validate the basic, low-level compatibility of the two types.
+
+  // As a minimum, require the sizes and alignments to match.
+  if (Context.getTypeInfo(left) != Context.getTypeInfo(right))
+    return false;
+
+  // Consider all the kinds of non-dependent canonical types:
+  // - functions and arrays aren't possible as return and parameter types
+  
+  // - vector types of equal size can be arbitrarily mixed
+  if (isa<VectorType>(left)) return isa<VectorType>(right);
+  if (isa<VectorType>(right)) return false;
+
+  // - references should only match references of identical type
+  // - structs, unions, and Objective-C objects must match exactly
+  // - everything else should be a scalar
+  if (!left->isScalarType() || !right->isScalarType())
+    return false;
+
+  // Make scalars agree in kind, except count bools as chars.
+  Type::ScalarTypeKind leftSK = left->getScalarTypeKind();
+  Type::ScalarTypeKind rightSK = right->getScalarTypeKind();
+  if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral;
+  if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral;
+
+  // Note that data member pointers and function member pointers don't
+  // intermix because of the size differences.
+
+  return (leftSK == rightSK);
+}
 
 /// MatchTwoMethodDeclarations - Checks that two methods have matching type and
 /// returns true, or false, accordingly.
 /// TODO: Handle protocol list; such as id<p1,p2> in type comparisons
-bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
-                                      const ObjCMethodDecl *PrevMethod,
-                                      bool matchBasedOnSizeAndAlignment,
-                                      bool matchBasedOnStrictEqulity) {
-  QualType T1 = Context.getCanonicalType(Method->getResultType());
-  QualType T2 = Context.getCanonicalType(PrevMethod->getResultType());
+bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
+                                      const ObjCMethodDecl *right,
+                                      MethodMatchStrategy strategy) {
+  if (!matchTypes(Context, strategy,
+                  left->getResultType(), right->getResultType()))
+    return false;
 
-  if (T1 != T2) {
-    // The result types are different.
-    if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
-      return false;
-    // Incomplete types don't have a size and alignment.
-    if (T1->isIncompleteType() || T2->isIncompleteType())
-      return false;
-    // Check is based on size and alignment.
-    if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
-      return false;
-  }
+  if (getLangOptions().ObjCAutoRefCount &&
+      (left->hasAttr<NSReturnsRetainedAttr>()
+         != right->hasAttr<NSReturnsRetainedAttr>() ||
+       left->hasAttr<NSConsumesSelfAttr>()
+         != right->hasAttr<NSConsumesSelfAttr>()))
+    return false;
 
-  ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
-       E = Method->param_end();
-  ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin();
+  ObjCMethodDecl::param_iterator
+    li = left->param_begin(), le = left->param_end(), ri = right->param_begin();
 
-  for (; ParamI != E; ++ParamI, ++PrevI) {
-    assert(PrevI != PrevMethod->param_end() && "Param mismatch");
-    T1 = Context.getCanonicalType((*ParamI)->getType());
-    T2 = Context.getCanonicalType((*PrevI)->getType());
-    if (T1 != T2) {
-      // The result types are different.
-      if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
-        return false;
-      // Incomplete types don't have a size and alignment.
-      if (T1->isIncompleteType() || T2->isIncompleteType())
-        return false;
-      // Check is based on size and alignment.
-      if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
-        return false;
-    }
+  for (; li != le; ++li, ++ri) {
+    assert(ri != right->param_end() && "Param mismatch");
+    ParmVarDecl *lparm = *li, *rparm = *ri;
+
+    if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType()))
+      return false;
+
+    if (getLangOptions().ObjCAutoRefCount &&
+        lparm->hasAttr<NSConsumedAttr>() != rparm->hasAttr<NSConsumedAttr>())
+      return false;
   }
   return true;
 }
@@ -1513,8 +1769,10 @@
 
   // We've seen a method with this name, see if we have already seen this type
   // signature.
-  for (ObjCMethodList *List = &Entry; List; List = List->Next)
-    if (MatchTwoMethodDeclarations(Method, List->Method)) {
+  for (ObjCMethodList *List = &Entry; List; List = List->Next) {
+    bool match = MatchTwoMethodDeclarations(Method, List->Method);
+
+    if (match) {
       ObjCMethodDecl *PrevObjCMethod = List->Method;
       PrevObjCMethod->setDefined(impl);
       // If a method is deprecated, push it in the global pool.
@@ -1531,6 +1789,7 @@
       }
       return;
     }
+  }
 
   // We have a new signature for an existing method - add it.
   // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
@@ -1538,6 +1797,25 @@
   Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
 }
 
+/// Determines if this is an "acceptable" loose mismatch in the global
+/// method pool.  This exists mostly as a hack to get around certain
+/// global mismatches which we can't afford to make warnings / errors.
+/// Really, what we want is a way to take a method out of the global
+/// method pool.
+static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
+                                       ObjCMethodDecl *other) {
+  if (!chosen->isInstanceMethod())
+    return false;
+
+  Selector sel = chosen->getSelector();
+  if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")
+    return false;
+
+  // Don't complain about mismatches for -length if the method we
+  // chose has an integral result type.
+  return (chosen->getResultType()->isIntegerType());
+}
+
 ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
                                                bool receiverIdOrClass,
                                                bool warn, bool instance) {
@@ -1551,32 +1829,52 @@
 
   ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
 
-  bool strictSelectorMatch = receiverIdOrClass && warn &&
-    (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
-                              R.getBegin()) != 
-      Diagnostic::Ignored);
   if (warn && MethList.Method && MethList.Next) {
-    bool issueWarning = false;
+    bool issueDiagnostic = false, issueError = false;
+
+    // We support a warning which complains about *any* difference in
+    // method signature.
+    bool strictSelectorMatch =
+      (receiverIdOrClass && warn &&
+       (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+                                 R.getBegin()) != 
+      Diagnostic::Ignored));
     if (strictSelectorMatch)
       for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
-        // This checks if the methods differ in type mismatch.
-        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, false, true))
-          issueWarning = true;
+        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+                                        MMS_strict)) {
+          issueDiagnostic = true;
+          break;
+        }
       }
 
-    if (!issueWarning)
+    // If we didn't see any strict differences, we won't see any loose
+    // differences.  In ARC, however, we also need to check for loose
+    // mismatches, because most of them are errors.
+    if (!strictSelectorMatch ||
+        (issueDiagnostic && getLangOptions().ObjCAutoRefCount))
       for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
-        // This checks if the methods differ by size & alignment.
-        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
-          issueWarning = true;
+        // This checks if the methods differ in type mismatch.
+        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+                                        MMS_loose) &&
+            !isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
+          issueDiagnostic = true;
+          if (getLangOptions().ObjCAutoRefCount)
+            issueError = true;
+          break;
+        }
       }
 
-    if (issueWarning) {
-      if (strictSelectorMatch)
+    if (issueDiagnostic) {
+      if (issueError)
+        Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
+      else if (strictSelectorMatch)
         Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
       else
         Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
-      Diag(MethList.Method->getLocStart(), diag::note_using)
+
+      Diag(MethList.Method->getLocStart(), 
+           issueError ? diag::note_possibility : diag::note_using)
         << MethList.Method->getSourceRange();
       for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
         Diag(Next->Method->getLocStart(), diag::note_also_found)
@@ -1804,6 +2102,7 @@
         DefaultSynthesizeProperties(S, IC, IDecl);
       ImplMethodsVsClassMethods(S, IC, IDecl);
       AtomicPropertySetterGetterRules(IC, IDecl);
+      DiagnoseOwningPropertyGetterSynthesis(IC);
   
       if (LangOpts.ObjCNonFragileABI2)
         while (IDecl->getSuperClass()) {
@@ -2112,7 +2411,11 @@
     mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
   }
   
-  if (!ObjCMethod->hasRelatedResultType() && 
+  bool ARCError = false;
+  if (getLangOptions().ObjCAutoRefCount)
+    ARCError = CheckARCMethodDecl(*this, ObjCMethod);
+
+  if (!ObjCMethod->hasRelatedResultType() && !ARCError &&
       getLangOptions().ObjCInferRelatedResultType) {
     bool InferRelatedResultType = false;
     switch (ObjCMethod->getMethodFamily()) {