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/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index bc1d823..ec2a88a 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -254,13 +254,13 @@
             return;
             
           if (Expr* E = V->getInit()) {
+            while (ExprWithCleanups *exprClean = dyn_cast<ExprWithCleanups>(E))
+              E = exprClean->getSubExpr();
+            
             // Don't warn on C++ objects (yet) until we can show that their
             // constructors/destructors don't have side effects.
             if (isa<CXXConstructExpr>(E))
               return;
-
-            if (isa<ExprWithCleanups>(E))
-              return;
             
             // A dead initialization is a variable that is dead after it
             // is initialized.  We don't flag warnings for those variables
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 07de870..73ce359 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -121,6 +121,11 @@
     return;  
   
   if (R->hasStackStorage()) {
+    // Automatic reference counting automatically copies blocks.
+    if (C.getASTContext().getLangOptions().ObjCAutoRefCount &&
+        isa<BlockDataRegion>(R))
+      return;
+
     EmitStackError(C, R, RetE);
     return;
   }
@@ -135,12 +140,13 @@
   // a memory region in the stack space.
   class CallBack : public StoreManager::BindingsHandler {
   private:
+    ExprEngine &Eng;
     const StackFrameContext *CurSFC;
   public:
     llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
 
-    CallBack(const LocationContext *LCtx)
-      : CurSFC(LCtx->getCurrentStackFrame()) {}
+    CallBack(ExprEngine &Eng, const LocationContext *LCtx)
+      : Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {}
     
     bool HandleBinding(StoreManager &SMgr, Store store,
                        const MemRegion *region, SVal val) {
@@ -151,7 +157,13 @@
       const MemRegion *vR = val.getAsRegion();
       if (!vR)
         return true;
-      
+        
+      // Under automated retain release, it is okay to assign a block
+      // directly to a global variable.
+      if (Eng.getContext().getLangOptions().ObjCAutoRefCount &&
+          isa<BlockDataRegion>(vR))
+        return true;
+
       if (const StackSpaceRegion *SSR = 
           dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
         // If the global variable holds a location in the current stack frame,
@@ -164,7 +176,7 @@
     }
   };
     
-  CallBack cb(B.getPredecessor()->getLocationContext());
+  CallBack cb(Eng, B.getPredecessor()->getLocationContext());
   state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
 
   if (cb.V.empty())
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index 0512e2f..33118fa 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -126,6 +126,7 @@
 /// ArgEffect is used to summarize a function/method call's effect on a
 /// particular argument.
 enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing,
+                 DecRefBridgedTransfered,
                  DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape,
                  NewAutoreleasePool, SelfOwn, StopTracking };
 
@@ -148,7 +149,8 @@
 class RetEffect {
 public:
   enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
-              NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias,
+              NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol,
+              ReceiverAlias,
               OwnedWhenTrackedReceiver };
 
   enum ObjKind { CF, ObjC, AnyObj };
@@ -195,7 +197,9 @@
   static RetEffect MakeGCNotOwned() {
     return RetEffect(GCNotOwnedSymbol, ObjC);
   }
-
+  static RetEffect MakeARCNotOwned() {
+    return RetEffect(ARCNotOwnedSymbol, ObjC);
+  }
   static RetEffect MakeNoRet() {
     return RetEffect(NoRet);
   }
@@ -636,6 +640,9 @@
   /// GCEnabled - Records whether or not the analyzed code runs in GC mode.
   const bool GCEnabled;
 
+  /// Records whether or not the analyzed code runs in ARC mode.
+  const bool ARCEnabled;
+
   /// FuncSummaries - A map from FunctionDecls to summaries.
   FuncSummariesTy FuncSummaries;
 
@@ -788,14 +795,20 @@
 
 public:
 
-  RetainSummaryManager(ASTContext& ctx, bool gcenabled)
+  RetainSummaryManager(ASTContext& ctx, bool gcenabled, bool usesARC)
    : Ctx(ctx),
      CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
-     GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
-     ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned()
-                             : RetEffect::MakeOwned(RetEffect::ObjC, true)),
-     ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned()
-                            : RetEffect::MakeOwnedWhenTrackedReceiver()),
+     GCEnabled(gcenabled),
+     ARCEnabled(usesARC),
+     AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
+     ObjCAllocRetE(gcenabled
+                    ? RetEffect::MakeGCNotOwned()
+                    : (usesARC ? RetEffect::MakeARCNotOwned()
+                               : RetEffect::MakeOwned(RetEffect::ObjC, true))),
+     ObjCInitRetE(gcenabled 
+                    ? RetEffect::MakeGCNotOwned()
+                    : (usesARC ? RetEffect::MakeARCNotOwned()
+                               : RetEffect::MakeOwnedWhenTrackedReceiver())),
      DefaultSummary(AF.getEmptyMap() /* per-argument effects (none) */,
                     RetEffect::MakeNoRet() /* return effect */,
                     MayEscape, /* default argument effect */
@@ -871,6 +884,10 @@
 
   bool isGCEnabled() const { return GCEnabled; }
 
+  bool isARCEnabled() const { return ARCEnabled; }
+  
+  bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
+
   RetainSummary *copySummary(RetainSummary *OldSumm) {
     RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
     new (Summ) RetainSummary(*OldSumm);
@@ -1654,7 +1671,6 @@
                        const char* nl, const char* sep);
   };
 
-private:
   typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*>
     SummaryLogTy;
 
@@ -1691,7 +1707,7 @@
 
 public:
   CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
-    : Summaries(Ctx, gcenabled),
+    : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount),
       LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
       deallocGC(0), deallocNotOwned(0),
       leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
@@ -1706,6 +1722,8 @@
   }
 
   bool isGCEnabled() const { return Summaries.isGCEnabled(); }
+  bool isARCorGCEnabled() const { return Summaries.isARCorGCEnabled(); }
+  
   const LangOptions& getLangOptions() const { return LOpts; }
 
   const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const {
@@ -2777,6 +2795,7 @@
     }
 
     case RetEffect::GCNotOwnedSymbol:
+    case RetEffect::ARCNotOwnedSymbol:
     case RetEffect::NotOwnedSymbol: {
       unsigned Count = Builder.getCurrentBlockCount();
       SValBuilder &svalBuilder = Eng.getSValBuilder();
@@ -3103,8 +3122,8 @@
   // In GC mode [... release] and [... retain] do nothing.
   switch (E) {
     default: break;
-    case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break;
-    case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break;
+    case IncRefMsg: E = isARCorGCEnabled() ? DoNothing : IncRef; break;
+    case DecRefMsg: E = isARCorGCEnabled() ? DoNothing : DecRef; break;
     case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
     case NewAutoreleasePool: E = isGCEnabled() ? DoNothing :
                                                  NewAutoreleasePool; break;
@@ -3118,9 +3137,13 @@
   }
 
   switch (E) {
-    default:
-      assert (false && "Unhandled CFRef transition.");
-
+    case DecRefMsg:
+    case IncRefMsg:
+    case MakeCollectable:
+      assert(false &&
+             "DecRefMsg/IncRefMsg/MakeCollectable already transformed");
+      return state;
+      
     case Dealloc:
       // Any use of -dealloc in GC is *bad*.
       if (isGCEnabled()) {
@@ -3193,6 +3216,7 @@
       V = V ^ RefVal::NotOwned;
       // Fall-through.
     case DecRef:
+    case DecRefBridgedTransfered:
       switch (V.getKind()) {
         default:
           // case 'RefVal::Released' handled above.
@@ -3200,7 +3224,9 @@
 
         case RefVal::Owned:
           assert(V.getCount() > 0);
-          if (V.getCount() == 1) V = V ^ RefVal::Released;
+          if (V.getCount() == 1)
+            V = V ^ (E == DecRefBridgedTransfered ? 
+                      RefVal::NotOwned : RefVal::Released);
           V = V - 1;
           break;
 
@@ -3468,7 +3494,9 @@
 
 namespace {
 class RetainReleaseChecker
-  : public Checker< check::PostStmt<BlockExpr>, check::RegionChanges > {
+  : public Checker< check::PostStmt<BlockExpr>,
+                    check::PostStmt<CastExpr>,
+                    check::RegionChanges > {
 public:
     bool wantsRegionUpdate;
     
@@ -3476,6 +3504,9 @@
     
     
     void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
+                      
+    void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
+
     const GRState *checkRegionChanges(const GRState *state,
                             const StoreManager::InvalidatedSymbols *invalidated,
                                       const MemRegion * const *begin,
@@ -3545,6 +3576,48 @@
   C.addTransition(state);
 }
 
+void RetainReleaseChecker::checkPostStmt(const CastExpr *CE,
+                                         CheckerContext &C) const {
+  const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
+  if (!BE)
+    return;
+  
+  ArgEffect AE;
+  
+  switch (BE->getBridgeKind()) {
+    case clang::OBC_Bridge:
+      // Do nothing.
+      return;
+    case clang::OBC_BridgeRetained:
+      AE = IncRef;
+      break;      
+    case clang::OBC_BridgeTransfer:
+      AE = DecRefBridgedTransfered;
+      break;
+  }
+  
+  const GRState *state = C.getState();
+  SymbolRef Sym = state->getSVal(CE).getAsLocSymbol();
+  if (!Sym)
+    return;
+  const RefVal* T = state->get<RefBindings>(Sym);
+  if (!T)
+    return;
+
+  // This is gross.  Once the checker and CFRefCount are unified,
+  // this will go away.
+  CFRefCount &cf = static_cast<CFRefCount&>(C.getEngine().getTF());
+  RefVal::Kind hasErr = (RefVal::Kind) 0;
+  state = cf.Update(state, Sym, *T, AE, hasErr);
+  
+  if (hasErr) {
+    
+    return;
+  }
+
+  C.generateNode(state);
+}
+
 //===----------------------------------------------------------------------===//
 // Transfer function creation for external clients.
 //===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index aed39eb..21efbac 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -442,7 +442,8 @@
   }
 
   switch (S->getStmtClass()) {
-    // C++ stuff we don't support yet.
+    // C++ and ARC stuff we don't support yet.
+    case Expr::ObjCIndirectCopyRestoreExprClass:
     case Stmt::CXXBindTemporaryExprClass:
     case Stmt::CXXCatchStmtClass:
     case Stmt::CXXDependentScopeMemberExprClass:
@@ -520,14 +521,27 @@
       VisitObjCPropertyRefExpr(cast<ObjCPropertyRefExpr>(S), Pred, Dst);
       break;
 
+    case Stmt::ImplicitValueInitExprClass: {
+      const GRState *state = GetState(Pred);
+      QualType ty = cast<ImplicitValueInitExpr>(S)->getType();
+      SVal val = svalBuilder.makeZeroVal(ty);
+      MakeNode(Dst, S, Pred, state->BindExpr(S, val));
+      break;
+    }
+      
+    case Stmt::ExprWithCleanupsClass: {
+      Visit(cast<ExprWithCleanups>(S)->getSubExpr(), Pred, Dst);
+      break;
+    }
+
     // Cases not handled yet; but will handle some day.
     case Stmt::DesignatedInitExprClass:
     case Stmt::ExtVectorElementExprClass:
     case Stmt::ImaginaryLiteralClass:
-    case Stmt::ImplicitValueInitExprClass:
     case Stmt::ObjCAtCatchStmtClass:
     case Stmt::ObjCAtFinallyStmtClass:
     case Stmt::ObjCAtTryStmtClass:
+    case Stmt::ObjCAutoreleasePoolStmtClass:
     case Stmt::ObjCEncodeExprClass:
     case Stmt::ObjCIsaExprClass:
     case Stmt::ObjCProtocolExprClass:
@@ -548,7 +562,6 @@
     case Stmt::IntegerLiteralClass:
     case Stmt::CharacterLiteralClass:
     case Stmt::CXXBoolLiteralExprClass:
-    case Stmt::ExprWithCleanupsClass:
     case Stmt::FloatingLiteralClass:
     case Stmt::SizeOfPackExprClass:
     case Stmt::CXXNullPtrLiteralExprClass:
@@ -668,9 +681,22 @@
     case Stmt::CXXDynamicCastExprClass:
     case Stmt::CXXReinterpretCastExprClass:
     case Stmt::CXXConstCastExprClass:
-    case Stmt::CXXFunctionalCastExprClass: {
+    case Stmt::CXXFunctionalCastExprClass: 
+    case Stmt::ObjCBridgedCastExprClass: {
       const CastExpr* C = cast<CastExpr>(S);
-      VisitCast(C, C->getSubExpr(), Pred, Dst);
+      // Handle the previsit checks.
+      ExplodedNodeSet dstPrevisit;
+      getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this);
+      
+      // Handle the expression itself.
+      ExplodedNodeSet dstExpr;
+      for (ExplodedNodeSet::iterator i = dstPrevisit.begin(),
+                                     e = dstPrevisit.end(); i != e ; ++i) { 
+        VisitCast(C, C->getSubExpr(), *i, dstExpr);
+      }
+
+      // Handle the postvisit checks.
+      getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
       break;
     }
 
@@ -2148,10 +2174,18 @@
     Pred = *I;
 
     switch (CastE->getCastKind()) {
+      case CK_LValueToRValue:
+        assert(false && "LValueToRValue casts handled earlier.");
+      case CK_GetObjCProperty:
+        assert(false && "GetObjCProperty casts handled earlier.");
       case CK_ToVoid:
         Dst.Add(Pred);
         continue;
-      case CK_LValueToRValue:
+      // The analyzer doesn't do anything special with these casts,
+      // since it understands retain/release semantics already.
+      case CK_ObjCProduceObject:
+      case CK_ObjCConsumeObject: // Fall-through.
+      // True no-ops.
       case CK_NoOp:
       case CK_FunctionToPointerDecay: {
         // Copy the SVal of Ex to CastE.
@@ -2161,7 +2195,6 @@
         MakeNode(Dst, CastE, Pred, state);
         continue;
       }
-      case CK_GetObjCProperty:
       case CK_Dependent:
       case CK_ArrayToPointerDecay:
       case CK_BitCast: