[cfe-commits] r50674 - /cfe/trunk/lib/Analysis/CFRefCount.cpp

Ted Kremenek kremenek at apple.com
Mon May 5 15:11:16 PDT 2008


Author: kremenek
Date: Mon May  5 17:11:16 2008
New Revision: 50674

URL: http://llvm.org/viewvc/llvm-project?rev=50674&view=rev
Log:
Initial work on refactoring the CFRefCount checker so that it is more
generic and handles reference counts for NSObjects.

Modified:
    cfe/trunk/lib/Analysis/CFRefCount.cpp

Modified: cfe/trunk/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFRefCount.cpp?rev=50674&r1=50673&r2=50674&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Mon May  5 17:11:16 2008
@@ -63,23 +63,25 @@
 class RetEffect {
 public:
   enum Kind { NoRet = 0x0, Alias = 0x1, OwnedSymbol = 0x2,
-              NotOwnedSymbol = 0x3 };
+              NotOwnedSymbol = 0x3, ReceiverAlias=0x4 };
 
 private:
   unsigned Data;
-  RetEffect(Kind k, unsigned D) { Data = (D << 2) | (unsigned) k; }
+  RetEffect(Kind k, unsigned D) { Data = (D << 3) | (unsigned) k; }
   
 public:
 
-  Kind getKind() const { return (Kind) (Data & 0x3); }
+  Kind getKind() const { return (Kind) (Data & 0x7); }
 
   unsigned getValue() const { 
     assert(getKind() == Alias);
-    return Data >> 2;
+    return Data >> 3;
   }
     
   static RetEffect MakeAlias(unsigned Idx) { return RetEffect(Alias, Idx); }
   
+  static RetEffect MakeReceiverAlias() { return RetEffect(ReceiverAlias, 0); }
+  
   static RetEffect MakeOwned() { return RetEffect(OwnedSymbol, 0); }
   
   static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
@@ -92,12 +94,12 @@
 };
 
   
-class CFRefSummary : public llvm::FoldingSetNode {
+class RetainSummary : public llvm::FoldingSetNode {
   ArgEffects* Args;
   RetEffect   Ret;
 public:
   
-  CFRefSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
+  RetainSummary(ArgEffects* A, RetEffect R) : Args(A), Ret(R) {}
   
   unsigned getNumArgs() const { return Args->size(); }
   
@@ -143,40 +145,86 @@
 };
 
   
-class CFRefSummaryManager {
-  typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> > AESetTy;
-  typedef llvm::FoldingSet<CFRefSummary>                SummarySetTy;
-  typedef llvm::DenseMap<FunctionDecl*, CFRefSummary*>  SummaryMapTy;
+class RetainSummaryManager {
+
+  //==-----------------------------------------------------------------==//
+  //  Typedefs.
+  //==-----------------------------------------------------------------==//
+  
+  typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<ArgEffects> >
+          ArgEffectsSetTy;
   
+  typedef llvm::FoldingSet<RetainSummary>
+          SummarySetTy;
+  
+  typedef llvm::DenseMap<FunctionDecl*, RetainSummary*>
+          FuncSummariesTy;
+  
+  typedef llvm::DenseMap<Selector, RetainSummary*>
+          ObjCMethodSummariesTy;
+    
+  //==-----------------------------------------------------------------==//
+  //  Data.
+  //==-----------------------------------------------------------------==//
+  
+  // Ctx - The ASTContext object for the analyzed ASTs.
   ASTContext& Ctx;
+  
+  // GCEnabled - Records whether or not the analyzed code runs in GC mode.
   const bool GCEnabled;
   
+  // SummarySet - A FoldingSet of uniqued summaries.
   SummarySetTy SummarySet;
-  SummaryMapTy SummaryMap;  
-  AESetTy AESet;  
-  llvm::BumpPtrAllocator BPAlloc;  
-  ArgEffects ScratchArgs;  
   
+  // FuncSummaries - A map from FunctionDecls to summaries.
+  FuncSummariesTy FuncSummaries; 
+  
+  // ObjCInstanceMethodSummaries - A map from selectors (for instance methods)
+  //  to summaries.
+  ObjCMethodSummariesTy ObjCInstanceMethodSummaries;
+
+  // ObjCMethodSummaries - A map from selectors to summaries.
+  ObjCMethodSummariesTy ObjCMethodSummaries;
+
+  // ArgEffectsSet - A FoldingSet of uniqued ArgEffects.
+  ArgEffectsSetTy ArgEffectsSet;
+  
+  // BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects,
+  //  and all other data used by the checker.
+  llvm::BumpPtrAllocator BPAlloc;
+  
+  // ScratchArgs - A holding buffer for construct ArgEffects.
+  ArgEffects ScratchArgs;
+  
+  //==-----------------------------------------------------------------==//
+  //  Methods.
+  //==-----------------------------------------------------------------==//
+  
+  // getArgEffects - Returns a persistent ArgEffects object based on the
+  //  data in ScratchArgs.
   ArgEffects*   getArgEffects();
 
   enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };  
-  CFRefSummary* getUnarySummary(FunctionDecl* FD, UnaryFuncKind func);
+  RetainSummary* getUnarySummary(FunctionDecl* FD, UnaryFuncKind func);
   
-  CFRefSummary* getNSSummary(FunctionDecl* FD, const char* FName);
-  CFRefSummary* getCFSummary(FunctionDecl* FD, const char* FName);
+  RetainSummary* getNSSummary(FunctionDecl* FD, const char* FName);
+  RetainSummary* getCFSummary(FunctionDecl* FD, const char* FName);
   
-  CFRefSummary* getCFSummaryCreateRule(FunctionDecl* FD);
-  CFRefSummary* getCFSummaryGetRule(FunctionDecl* FD);  
+  RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD);
+  RetainSummary* getCFSummaryGetRule(FunctionDecl* FD);  
   
-  CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
+  RetainSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
     
 public:
-  CFRefSummaryManager(ASTContext& ctx, bool gcenabled)
+  
+  RetainSummaryManager(ASTContext& ctx, bool gcenabled)
    : Ctx(ctx), GCEnabled(gcenabled) {}
   
-  ~CFRefSummaryManager();
+  ~RetainSummaryManager();
+  
+  RetainSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
   
-  CFRefSummary* getSummary(FunctionDecl* FD, ASTContext& Ctx);
+  bool isGCEnabled() const { return GCEnabled; }
 };
   
 } // end anonymous namespace
@@ -185,17 +233,17 @@
 // Implementation of checker data structures.
 //===----------------------------------------------------------------------===//
 
-CFRefSummaryManager::~CFRefSummaryManager() {
+RetainSummaryManager::~RetainSummaryManager() {
   
   // FIXME: The ArgEffects could eventually be allocated from BPAlloc, 
   //   mitigating the need to do explicit cleanup of the
   //   Argument-Effect summaries.
   
-  for (AESetTy::iterator I = AESet.begin(), E = AESet.end(); I!=E; ++I)
+  for (ArgEffectsSetTy::iterator I = ArgEffectsSet.begin(), E = ArgEffectsSet.end(); I!=E; ++I)
     I->getValue().~ArgEffects();
 }
 
-ArgEffects* CFRefSummaryManager::getArgEffects() {
+ArgEffects* RetainSummaryManager::getArgEffects() {
 
   if (ScratchArgs.empty())
     return NULL;
@@ -210,7 +258,7 @@
   // Look up the uniqued copy, or create a new one.
   
   llvm::FoldingSetNodeWrapper<ArgEffects>* E =
-    AESet.FindNodeOrInsertPos(profile, InsertPos);
+    ArgEffectsSet.FindNodeOrInsertPos(profile, InsertPos);
   
   if (E) {
     ScratchArgs.clear();
@@ -221,36 +269,39 @@
       BPAlloc.Allocate<llvm::FoldingSetNodeWrapper<ArgEffects> >();
                        
   new (E) llvm::FoldingSetNodeWrapper<ArgEffects>(ScratchArgs);
-  AESet.InsertNode(E, InsertPos);
+  ArgEffectsSet.InsertNode(E, InsertPos);
 
   ScratchArgs.clear();
   return &E->getValue();
 }
 
-CFRefSummary* CFRefSummaryManager::getPersistentSummary(ArgEffects* AE,
+RetainSummary* RetainSummaryManager::getPersistentSummary(ArgEffects* AE,
                                                         RetEffect RE) {
   
   // Generate a profile for the summary.
   llvm::FoldingSetNodeID profile;
-  CFRefSummary::Profile(profile, AE, RE);
+  RetainSummary::Profile(profile, AE, RE);
   
   // Look up the uniqued summary, or create one if it doesn't exist.
   void* InsertPos;  
-  CFRefSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
+  RetainSummary* Summ = SummarySet.FindNodeOrInsertPos(profile, InsertPos);
   
   if (Summ)
     return Summ;
   
   // Create the summary and return it.
-  Summ = (CFRefSummary*) BPAlloc.Allocate<CFRefSummary>();
-  new (Summ) CFRefSummary(AE, RE);
+  Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+  new (Summ) RetainSummary(AE, RE);
   SummarySet.InsertNode(Summ, InsertPos);
   
   return Summ;
 }
 
+//===----------------------------------------------------------------------===//
+// Summary creation for functions (largely uses of Core Foundation).
+//===----------------------------------------------------------------------===//
 
-CFRefSummary* CFRefSummaryManager::getSummary(FunctionDecl* FD,
+RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD,
                                               ASTContext& Ctx) {
 
   SourceLocation Loc = FD->getLocation();
@@ -259,26 +310,26 @@
     return NULL;
   
   // Look up a summary in our cache of FunctionDecls -> Summaries.
-  SummaryMapTy::iterator I = SummaryMap.find(FD);
+  FuncSummariesTy::iterator I = FuncSummaries.find(FD);
 
-  if (I != SummaryMap.end())
+  if (I != FuncSummaries.end())
     return I->second;
 
   // No summary.  Generate one.
   const char* FName = FD->getIdentifier()->getName();
     
-  CFRefSummary *S = 0;
+  RetainSummary *S = 0;
   
   if (FName[0] == 'C' && FName[1] == 'F')
     S = getCFSummary(FD, FName);
   else if (FName[0] == 'N' && FName[1] == 'S')
     S = getNSSummary(FD, FName);
 
-  SummaryMap[FD] = S;
+  FuncSummaries[FD] = S;
   return S;  
 }
 
-CFRefSummary* CFRefSummaryManager::getNSSummary(FunctionDecl* FD,
+RetainSummary* RetainSummaryManager::getNSSummary(FunctionDecl* FD,
                                                 const char* FName) {
   FName += 2;
   
@@ -288,7 +339,7 @@
   return 0;  
 }
   
-CFRefSummary* CFRefSummaryManager::getCFSummary(FunctionDecl* FD,
+RetainSummary* RetainSummaryManager::getCFSummary(FunctionDecl* FD,
                                                 const char* FName) {
 
   FName += 2;
@@ -311,8 +362,8 @@
   return 0;
 }
 
-CFRefSummary*
-CFRefSummaryManager::getUnarySummary(FunctionDecl* FD, UnaryFuncKind func) {
+RetainSummary*
+RetainSummaryManager::getUnarySummary(FunctionDecl* FD, UnaryFuncKind func) {
   
   FunctionTypeProto* FT =
     dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
@@ -330,7 +381,7 @@
     if (!ArgT->isPointerType())
       return NULL;
   }
-
+  
   assert (ScratchArgs.empty());
   
   switch (func) {
@@ -380,8 +431,7 @@
   return true;
 }
 
-CFRefSummary*
-CFRefSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) {
+RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) {
  
   FunctionTypeProto* FT =
     dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
@@ -396,8 +446,7 @@
   return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
 }
 
-CFRefSummary*
-CFRefSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) {
+RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) {
   
   FunctionTypeProto* FT =
     dyn_cast<FunctionTypeProto>(FD->getType().getTypePtr());
@@ -423,6 +472,13 @@
 }
 
 //===----------------------------------------------------------------------===//
+// Summary creation for Selectors.
+//===----------------------------------------------------------------------===//
+
+
+
+
+//===----------------------------------------------------------------------===//
 // Reference-counting logic (typestate + counts).
 //===----------------------------------------------------------------------===//
 
@@ -610,11 +666,10 @@
 private:
   // Instance variables.
   
-  CFRefSummaryManager Summaries;  
-  const bool          GCEnabled;
-  const bool          EmitStandardWarnings;  
-  const LangOptions&  LOpts;
-  RefBFactoryTy       RefBFactory;
+  RetainSummaryManager Summaries;  
+  const bool           EmitStandardWarnings;  
+  const LangOptions&   LOpts;
+  RefBFactoryTy        RefBFactory;
      
   UseAfterReleasesTy UseAfterReleases;
   ReleasesNotOwnedTy ReleasesNotOwned;
@@ -663,7 +718,6 @@
   CFRefCount(ASTContext& Ctx, bool gcenabled, bool StandardWarnings,
              const LangOptions& lopts)
     : Summaries(Ctx, gcenabled),
-      GCEnabled(gcenabled),
       EmitStandardWarnings(StandardWarnings),
       LOpts(lopts),
       RetainSelector(GetNullarySelector("retain", Ctx)),
@@ -681,17 +735,27 @@
     return &Printer;
   }
   
-  bool isGCEnabled() const { return GCEnabled; }
+  bool isGCEnabled() const { return Summaries.isGCEnabled(); }
   const LangOptions& getLangOptions() const { return LOpts; }
   
   // Calls.
-  
+
+  void EvalSummary(ExplodedNodeSet<ValueState>& Dst,
+                   GRExprEngine& Eng,
+                   GRStmtNodeBuilder<ValueState>& Builder,
+                   Expr* Ex,
+                   Expr* Receiver,
+                   RetainSummary* Summ,
+                   Expr** arg_beg, Expr** arg_end,                             
+                   ExplodedNode<ValueState>* Pred);
+    
   virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
                         GRExprEngine& Eng,
                         GRStmtNodeBuilder<ValueState>& Builder,
                         CallExpr* CE, RVal L,
                         ExplodedNode<ValueState>* Pred);  
   
+  
   virtual void EvalObjCMessageExpr(ExplodedNodeSet<ValueState>& Dst,
                                    GRExprEngine& Engine,
                                    GRStmtNodeBuilder<ValueState>& Builder,
@@ -772,11 +836,11 @@
   }
 }
 
-static inline ArgEffect GetArgE(CFRefSummary* Summ, unsigned idx) {
+static inline ArgEffect GetArgE(RetainSummary* Summ, unsigned idx) {
   return Summ ? Summ->getArg(idx) : DoNothing;
 }
 
-static inline RetEffect GetRetE(CFRefSummary* Summ) {
+static inline RetEffect GetRetE(RetainSummary* Summ) {
   return Summ ? Summ->getRet() : RetEffect::MakeNoRet();
 }
 
@@ -803,33 +867,25 @@
   }
 }
 
-void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
-                          GRExprEngine& Eng,
-                          GRStmtNodeBuilder<ValueState>& Builder,
-                          CallExpr* CE, RVal L,
-                          ExplodedNode<ValueState>* Pred) {
+void CFRefCount::EvalSummary(ExplodedNodeSet<ValueState>& Dst,
+                             GRExprEngine& Eng,
+                             GRStmtNodeBuilder<ValueState>& Builder,
+                             Expr* Ex,
+                             Expr* Receiver,
+                             RetainSummary* Summ,
+                             Expr** arg_beg, Expr** arg_end,                             
+                             ExplodedNode<ValueState>* Pred) {
   
-  ValueStateManager& StateMgr = Eng.getStateManager();
-  
-  CFRefSummary* Summ = NULL;
   
-  // Get the summary.
-
-  if (isa<lval::FuncVal>(L)) {  
-    lval::FuncVal FV = cast<lval::FuncVal>(L);
-    FunctionDecl* FD = FV.getDecl();
-    Summ = Summaries.getSummary(FD, Eng.getContext());
-  }
-
   // Get the state.
-  
+  ValueStateManager& StateMgr = Eng.getStateManager();  
   ValueState* St = Builder.GetState(Pred);
   
   // Evaluate the effects of the call.
   
   ValueState StVals = *St;
   RefVal::Kind hasErr = (RefVal::Kind) 0;
- 
+  
   // This function has a summary.  Evaluate the effect of the arguments.
   
   unsigned idx = 0;
@@ -837,8 +893,7 @@
   Expr* ErrorExpr = NULL;
   SymbolID ErrorSym = 0;                                        
   
-  for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
-        I != E; ++I, ++idx) {
+  for (Expr **I = arg_beg, **E = arg_end; I != E; ++I, ++idx) {
     
     RVal V = StateMgr.GetRVal(St, *I);
     
@@ -857,24 +912,22 @@
         }
       }
     }  
-    else if (isa<LVal>(V)) { // Nuke all arguments passed by reference.
-      
-      // FIXME: This is basically copy-and-paste from GRSimpleVals.  We 
-      //  should compose behavior, not copy it.
+    else if (isa<LVal>(V)) {
+      // Nuke all arguments passed by reference.
       StateMgr.Unbind(StVals, cast<LVal>(V));
     }
     else if (isa<nonlval::LValAsInteger>(V))
       StateMgr.Unbind(StVals, cast<nonlval::LValAsInteger>(V).getLVal());
-  }    
+  } 
   
   St = StateMgr.getPersistentState(StVals);
-    
+  
   if (hasErr) {
-    ProcessNonLeakError(Dst, Builder, CE, ErrorExpr, Pred, St,
+    ProcessNonLeakError(Dst, Builder, Ex, ErrorExpr, Pred, St,
                         hasErr, ErrorSym);
     return;
   }
-    
+  
   // Finally, consult the summary for the return value.
   
   RetEffect RE = GetRetE(Summ);
@@ -882,66 +935,89 @@
   switch (RE.getKind()) {
     default:
       assert (false && "Unhandled RetEffect."); break;
-    
+      
     case RetEffect::NoRet:
-    
+      
       // Make up a symbol for the return value (not reference counted).
       // FIXME: This is basically copy-and-paste from GRSimpleVals.  We 
       //  should compose behavior, not copy it.
       
-      if (CE->getType() != Eng.getContext().VoidTy) {    
+      if (Ex->getType() != Eng.getContext().VoidTy) {    
         unsigned Count = Builder.getCurrentBlockCount();
-        SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
+        SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
         
-        RVal X = CE->getType()->isPointerType() 
-          ? cast<RVal>(lval::SymbolVal(Sym)) 
-          : cast<RVal>(nonlval::SymbolVal(Sym));
+        RVal X = Ex->getType()->isPointerType() 
+        ? cast<RVal>(lval::SymbolVal(Sym)) 
+        : cast<RVal>(nonlval::SymbolVal(Sym));
         
-        St = StateMgr.SetRVal(St, CE, X, Eng.getCFG().isBlkExpr(CE), false);
+        St = StateMgr.SetRVal(St, Ex, X, Eng.getCFG().isBlkExpr(Ex), false);
       }      
       
       break;
       
     case RetEffect::Alias: {
       unsigned idx = RE.getValue();
-      assert (idx < CE->getNumArgs());
-      RVal V = StateMgr.GetRVal(St, CE->getArg(idx));
-      St = StateMgr.SetRVal(St, CE, V, Eng.getCFG().isBlkExpr(CE), false);
+      assert ((arg_end - arg_beg) >= 0);
+      assert (idx < (unsigned) (arg_end - arg_beg));
+      RVal V = StateMgr.GetRVal(St, arg_beg[idx]);
+      St = StateMgr.SetRVal(St, Ex, V, Eng.getCFG().isBlkExpr(Ex), false);
       break;
     }
       
     case RetEffect::OwnedSymbol: {
       unsigned Count = Builder.getCurrentBlockCount();
-      SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
-
+      SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
+      
       ValueState StImpl = *St;
       RefBindings B = GetRefBindings(StImpl);
       SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeOwned()));
       
       St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
-                            CE, lval::SymbolVal(Sym),
-                            Eng.getCFG().isBlkExpr(CE), false);
+                            Ex, lval::SymbolVal(Sym),
+                            Eng.getCFG().isBlkExpr(Ex), false);
       
       break;
     }
       
     case RetEffect::NotOwnedSymbol: {
       unsigned Count = Builder.getCurrentBlockCount();
-      SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(CE, Count);
+      SymbolID Sym = Eng.getSymbolManager().getConjuredSymbol(Ex, Count);
       
       ValueState StImpl = *St;
       RefBindings B = GetRefBindings(StImpl);
       SetRefBindings(StImpl, RefBFactory.Add(B, Sym, RefVal::makeNotOwned()));
       
       St = StateMgr.SetRVal(StateMgr.getPersistentState(StImpl),
-                            CE, lval::SymbolVal(Sym),
-                            Eng.getCFG().isBlkExpr(CE), false);
+                            Ex, lval::SymbolVal(Sym),
+                            Eng.getCFG().isBlkExpr(Ex), false);
       
       break;
     }
   }
-      
-  Builder.MakeNode(Dst, CE, Pred, St);
+  
+  Builder.MakeNode(Dst, Ex, Pred, St);
+}
+
+
+void CFRefCount::EvalCall(ExplodedNodeSet<ValueState>& Dst,
+                          GRExprEngine& Eng,
+                          GRStmtNodeBuilder<ValueState>& Builder,
+                          CallExpr* CE, RVal L,
+                          ExplodedNode<ValueState>* Pred) {
+  
+  
+  RetainSummary* Summ = NULL;
+  
+  // Get the summary.
+
+  if (isa<lval::FuncVal>(L)) {  
+    lval::FuncVal FV = cast<lval::FuncVal>(L);
+    FunctionDecl* FD = FV.getDecl();
+    Summ = Summaries.getSummary(FD, Eng.getContext());
+  }
+  
+  EvalSummary(Dst, Eng, Builder, CE, 0, Summ,
+              CE->arg_begin(), CE->arg_end(), Pred);
 }
 
 
@@ -996,7 +1072,7 @@
                                         ObjCMessageExpr* ME,
                                         ExplodedNode<ValueState>* Pred) {
   
-  if (GCEnabled)
+  if (isGCEnabled())
     return true;
   
   // Handle "toll-free bridging" of calls to "Release" and "Retain".
@@ -1344,7 +1420,7 @@
       assert (false && "Unhandled CFRef transition.");
       
     case DoNothing:
-      if (!GCEnabled && V.getKind() == RefVal::Released) {
+      if (!isGCEnabled() && V.getKind() == RefVal::Released) {
         V = RefVal::makeUseAfterRelease();        
         hasErr = V.getKind();
         break;
@@ -1366,7 +1442,7 @@
           break;
           
         case RefVal::Released:
-          if (GCEnabled)
+          if (isGCEnabled())
             V = RefVal::makeOwned();
           else {          
             V = RefVal::makeUseAfterRelease();





More information about the cfe-commits mailing list