[cfe-commits] r73572 - in /cfe/trunk: include/clang/Analysis/PathSensitive/Store.h lib/Analysis/RegionStore.cpp

Ted Kremenek kremenek at apple.com
Tue Jun 16 15:36:44 PDT 2009


Author: kremenek
Date: Tue Jun 16 17:36:44 2009
New Revision: 73572

URL: http://llvm.org/viewvc/llvm-project?rev=73572&view=rev
Log:
RegionStoreManager:
- Add "sections" to RegionStoreManager.cpp to delineate functionality.
- Add new function "CreateFieldsOnlyRegionStoreManager" that uses the new
  RegionStoreFeatures class to use a reduced set of features from
  RegionStoreManager (in this case, only field-sensitivity). This isn't
  completely hooked up yet.

Modified:
    cfe/trunk/include/clang/Analysis/PathSensitive/Store.h
    cfe/trunk/lib/Analysis/RegionStore.cpp

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/Store.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/Store.h?rev=73572&r1=73571&r2=73572&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/Store.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/Store.h Tue Jun 16 17:36:44 2009
@@ -196,8 +196,9 @@
   virtual bool iterSubRegions(const MemRegion* R, Visitor& V) const = 0;  
 };
   
-StoreManager* CreateBasicStoreManager(GRStateManager& StMgr);
-StoreManager* CreateRegionStoreManager(GRStateManager& StMgr);
+StoreManager *CreateBasicStoreManager(GRStateManager& StMgr);
+StoreManager *CreateRegionStoreManager(GRStateManager& StMgr);
+StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr);
   
 } // end clang namespace
 

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

==============================================================================
--- cfe/trunk/lib/Analysis/RegionStore.cpp (original)
+++ cfe/trunk/lib/Analysis/RegionStore.cpp Tue Jun 16 17:36:44 2009
@@ -31,6 +31,32 @@
 typedef llvm::ImmutableMap<const MemRegion*, SVal> RegionBindingsTy;
 
 //===----------------------------------------------------------------------===//
+// Fine-grained control of RegionStoreManager.
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct VISIBILITY_HIDDEN minimal_features_tag {};
+struct VISIBILITY_HIDDEN maximal_features_tag {};  
+  
+class VISIBILITY_HIDDEN RegionStoreFeatures {
+  bool SupportsFields;
+  bool SupportsRemaining;
+  
+public:
+  RegionStoreFeatures(minimal_features_tag) :
+    SupportsFields(false), SupportsRemaining(false) {}
+  
+  RegionStoreFeatures(maximal_features_tag) :
+    SupportsFields(true), SupportsRemaining(false) {}
+  
+  void enableFields(bool t) { SupportsFields = t; }
+  
+  bool supportsFields() const { return SupportsFields; }
+  bool supportsRemaining() const { return SupportsRemaining; }
+};
+}
+
+//===----------------------------------------------------------------------===//
 // Region "Views"
 //===----------------------------------------------------------------------===//
 //
@@ -151,6 +177,7 @@
 };  
 
 class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
+  const RegionStoreFeatures Features;
   RegionBindingsTy::Factory RBFactory;
   RegionViews::Factory RVFactory;
 
@@ -158,8 +185,9 @@
   const ImplicitParamDecl *SelfDecl;
 
 public:
-  RegionStoreManager(GRStateManager& mgr) 
+  RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f) 
     : StoreManager(mgr),
+      Features(f),
       RBFactory(mgr.getAllocator()),
       RVFactory(mgr.getAllocator()),
       SelfRegion(0), SelfDecl(0) {
@@ -308,8 +336,19 @@
 
 } // end anonymous namespace
 
-StoreManager* clang::CreateRegionStoreManager(GRStateManager& StMgr) {
-  return new RegionStoreManager(StMgr);
+//===----------------------------------------------------------------------===//
+// RegionStore creation.
+//===----------------------------------------------------------------------===//
+
+StoreManager *clang::CreateRegionStoreManager(GRStateManager& StMgr) {
+  RegionStoreFeatures F = maximal_features_tag();
+  return new RegionStoreManager(StMgr, F);
+}
+
+StoreManager *clang::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) {
+  RegionStoreFeatures F = minimal_features_tag();
+  F.enableFields(true);
+  return new RegionStoreManager(StMgr, F);
 }
 
 SubRegionMap* RegionStoreManager::getSubRegionMap(const GRState *state) {
@@ -324,6 +363,10 @@
   return M;
 }
 
+//===----------------------------------------------------------------------===//
+// getLValueXXX methods.
+//===----------------------------------------------------------------------===//
+
 /// getLValueString - Returns an SVal representing the lvalue of a
 ///  StringLiteral.  Within RegionStore a StringLiteral has an
 ///  associated StringRegion, and the lvalue of a StringLiteral is the
@@ -477,6 +520,10 @@
 						  getContext()));
 }
 
+//===----------------------------------------------------------------------===//
+// Extents for regions.
+//===----------------------------------------------------------------------===//
+
 SVal RegionStoreManager::getSizeInElements(const GRState* St,
                                            const MemRegion* R) {
   if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
@@ -539,6 +586,16 @@
   return UnknownVal();
 }
 
+const GRState* RegionStoreManager::setExtent(const GRState* St,
+                                             const MemRegion* R, SVal Extent) {
+  GRStateRef state(St, StateMgr);
+  return state.set<RegionExtents>(R, Extent);
+}
+
+//===----------------------------------------------------------------------===//
+// Location and region casting.
+//===----------------------------------------------------------------------===//
+
 /// ArrayToPointer - Emulates the "decay" of an array to a pointer
 ///  type.  'Array' represents the lvalue of the array being decayed
 ///  to a pointer, and the returned SVal represents the decayed
@@ -637,6 +694,10 @@
   return 0;
 }
 
+//===----------------------------------------------------------------------===//
+// Pointer arithmetic.
+//===----------------------------------------------------------------------===//
+
 SVal RegionStoreManager::EvalBinOp(const GRState *state, 
                                    BinaryOperator::Opcode Op, Loc L, NonLoc R) {
   // Assume the base location is MemRegionVal.
@@ -696,6 +757,10 @@
   return UnknownVal();
 }
 
+//===----------------------------------------------------------------------===//
+// Loading values from regions.
+//===----------------------------------------------------------------------===//
+
 SVal RegionStoreManager::Retrieve(const GRState* St, Loc L, QualType T) {
   assert(!isa<UnknownVal>(L) && "location unknown");
   assert(!isa<UndefinedVal>(L) && "location undefined");
@@ -883,45 +948,49 @@
   return NonLoc::MakeCompoundVal(T, ArrayVal, getBasicVals());
 }
 
+//===----------------------------------------------------------------------===//
+// Binding values to regions.
+//===----------------------------------------------------------------------===//
+
+Store RegionStoreManager::Remove(Store store, Loc L) {
+  const MemRegion* R = 0;
+  
+  if (isa<loc::MemRegionVal>(L))
+    R = cast<loc::MemRegionVal>(L).getRegion();
+  
+  if (R) {
+    RegionBindingsTy B = GetRegionBindings(store);  
+    return RBFactory.Remove(B, R).getRoot();
+  }
+  
+  return store;
+}
+
 const GRState* RegionStoreManager::Bind(const GRState* St, Loc L, SVal V) {
   // If we get here, the location should be a region.
   const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion();
   assert(R);
-
+  
   // Check if the region is a struct region.
   if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
     if (TR->getValueType(getContext())->isStructureType())
       return BindStruct(St, TR, V);
-
+  
   Store store = St->getStore();
   RegionBindingsTy B = GetRegionBindings(store);
-
+  
   if (V.isUnknown()) {
     // Remove the binding.
     store = RBFactory.Remove(B, R).getRoot();
-
+    
     // Add the region to the killset.
     GRStateRef state(St, StateMgr);
     St = state.add<RegionKills>(R);
   } 
   else
     store = RBFactory.Add(B, R, V).getRoot();
-
-  return StateMgr.MakeStateWithStore(St, store);
-}
-
-Store RegionStoreManager::Remove(Store store, Loc L) {
-  const MemRegion* R = 0;
-  
-  if (isa<loc::MemRegionVal>(L))
-    R = cast<loc::MemRegionVal>(L).getRegion();
   
-  if (R) {
-    RegionBindingsTy B = GetRegionBindings(store);  
-    return RBFactory.Remove(B, R).getRoot();
-  }
-  
-  return store;
+  return StateMgr.MakeStateWithStore(St, store);
 }
 
 const GRState* RegionStoreManager::BindDecl(const GRState* St, 
@@ -946,182 +1015,6 @@
   return Bind(St, loc::MemRegionVal(R), V);
 }
 
-const GRState* RegionStoreManager::setExtent(const GRState* St,
-                                             const MemRegion* R, SVal Extent) {
-  GRStateRef state(St, StateMgr);
-  return state.set<RegionExtents>(R, Extent);
-}
-
-
-static void UpdateLiveSymbols(SVal X, SymbolReaper& SymReaper) {
-  if (loc::MemRegionVal *XR = dyn_cast<loc::MemRegionVal>(&X)) {
-    const MemRegion *R = XR->getRegion();
-    
-    while (R) {
-      if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
-        SymReaper.markLive(SR->getSymbol());
-        return;
-      }
-      
-      if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
-        R = SR->getSuperRegion();
-        continue;
-      }
-      
-      break;
-    }
-    
-    return;
-  }
-  
-  for (SVal::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();SI!=SE;++SI)
-    SymReaper.markLive(*SI);
-}
-
-Store RegionStoreManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, 
-                                             SymbolReaper& SymReaper,
-                           llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
-{
-
-  Store store = state->getStore();
-  RegionBindingsTy B = GetRegionBindings(store);
-  
-  // Lazily constructed backmap from MemRegions to SubRegions.
-  typedef llvm::ImmutableSet<const MemRegion*> SubRegionsTy;
-  typedef llvm::ImmutableMap<const MemRegion*, SubRegionsTy> SubRegionsMapTy;
-  
-  // FIXME: As a future optimization we can modifiy BumpPtrAllocator to have
-  // the ability to reuse memory.  This way we can keep TmpAlloc around as
-  // an instance variable of RegionStoreManager (avoiding repeated malloc
-  // overhead).
-  llvm::BumpPtrAllocator TmpAlloc;
-  
-  // Factory objects.
-  SubRegionsMapTy::Factory SubRegMapF(TmpAlloc);
-  SubRegionsTy::Factory SubRegF(TmpAlloc);
-  
-  // The backmap from regions to subregions.
-  SubRegionsMapTy SubRegMap = SubRegMapF.GetEmptyMap();
-  
-  // Do a pass over the regions in the store.  For VarRegions we check if
-  // the variable is still live and if so add it to the list of live roots.
-  // For other regions we populate our region backmap.
-
-  llvm::SmallVector<const MemRegion*, 10> IntermediateRoots;
-
-  for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
-    IntermediateRoots.push_back(I.getKey());
-  }
-
-  while (!IntermediateRoots.empty()) {
-    const MemRegion* R = IntermediateRoots.back();
-    IntermediateRoots.pop_back();
-
-    if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
-      if (SymReaper.isLive(Loc, VR->getDecl()))
-        RegionRoots.push_back(VR); // This is a live "root".
-    } 
-    else if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
-      if (SymReaper.isLive(SR->getSymbol()))
-        RegionRoots.push_back(SR);
-    }
-    else {
-      // Get the super region for R.
-      const MemRegion* SuperR = cast<SubRegion>(R)->getSuperRegion();
-
-      // Get the current set of subregions for SuperR.
-      const SubRegionsTy* SRptr = SubRegMap.lookup(SuperR);
-      SubRegionsTy SRs = SRptr ? *SRptr : SubRegF.GetEmptySet();
-
-      // Add R to the subregions of SuperR.
-      SubRegMap = SubRegMapF.Add(SubRegMap, SuperR, SubRegF.Add(SRs, R));
-
-      // Super region may be VarRegion or subregion of another VarRegion. Add it
-      // to the work list.
-      if (isa<SubRegion>(SuperR))
-        IntermediateRoots.push_back(SuperR);
-    }
-  }
-  
-  // Process the worklist of RegionRoots.  This performs a "mark-and-sweep"
-  // of the store.  We want to find all live symbols and dead regions.  
-  llvm::SmallPtrSet<const MemRegion*, 10> Marked;
-  
-  while (!RegionRoots.empty()) {
-    // Dequeue the next region on the worklist.
-    const MemRegion* R = RegionRoots.back();
-    RegionRoots.pop_back();
-
-    // Check if we have already processed this region.
-    if (Marked.count(R)) continue;
-
-    // Mark this region as processed.  This is needed for termination in case
-    // a region is referenced more than once.
-    Marked.insert(R);
-    
-    // Mark the symbol for any live SymbolicRegion as "live".  This means we
-    // should continue to track that symbol.
-    if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
-      SymReaper.markLive(SymR->getSymbol());
-
-    // Get the data binding for R (if any).
-    RegionBindingsTy::data_type* Xptr = B.lookup(R);
-    if (Xptr) {
-      SVal X = *Xptr;
-      UpdateLiveSymbols(X, SymReaper); // Update the set of live symbols.
-    
-      // If X is a region, then add it the RegionRoots.
-      if (loc::MemRegionVal* RegionX = dyn_cast<loc::MemRegionVal>(&X))
-        RegionRoots.push_back(RegionX->getRegion());
-    }
-    
-    // Get the subregions of R.  These are RegionRoots as well since they
-    // represent values that are also bound to R.
-    const SubRegionsTy* SRptr = SubRegMap.lookup(R);      
-    if (!SRptr) continue;
-    SubRegionsTy SR = *SRptr;
-    
-    for (SubRegionsTy::iterator I=SR.begin(), E=SR.end(); I!=E; ++I)
-      RegionRoots.push_back(*I);
-  }
-  
-  // We have now scanned the store, marking reachable regions and symbols
-  // as live.  We now remove all the regions that are dead from the store
-  // as well as update DSymbols with the set symbols that are now dead.  
-  for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
-    const MemRegion* R = I.getKey();
-    
-    // If this region live?  Is so, none of its symbols are dead.
-    if (Marked.count(R))
-      continue;
-    
-    // Remove this dead region from the store.
-    store = Remove(store, Loc::MakeVal(R));
-
-    // Mark all non-live symbols that this region references as dead.
-    if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
-      SymReaper.maybeDead(SymR->getSymbol());
-
-    SVal X = I.getData();
-    SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
-    for (; SI != SE; ++SI) SymReaper.maybeDead(*SI);
-  }
-  
-  return store;
-}
-
-void RegionStoreManager::print(Store store, std::ostream& Out, 
-                               const char* nl, const char *sep) {
-  llvm::raw_os_ostream OS(Out);
-  RegionBindingsTy B = GetRegionBindings(store);
-  OS << "Store:" << nl;
-
-  for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
-    OS << ' '; I.getKey()->print(OS); OS << " : ";
-    I.getData().print(OS); OS << nl;
-  }
-}
-
 const GRState* RegionStoreManager::BindArray(const GRState* St, 
                                              const TypedRegion* R, SVal Init) {
   QualType T = R->getValueType(getContext());
@@ -1264,6 +1157,10 @@
   return StateMgr.MakeStateWithStore(St, store);
 }
 
+//===----------------------------------------------------------------------===//
+// Region views.
+//===----------------------------------------------------------------------===//
+
 const GRState* RegionStoreManager::AddRegionView(const GRState* St,
                                                  const MemRegion* View,
                                                  const MemRegion* Base) {
@@ -1310,3 +1207,180 @@
   GRStateRef state(St, StateMgr);
   return state.set<RegionDefaultValue>(R, V);
 }
+
+//===----------------------------------------------------------------------===//
+// State pruning.
+//===----------------------------------------------------------------------===//
+
+static void UpdateLiveSymbols(SVal X, SymbolReaper& SymReaper) {
+  if (loc::MemRegionVal *XR = dyn_cast<loc::MemRegionVal>(&X)) {
+    const MemRegion *R = XR->getRegion();
+    
+    while (R) {
+      if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
+        SymReaper.markLive(SR->getSymbol());
+        return;
+      }
+      
+      if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
+        R = SR->getSuperRegion();
+        continue;
+      }
+      
+      break;
+    }
+    
+    return;
+  }
+  
+  for (SVal::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();SI!=SE;++SI)
+    SymReaper.markLive(*SI);
+}
+
+Store RegionStoreManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, 
+                                             SymbolReaper& SymReaper,
+                           llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
+  
+  Store store = state->getStore();
+  RegionBindingsTy B = GetRegionBindings(store);
+  
+  // Lazily constructed backmap from MemRegions to SubRegions.
+  typedef llvm::ImmutableSet<const MemRegion*> SubRegionsTy;
+  typedef llvm::ImmutableMap<const MemRegion*, SubRegionsTy> SubRegionsMapTy;
+  
+  // FIXME: As a future optimization we can modifiy BumpPtrAllocator to have
+  // the ability to reuse memory.  This way we can keep TmpAlloc around as
+  // an instance variable of RegionStoreManager (avoiding repeated malloc
+  // overhead).
+  llvm::BumpPtrAllocator TmpAlloc;
+  
+  // Factory objects.
+  SubRegionsMapTy::Factory SubRegMapF(TmpAlloc);
+  SubRegionsTy::Factory SubRegF(TmpAlloc);
+  
+  // The backmap from regions to subregions.
+  SubRegionsMapTy SubRegMap = SubRegMapF.GetEmptyMap();
+  
+  // Do a pass over the regions in the store.  For VarRegions we check if
+  // the variable is still live and if so add it to the list of live roots.
+  // For other regions we populate our region backmap.
+  
+  llvm::SmallVector<const MemRegion*, 10> IntermediateRoots;
+  
+  for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+    IntermediateRoots.push_back(I.getKey());
+  }
+  
+  while (!IntermediateRoots.empty()) {
+    const MemRegion* R = IntermediateRoots.back();
+    IntermediateRoots.pop_back();
+    
+    if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
+      if (SymReaper.isLive(Loc, VR->getDecl()))
+        RegionRoots.push_back(VR); // This is a live "root".
+    } 
+    else if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
+      if (SymReaper.isLive(SR->getSymbol()))
+        RegionRoots.push_back(SR);
+    }
+    else {
+      // Get the super region for R.
+      const MemRegion* SuperR = cast<SubRegion>(R)->getSuperRegion();
+      
+      // Get the current set of subregions for SuperR.
+      const SubRegionsTy* SRptr = SubRegMap.lookup(SuperR);
+      SubRegionsTy SRs = SRptr ? *SRptr : SubRegF.GetEmptySet();
+      
+      // Add R to the subregions of SuperR.
+      SubRegMap = SubRegMapF.Add(SubRegMap, SuperR, SubRegF.Add(SRs, R));
+      
+      // Super region may be VarRegion or subregion of another VarRegion. Add it
+      // to the work list.
+      if (isa<SubRegion>(SuperR))
+        IntermediateRoots.push_back(SuperR);
+    }
+  }
+  
+  // Process the worklist of RegionRoots.  This performs a "mark-and-sweep"
+  // of the store.  We want to find all live symbols and dead regions.  
+  llvm::SmallPtrSet<const MemRegion*, 10> Marked;
+  
+  while (!RegionRoots.empty()) {
+    // Dequeue the next region on the worklist.
+    const MemRegion* R = RegionRoots.back();
+    RegionRoots.pop_back();
+    
+    // Check if we have already processed this region.
+    if (Marked.count(R)) continue;
+    
+    // Mark this region as processed.  This is needed for termination in case
+    // a region is referenced more than once.
+    Marked.insert(R);
+    
+    // Mark the symbol for any live SymbolicRegion as "live".  This means we
+    // should continue to track that symbol.
+    if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
+      SymReaper.markLive(SymR->getSymbol());
+    
+    // Get the data binding for R (if any).
+    RegionBindingsTy::data_type* Xptr = B.lookup(R);
+    if (Xptr) {
+      SVal X = *Xptr;
+      UpdateLiveSymbols(X, SymReaper); // Update the set of live symbols.
+      
+      // If X is a region, then add it the RegionRoots.
+      if (loc::MemRegionVal* RegionX = dyn_cast<loc::MemRegionVal>(&X))
+        RegionRoots.push_back(RegionX->getRegion());
+    }
+    
+    // Get the subregions of R.  These are RegionRoots as well since they
+    // represent values that are also bound to R.
+    const SubRegionsTy* SRptr = SubRegMap.lookup(R);      
+    if (!SRptr) continue;
+    SubRegionsTy SR = *SRptr;
+    
+    for (SubRegionsTy::iterator I=SR.begin(), E=SR.end(); I!=E; ++I)
+      RegionRoots.push_back(*I);
+  }
+  
+  // We have now scanned the store, marking reachable regions and symbols
+  // as live.  We now remove all the regions that are dead from the store
+  // as well as update DSymbols with the set symbols that are now dead.  
+  for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+    const MemRegion* R = I.getKey();
+    
+    // If this region live?  Is so, none of its symbols are dead.
+    if (Marked.count(R))
+      continue;
+    
+    // Remove this dead region from the store.
+    store = Remove(store, Loc::MakeVal(R));
+    
+    // Mark all non-live symbols that this region references as dead.
+    if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
+      SymReaper.maybeDead(SymR->getSymbol());
+    
+    SVal X = I.getData();
+    SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
+    for (; SI != SE; ++SI) SymReaper.maybeDead(*SI);
+  }
+  
+  return store;
+}
+
+//===----------------------------------------------------------------------===//
+// Utility methods.
+//===----------------------------------------------------------------------===//
+
+void RegionStoreManager::print(Store store, std::ostream& Out, 
+                               const char* nl, const char *sep) {
+  llvm::raw_os_ostream OS(Out);
+  RegionBindingsTy B = GetRegionBindings(store);
+  OS << "Store:" << nl;
+  
+  for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+    OS << ' '; I.getKey()->print(OS); OS << " : ";
+    I.getData().print(OS); OS << nl;
+  }
+}





More information about the cfe-commits mailing list