Add CFG support for the start and end of scopes and infrastructure for

implicit destructor calls.  WIP.

llvm-svn: 93922
This commit is contained in:
Mike Stump 2010-01-19 22:00:14 +00:00
parent d693472821
commit 92244b00c7
2 changed files with 109 additions and 20 deletions

View File

@ -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 @@ namespace clang {
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 @@ public:
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 @@ public:
/// 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.

View File

@ -93,7 +93,7 @@ public:
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 @@ private:
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 @@ private:
}
bool badCFG;
bool AddScopes;
};
// FIXME: Add support for dependent-sized array types in C++?
@ -209,12 +229,13 @@ static VariableArrayType* FindVA(Type* t) {
/// 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 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
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::VisitChooseExpr(ChooseExpr *C,
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 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
if (badCFG)
return NULL;
}
LastBlock = StartScope(C, LastBlock);
return LastBlock;
}
@ -1648,9 +1695,9 @@ CFGBlock* CFG::createBlock() {
/// 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 @@ public:
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 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
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 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
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);