Changeset View
Changeset View
Standalone View
Standalone View
lib/Analysis/CFG.cpp
Show First 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | const_iterator(const LocalScope& S, unsigned I) | ||||
*this = Scope->Prev; | *this = Scope->Prev; | ||||
} | } | ||||
VarDecl *const* operator->() const { | VarDecl *const* operator->() const { | ||||
assert(Scope && "Dereferencing invalid iterator is not allowed"); | assert(Scope && "Dereferencing invalid iterator is not allowed"); | ||||
assert(VarIter != 0 && "Iterator has invalid value of VarIter member"); | assert(VarIter != 0 && "Iterator has invalid value of VarIter member"); | ||||
return &Scope->Vars[VarIter - 1]; | return &Scope->Vars[VarIter - 1]; | ||||
} | } | ||||
const VarDecl *getFirstVarInScope() const { | |||||
assert(Scope && "Dereferencing invalid iterator is not allowed"); | |||||
assert(VarIter != 0 && "Iterator has invalid value of VarIter member"); | |||||
return Scope->Vars[0]; | |||||
} | |||||
VarDecl *operator*() const { | VarDecl *operator*() const { | ||||
return *this->operator->(); | return *this->operator->(); | ||||
} | } | ||||
const_iterator &operator++() { | const_iterator &operator++() { | ||||
if (!Scope) | if (!Scope) | ||||
return *this; | return *this; | ||||
dcoughlin: I think it would be helpful to name this something more expressive (perhaps "TriggerStmt") so… | |||||
assert(VarIter != 0 && "Iterator has invalid value of VarIter member"); | assert(VarIter != 0 && "Iterator has invalid value of VarIter member"); | ||||
--VarIter; | --VarIter; | ||||
if (VarIter == 0) | if (VarIter == 0) | ||||
*this = Scope->Prev; | *this = Scope->Prev; | ||||
return *this; | return *this; | ||||
} | } | ||||
const_iterator operator++(int) { | const_iterator operator++(int) { | ||||
Show All 10 Lines | public: | ||||
} | } | ||||
explicit operator bool() const { | explicit operator bool() const { | ||||
return *this != const_iterator(); | return *this != const_iterator(); | ||||
} | } | ||||
int distance(const_iterator L); | int distance(const_iterator L); | ||||
const_iterator shared_parent(const_iterator L); | const_iterator shared_parent(const_iterator L); | ||||
bool pointsToFirstDeclaredVar() { return VarIter == 1; } | |||||
}; | }; | ||||
private: | private: | ||||
BumpVectorContext ctx; | BumpVectorContext ctx; | ||||
/// Automatic variables in order of declaration. | /// Automatic variables in order of declaration. | ||||
AutomaticVarsTy Vars; | AutomaticVarsTy Vars; | ||||
▲ Show 20 Lines • Show All 284 Lines • ▼ Show 20 Lines | private: | ||||
CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc); | CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc); | ||||
CFGBlock *VisitWhileStmt(WhileStmt *W); | CFGBlock *VisitWhileStmt(WhileStmt *W); | ||||
CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd); | CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd); | ||||
CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc); | CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc); | ||||
CFGBlock *VisitChildren(Stmt *S); | CFGBlock *VisitChildren(Stmt *S); | ||||
CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc); | CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc); | ||||
void maybeAddScopeBeginForVarDecl(CFGBlock *B, const VarDecl *VD, | |||||
const Stmt *S) { | |||||
if (ScopePos && (VD == ScopePos.getFirstVarInScope())) | |||||
appendScopeBegin(B, VD, S); | |||||
} | |||||
/// When creating the CFG for temporary destructors, we want to mirror the | /// When creating the CFG for temporary destructors, we want to mirror the | ||||
/// branch structure of the corresponding constructor calls. | /// branch structure of the corresponding constructor calls. | ||||
/// Thus, while visiting a statement for temporary destructors, we keep a | /// Thus, while visiting a statement for temporary destructors, we keep a | ||||
/// context to keep track of the following information: | /// context to keep track of the following information: | ||||
/// - whether a subexpression is executed unconditionally | /// - whether a subexpression is executed unconditionally | ||||
/// - if a subexpression is executed conditionally, the first | /// - if a subexpression is executed conditionally, the first | ||||
/// CXXBindTemporaryExpr we encounter in that subexpression (which | /// CXXBindTemporaryExpr we encounter in that subexpression (which | ||||
/// corresponds to the last temporary destructor we have to call for this | /// corresponds to the last temporary destructor we have to call for this | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | private: | ||||
CFGBlock *addStmt(Stmt *S) { | CFGBlock *addStmt(Stmt *S) { | ||||
return Visit(S, AddStmtChoice::AlwaysAdd); | return Visit(S, AddStmtChoice::AlwaysAdd); | ||||
} | } | ||||
CFGBlock *addInitializer(CXXCtorInitializer *I); | CFGBlock *addInitializer(CXXCtorInitializer *I); | ||||
void addLoopExit(const Stmt *LoopStmt); | void addLoopExit(const Stmt *LoopStmt); | ||||
void addAutomaticObjDtors(LocalScope::const_iterator B, | void addAutomaticObjDtors(LocalScope::const_iterator B, | ||||
LocalScope::const_iterator E, Stmt *S); | LocalScope::const_iterator E, | ||||
Stmt *TriggerAutoObjDtorsStmt); | |||||
void addLifetimeEnds(LocalScope::const_iterator B, | void addLifetimeEnds(LocalScope::const_iterator B, | ||||
LocalScope::const_iterator E, Stmt *S); | LocalScope::const_iterator E, Stmt *S); | ||||
void addAutomaticObjHandling(LocalScope::const_iterator B, | void addAutomaticObjHandling(LocalScope::const_iterator B, | ||||
LocalScope::const_iterator E, Stmt *S); | LocalScope::const_iterator E, Stmt *S); | ||||
void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD); | void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD); | ||||
void addScopesEnd(LocalScope::const_iterator B, LocalScope::const_iterator E, | |||||
Stmt *S); | |||||
// Local scopes creation. | // Local scopes creation. | ||||
LocalScope* createOrReuseLocalScope(LocalScope* Scope); | LocalScope *createOrReuseLocalScope(LocalScope *Scope); | ||||
void addLocalScopeForStmt(Stmt *S); | void addLocalScopeForStmt(Stmt *S); | ||||
LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS, | LocalScope *addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope *Scope = nullptr); | ||||
LocalScope* Scope = nullptr); | |||||
LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = nullptr); | LocalScope *addLocalScopeForVarDecl(VarDecl *VD, LocalScope *Scope = nullptr); | ||||
void addLocalScopeAndDtors(Stmt *S); | void addLocalScopeAndDtors(Stmt *S); | ||||
// Interface to CFGBlock - adding CFGElements. | // Interface to CFGBlock - adding CFGElements. | ||||
void appendStmt(CFGBlock *B, const Stmt *S) { | void appendStmt(CFGBlock *B, const Stmt *S) { | ||||
if (alwaysAdd(S) && cachedEntry) | if (alwaysAdd(S) && cachedEntry) | ||||
cachedEntry->second = B; | cachedEntry->second = B; | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | private: | ||||
void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, | void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, | ||||
LocalScope::const_iterator B, LocalScope::const_iterator E); | LocalScope::const_iterator B, LocalScope::const_iterator E); | ||||
void prependAutomaticObjLifetimeWithTerminator(CFGBlock *Blk, | void prependAutomaticObjLifetimeWithTerminator(CFGBlock *Blk, | ||||
LocalScope::const_iterator B, | LocalScope::const_iterator B, | ||||
LocalScope::const_iterator E); | LocalScope::const_iterator E); | ||||
const VarDecl * | |||||
prependAutomaticObjScopeEndWithTerminator(CFGBlock *Blk, | |||||
LocalScope::const_iterator B, | |||||
LocalScope::const_iterator E); | |||||
void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) { | void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) { | ||||
B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable), | B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable), | ||||
cfg->getBumpVectorContext()); | cfg->getBumpVectorContext()); | ||||
} | } | ||||
/// Add a reachable successor to a block, with the alternate variant that is | /// Add a reachable successor to a block, with the alternate variant that is | ||||
/// unreachable. | /// unreachable. | ||||
void addSuccessor(CFGBlock *B, CFGBlock *ReachableBlock, CFGBlock *AltBlock) { | void addSuccessor(CFGBlock *B, CFGBlock *ReachableBlock, CFGBlock *AltBlock) { | ||||
B->addSuccessor(CFGBlock::AdjacentBlock(ReachableBlock, AltBlock), | B->addSuccessor(CFGBlock::AdjacentBlock(ReachableBlock, AltBlock), | ||||
cfg->getBumpVectorContext()); | cfg->getBumpVectorContext()); | ||||
} | } | ||||
void appendScopeBegin(CFGBlock *B, const VarDecl *VD, const Stmt *S) { | |||||
if (BuildOpts.AddScopes) | |||||
B->appendScopeBegin(VD, S, cfg->getBumpVectorContext()); | |||||
} | |||||
void prependScopeBegin(CFGBlock *B, const VarDecl *VD, const Stmt *S) { | |||||
if (BuildOpts.AddScopes) | |||||
B->prependScopeBegin(VD, S, cfg->getBumpVectorContext()); | |||||
} | |||||
void appendScopeEnd(CFGBlock *B, const VarDecl *VD, const Stmt *S) { | |||||
if (BuildOpts.AddScopes) | |||||
B->appendScopeEnd(VD, S, cfg->getBumpVectorContext()); | |||||
} | |||||
void prependScopeEnd(CFGBlock *B, const VarDecl *VD, const Stmt *S) { | |||||
if (BuildOpts.AddScopes) | |||||
B->prependScopeEnd(VD, S, cfg->getBumpVectorContext()); | |||||
} | |||||
/// \brief Find a relational comparison with an expression evaluating to a | /// \brief Find a relational comparison with an expression evaluating to a | ||||
/// boolean and a constant other than 0 and 1. | /// boolean and a constant other than 0 and 1. | ||||
/// e.g. if ((x < y) == 10) | /// e.g. if ((x < y) == 10) | ||||
TryResult checkIncorrectRelationalOperator(const BinaryOperator *B) { | TryResult checkIncorrectRelationalOperator(const BinaryOperator *B) { | ||||
const Expr *LHSExpr = B->getLHS()->IgnoreParens(); | const Expr *LHSExpr = B->getLHS()->IgnoreParens(); | ||||
const Expr *RHSExpr = B->getRHS()->IgnoreParens(); | const Expr *RHSExpr = B->getRHS()->IgnoreParens(); | ||||
const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr); | const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr); | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | TryResult checkIncorrectLogicOperator(const BinaryOperator *B) { | ||||
if (AlwaysTrue || AlwaysFalse) { | if (AlwaysTrue || AlwaysFalse) { | ||||
if (BuildOpts.Observer) | if (BuildOpts.Observer) | ||||
BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue); | BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue); | ||||
return TryResult(AlwaysTrue); | return TryResult(AlwaysTrue); | ||||
} | } | ||||
return {}; | return {}; | ||||
} | } | ||||
void removeAllSuccessors(CFGBlock *B) { | |||||
B->removeAllSuccessors(); | |||||
} | |||||
/// Try and evaluate an expression to an integer constant. | /// Try and evaluate an expression to an integer constant. | ||||
bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) { | bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) { | ||||
if (!BuildOpts.PruneTriviallyFalseEdges) | if (!BuildOpts.PruneTriviallyFalseEdges) | ||||
return false; | return false; | ||||
return !S->isTypeDependent() && | return !S->isTypeDependent() && | ||||
!S->isValueDependent() && | !S->isValueDependent() && | ||||
S->EvaluateAsRValue(outResult, *Context); | S->EvaluateAsRValue(outResult, *Context); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 211 Lines • ▼ Show 20 Lines | for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(), | ||||
// incomplete AST. Handle this by not registering a successor. | // incomplete AST. Handle this by not registering a successor. | ||||
if (LI == LabelMap.end()) continue; | if (LI == LabelMap.end()) continue; | ||||
JumpTarget JT = LI->second; | JumpTarget JT = LI->second; | ||||
prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition, | prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition, | ||||
JT.scopePosition); | JT.scopePosition); | ||||
prependAutomaticObjDtorsWithTerminator(B, I->scopePosition, | prependAutomaticObjDtorsWithTerminator(B, I->scopePosition, | ||||
JT.scopePosition); | JT.scopePosition); | ||||
const VarDecl *VD = prependAutomaticObjScopeEndWithTerminator( | |||||
B, I->scopePosition, JT.scopePosition); | |||||
What is the difference between TriggerStmt and ScopeCreator? Do we need them both here? dcoughlin: What is the difference between TriggerStmt and ScopeCreator? Do we need them both here? | |||||
appendScopeBegin(JT.block, VD, G); | |||||
addSuccessor(B, JT.block); | addSuccessor(B, JT.block); | ||||
} | } | ||||
// Add successors to the Indirect Goto Dispatch block (if we have one). | // Add successors to the Indirect Goto Dispatch block (if we have one). | ||||
if (CFGBlock *B = cfg->getIndirectGotoBlock()) | if (CFGBlock *B = cfg->getIndirectGotoBlock()) | ||||
for (LabelSetTy::iterator I = AddressTakenLabels.begin(), | for (LabelSetTy::iterator I = AddressTakenLabels.begin(), | ||||
E = AddressTakenLabels.end(); I != E; ++I ) { | E = AddressTakenLabels.end(); I != E; ++I ) { | ||||
// Lookup the target block. | // Lookup the target block. | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | |||||
void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B, | void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B, | ||||
LocalScope::const_iterator E, | LocalScope::const_iterator E, | ||||
Stmt *S) { | Stmt *S) { | ||||
if (BuildOpts.AddImplicitDtors) | if (BuildOpts.AddImplicitDtors) | ||||
addAutomaticObjDtors(B, E, S); | addAutomaticObjDtors(B, E, S); | ||||
if (BuildOpts.AddLifetime) | if (BuildOpts.AddLifetime) | ||||
addLifetimeEnds(B, E, S); | addLifetimeEnds(B, E, S); | ||||
if (BuildOpts.AddScopes) | |||||
addScopesEnd(B, E, S); | |||||
} | } | ||||
/// Add to current block automatic objects that leave the scope. | /// Add to current block automatic objects that leave the scope. | ||||
void CFGBuilder::addLifetimeEnds(LocalScope::const_iterator B, | void CFGBuilder::addLifetimeEnds(LocalScope::const_iterator B, | ||||
LocalScope::const_iterator E, Stmt *S) { | LocalScope::const_iterator E, Stmt *S) { | ||||
if (!BuildOpts.AddLifetime) | if (!BuildOpts.AddLifetime) | ||||
return; | return; | ||||
Show All 29 Lines | for (SmallVectorImpl<VarDecl *>::reverse_iterator I = DeclsTrivial.rbegin(), | ||||
I != E; ++I) | I != E; ++I) | ||||
appendLifetimeEnds(Block, *I, S); | appendLifetimeEnds(Block, *I, S); | ||||
for (SmallVectorImpl<VarDecl *>::reverse_iterator | for (SmallVectorImpl<VarDecl *>::reverse_iterator | ||||
I = DeclsNonTrivial.rbegin(), | I = DeclsNonTrivial.rbegin(), | ||||
E = DeclsNonTrivial.rend(); | E = DeclsNonTrivial.rend(); | ||||
I != E; ++I) | I != E; ++I) | ||||
appendLifetimeEnds(Block, *I, S); | appendLifetimeEnds(Block, *I, S); | ||||
} | } | ||||
I think it is very important to document the different between 'S' and 'ScopeCreator' here. dcoughlin: I think it is very important to document the different between 'S' and 'ScopeCreator' here. | |||||
void CFGBuilder::addScopesEnd(LocalScope::const_iterator B, | |||||
LocalScope::const_iterator E, Stmt *S) { | |||||
if (!BuildOpts.AddScopes) | |||||
return; | |||||
if (B == E) | |||||
return; | |||||
// To go from B to E, one first goes up the scopes from B to P | |||||
// then sideways in one scope from P to P' and then down | |||||
// the scopes from P' to E. | |||||
// The lifetime of all objects between B and P end. | |||||
LocalScope::const_iterator P = B.shared_parent(E); | |||||
int Dist = B.distance(P); | |||||
if (Dist <= 0) | |||||
return; | |||||
// We need to perform the scope leaving in reverse order | |||||
SmallVector<VarDecl *, 10> DeclsWithEndedScope; | |||||
DeclsWithEndedScope.reserve(Dist); | |||||
for (LocalScope::const_iterator I = B; I != P; ++I) | |||||
if (I.pointsToFirstDeclaredVar()) | |||||
DeclsWithEndedScope.push_back(*I); | |||||
autoCreateBlock(); | |||||
for (const auto *VD : DeclsWithEndedScope) | |||||
appendScopeEnd(Block, VD, S); | |||||
return; | |||||
} | |||||
/// addAutomaticObjDtors - Add to current block automatic objects destructors | /// addAutomaticObjDtors - Add to current block automatic objects destructors | ||||
/// for objects in range of local scope positions. Use S as trigger statement | /// for objects in range of local scope positions. Use S as trigger statement | ||||
/// for destructors. | /// for destructors. | ||||
Not Done ReplyInline ActionsYes. I have renamed TriggerStmt to TriggerAutoObjDtorsStmt and ScopeCreator to TriggerScopeStmt. The former tells us when to add ScopeEnd element and the former ScopeBegin element. Addition of TriggerScopeStmt was necessary because TriggerAutoObjDtorsStmt doesn't tell us anything about the present scope's context; only that the present scope is going to end. bshastry: Yes. I have renamed TriggerStmt to TriggerAutoObjDtorsStmt and ScopeCreator to TriggerScopeStmt. | |||||
void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, | void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, | ||||
LocalScope::const_iterator E, Stmt *S) { | LocalScope::const_iterator E, Stmt *S) { | ||||
if (!BuildOpts.AddImplicitDtors) | if (!BuildOpts.AddImplicitDtors) | ||||
return; | return; | ||||
if (B == E) | if (B == E) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl()) | ||||
autoCreateBlock(); | autoCreateBlock(); | ||||
appendMemberDtor(Block, FI); | appendMemberDtor(Block, FI); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/// createOrReuseLocalScope - If Scope is NULL create new LocalScope. Either | /// createOrReuseLocalScope - If Scope is NULL create new LocalScope. Either | ||||
/// way return valid LocalScope object. | /// way return valid LocalScope object. | ||||
LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) { | LocalScope *CFGBuilder::createOrReuseLocalScope(LocalScope *Scope) { | ||||
Not Done ReplyInline ActionsIt seems that something has moved asterisks to a weird spot, might be a rebase artifact or accidental tooling. NoQ: It seems that something has moved asterisks to a weird spot, might be a rebase artifact or… | |||||
Not Done ReplyInline ActionsUhm, it was always this way, just weird history when i looked at the diff between diffs, nvm, sorry. NoQ: Uhm, it was always this way, just weird history when i looked at the diff between diffs, nvm… | |||||
if (Scope) | if (Scope) | ||||
return Scope; | return Scope; | ||||
llvm::BumpPtrAllocator &alloc = cfg->getAllocator(); | llvm::BumpPtrAllocator &alloc = cfg->getAllocator(); | ||||
return new (alloc.Allocate<LocalScope>()) | return new (alloc.Allocate<LocalScope>()) | ||||
LocalScope(BumpVectorContext(alloc), ScopePos); | LocalScope(BumpVectorContext(alloc), ScopePos); | ||||
} | } | ||||
/// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement | /// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement | ||||
/// that should create implicit scope (e.g. if/else substatements). | /// that should create implicit scope (e.g. if/else substatements). | ||||
void CFGBuilder::addLocalScopeForStmt(Stmt *S) { | void CFGBuilder::addLocalScopeForStmt(Stmt *S) { | ||||
if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) | if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime && | ||||
!BuildOpts.AddScopes) | |||||
return; | return; | ||||
LocalScope *Scope = nullptr; | LocalScope *Scope = nullptr; | ||||
// For compound statement we will be creating explicit scope. | // For compound statement we will be creating explicit scope. | ||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) { | if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) { | ||||
for (auto *BI : CS->body()) { | for (auto *BI : CS->body()) { | ||||
Stmt *SI = BI->stripLabelLikeStatements(); | Stmt *SI = BI->stripLabelLikeStatements(); | ||||
if (DeclStmt *DS = dyn_cast<DeclStmt>(SI)) | if (DeclStmt *DS = dyn_cast<DeclStmt>(SI)) | ||||
Scope = addLocalScopeForDeclStmt(DS, Scope); | Scope = addLocalScopeForDeclStmt(DS, Scope); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
// For any other statement scope will be implicit and as such will be | // For any other statement scope will be implicit and as such will be | ||||
// interesting only for DeclStmt. | // interesting only for DeclStmt. | ||||
if (DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements())) | if (DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements())) | ||||
addLocalScopeForDeclStmt(DS); | addLocalScopeForDeclStmt(DS); | ||||
} | } | ||||
/// addLocalScopeForDeclStmt - Add LocalScope for declaration statement. Will | /// addLocalScopeForDeclStmt - Add LocalScope for declaration statement. Will | ||||
/// reuse Scope if not NULL. | /// reuse Scope if not NULL. | ||||
LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS, | LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS, | ||||
LocalScope* Scope) { | LocalScope* Scope) { | ||||
if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) | if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime && | ||||
!BuildOpts.AddScopes) | |||||
return Scope; | return Scope; | ||||
for (auto *DI : DS->decls()) | for (auto *DI : DS->decls()) | ||||
if (VarDecl *VD = dyn_cast<VarDecl>(DI)) | if (VarDecl *VD = dyn_cast<VarDecl>(DI)) | ||||
Scope = addLocalScopeForVarDecl(VD, Scope); | Scope = addLocalScopeForVarDecl(VD, Scope); | ||||
return Scope; | return Scope; | ||||
} | } | ||||
Show All 35 Lines | |||||
/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will | /// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will | ||||
/// create add scope for automatic objects and temporary objects bound to | /// create add scope for automatic objects and temporary objects bound to | ||||
/// const reference. Will reuse Scope if not NULL. | /// const reference. Will reuse Scope if not NULL. | ||||
LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, | LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, | ||||
LocalScope* Scope) { | LocalScope* Scope) { | ||||
assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) && | assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) && | ||||
"AddImplicitDtors and AddLifetime cannot be used at the same time"); | "AddImplicitDtors and AddLifetime cannot be used at the same time"); | ||||
if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) | if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime && | ||||
!BuildOpts.AddScopes) | |||||
return Scope; | return Scope; | ||||
// Check if variable is local. | // Check if variable is local. | ||||
switch (VD->getStorageClass()) { | switch (VD->getStorageClass()) { | ||||
case SC_None: | case SC_None: | ||||
case SC_Auto: | case SC_Auto: | ||||
case SC_Register: | case SC_Register: | ||||
break; | break; | ||||
default: return Scope; | default: return Scope; | ||||
} | } | ||||
if (BuildOpts.AddImplicitDtors) { | if (BuildOpts.AddImplicitDtors) { | ||||
if (!hasTrivialDestructor(VD)) { | if (!hasTrivialDestructor(VD) || BuildOpts.AddScopes) { | ||||
// Add the variable to scope | // Add the variable to scope | ||||
Scope = createOrReuseLocalScope(Scope); | Scope = createOrReuseLocalScope(Scope); | ||||
Scope->addVar(VD); | Scope->addVar(VD); | ||||
ScopePos = Scope->begin(); | ScopePos = Scope->begin(); | ||||
} | } | ||||
return Scope; | return Scope; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (!BuildOpts.AddLifetime) | ||||
return; | return; | ||||
BumpVectorContext &C = cfg->getBumpVectorContext(); | BumpVectorContext &C = cfg->getBumpVectorContext(); | ||||
CFGBlock::iterator InsertPos = | CFGBlock::iterator InsertPos = | ||||
Blk->beginLifetimeEndsInsert(Blk->end(), B.distance(E), C); | Blk->beginLifetimeEndsInsert(Blk->end(), B.distance(E), C); | ||||
for (LocalScope::const_iterator I = B; I != E; ++I) | for (LocalScope::const_iterator I = B; I != E; ++I) | ||||
InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator()); | InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator()); | ||||
} | } | ||||
/// prependAutomaticObjScopeEndWithTerminator - Prepend scope end CFGElements for | |||||
/// variables with automatic storage duration to CFGBlock's elements vector. | |||||
/// Elements will be prepended to physical beginning of the vector which | |||||
/// happens to be logical end. Use blocks terminator as statement that specifies | |||||
/// where scope ends. | |||||
const VarDecl * | |||||
CFGBuilder::prependAutomaticObjScopeEndWithTerminator( | |||||
CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) { | |||||
if (!BuildOpts.AddScopes) | |||||
return nullptr; | |||||
BumpVectorContext &C = cfg->getBumpVectorContext(); | |||||
CFGBlock::iterator InsertPos = | |||||
Blk->beginScopeEndInsert(Blk->end(), 1, C); | |||||
LocalScope::const_iterator PlaceToInsert = B; | |||||
for (LocalScope::const_iterator I = B; I != E; ++I) | |||||
PlaceToInsert = I; | |||||
Blk->insertScopeEnd(InsertPos, *PlaceToInsert, Blk->getTerminator()); | |||||
return *PlaceToInsert; | |||||
} | |||||
/// Visit - Walk the subtree of a statement and add extra | /// Visit - Walk the subtree of a statement and add extra | ||||
/// blocks for ternary operators, &&, and ||. We also process "," and | /// blocks for ternary operators, &&, and ||. We also process "," and | ||||
/// DeclStmts (which may contain nested control-flow). | /// DeclStmts (which may contain nested control-flow). | ||||
CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { | CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { | ||||
if (!S) { | if (!S) { | ||||
badCFG = true; | badCFG = true; | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 709 Lines • ▼ Show 20 Lines | CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { | ||||
// If the type of VD is a VLA, then we must process its size expressions. | // If the type of VD is a VLA, then we must process its size expressions. | ||||
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); | for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); | ||||
VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr())) { | VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr())) { | ||||
if (CFGBlock *newBlock = addStmt(VA->getSizeExpr())) | if (CFGBlock *newBlock = addStmt(VA->getSizeExpr())) | ||||
LastBlock = newBlock; | LastBlock = newBlock; | ||||
} | } | ||||
maybeAddScopeBeginForVarDecl(Block, VD, DS); | |||||
// Remove variable from local scope. | // Remove variable from local scope. | ||||
if (ScopePos && VD == *ScopePos) | if (ScopePos && VD == *ScopePos) | ||||
++ScopePos; | ++ScopePos; | ||||
CFGBlock *B = LastBlock; | CFGBlock *B = LastBlock; | ||||
if (blockAfterStaticInit) { | if (blockAfterStaticInit) { | ||||
Succ = B; | Succ = B; | ||||
Block = createBlock(false); | Block = createBlock(false); | ||||
▲ Show 20 Lines • Show All 444 Lines • ▼ Show 20 Lines | CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { | ||||
// Because of short-circuit evaluation, the condition of the loop can span | // Because of short-circuit evaluation, the condition of the loop can span | ||||
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that | // multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that | ||||
// evaluate the condition. | // evaluate the condition. | ||||
CFGBlock *EntryConditionBlock = nullptr, *ExitConditionBlock = nullptr; | CFGBlock *EntryConditionBlock = nullptr, *ExitConditionBlock = nullptr; | ||||
do { | do { | ||||
Expr *C = F->getCond(); | Expr *C = F->getCond(); | ||||
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); | |||||
// Specially handle logical operators, which have a slightly | // Specially handle logical operators, which have a slightly | ||||
// more optimal CFG representation. | // more optimal CFG representation. | ||||
if (BinaryOperator *Cond = | if (BinaryOperator *Cond = | ||||
dyn_cast_or_null<BinaryOperator>(C ? C->IgnoreParens() : nullptr)) | dyn_cast_or_null<BinaryOperator>(C ? C->IgnoreParens() : nullptr)) | ||||
if (Cond->isLogicalOp()) { | if (Cond->isLogicalOp()) { | ||||
std::tie(EntryConditionBlock, ExitConditionBlock) = | std::tie(EntryConditionBlock, ExitConditionBlock) = | ||||
VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor); | VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor); | ||||
Show All 17 Lines | if (C) { | ||||
// If this block contains a condition variable, add both the condition | // If this block contains a condition variable, add both the condition | ||||
// variable and initializer to the CFG. | // variable and initializer to the CFG. | ||||
if (VarDecl *VD = F->getConditionVariable()) { | if (VarDecl *VD = F->getConditionVariable()) { | ||||
if (Expr *Init = VD->getInit()) { | if (Expr *Init = VD->getInit()) { | ||||
autoCreateBlock(); | autoCreateBlock(); | ||||
appendStmt(Block, F->getConditionVariableDeclStmt()); | appendStmt(Block, F->getConditionVariableDeclStmt()); | ||||
EntryConditionBlock = addStmt(Init); | EntryConditionBlock = addStmt(Init); | ||||
assert(Block == EntryConditionBlock); | assert(Block == EntryConditionBlock); | ||||
maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD, C); | |||||
} | } | ||||
} | } | ||||
if (Block && badCFG) | if (Block && badCFG) | ||||
return nullptr; | return nullptr; | ||||
KnownVal = tryEvaluateBool(C); | KnownVal = tryEvaluateBool(C); | ||||
} | } | ||||
Show All 10 Lines | CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { | ||||
addSuccessor(TransitionBlock, EntryConditionBlock); | addSuccessor(TransitionBlock, EntryConditionBlock); | ||||
// The condition block is the implicit successor for any code above the loop. | // The condition block is the implicit successor for any code above the loop. | ||||
Succ = EntryConditionBlock; | Succ = EntryConditionBlock; | ||||
// If the loop contains initialization, create a new block for those | // If the loop contains initialization, create a new block for those | ||||
// statements. This block can also contain statements that precede the loop. | // statements. This block can also contain statements that precede the loop. | ||||
if (Stmt *I = F->getInit()) { | if (Stmt *I = F->getInit()) { | ||||
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); | |||||
ScopePos = LoopBeginScopePos; | |||||
Block = createBlock(); | Block = createBlock(); | ||||
return addStmt(I); | return addStmt(I); | ||||
} | } | ||||
// There is no loop initialization. We are thus basically a while loop. | // There is no loop initialization. We are thus basically a while loop. | ||||
// NULL out Block to force lazy block construction. | // NULL out Block to force lazy block construction. | ||||
Block = nullptr; | Block = nullptr; | ||||
Succ = EntryConditionBlock; | Succ = EntryConditionBlock; | ||||
▲ Show 20 Lines • Show All 270 Lines • ▼ Show 20 Lines | do { | ||||
// If this block contains a condition variable, add both the condition | // If this block contains a condition variable, add both the condition | ||||
// variable and initializer to the CFG. | // variable and initializer to the CFG. | ||||
if (VarDecl *VD = W->getConditionVariable()) { | if (VarDecl *VD = W->getConditionVariable()) { | ||||
if (Expr *Init = VD->getInit()) { | if (Expr *Init = VD->getInit()) { | ||||
autoCreateBlock(); | autoCreateBlock(); | ||||
appendStmt(Block, W->getConditionVariableDeclStmt()); | appendStmt(Block, W->getConditionVariableDeclStmt()); | ||||
EntryConditionBlock = addStmt(Init); | EntryConditionBlock = addStmt(Init); | ||||
assert(Block == EntryConditionBlock); | assert(Block == EntryConditionBlock); | ||||
maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD, C); | |||||
} | } | ||||
} | } | ||||
if (Block && badCFG) | if (Block && badCFG) | ||||
return nullptr; | return nullptr; | ||||
// See if this is a known constant. | // See if this is a known constant. | ||||
const TryResult& KnownVal = tryEvaluateBool(C); | const TryResult& KnownVal = tryEvaluateBool(C); | ||||
▲ Show 20 Lines • Show All 1,041 Lines • ▼ Show 20 Lines | |||||
const CXXDestructorDecl * | const CXXDestructorDecl * | ||||
CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { | CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { | ||||
switch (getKind()) { | switch (getKind()) { | ||||
case CFGElement::Statement: | case CFGElement::Statement: | ||||
case CFGElement::Initializer: | case CFGElement::Initializer: | ||||
case CFGElement::NewAllocator: | case CFGElement::NewAllocator: | ||||
case CFGElement::LoopExit: | case CFGElement::LoopExit: | ||||
case CFGElement::LifetimeEnds: | case CFGElement::LifetimeEnds: | ||||
case CFGElement::ScopeBegin: | |||||
case CFGElement::ScopeEnd: | |||||
llvm_unreachable("getDestructorDecl should only be used with " | llvm_unreachable("getDestructorDecl should only be used with " | ||||
"ImplicitDtors"); | "ImplicitDtors"); | ||||
case CFGElement::AutomaticObjectDtor: { | case CFGElement::AutomaticObjectDtor: { | ||||
const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl(); | const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl(); | ||||
QualType ty = var->getType(); | QualType ty = var->getType(); | ||||
// FIXME: See CFGBuilder::addLocalScopeForVarDecl. | // FIXME: See CFGBuilder::addLocalScopeForVarDecl. | ||||
// | // | ||||
▲ Show 20 Lines • Show All 399 Lines • ▼ Show 20 Lines | static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, | ||||
} else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) { | } else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) { | ||||
const VarDecl *VD = DE->getVarDecl(); | const VarDecl *VD = DE->getVarDecl(); | ||||
Helper.handleDecl(VD, OS); | Helper.handleDecl(VD, OS); | ||||
OS << " (Lifetime ends)\n"; | OS << " (Lifetime ends)\n"; | ||||
} else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) { | } else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) { | ||||
const Stmt *LoopStmt = LE->getLoopStmt(); | const Stmt *LoopStmt = LE->getLoopStmt(); | ||||
OS << LoopStmt->getStmtClassName() << " (LoopExit)\n"; | OS << LoopStmt->getStmtClassName() << " (LoopExit)\n"; | ||||
} else if (Optional<CFGScopeBegin> SB = E.getAs<CFGScopeBegin>()) { | |||||
OS << "CFGScopeBegin("; | |||||
if (const VarDecl *VD = SB->getVarDecl()) | |||||
OS << VD->getQualifiedNameAsString(); | |||||
OS << ")\n"; | |||||
} else if (Optional<CFGScopeEnd> SE = E.getAs<CFGScopeEnd>()) { | |||||
OS << "CFGScopeEnd("; | |||||
if (const VarDecl *VD = SE->getVarDecl()) | |||||
OS << VD->getQualifiedNameAsString(); | |||||
OS << ")\n"; | |||||
} else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) { | } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) { | ||||
OS << "CFGNewAllocator("; | OS << "CFGNewAllocator("; | ||||
if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr()) | if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr()) | ||||
AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); | AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); | ||||
OS << ")\n"; | OS << ")\n"; | ||||
} else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) { | } else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) { | ||||
const CXXRecordDecl *RD = DE->getCXXRecordDecl(); | const CXXRecordDecl *RD = DE->getCXXRecordDecl(); | ||||
if (!RD) | if (!RD) | ||||
▲ Show 20 Lines • Show All 369 Lines • Show Last 20 Lines |
I think it would be helpful to name this something more expressive (perhaps "TriggerStmt") so it is immediately clear what the relationship between the statement the LocalScope is.