Bug fix in CFG::getBlockEdgeImpl(): Use a BumpPtrAllocator to allocate
std::pair<CFGBlock*, CFGBlock*> that have an 8-byte alignment for use with
ProgramPoint. This fixes a bug reported by Argiris where using std::set<> on
Windows would result in a 4-byte alignment, not an 8-byte alignment.

Fixes: <rdar://problem/5892265>


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50364 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/CFG.h b/include/clang/AST/CFG.h
index 2cc3c62..162240a 100644
--- a/include/clang/AST/CFG.h
+++ b/include/clang/AST/CFG.h
@@ -281,7 +281,7 @@
   //===--------------------------------------------------------------------===//
 
   CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0), 
-          BlkExprMap(NULL), BlkEdgeSet(NULL) {};
+          BlkExprMap(NULL), BlkEdgeSet(NULL), Allocator(NULL) {};
   
   ~CFG();
     
@@ -298,13 +298,16 @@
   //  block-level expressions and their "statement number" in the CFG.
   void*     BlkExprMap;
   
-  /// BlkEdgeSet - An opaque pointer to prevent inclusion of <set>.
+  /// BlkEdgeSet - An opaque pointer to prevent inclusion of FoldingSet.h.
   ///  The set contains std::pair<CFGBlock*,CFGBlock*> objects that have
   ///  stable references for use by the 'BlockEdge' class.  This set is intended
   ///  to be sparse, as it only contains edges whether both the source
   ///  and destination block have multiple successors/predecessors.
   void*     BlkEdgeSet;
   
+  /// Alloc - An internal allocator used for BlkEdgeSet.
+  void*     Allocator;
+  
   friend class BlockEdge;
   
   /// getBlockEdgeImpl - Utility method used by the class BlockEdge.  The CFG
diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp
index 6277aae..aa5bbe4 100644
--- a/lib/AST/CFG.cpp
+++ b/lib/AST/CFG.cpp
@@ -21,11 +21,10 @@
 #include "llvm/Support/GraphWriter.h"
 #include "llvm/Support/Streams.h"
 #include "llvm/Support/Compiler.h"
-#include <set>
+#include <llvm/Support/Allocator.h>
 #include <iomanip>
 #include <algorithm>
 #include <sstream>
-#include <iostream>
 
 using namespace clang;
 
@@ -115,14 +114,20 @@
   
   // FIXME: Add support for ObjC-specific control-flow structures.
   
-  CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* Terminator) {
+  // NYS == Not Yet Supported
+  CFGBlock* NYS() {
     badCFG = true;
     return Block;
   }
   
-  CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* Terminator) {
-    badCFG = true;
-    return Block;
+  CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S){ return NYS();}
+  CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S) { return NYS(); }
+  CFGBlock* VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) { return NYS(); }
+  CFGBlock* VisitObjCAtFinallyStmt(ObjCAtFinallyStmt* S) { return NYS(); }
+  CFGBlock* VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) { return NYS(); }
+
+  CFGBlock* VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S){
+    return NYS();
   }
   
 private:
@@ -1150,21 +1155,77 @@
   }
 }
 
-typedef std::set<std::pair<CFGBlock*,CFGBlock*> > BlkEdgeSetTy;
+//===----------------------------------------------------------------------===//
+// Internal Block-Edge Set; used for modeling persistent <CFGBlock*,CFGBlock*>
+// pairs for use with ProgramPoint.
+//===----------------------------------------------------------------------===//
+
+typedef std::pair<CFGBlock*,CFGBlock*> BPairTy;
+
+namespace llvm {
+  template<> struct FoldingSetTrait<BPairTy*> {
+    static void Profile(const BPairTy* X, FoldingSetNodeID& profile) {
+      profile.AddPointer(X->first);
+      profile.AddPointer(X->second);
+    }
+  };
+}
+
+typedef llvm::FoldingSetNodeWrapper<BPairTy*> PersistPairTy;
+typedef llvm::FoldingSet<PersistPairTy> BlkEdgeSetTy;
 
 const std::pair<CFGBlock*,CFGBlock*>*
 CFG::getBlockEdgeImpl(const CFGBlock* B1, const CFGBlock* B2) {
   
-  BlkEdgeSetTy*& p = reinterpret_cast<BlkEdgeSetTy*&>(BlkEdgeSet);
-  if (!p) p = new BlkEdgeSetTy();
+  llvm::BumpPtrAllocator*& Alloc =
+    reinterpret_cast<llvm::BumpPtrAllocator*&>(Allocator);
   
-  return &*(p->insert(std::make_pair(const_cast<CFGBlock*>(B1),
-                                     const_cast<CFGBlock*>(B2))).first);
+  if (!Alloc)
+    Alloc = new llvm::BumpPtrAllocator();
+
+  BlkEdgeSetTy*& p = reinterpret_cast<BlkEdgeSetTy*&>(BlkEdgeSet);
+
+  if (!p)
+    p = new BlkEdgeSetTy();
+  
+  // Profile the edges.
+  llvm::FoldingSetNodeID profile;
+  void* InsertPos;
+  
+  profile.AddPointer(B1);
+  profile.AddPointer(B2);
+  
+  PersistPairTy* V = p->FindNodeOrInsertPos(profile, InsertPos);  
+  
+  if (!V) {
+    assert (llvm::AlignOf<BPairTy>::Alignment_LessEqual_8Bytes);
+    
+    // Allocate the pair, forcing an 8-byte alignment.
+    BPairTy* pair = (BPairTy*) Alloc->Allocate(sizeof(*pair), 8);
+
+    new (pair) BPairTy(const_cast<CFGBlock*>(B1),
+                       const_cast<CFGBlock*>(B2));
+    
+    // Allocate the meta data to store the pair in the FoldingSet.
+    PersistPairTy* ppair = (PersistPairTy*) Alloc->Allocate<PersistPairTy>();
+    new (ppair) PersistPairTy(pair);
+    
+    p->InsertNode(ppair, InsertPos);
+    
+    return pair;
+  }
+  
+  return V->getValue();
 }
 
+//===----------------------------------------------------------------------===//
+// Cleanup: CFG dstor.
+//===----------------------------------------------------------------------===//
+
 CFG::~CFG() {
   delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
   delete reinterpret_cast<BlkEdgeSetTy*>(BlkEdgeSet);
+  delete reinterpret_cast<llvm::BumpPtrAllocator*> (Allocator);
 }
   
 //===----------------------------------------------------------------------===//
@@ -1542,9 +1603,6 @@
   GraphHelper = &H;
   llvm::ViewGraph(this,"CFG");
   GraphHelper = NULL;
-#else
-  std::cerr << "CFG::viewCFG is only available in debug builds on "
-            << "systems with Graphviz or gv!\n";
 #endif
 }