Speed up compilation by avoiding generating exceptional edges from
CallExprs as those edges help cause a n^2 explosion in the number of
destructor calls.  Other consumers, such as static analysis, that
would like to have more a more complete CFG can select the inclusion
of those edges as CFG build time.

This also fixes up the two compilation users of CFGs to be tolerant of
having or not having those edges.  All catch code is assumed be to
live if we didn't generate the exceptional edges for CallExprs.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94074 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 57053b1..ef3cdd8 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -94,7 +94,8 @@
                           TryTerminatedBlock(NULL) {}
 
   // buildCFG - Used by external clients to construct the CFG.
-  CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddScopes);
+  CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddEHEdges,
+                bool AddScopes);
 
 private:
   // Visitors to walk an AST and construct the CFG.
@@ -208,6 +209,11 @@
   }
 
   bool badCFG;
+
+  // True iff EH edges on CallExprs should be added to the CFG.
+  bool AddEHEdges;
+
+  // True iff scope start and scope end notes should be added to the CFG.
   bool AddScopes;
 };
 
@@ -231,7 +237,7 @@
 ///  transferred to the caller.  If CFG construction fails, this method returns
 ///  NULL.
 CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
-                          bool AddScopes) {
+                          bool AddEHEdges, bool AddScopes) {
   Context = C;
   assert(cfg.get());
   if (!Statement)
@@ -540,6 +546,22 @@
   return Block;
 }
 
+static bool CanThrow(Expr *E) {
+  QualType Ty = E->getType();
+  if (Ty->isFunctionPointerType())
+    Ty = Ty->getAs<PointerType>()->getPointeeType();
+  else if (Ty->isBlockPointerType())
+    Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
+    
+  const FunctionType *FT = Ty->getAs<FunctionType>();
+  if (FT) {
+    if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
+      if (Proto->hasEmptyExceptionSpec())
+        return false;
+  }
+  return true;
+}
+
 CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
   // If this is a call to a no-return function, this stops the block here.
   bool NoReturn = false;
@@ -547,21 +569,25 @@
     NoReturn = true;
   }
 
-  bool CanThrow = false;
+  bool AddEHEdge = false;
 
   // Languages without exceptions are assumed to not throw.
   if (Context->getLangOptions().Exceptions) {
-    CanThrow = true;
+    if (AddEHEdges)
+      AddEHEdge = true;
   }
 
   if (FunctionDecl *FD = C->getDirectCallee()) {
     if (FD->hasAttr<NoReturnAttr>())
       NoReturn = true;
     if (FD->hasAttr<NoThrowAttr>())
-      CanThrow = false;
+      AddEHEdge = false;
   }
 
-  if (!NoReturn && !CanThrow)
+  if (!CanThrow(C->getCallee()))
+    AddEHEdge = false;
+
+  if (!NoReturn && !AddEHEdge)
     return VisitStmt(C, asc);
 
   if (Block) {
@@ -577,7 +603,7 @@
     // Wire this to the exit block directly.
     AddSuccessor(Block, &cfg->getExit());
   }
-  if (CanThrow) {
+  if (AddEHEdge) {
     // Add exceptional edges.
     if (TryTerminatedBlock)
       AddSuccessor(Block, TryTerminatedBlock);
@@ -1714,9 +1740,9 @@
 /// buildCFG - Constructs a CFG from an AST.  Ownership of the returned
 ///  CFG is returned to the caller.
 CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C,
-                   bool AddScopes) {
+                   bool AddEHEdges, bool AddScopes) {
   CFGBuilder Builder;
-  return Builder.buildCFG(D, Statement, C, AddScopes);
+  return Builder.buildCFG(D, Statement, C, AddEHEdges, AddScopes);
 }
 
 //===----------------------------------------------------------------------===//