[cfe-commits] r93922 - in /cfe/trunk: include/clang/Analysis/CFG.h lib/Analysis/CFG.cpp

Mike Stump mrs at apple.com
Tue Jan 19 14:00:14 PST 2010


Author: mrs
Date: Tue Jan 19 16:00:14 2010
New Revision: 93922

URL: http://llvm.org/viewvc/llvm-project?rev=93922&view=rev
Log:
Add CFG support for the start and end of scopes and infrastructure for
implicit destructor calls.  WIP.

Modified:
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/lib/Analysis/CFG.cpp

Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=93922&r1=93921&r2=93922&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Tue Jan 19 16:00:14 2010
@@ -20,6 +20,7 @@
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
 #include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Basic/SourceLocation.h"
 #include <cassert>
 
 namespace llvm {
@@ -33,15 +34,39 @@
   class LangOptions;
   class ASTContext;
 
+namespace {
+// An element of the CFG for implicit descructor calls implied by the language
+// rules.
+class Dtor {
+  // Statement that introduces the variable.
+  Stmt *S;
+  // A token which ends the scope, return, goto, throw, }.
+  SourceLocation Loc;
+public:
+  Dtor(Stmt *s, SourceLocation l) : S(s), Loc(l) {
+  }
+  SourceLocation getLoc() { return Loc; }
+  Stmt *getStmt() { return S; }
+};
+}
+
 /// CFGElement - Represents a top-level expression in a basic block.
 class CFGElement {
-  llvm::PointerIntPair<Stmt *, 1> Data;
+  llvm::PointerIntPair<Stmt *, 2> Data;
 public:
+  enum Type { StartScope, EndScope };
   explicit CFGElement() {}
   CFGElement(Stmt *S, bool lvalue) : Data(S, lvalue ? 1 : 0) {}
+  CFGElement(Stmt *S, Type t) : Data(S, t == StartScope ? 2 : 3) {}
+  // CFGElement(Dtor *S, Type t) : Data(reinterpret_cast<Stmt*>(S), 4) {}
   Stmt *getStmt() const { return Data.getPointer(); }
   bool asLValue() const { return Data.getInt() == 1; }
+  bool asStartScope() const { return Data.getInt() == 2; }
+  bool asEndScope() const { return Data.getInt() == 3; }
+  bool asDtor() const { return Data.getInt() == 4; }
   operator Stmt*() const { return getStmt(); }
+  operator bool() const { return getStmt() != 0; }
+  operator Dtor*() const { return reinterpret_cast<Dtor*>(getStmt()); }
 };
 
 /// CFGBlock - Represents a single basic block in a source-level CFG.
@@ -236,6 +261,12 @@
   void appendStmt(Stmt* Statement, BumpVectorContext &C, bool asLValue) {
       Stmts.push_back(CFGElement(Statement, asLValue), C);
   }  
+  void StartScope(Stmt* S, BumpVectorContext &C) {
+    Stmts.push_back(CFGElement(S, CFGElement::StartScope), C);
+  }
+  void EndScope(Stmt* S, BumpVectorContext &C) {
+    Stmts.push_back(CFGElement(S, CFGElement::EndScope), C);
+  }
 };
 
 
@@ -254,7 +285,7 @@
 
   /// buildCFG - Builds a CFG from an AST.  The responsibility to free the
   ///   constructed CFG belongs to the caller.
-  static CFG* buildCFG(Stmt* AST, ASTContext *C);
+  static CFG* buildCFG(Stmt* AST, ASTContext *C, bool AddScopes = false);
 
   /// createBlock - Create a new block in the CFG.  The CFG owns the block;
   ///  the caller should not directly free it.

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

==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Tue Jan 19 16:00:14 2010
@@ -93,7 +93,7 @@
                           TryTerminatedBlock(NULL) {}
 
   // buildCFG - Used by external clients to construct the CFG.
-  CFG* buildCFG(Stmt *Statement, ASTContext *C);
+  CFG* buildCFG(Stmt *Statement, ASTContext *C, bool AddScopes);
 
 private:
   // Visitors to walk an AST and construct the CFG.
@@ -141,6 +141,25 @@
     return Block;
   }
 
+  CFGBlock *StartScope(Stmt *S, CFGBlock *B) {
+    if (!AddScopes)
+      return B;
+
+    if (B == 0)
+      B = createBlock();
+    B->StartScope(S, cfg->getBumpVectorContext());
+    return B;
+  }
+
+  void EndScope(Stmt *S) {
+    if (!AddScopes)
+      return;
+
+    if (Block == 0)
+      Block = createBlock();
+    Block->EndScope(S, cfg->getBumpVectorContext());
+  }
+
   void autoCreateBlock() { if (!Block) Block = createBlock(); }
   CFGBlock *createBlock(bool add_successor = true);
   bool FinishBlock(CFGBlock* B);
@@ -188,6 +207,7 @@
   }
 
   bool badCFG;
+  bool AddScopes;
 };
 
 // FIXME: Add support for dependent-sized array types in C++?
@@ -209,12 +229,13 @@
 ///  body (compound statement).  The ownership of the returned CFG is
 ///  transferred to the caller.  If CFG construction fails, this method returns
 ///  NULL.
-CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) {
+CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C, bool AddScopes) {
   Context = C;
   assert(cfg.get());
   if (!Statement)
     return NULL;
 
+  this->AddScopes = AddScopes;
   badCFG = false;
 
   // Create an empty block that will serve as the exit block for the CFG.  Since
@@ -519,22 +540,43 @@
     NoReturn = true;
   }
 
-  if (FunctionDecl *FD = C->getDirectCallee())
+  bool CanThrow = false;
+
+  // Languages without exceptions are assumed to not throw.
+  if (Context->getLangOptions().Exceptions) {
+    CanThrow = true;
+  }
+
+  if (FunctionDecl *FD = C->getDirectCallee()) {
     if (FD->hasAttr<NoReturnAttr>())
       NoReturn = true;
+    if (FD->hasAttr<NoThrowAttr>())
+      CanThrow = false;
+  }
 
-  if (!NoReturn)
+  if (!NoReturn && !CanThrow)
     return VisitStmt(C, asc);
 
-  if (Block && !FinishBlock(Block))
-    return 0;
+  if (Block) {
+    Succ = Block;
+    if (!FinishBlock(Block))
+      return 0;
+  }
 
-  // Create new block with no successor for the remaining pieces.
-  Block = createBlock(false);
+  Block = createBlock(!NoReturn);
   AppendStmt(Block, C, asc);
 
-  // Wire this to the exit block directly.
-  AddSuccessor(Block, &cfg->getExit());
+  if (NoReturn) {
+    // Wire this to the exit block directly.
+    AddSuccessor(Block, &cfg->getExit());
+  }
+  if (CanThrow) {
+    // Add exceptional edges.
+    if (TryTerminatedBlock)
+      AddSuccessor(Block, TryTerminatedBlock);
+    else
+      AddSuccessor(Block, &cfg->getExit());
+  }
 
   return VisitChildren(C);
 }
@@ -569,6 +611,8 @@
 
 
 CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
+  EndScope(C);
+
   CFGBlock* LastBlock = Block;
 
   for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
@@ -578,6 +622,9 @@
     if (badCFG)
       return NULL;
   }
+
+  LastBlock = StartScope(C, LastBlock);
+
   return LastBlock;
 }
 
@@ -1648,9 +1695,9 @@
 
 /// buildCFG - Constructs a CFG from an AST.  Ownership of the returned
 ///  CFG is returned to the caller.
-CFG* CFG::buildCFG(Stmt* Statement, ASTContext *C) {
+CFG* CFG::buildCFG(Stmt* Statement, ASTContext *C, bool AddScopes) {
   CFGBuilder Builder;
-  return Builder.buildCFG(Statement, C);
+  return Builder.buildCFG(Statement, C, AddScopes);
 }
 
 //===----------------------------------------------------------------------===//
@@ -1909,7 +1956,18 @@
 
 
 static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
-                       Stmt* Terminator) {
+                       const CFGElement &E) {
+  Stmt *Terminator = E;
+
+  if (E.asStartScope()) {
+    OS << "start scope\n";
+    return;
+  }
+  if (E.asEndScope()) {
+    OS << "end scope\n";
+    return;
+  }
+
   if (Helper) {
     // special printing for statement-expressions.
     if (StmtExpr* SE = dyn_cast<StmtExpr>(Terminator)) {
@@ -1959,14 +2017,14 @@
     OS << " ]\n";
 
   // Print the label of this block.
-  if (Stmt* Terminator = const_cast<Stmt*>(B.getLabel())) {
+  if (Stmt* Label = const_cast<Stmt*>(B.getLabel())) {
 
     if (print_edges)
       OS << "    ";
 
-    if (LabelStmt* L = dyn_cast<LabelStmt>(Terminator))
+    if (LabelStmt* L = dyn_cast<LabelStmt>(Label))
       OS << L->getName();
-    else if (CaseStmt* C = dyn_cast<CaseStmt>(Terminator)) {
+    else if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
       OS << "case ";
       C->getLHS()->printPretty(OS, Helper,
                                PrintingPolicy(Helper->getLangOpts()));
@@ -1975,9 +2033,9 @@
         C->getRHS()->printPretty(OS, Helper,
                                  PrintingPolicy(Helper->getLangOpts()));
       }
-    } else if (isa<DefaultStmt>(Terminator))
+    } else if (isa<DefaultStmt>(Label))
       OS << "default";
-    else if (CXXCatchStmt *CS = dyn_cast<CXXCatchStmt>(Terminator)) {
+    else if (CXXCatchStmt *CS = dyn_cast<CXXCatchStmt>(Label)) {
       OS << "catch (";
       CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper->getLangOpts()),
         0);





More information about the cfe-commits mailing list