2012-07-14 13:04:01 +08:00
|
|
|
//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
|
2007-08-22 05:42:03 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-08-22 05:42:03 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the CFG and CFGBuilder classes for representing and
|
|
|
|
// building Control-Flow Graphs (CFGs) from ASTs.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-03-02 03:45:56 +08:00
|
|
|
#include "llvm/Support/SaveAndRestore.h"
|
2009-07-17 02:13:04 +08:00
|
|
|
#include "clang/Analysis/CFG.h"
|
2012-07-05 01:04:04 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2010-01-21 10:21:40 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2007-08-22 06:06:14 +08:00
|
|
|
#include "clang/AST/StmtVisitor.h"
|
2007-09-01 05:30:12 +08:00
|
|
|
#include "clang/AST/PrettyPrinter.h"
|
2011-02-23 13:11:46 +08:00
|
|
|
#include "clang/AST/CharUnits.h"
|
2012-04-14 08:33:13 +08:00
|
|
|
#include "clang/Basic/AttrKinds.h"
|
2007-08-30 05:56:09 +08:00
|
|
|
#include "llvm/Support/GraphWriter.h"
|
2009-08-23 20:08:50 +08:00
|
|
|
#include "llvm/Support/Allocator.h"
|
|
|
|
#include "llvm/Support/Format.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
2009-10-21 07:46:25 +08:00
|
|
|
#include "llvm/ADT/OwningPtr.h"
|
2008-01-11 08:40:29 +08:00
|
|
|
|
2007-08-22 05:42:03 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
static SourceLocation GetEndLoc(Decl *D) {
|
|
|
|
if (VarDecl *VD = dyn_cast<VarDecl>(D))
|
|
|
|
if (Expr *Ex = VD->getInit())
|
2008-08-07 07:20:50 +08:00
|
|
|
return Ex->getSourceRange().getEnd();
|
2009-07-17 09:31:16 +08:00
|
|
|
return D->getLocation();
|
2008-08-07 07:20:50 +08:00
|
|
|
}
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2011-03-10 09:14:11 +08:00
|
|
|
class CFGBuilder;
|
|
|
|
|
2010-11-24 11:28:53 +08:00
|
|
|
/// The CFG builder uses a recursive algorithm to build the CFG. When
|
|
|
|
/// we process an expression, sometimes we know that we must add the
|
|
|
|
/// subexpressions as block-level expressions. For example:
|
|
|
|
///
|
|
|
|
/// exp1 || exp2
|
|
|
|
///
|
|
|
|
/// When processing the '||' expression, we know that exp1 and exp2
|
|
|
|
/// need to be added as block-level expressions, even though they
|
|
|
|
/// might not normally need to be. AddStmtChoice records this
|
|
|
|
/// contextual information. If AddStmtChoice is 'NotAlwaysAdd', then
|
|
|
|
/// the builder has an option not to add a subexpression as a
|
|
|
|
/// block-level expression.
|
|
|
|
///
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
class AddStmtChoice {
|
|
|
|
public:
|
2010-12-16 15:46:53 +08:00
|
|
|
enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 };
|
2010-03-03 05:43:54 +08:00
|
|
|
|
2010-11-24 11:28:53 +08:00
|
|
|
AddStmtChoice(Kind a_kind = NotAlwaysAdd) : kind(a_kind) {}
|
2010-03-03 05:43:54 +08:00
|
|
|
|
2011-03-10 09:14:11 +08:00
|
|
|
bool alwaysAdd(CFGBuilder &builder,
|
|
|
|
const Stmt *stmt) const;
|
2010-11-24 11:28:53 +08:00
|
|
|
|
|
|
|
/// Return a copy of this object, except with the 'always-add' bit
|
|
|
|
/// set as specified.
|
|
|
|
AddStmtChoice withAlwaysAdd(bool alwaysAdd) const {
|
2011-03-10 09:14:11 +08:00
|
|
|
return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
|
2010-11-24 11:28:53 +08:00
|
|
|
}
|
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
private:
|
2010-11-24 11:28:53 +08:00
|
|
|
Kind kind;
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
};
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-25 19:05:21 +08:00
|
|
|
/// LocalScope - Node in tree of local scopes created for C++ implicit
|
|
|
|
/// destructor calls generation. It contains list of automatic variables
|
|
|
|
/// declared in the scope and link to position in previous scope this scope
|
|
|
|
/// began in.
|
|
|
|
///
|
|
|
|
/// The process of creating local scopes is as follows:
|
|
|
|
/// - Init CFGBuilder::ScopePos with invalid position (equivalent for null),
|
|
|
|
/// - Before processing statements in scope (e.g. CompoundStmt) create
|
|
|
|
/// LocalScope object using CFGBuilder::ScopePos as link to previous scope
|
|
|
|
/// and set CFGBuilder::ScopePos to the end of new scope,
|
2010-10-01 06:42:32 +08:00
|
|
|
/// - On every occurrence of VarDecl increase CFGBuilder::ScopePos if it points
|
2010-09-25 19:05:21 +08:00
|
|
|
/// at this VarDecl,
|
|
|
|
/// - For every normal (without jump) end of scope add to CFGBlock destructors
|
|
|
|
/// for objects in the current scope,
|
|
|
|
/// - For every jump add to CFGBlock destructors for objects
|
|
|
|
/// between CFGBuilder::ScopePos and local scope position saved for jump
|
|
|
|
/// target. Thanks to C++ restrictions on goto jumps we can be sure that
|
|
|
|
/// jump target position will be on the path to root from CFGBuilder::ScopePos
|
|
|
|
/// (adding any variable that doesn't need constructor to be called to
|
|
|
|
/// LocalScope can break this assumption),
|
|
|
|
///
|
|
|
|
class LocalScope {
|
|
|
|
public:
|
2011-02-15 10:47:45 +08:00
|
|
|
typedef BumpVector<VarDecl*> AutomaticVarsTy;
|
2010-09-25 19:05:21 +08:00
|
|
|
|
|
|
|
/// const_iterator - Iterates local scope backwards and jumps to previous
|
2010-10-01 06:42:32 +08:00
|
|
|
/// scope on reaching the beginning of currently iterated scope.
|
2010-09-25 19:05:21 +08:00
|
|
|
class const_iterator {
|
|
|
|
const LocalScope* Scope;
|
|
|
|
|
|
|
|
/// VarIter is guaranteed to be greater then 0 for every valid iterator.
|
|
|
|
/// Invalid iterator (with null Scope) has VarIter equal to 0.
|
|
|
|
unsigned VarIter;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// Create invalid iterator. Dereferencing invalid iterator is not allowed.
|
|
|
|
/// Incrementing invalid iterator is allowed and will result in invalid
|
|
|
|
/// iterator.
|
|
|
|
const_iterator()
|
|
|
|
: Scope(NULL), VarIter(0) {}
|
|
|
|
|
|
|
|
/// Create valid iterator. In case when S.Prev is an invalid iterator and
|
|
|
|
/// I is equal to 0, this will create invalid iterator.
|
|
|
|
const_iterator(const LocalScope& S, unsigned I)
|
|
|
|
: Scope(&S), VarIter(I) {
|
|
|
|
// Iterator to "end" of scope is not allowed. Handle it by going up
|
|
|
|
// in scopes tree possibly up to invalid iterator in the root.
|
|
|
|
if (VarIter == 0 && Scope)
|
|
|
|
*this = Scope->Prev;
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
VarDecl *const* operator->() const {
|
2010-09-25 19:05:21 +08:00
|
|
|
assert (Scope && "Dereferencing invalid iterator is not allowed");
|
|
|
|
assert (VarIter != 0 && "Iterator has invalid value of VarIter member");
|
|
|
|
return &Scope->Vars[VarIter - 1];
|
|
|
|
}
|
2011-08-13 07:37:29 +08:00
|
|
|
VarDecl *operator*() const {
|
2010-09-25 19:05:21 +08:00
|
|
|
return *this->operator->();
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
const_iterator &operator++() {
|
2010-09-25 19:05:21 +08:00
|
|
|
if (!Scope)
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
assert (VarIter != 0 && "Iterator has invalid value of VarIter member");
|
|
|
|
--VarIter;
|
|
|
|
if (VarIter == 0)
|
|
|
|
*this = Scope->Prev;
|
|
|
|
return *this;
|
|
|
|
}
|
2010-10-01 06:42:32 +08:00
|
|
|
const_iterator operator++(int) {
|
|
|
|
const_iterator P = *this;
|
|
|
|
++*this;
|
|
|
|
return P;
|
|
|
|
}
|
2010-09-25 19:05:21 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
bool operator==(const const_iterator &rhs) const {
|
2010-09-25 19:05:21 +08:00
|
|
|
return Scope == rhs.Scope && VarIter == rhs.VarIter;
|
|
|
|
}
|
2011-08-13 07:37:29 +08:00
|
|
|
bool operator!=(const const_iterator &rhs) const {
|
2010-09-25 19:05:21 +08:00
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
2010-10-01 06:42:32 +08:00
|
|
|
|
|
|
|
operator bool() const {
|
|
|
|
return *this != const_iterator();
|
|
|
|
}
|
|
|
|
|
|
|
|
int distance(const_iterator L);
|
2010-09-25 19:05:21 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
friend class const_iterator;
|
|
|
|
|
|
|
|
private:
|
2011-02-15 10:47:45 +08:00
|
|
|
BumpVectorContext ctx;
|
|
|
|
|
2010-09-25 19:05:21 +08:00
|
|
|
/// Automatic variables in order of declaration.
|
|
|
|
AutomaticVarsTy Vars;
|
|
|
|
/// Iterator to variable in previous scope that was declared just before
|
|
|
|
/// begin of this scope.
|
|
|
|
const_iterator Prev;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// Constructs empty scope linked to previous scope in specified place.
|
2011-02-15 10:47:45 +08:00
|
|
|
LocalScope(BumpVectorContext &ctx, const_iterator P)
|
|
|
|
: ctx(ctx), Vars(ctx, 4), Prev(P) {}
|
2010-09-25 19:05:21 +08:00
|
|
|
|
|
|
|
/// Begin of scope in direction of CFG building (backwards).
|
|
|
|
const_iterator begin() const { return const_iterator(*this, Vars.size()); }
|
2010-10-01 06:42:32 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void addVar(VarDecl *VD) {
|
2011-02-15 10:47:45 +08:00
|
|
|
Vars.push_back(VD, ctx);
|
2010-10-01 06:42:32 +08:00
|
|
|
}
|
2010-09-25 19:05:21 +08:00
|
|
|
};
|
|
|
|
|
2010-10-01 06:42:32 +08:00
|
|
|
/// distance - Calculates distance from this to L. L must be reachable from this
|
|
|
|
/// (with use of ++ operator). Cost of calculating the distance is linear w.r.t.
|
|
|
|
/// number of scopes between this and L.
|
|
|
|
int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
|
|
|
|
int D = 0;
|
|
|
|
const_iterator F = *this;
|
|
|
|
while (F.Scope != L.Scope) {
|
2011-08-12 22:41:23 +08:00
|
|
|
assert (F != const_iterator()
|
|
|
|
&& "L iterator is not reachable from F iterator.");
|
2010-10-01 06:42:32 +08:00
|
|
|
D += F.VarIter;
|
|
|
|
F = F.Scope->Prev;
|
|
|
|
}
|
|
|
|
D += F.VarIter - L.VarIter;
|
|
|
|
return D;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// BlockScopePosPair - Structure for specifying position in CFG during its
|
|
|
|
/// build process. It consists of CFGBlock that specifies position in CFG graph
|
|
|
|
/// and LocalScope::const_iterator that specifies position in LocalScope graph.
|
2010-09-25 19:05:21 +08:00
|
|
|
struct BlockScopePosPair {
|
2011-01-08 03:37:16 +08:00
|
|
|
BlockScopePosPair() : block(0) {}
|
2011-08-13 07:37:29 +08:00
|
|
|
BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos)
|
2011-01-08 03:37:16 +08:00
|
|
|
: block(b), scopePosition(scopePos) {}
|
2010-09-25 19:05:21 +08:00
|
|
|
|
2011-01-08 03:37:16 +08:00
|
|
|
CFGBlock *block;
|
|
|
|
LocalScope::const_iterator scopePosition;
|
2010-09-25 19:05:21 +08:00
|
|
|
};
|
|
|
|
|
2011-03-02 07:12:55 +08:00
|
|
|
/// TryResult - a class representing a variant over the values
|
|
|
|
/// 'true', 'false', or 'unknown'. This is returned by tryEvaluateBool,
|
|
|
|
/// and is used by the CFGBuilder to decide if a branch condition
|
|
|
|
/// can be decided up front during CFG construction.
|
|
|
|
class TryResult {
|
|
|
|
int X;
|
|
|
|
public:
|
|
|
|
TryResult(bool b) : X(b ? 1 : 0) {}
|
|
|
|
TryResult() : X(-1) {}
|
|
|
|
|
|
|
|
bool isTrue() const { return X == 1; }
|
|
|
|
bool isFalse() const { return X == 0; }
|
|
|
|
bool isKnown() const { return X >= 0; }
|
|
|
|
void negate() {
|
|
|
|
assert(isKnown());
|
|
|
|
X ^= 0x1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-08-05 06:51:42 +08:00
|
|
|
/// CFGBuilder - This class implements CFG construction from an AST.
|
2007-08-22 05:42:03 +08:00
|
|
|
/// The builder is stateful: an instance of the builder should be used to only
|
|
|
|
/// construct a single CFG.
|
|
|
|
///
|
|
|
|
/// Example usage:
|
|
|
|
///
|
|
|
|
/// CFGBuilder builder;
|
|
|
|
/// CFG* cfg = builder.BuildAST(stmt1);
|
|
|
|
///
|
2009-07-17 09:31:16 +08:00
|
|
|
/// CFG construction is done via a recursive walk of an AST. We actually parse
|
|
|
|
/// the AST in reverse order so that the successor of a basic block is
|
|
|
|
/// constructed prior to its predecessor. This allows us to nicely capture
|
|
|
|
/// implicit fall-throughs without extra basic blocks.
|
2007-08-22 06:06:14 +08:00
|
|
|
///
|
2009-11-28 14:07:30 +08:00
|
|
|
class CFGBuilder {
|
2010-09-25 19:05:21 +08:00
|
|
|
typedef BlockScopePosPair JumpTarget;
|
|
|
|
typedef BlockScopePosPair JumpSource;
|
|
|
|
|
2009-07-21 07:24:15 +08:00
|
|
|
ASTContext *Context;
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<CFG> cfg;
|
2009-10-13 04:55:07 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *Block;
|
|
|
|
CFGBlock *Succ;
|
2010-09-25 19:05:21 +08:00
|
|
|
JumpTarget ContinueJumpTarget;
|
|
|
|
JumpTarget BreakJumpTarget;
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *SwitchTerminatedBlock;
|
|
|
|
CFGBlock *DefaultCaseBlock;
|
|
|
|
CFGBlock *TryTerminatedBlock;
|
2011-03-02 07:12:55 +08:00
|
|
|
|
2010-09-25 19:05:21 +08:00
|
|
|
// Current position in local scope.
|
|
|
|
LocalScope::const_iterator ScopePos;
|
|
|
|
|
|
|
|
// LabelMap records the mapping from Label expressions to their jump targets.
|
2011-02-17 15:39:24 +08:00
|
|
|
typedef llvm::DenseMap<LabelDecl*, JumpTarget> LabelMapTy;
|
2007-08-22 07:26:17 +08:00
|
|
|
LabelMapTy LabelMap;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// A list of blocks that end with a "goto" that must be backpatched to their
|
|
|
|
// resolved targets upon completion of CFG construction.
|
2010-09-25 19:05:21 +08:00
|
|
|
typedef std::vector<JumpSource> BackpatchBlocksTy;
|
2007-08-22 07:26:17 +08:00
|
|
|
BackpatchBlocksTy BackpatchBlocks;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-29 03:26:49 +08:00
|
|
|
// A list of labels whose address has been taken (for indirect gotos).
|
2011-02-17 15:39:24 +08:00
|
|
|
typedef llvm::SmallPtrSet<LabelDecl*, 5> LabelSetTy;
|
2007-08-29 03:26:49 +08:00
|
|
|
LabelSetTy AddressTakenLabels;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-16 11:28:18 +08:00
|
|
|
bool badCFG;
|
2011-03-10 09:14:05 +08:00
|
|
|
const CFG::BuildOptions &BuildOpts;
|
2011-03-02 07:12:55 +08:00
|
|
|
|
|
|
|
// State to track for building switch statements.
|
|
|
|
bool switchExclusivelyCovered;
|
2011-03-04 09:03:41 +08:00
|
|
|
Expr::EvalResult *switchCond;
|
2011-03-10 11:50:34 +08:00
|
|
|
|
|
|
|
CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry;
|
2011-03-24 05:33:21 +08:00
|
|
|
const Stmt *lastLookup;
|
2010-09-16 11:28:18 +08:00
|
|
|
|
2012-03-23 08:59:17 +08:00
|
|
|
// Caches boolean evaluations of expressions to avoid multiple re-evaluations
|
|
|
|
// during construction of branches for chained logical operators.
|
2012-03-25 14:30:37 +08:00
|
|
|
typedef llvm::DenseMap<Expr *, TryResult> CachedBoolEvalsTy;
|
|
|
|
CachedBoolEvalsTy CachedBoolEvals;
|
2012-03-23 08:59:17 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
public:
|
2011-03-10 09:14:05 +08:00
|
|
|
explicit CFGBuilder(ASTContext *astContext,
|
|
|
|
const CFG::BuildOptions &buildOpts)
|
|
|
|
: Context(astContext), cfg(new CFG()), // crew a new CFG
|
|
|
|
Block(NULL), Succ(NULL),
|
|
|
|
SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
|
|
|
|
TryTerminatedBlock(NULL), badCFG(false), BuildOpts(buildOpts),
|
2011-03-10 11:50:34 +08:00
|
|
|
switchExclusivelyCovered(false), switchCond(0),
|
2011-03-24 05:33:21 +08:00
|
|
|
cachedEntry(0), lastLookup(0) {}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// buildCFG - Used by external clients to construct the CFG.
|
2011-03-10 09:14:05 +08:00
|
|
|
CFG* buildCFG(const Decl *D, Stmt *Statement);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-03-10 11:50:34 +08:00
|
|
|
bool alwaysAdd(const Stmt *stmt);
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
private:
|
|
|
|
// Visitors to walk an AST and construct the CFG.
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
|
|
|
|
CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitBreakStmt(BreakStmt *B);
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitCaseStmt(CaseStmt *C);
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
|
2009-07-18 02:20:32 +08:00
|
|
|
CFGBlock *VisitCompoundStmt(CompoundStmt *C);
|
2011-02-17 18:25:35 +08:00
|
|
|
CFGBlock *VisitConditionalOperator(AbstractConditionalOperator *C,
|
|
|
|
AddStmtChoice asc);
|
2009-07-18 02:20:32 +08:00
|
|
|
CFGBlock *VisitContinueStmt(ContinueStmt *C);
|
2012-07-14 13:04:01 +08:00
|
|
|
CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
|
|
|
|
AddStmtChoice asc);
|
|
|
|
CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
|
|
|
|
CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
|
|
|
|
CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
|
|
|
|
CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
|
|
|
|
AddStmtChoice asc);
|
|
|
|
CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
|
|
|
|
AddStmtChoice asc);
|
|
|
|
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
|
|
|
|
CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitDeclStmt(DeclStmt *DS);
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *VisitDeclSubExpr(DeclStmt *DS);
|
2009-07-18 02:20:32 +08:00
|
|
|
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
|
|
|
|
CFGBlock *VisitDoStmt(DoStmt *D);
|
2012-07-14 13:04:01 +08:00
|
|
|
CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, AddStmtChoice asc);
|
2009-07-18 02:20:32 +08:00
|
|
|
CFGBlock *VisitForStmt(ForStmt *F);
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *VisitGotoStmt(GotoStmt *G);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitIfStmt(IfStmt *I);
|
2010-11-01 21:04:58 +08:00
|
|
|
CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
|
|
|
|
CFGBlock *VisitLabelStmt(LabelStmt *L);
|
2012-07-14 13:04:01 +08:00
|
|
|
CFGBlock *VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc);
|
2012-07-14 13:04:06 +08:00
|
|
|
CFGBlock *VisitLogicalOperator(BinaryOperator *B);
|
2012-07-14 13:04:10 +08:00
|
|
|
std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(BinaryOperator *B,
|
|
|
|
Stmt *Term,
|
|
|
|
CFGBlock *TrueBlock,
|
|
|
|
CFGBlock *FalseBlock);
|
2010-04-12 01:02:10 +08:00
|
|
|
CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
|
|
|
|
CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
|
|
|
|
CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
|
|
|
|
CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
|
2012-07-14 13:04:01 +08:00
|
|
|
CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
|
2011-11-06 17:01:30 +08:00
|
|
|
CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
|
2012-07-14 13:04:01 +08:00
|
|
|
CFGBlock *VisitReturnStmt(ReturnStmt *R);
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitSwitchStmt(SwitchStmt *S);
|
2012-07-14 13:04:01 +08:00
|
|
|
CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
|
|
|
|
AddStmtChoice asc);
|
2010-11-22 16:45:56 +08:00
|
|
|
CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc);
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *VisitWhileStmt(WhileStmt *W);
|
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd);
|
|
|
|
CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *VisitChildren(Stmt *S);
|
2012-04-13 04:03:44 +08:00
|
|
|
CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc);
|
2009-07-17 09:04:31 +08:00
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
// Visitors to walk an AST and generate destructors of temporaries in
|
|
|
|
// full expression.
|
|
|
|
CFGBlock *VisitForTemporaryDtors(Stmt *E, bool BindToTemporary = false);
|
|
|
|
CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E);
|
|
|
|
CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E);
|
|
|
|
CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(CXXBindTemporaryExpr *E,
|
|
|
|
bool BindToTemporary);
|
2011-02-17 18:25:35 +08:00
|
|
|
CFGBlock *
|
|
|
|
VisitConditionalOperatorForTemporaryDtors(AbstractConditionalOperator *E,
|
|
|
|
bool BindToTemporary);
|
2010-11-03 14:19:35 +08:00
|
|
|
|
2008-04-29 02:00:46 +08:00
|
|
|
// NYS == Not Yet Supported
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *NYS() {
|
2008-03-13 11:04:22 +08:00
|
|
|
badCFG = true;
|
|
|
|
return Block;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
void autoCreateBlock() { if (!Block) Block = createBlock(); }
|
|
|
|
CFGBlock *createBlock(bool add_successor = true);
|
2011-09-13 17:13:49 +08:00
|
|
|
CFGBlock *createNoReturnBlock();
|
2010-09-06 15:32:31 +08:00
|
|
|
|
2010-06-03 14:43:23 +08:00
|
|
|
CFGBlock *addStmt(Stmt *S) {
|
|
|
|
return Visit(S, AddStmtChoice::AlwaysAdd);
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
}
|
2011-01-09 04:30:50 +08:00
|
|
|
CFGBlock *addInitializer(CXXCtorInitializer *I);
|
2010-10-01 11:22:39 +08:00
|
|
|
void addAutomaticObjDtors(LocalScope::const_iterator B,
|
2011-08-13 07:37:29 +08:00
|
|
|
LocalScope::const_iterator E, Stmt *S);
|
2010-10-05 13:37:00 +08:00
|
|
|
void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD);
|
2010-10-01 07:05:00 +08:00
|
|
|
|
|
|
|
// Local scopes creation.
|
|
|
|
LocalScope* createOrReuseLocalScope(LocalScope* Scope);
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void addLocalScopeForStmt(Stmt *S);
|
|
|
|
LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope = NULL);
|
|
|
|
LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = NULL);
|
2010-10-01 07:05:00 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void addLocalScopeAndDtors(Stmt *S);
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2010-10-01 07:05:00 +08:00
|
|
|
// Interface to CFGBlock - adding CFGElements.
|
2011-04-05 07:29:12 +08:00
|
|
|
void appendStmt(CFGBlock *B, const Stmt *S) {
|
2011-07-19 22:18:43 +08:00
|
|
|
if (alwaysAdd(S) && cachedEntry)
|
2011-03-10 11:50:34 +08:00
|
|
|
cachedEntry->second = B;
|
|
|
|
|
2011-06-10 16:49:37 +08:00
|
|
|
// All block-level expressions should have already been IgnoreParens()ed.
|
|
|
|
assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S);
|
2011-04-05 07:29:12 +08:00
|
|
|
B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext());
|
2009-10-13 04:55:07 +08:00
|
|
|
}
|
2011-01-09 04:30:50 +08:00
|
|
|
void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
|
2010-10-04 11:38:22 +08:00
|
|
|
B->appendInitializer(I, cfg->getBumpVectorContext());
|
|
|
|
}
|
2010-10-05 13:37:00 +08:00
|
|
|
void appendBaseDtor(CFGBlock *B, const CXXBaseSpecifier *BS) {
|
|
|
|
B->appendBaseDtor(BS, cfg->getBumpVectorContext());
|
|
|
|
}
|
|
|
|
void appendMemberDtor(CFGBlock *B, FieldDecl *FD) {
|
|
|
|
B->appendMemberDtor(FD, cfg->getBumpVectorContext());
|
|
|
|
}
|
2010-11-03 14:19:35 +08:00
|
|
|
void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) {
|
|
|
|
B->appendTemporaryDtor(E, cfg->getBumpVectorContext());
|
|
|
|
}
|
Enhance the CFG construction to detect no-return destructors for
temporary objects and local variables. When detected, these split the
block, marking the new one as having only the exit block as a successor.
This prevents a large number of false positives in warnings sensitive to
no-return constructs such as -Wreturn-type, and fixes the remainder of
PR10063 along with several variations of this bug that had not been
reported. The test cases are extended across the board to cover these
patterns.
This also checks in a stress test for these types of CFGs. The stress
test declares some 32k variables, a mixture of no-return and normal
destructors. Previously, this resulted in roughly 2500 CFG blocks, but
didn't model any of the no-return destructors. With this patch, it
results in over 33k blocks, many of them now unreachable.
The nice thing about how the analyzer is set up? This causes *no*
regression in performance of building the CFG. It actually in some cases
makes it faster, as best I can benchmark. The analysis for -Wreturn-type
(and any other that cares about no-return code paths) is technically
slower now as it has to look at many more candidate blocks, but it
computes the correct answer. I have more test cases to follow, I think
they all work now. Also I have further work that should dramatically
simplify analyses in the presence of no-return.
llvm-svn: 139586
2011-09-13 14:09:01 +08:00
|
|
|
void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) {
|
|
|
|
B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
|
|
|
|
}
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
|
2010-10-01 06:54:37 +08:00
|
|
|
LocalScope::const_iterator B, LocalScope::const_iterator E);
|
|
|
|
|
2010-12-17 12:44:39 +08:00
|
|
|
void addSuccessor(CFGBlock *B, CFGBlock *S) {
|
2009-10-13 04:55:07 +08:00
|
|
|
B->addSuccessor(S, cfg->getBumpVectorContext());
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-02 07:12:55 +08:00
|
|
|
/// Try and evaluate an expression to an integer constant.
|
|
|
|
bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
|
|
|
|
if (!BuildOpts.PruneTriviallyFalseEdges)
|
|
|
|
return false;
|
|
|
|
return !S->isTypeDependent() &&
|
2011-04-05 04:30:58 +08:00
|
|
|
!S->isValueDependent() &&
|
2011-10-29 08:50:52 +08:00
|
|
|
S->EvaluateAsRValue(outResult, *Context);
|
2011-03-02 07:12:55 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-12-17 12:44:39 +08:00
|
|
|
/// tryEvaluateBool - Try and evaluate the Stmt and return 0 or 1
|
2009-07-24 07:25:26 +08:00
|
|
|
/// if we can evaluate to a known value, otherwise return -1.
|
2010-12-17 12:44:39 +08:00
|
|
|
TryResult tryEvaluateBool(Expr *S) {
|
2011-10-15 04:22:00 +08:00
|
|
|
if (!BuildOpts.PruneTriviallyFalseEdges ||
|
2012-03-23 08:59:17 +08:00
|
|
|
S->isTypeDependent() || S->isValueDependent())
|
2011-03-02 07:12:55 +08:00
|
|
|
return TryResult();
|
2012-03-23 08:59:17 +08:00
|
|
|
|
|
|
|
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
|
|
|
|
if (Bop->isLogicalOp()) {
|
|
|
|
// Check the cache first.
|
2012-03-25 14:30:37 +08:00
|
|
|
CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
|
|
|
|
if (I != CachedBoolEvals.end())
|
2012-03-23 08:59:17 +08:00
|
|
|
return I->second; // already in map;
|
2012-03-25 14:30:32 +08:00
|
|
|
|
|
|
|
// Retrieve result at first, or the map might be updated.
|
|
|
|
TryResult Result = evaluateAsBooleanConditionNoCache(S);
|
|
|
|
CachedBoolEvals[S] = Result; // update or insert
|
|
|
|
return Result;
|
2012-03-23 08:59:17 +08:00
|
|
|
}
|
2012-08-24 15:42:09 +08:00
|
|
|
else {
|
|
|
|
switch (Bop->getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
// For 'x & 0' and 'x * 0', we can determine that
|
|
|
|
// the value is always false.
|
|
|
|
case BO_Mul:
|
|
|
|
case BO_And: {
|
|
|
|
// If either operand is zero, we know the value
|
|
|
|
// must be false.
|
|
|
|
llvm::APSInt IntVal;
|
|
|
|
if (Bop->getLHS()->EvaluateAsInt(IntVal, *Context)) {
|
|
|
|
if (IntVal.getBoolValue() == false) {
|
|
|
|
return TryResult(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Bop->getRHS()->EvaluateAsInt(IntVal, *Context)) {
|
|
|
|
if (IntVal.getBoolValue() == false) {
|
|
|
|
return TryResult(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-03-23 08:59:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return evaluateAsBooleanConditionNoCache(S);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Evaluate as boolean \param E without using the cache.
|
|
|
|
TryResult evaluateAsBooleanConditionNoCache(Expr *E) {
|
|
|
|
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(E)) {
|
|
|
|
if (Bop->isLogicalOp()) {
|
|
|
|
TryResult LHS = tryEvaluateBool(Bop->getLHS());
|
|
|
|
if (LHS.isKnown()) {
|
|
|
|
// We were able to evaluate the LHS, see if we can get away with not
|
|
|
|
// evaluating the RHS: 0 && X -> 0, 1 || X -> 1
|
|
|
|
if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
|
|
|
|
return LHS.isTrue();
|
|
|
|
|
|
|
|
TryResult RHS = tryEvaluateBool(Bop->getRHS());
|
|
|
|
if (RHS.isKnown()) {
|
|
|
|
if (Bop->getOpcode() == BO_LOr)
|
|
|
|
return LHS.isTrue() || RHS.isTrue();
|
|
|
|
else
|
|
|
|
return LHS.isTrue() && RHS.isTrue();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TryResult RHS = tryEvaluateBool(Bop->getRHS());
|
|
|
|
if (RHS.isKnown()) {
|
|
|
|
// We can't evaluate the LHS; however, sometimes the result
|
|
|
|
// is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
|
|
|
|
if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
|
|
|
|
return RHS.isTrue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TryResult();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Result;
|
|
|
|
if (E->EvaluateAsBooleanCondition(Result, *Context))
|
|
|
|
return Result;
|
|
|
|
|
|
|
|
return TryResult();
|
2009-07-24 07:25:26 +08:00
|
|
|
}
|
2011-03-02 07:12:55 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
};
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-03-10 11:50:34 +08:00
|
|
|
inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
|
|
|
|
const Stmt *stmt) const {
|
|
|
|
return builder.alwaysAdd(stmt) || kind == AlwaysAdd;
|
|
|
|
}
|
2011-03-24 05:33:21 +08:00
|
|
|
|
2011-03-10 11:50:34 +08:00
|
|
|
bool CFGBuilder::alwaysAdd(const Stmt *stmt) {
|
2011-07-19 22:18:43 +08:00
|
|
|
bool shouldAdd = BuildOpts.alwaysAdd(stmt);
|
|
|
|
|
2011-03-10 11:50:34 +08:00
|
|
|
if (!BuildOpts.forcedBlkExprs)
|
2011-07-19 22:18:43 +08:00
|
|
|
return shouldAdd;
|
2011-03-24 05:33:21 +08:00
|
|
|
|
|
|
|
if (lastLookup == stmt) {
|
|
|
|
if (cachedEntry) {
|
|
|
|
assert(cachedEntry->first == stmt);
|
|
|
|
return true;
|
|
|
|
}
|
2011-07-19 22:18:43 +08:00
|
|
|
return shouldAdd;
|
2011-03-24 05:33:21 +08:00
|
|
|
}
|
2011-03-10 11:50:34 +08:00
|
|
|
|
2011-03-24 05:33:21 +08:00
|
|
|
lastLookup = stmt;
|
|
|
|
|
|
|
|
// Perform the lookup!
|
2011-03-10 11:50:34 +08:00
|
|
|
CFG::BuildOptions::ForcedBlkExprs *fb = *BuildOpts.forcedBlkExprs;
|
|
|
|
|
2011-03-24 05:33:21 +08:00
|
|
|
if (!fb) {
|
|
|
|
// No need to update 'cachedEntry', since it will always be null.
|
|
|
|
assert(cachedEntry == 0);
|
2011-07-19 22:18:43 +08:00
|
|
|
return shouldAdd;
|
2011-03-24 05:33:21 +08:00
|
|
|
}
|
2011-03-10 11:50:34 +08:00
|
|
|
|
|
|
|
CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt);
|
2011-03-24 05:33:21 +08:00
|
|
|
if (itr == fb->end()) {
|
|
|
|
cachedEntry = 0;
|
2011-07-19 22:18:43 +08:00
|
|
|
return shouldAdd;
|
2011-03-24 05:33:21 +08:00
|
|
|
}
|
|
|
|
|
2011-03-10 11:50:34 +08:00
|
|
|
cachedEntry = &*itr;
|
|
|
|
return true;
|
2011-03-10 09:14:11 +08:00
|
|
|
}
|
|
|
|
|
2008-12-06 07:32:09 +08:00
|
|
|
// FIXME: Add support for dependent-sized array types in C++?
|
|
|
|
// Does it even make sense to build a CFG for an uninstantiated template?
|
2011-01-19 14:33:43 +08:00
|
|
|
static const VariableArrayType *FindVA(const Type *t) {
|
|
|
|
while (const ArrayType *vt = dyn_cast<ArrayType>(t)) {
|
|
|
|
if (const VariableArrayType *vat = dyn_cast<VariableArrayType>(vt))
|
2008-09-27 06:58:57 +08:00
|
|
|
if (vat->getSizeExpr())
|
|
|
|
return vat;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-09-27 06:58:57 +08:00
|
|
|
t = vt->getElementType().getTypePtr();
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-09-27 06:58:57 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can represent an
|
|
|
|
/// arbitrary statement. Examples include a single expression or a function
|
|
|
|
/// body (compound statement). The ownership of the returned CFG is
|
|
|
|
/// transferred to the caller. If CFG construction fails, this method returns
|
|
|
|
/// NULL.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
|
2009-10-21 07:46:25 +08:00
|
|
|
assert(cfg.get());
|
2009-07-18 06:18:43 +08:00
|
|
|
if (!Statement)
|
|
|
|
return NULL;
|
2007-08-24 05:42:29 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
// Create an empty block that will serve as the exit block for the CFG. Since
|
|
|
|
// this is the first block added to the CFG, it will be implicitly registered
|
|
|
|
// as the exit block.
|
2007-08-28 03:46:09 +08:00
|
|
|
Succ = createBlock();
|
2009-10-13 04:55:07 +08:00
|
|
|
assert(Succ == &cfg->getExit());
|
2007-08-28 03:46:09 +08:00
|
|
|
Block = NULL; // the EXIT block is empty. Create all other blocks lazily.
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-10-05 13:37:00 +08:00
|
|
|
if (BuildOpts.AddImplicitDtors)
|
|
|
|
if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
|
|
|
|
addImplicitDtorsForDestructor(DD);
|
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Visit the statements and create the CFG.
|
2010-09-06 15:04:06 +08:00
|
|
|
CFGBlock *B = addStmt(Statement);
|
|
|
|
|
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
|
|
|
|
2010-10-04 11:38:22 +08:00
|
|
|
// For C++ constructor add initializers to CFG.
|
2010-01-21 10:21:40 +08:00
|
|
|
if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
|
2010-10-04 11:38:22 +08:00
|
|
|
for (CXXConstructorDecl::init_const_reverse_iterator I = CD->init_rbegin(),
|
|
|
|
E = CD->init_rend(); I != E; ++I) {
|
|
|
|
B = addInitializer(*I);
|
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-01-21 10:21:40 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-10-04 11:38:22 +08:00
|
|
|
if (B)
|
|
|
|
Succ = B;
|
|
|
|
|
2010-09-06 15:04:06 +08:00
|
|
|
// Backpatch the gotos whose label -> block mappings we didn't know when we
|
|
|
|
// encountered them.
|
|
|
|
for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
|
|
|
|
E = BackpatchBlocks.end(); I != E; ++I ) {
|
2010-02-22 13:58:59 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *B = I->block;
|
|
|
|
GotoStmt *G = cast<GotoStmt>(B->getTerminator());
|
2010-09-06 15:04:06 +08:00
|
|
|
LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-06 15:04:06 +08:00
|
|
|
// If there is no target for the goto, then we are looking at an
|
|
|
|
// incomplete AST. Handle this by not registering a successor.
|
|
|
|
if (LI == LabelMap.end()) continue;
|
2007-08-24 05:42:29 +08:00
|
|
|
|
2010-09-25 19:05:21 +08:00
|
|
|
JumpTarget JT = LI->second;
|
2011-01-08 03:37:16 +08:00
|
|
|
prependAutomaticObjDtorsWithTerminator(B, I->scopePosition,
|
|
|
|
JT.scopePosition);
|
|
|
|
addSuccessor(B, JT.block);
|
2010-09-06 15:04:06 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-06 15:04:06 +08:00
|
|
|
// Add successors to the Indirect Goto Dispatch block (if we have one).
|
2011-08-13 07:37:29 +08:00
|
|
|
if (CFGBlock *B = cfg->getIndirectGotoBlock())
|
2010-09-06 15:04:06 +08:00
|
|
|
for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
|
|
|
|
E = AddressTakenLabels.end(); I != E; ++I ) {
|
|
|
|
|
|
|
|
// Lookup the target block.
|
|
|
|
LabelMapTy::iterator LI = LabelMap.find(*I);
|
|
|
|
|
|
|
|
// If there is no target block that contains label, then we are looking
|
|
|
|
// at an incomplete AST. Handle this by not registering a successor.
|
|
|
|
if (LI == LabelMap.end()) continue;
|
|
|
|
|
2011-01-08 03:37:16 +08:00
|
|
|
addSuccessor(B, LI->second.block);
|
2010-02-22 13:58:59 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Create an empty entry block that has no predecessors.
|
2007-09-27 05:23:31 +08:00
|
|
|
cfg->setEntry(createBlock());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-06 15:04:06 +08:00
|
|
|
return cfg.take();
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
/// createBlock - Used to lazily create blocks that are connected
|
|
|
|
/// to the current (global) succcessor.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::createBlock(bool add_successor) {
|
|
|
|
CFGBlock *B = cfg->createBlock();
|
2009-07-18 06:18:43 +08:00
|
|
|
if (add_successor && Succ)
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(B, Succ);
|
2007-08-24 05:42:29 +08:00
|
|
|
return B;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-09-13 17:13:49 +08:00
|
|
|
/// createNoReturnBlock - Used to create a block is a 'noreturn' point in the
|
|
|
|
/// CFG. It is *not* connected to the current (global) successor, and instead
|
|
|
|
/// directly tied to the exit block in order to be reachable.
|
|
|
|
CFGBlock *CFGBuilder::createNoReturnBlock() {
|
|
|
|
CFGBlock *B = createBlock(false);
|
2011-09-13 17:53:55 +08:00
|
|
|
B->setHasNoReturnElement();
|
2011-09-13 17:13:49 +08:00
|
|
|
addSuccessor(B, &cfg->getExit());
|
|
|
|
return B;
|
|
|
|
}
|
|
|
|
|
2010-10-04 11:38:22 +08:00
|
|
|
/// addInitializer - Add C++ base or member initializer element to CFG.
|
2011-01-09 04:30:50 +08:00
|
|
|
CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
|
2010-10-04 11:38:22 +08:00
|
|
|
if (!BuildOpts.AddInitializers)
|
|
|
|
return Block;
|
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
bool IsReference = false;
|
|
|
|
bool HasTemporaries = false;
|
2010-10-04 11:38:22 +08:00
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
// Destructors of temporaries in initialization expression should be called
|
|
|
|
// after initialization finishes.
|
|
|
|
Expr *Init = I->getInit();
|
|
|
|
if (Init) {
|
2010-12-04 17:14:42 +08:00
|
|
|
if (FieldDecl *FD = I->getAnyMember())
|
2010-11-03 14:19:35 +08:00
|
|
|
IsReference = FD->getType()->isReferenceType();
|
2010-12-06 16:20:24 +08:00
|
|
|
HasTemporaries = isa<ExprWithCleanups>(Init);
|
2010-10-04 11:38:22 +08:00
|
|
|
|
[analyzer] Always include destructors in the analysis CFG.
While destructors will continue to not be inlined (unless the analyzer
config option 'c++-inlining' is set to 'destructors'), leaving them out
of the CFG is an incomplete model of the behavior of an object, and
can cause false positive warnings (like PR13751, now working).
Destructors for temporaries are still not on by default, since
(a) we haven't actually checked this code to be sure it's fully correct
(in particular, we probably need to be very careful with regard to
lifetime-extension when a temporary is bound to a reference,
C++11 [class.temporary]p5), and
(b) ExprEngine doesn't actually do anything when it sees a temporary
destructor in the CFG -- not even invalidate the object region.
To enable temporary destructors, set the 'cfg-temporary-dtors' analyzer
config option to '1'. The old -cfg-add-implicit-dtors cc1 option, which
controlled all implicit destructors, has been removed.
llvm-svn: 163264
2012-09-06 06:55:23 +08:00
|
|
|
if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
|
2010-11-03 14:19:35 +08:00
|
|
|
// Generate destructors for temporaries in initialization expression.
|
2010-12-06 16:20:24 +08:00
|
|
|
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
|
2010-11-03 14:19:35 +08:00
|
|
|
IsReference);
|
|
|
|
}
|
2010-10-04 11:38:22 +08:00
|
|
|
}
|
2010-11-03 14:19:35 +08:00
|
|
|
|
|
|
|
autoCreateBlock();
|
|
|
|
appendInitializer(Block, I);
|
|
|
|
|
|
|
|
if (Init) {
|
2010-12-16 15:46:53 +08:00
|
|
|
if (HasTemporaries) {
|
2010-11-03 14:19:35 +08:00
|
|
|
// For expression with temporaries go directly to subexpression to omit
|
|
|
|
// generating destructors for the second time.
|
2010-12-16 15:46:53 +08:00
|
|
|
return Visit(cast<ExprWithCleanups>(Init)->getSubExpr());
|
|
|
|
}
|
|
|
|
return Visit(Init);
|
2010-11-03 14:19:35 +08:00
|
|
|
}
|
|
|
|
|
2010-10-04 11:38:22 +08:00
|
|
|
return Block;
|
|
|
|
}
|
|
|
|
|
2011-11-15 23:29:30 +08:00
|
|
|
/// \brief Retrieve the type of the temporary object whose lifetime was
|
|
|
|
/// extended by a local reference with the given initializer.
|
|
|
|
static QualType getReferenceInitTemporaryType(ASTContext &Context,
|
|
|
|
const Expr *Init) {
|
|
|
|
while (true) {
|
|
|
|
// Skip parentheses.
|
|
|
|
Init = Init->IgnoreParens();
|
|
|
|
|
|
|
|
// Skip through cleanups.
|
|
|
|
if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init)) {
|
|
|
|
Init = EWC->getSubExpr();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip through the temporary-materialization expression.
|
|
|
|
if (const MaterializeTemporaryExpr *MTE
|
|
|
|
= dyn_cast<MaterializeTemporaryExpr>(Init)) {
|
|
|
|
Init = MTE->GetTemporaryExpr();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip derived-to-base and no-op casts.
|
|
|
|
if (const CastExpr *CE = dyn_cast<CastExpr>(Init)) {
|
|
|
|
if ((CE->getCastKind() == CK_DerivedToBase ||
|
|
|
|
CE->getCastKind() == CK_UncheckedDerivedToBase ||
|
|
|
|
CE->getCastKind() == CK_NoOp) &&
|
|
|
|
Init->getType()->isRecordType()) {
|
|
|
|
Init = CE->getSubExpr();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip member accesses into rvalues.
|
|
|
|
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Init)) {
|
|
|
|
if (!ME->isArrow() && ME->getBase()->isRValue()) {
|
|
|
|
Init = ME->getBase();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Init->getType();
|
|
|
|
}
|
|
|
|
|
2010-10-01 07:05:00 +08:00
|
|
|
/// addAutomaticObjDtors - Add to current block automatic objects destructors
|
|
|
|
/// for objects in range of local scope positions. Use S as trigger statement
|
|
|
|
/// for destructors.
|
2010-10-01 11:22:39 +08:00
|
|
|
void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B,
|
2011-08-13 07:37:29 +08:00
|
|
|
LocalScope::const_iterator E, Stmt *S) {
|
2010-10-01 07:05:00 +08:00
|
|
|
if (!BuildOpts.AddImplicitDtors)
|
2010-10-01 11:22:39 +08:00
|
|
|
return;
|
|
|
|
|
2010-10-01 07:05:00 +08:00
|
|
|
if (B == E)
|
2010-10-01 11:22:39 +08:00
|
|
|
return;
|
2010-10-01 07:05:00 +08:00
|
|
|
|
Enhance the CFG construction to detect no-return destructors for
temporary objects and local variables. When detected, these split the
block, marking the new one as having only the exit block as a successor.
This prevents a large number of false positives in warnings sensitive to
no-return constructs such as -Wreturn-type, and fixes the remainder of
PR10063 along with several variations of this bug that had not been
reported. The test cases are extended across the board to cover these
patterns.
This also checks in a stress test for these types of CFGs. The stress
test declares some 32k variables, a mixture of no-return and normal
destructors. Previously, this resulted in roughly 2500 CFG blocks, but
didn't model any of the no-return destructors. With this patch, it
results in over 33k blocks, many of them now unreachable.
The nice thing about how the analyzer is set up? This causes *no*
regression in performance of building the CFG. It actually in some cases
makes it faster, as best I can benchmark. The analysis for -Wreturn-type
(and any other that cares about no-return code paths) is technically
slower now as it has to look at many more candidate blocks, but it
computes the correct answer. I have more test cases to follow, I think
they all work now. Also I have further work that should dramatically
simplify analyses in the presence of no-return.
llvm-svn: 139586
2011-09-13 14:09:01 +08:00
|
|
|
// We need to append the destructors in reverse order, but any one of them
|
|
|
|
// may be a no-return destructor which changes the CFG. As a result, buffer
|
|
|
|
// this sequence up and replay them in reverse order when appending onto the
|
|
|
|
// CFGBlock(s).
|
|
|
|
SmallVector<VarDecl*, 10> Decls;
|
|
|
|
Decls.reserve(B.distance(E));
|
|
|
|
for (LocalScope::const_iterator I = B; I != E; ++I)
|
|
|
|
Decls.push_back(*I);
|
|
|
|
|
|
|
|
for (SmallVectorImpl<VarDecl*>::reverse_iterator I = Decls.rbegin(),
|
|
|
|
E = Decls.rend();
|
|
|
|
I != E; ++I) {
|
|
|
|
// If this destructor is marked as a no-return destructor, we need to
|
|
|
|
// create a new block for the destructor which does not have as a successor
|
|
|
|
// anything built thus far: control won't flow out of this block.
|
2012-07-18 12:57:57 +08:00
|
|
|
QualType Ty = (*I)->getType();
|
|
|
|
if (Ty->isReferenceType()) {
|
2011-11-15 23:29:30 +08:00
|
|
|
Ty = getReferenceInitTemporaryType(*Context, (*I)->getInit());
|
|
|
|
}
|
2012-07-18 12:57:57 +08:00
|
|
|
Ty = Context->getBaseElementType(Ty);
|
|
|
|
|
Enhance the CFG construction to detect no-return destructors for
temporary objects and local variables. When detected, these split the
block, marking the new one as having only the exit block as a successor.
This prevents a large number of false positives in warnings sensitive to
no-return constructs such as -Wreturn-type, and fixes the remainder of
PR10063 along with several variations of this bug that had not been
reported. The test cases are extended across the board to cover these
patterns.
This also checks in a stress test for these types of CFGs. The stress
test declares some 32k variables, a mixture of no-return and normal
destructors. Previously, this resulted in roughly 2500 CFG blocks, but
didn't model any of the no-return destructors. With this patch, it
results in over 33k blocks, many of them now unreachable.
The nice thing about how the analyzer is set up? This causes *no*
regression in performance of building the CFG. It actually in some cases
makes it faster, as best I can benchmark. The analysis for -Wreturn-type
(and any other that cares about no-return code paths) is technically
slower now as it has to look at many more candidate blocks, but it
computes the correct answer. I have more test cases to follow, I think
they all work now. Also I have further work that should dramatically
simplify analyses in the presence of no-return.
llvm-svn: 139586
2011-09-13 14:09:01 +08:00
|
|
|
const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
|
2012-01-24 12:51:48 +08:00
|
|
|
if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr())
|
2011-09-13 17:13:49 +08:00
|
|
|
Block = createNoReturnBlock();
|
|
|
|
else
|
Enhance the CFG construction to detect no-return destructors for
temporary objects and local variables. When detected, these split the
block, marking the new one as having only the exit block as a successor.
This prevents a large number of false positives in warnings sensitive to
no-return constructs such as -Wreturn-type, and fixes the remainder of
PR10063 along with several variations of this bug that had not been
reported. The test cases are extended across the board to cover these
patterns.
This also checks in a stress test for these types of CFGs. The stress
test declares some 32k variables, a mixture of no-return and normal
destructors. Previously, this resulted in roughly 2500 CFG blocks, but
didn't model any of the no-return destructors. With this patch, it
results in over 33k blocks, many of them now unreachable.
The nice thing about how the analyzer is set up? This causes *no*
regression in performance of building the CFG. It actually in some cases
makes it faster, as best I can benchmark. The analysis for -Wreturn-type
(and any other that cares about no-return code paths) is technically
slower now as it has to look at many more candidate blocks, but it
computes the correct answer. I have more test cases to follow, I think
they all work now. Also I have further work that should dramatically
simplify analyses in the presence of no-return.
llvm-svn: 139586
2011-09-13 14:09:01 +08:00
|
|
|
autoCreateBlock();
|
|
|
|
|
|
|
|
appendAutomaticObjDtor(Block, *I, S);
|
|
|
|
}
|
2010-10-01 07:05:00 +08:00
|
|
|
}
|
|
|
|
|
2010-10-05 13:37:00 +08:00
|
|
|
/// addImplicitDtorsForDestructor - Add implicit destructors generated for
|
|
|
|
/// base and member objects in destructor.
|
|
|
|
void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
|
|
|
|
assert (BuildOpts.AddImplicitDtors
|
|
|
|
&& "Can be called only when dtors should be added");
|
|
|
|
const CXXRecordDecl *RD = DD->getParent();
|
|
|
|
|
|
|
|
// At the end destroy virtual base objects.
|
|
|
|
for (CXXRecordDecl::base_class_const_iterator VI = RD->vbases_begin(),
|
|
|
|
VE = RD->vbases_end(); VI != VE; ++VI) {
|
|
|
|
const CXXRecordDecl *CD = VI->getType()->getAsCXXRecordDecl();
|
|
|
|
if (!CD->hasTrivialDestructor()) {
|
|
|
|
autoCreateBlock();
|
|
|
|
appendBaseDtor(Block, VI);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Before virtual bases destroy direct base objects.
|
|
|
|
for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(),
|
|
|
|
BE = RD->bases_end(); BI != BE; ++BI) {
|
2012-01-24 12:51:48 +08:00
|
|
|
if (!BI->isVirtual()) {
|
|
|
|
const CXXRecordDecl *CD = BI->getType()->getAsCXXRecordDecl();
|
|
|
|
if (!CD->hasTrivialDestructor()) {
|
|
|
|
autoCreateBlock();
|
|
|
|
appendBaseDtor(Block, BI);
|
|
|
|
}
|
|
|
|
}
|
2010-10-05 13:37:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// First destroy member objects.
|
|
|
|
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
|
|
|
|
FE = RD->field_end(); FI != FE; ++FI) {
|
2010-10-25 15:05:54 +08:00
|
|
|
// Check for constant size array. Set type to array element type.
|
|
|
|
QualType QT = FI->getType();
|
|
|
|
if (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
|
|
|
|
if (AT->getSize() == 0)
|
|
|
|
continue;
|
|
|
|
QT = AT->getElementType();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
|
2010-10-05 13:37:00 +08:00
|
|
|
if (!CD->hasTrivialDestructor()) {
|
|
|
|
autoCreateBlock();
|
2012-06-07 04:45:41 +08:00
|
|
|
appendMemberDtor(Block, *FI);
|
2010-10-05 13:37:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-01 07:05:00 +08:00
|
|
|
/// createOrReuseLocalScope - If Scope is NULL create new LocalScope. Either
|
|
|
|
/// way return valid LocalScope object.
|
|
|
|
LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
|
|
|
|
if (!Scope) {
|
2011-02-15 10:47:45 +08:00
|
|
|
llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
|
|
|
|
Scope = alloc.Allocate<LocalScope>();
|
|
|
|
BumpVectorContext ctx(alloc);
|
|
|
|
new (Scope) LocalScope(ctx, ScopePos);
|
2010-10-01 07:05:00 +08:00
|
|
|
}
|
|
|
|
return Scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement
|
2010-10-01 11:00:16 +08:00
|
|
|
/// that should create implicit scope (e.g. if/else substatements).
|
2011-08-13 07:37:29 +08:00
|
|
|
void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
|
2010-10-01 07:05:00 +08:00
|
|
|
if (!BuildOpts.AddImplicitDtors)
|
2010-10-01 11:00:16 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
LocalScope *Scope = 0;
|
2010-10-01 07:05:00 +08:00
|
|
|
|
|
|
|
// For compound statement we will be creating explicit scope.
|
2011-02-17 15:39:24 +08:00
|
|
|
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
|
2010-10-01 07:05:00 +08:00
|
|
|
for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end()
|
|
|
|
; BI != BE; ++BI) {
|
2011-09-10 08:02:34 +08:00
|
|
|
Stmt *SI = (*BI)->stripLabelLikeStatements();
|
2011-02-17 15:39:24 +08:00
|
|
|
if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
|
2010-10-01 07:05:00 +08:00
|
|
|
Scope = addLocalScopeForDeclStmt(DS, Scope);
|
|
|
|
}
|
2010-10-01 11:00:16 +08:00
|
|
|
return;
|
2010-10-01 07:05:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// For any other statement scope will be implicit and as such will be
|
|
|
|
// interesting only for DeclStmt.
|
2011-09-10 08:02:34 +08:00
|
|
|
if (DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements()))
|
2010-10-01 11:09:09 +08:00
|
|
|
addLocalScopeForDeclStmt(DS);
|
2010-10-01 07:05:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// addLocalScopeForDeclStmt - Add LocalScope for declaration statement. Will
|
|
|
|
/// reuse Scope if not NULL.
|
2011-08-13 07:37:29 +08:00
|
|
|
LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
|
2010-10-01 11:09:09 +08:00
|
|
|
LocalScope* Scope) {
|
2010-10-01 07:05:00 +08:00
|
|
|
if (!BuildOpts.AddImplicitDtors)
|
|
|
|
return Scope;
|
|
|
|
|
|
|
|
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end()
|
|
|
|
; DI != DE; ++DI) {
|
2011-08-13 07:37:29 +08:00
|
|
|
if (VarDecl *VD = dyn_cast<VarDecl>(*DI))
|
2010-10-01 07:05:00 +08:00
|
|
|
Scope = addLocalScopeForVarDecl(VD, Scope);
|
|
|
|
}
|
|
|
|
return Scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will
|
|
|
|
/// create add scope for automatic objects and temporary objects bound to
|
|
|
|
/// const reference. Will reuse Scope if not NULL.
|
2011-08-13 07:37:29 +08:00
|
|
|
LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
|
2010-10-01 11:09:09 +08:00
|
|
|
LocalScope* Scope) {
|
2010-10-01 07:05:00 +08:00
|
|
|
if (!BuildOpts.AddImplicitDtors)
|
|
|
|
return Scope;
|
|
|
|
|
|
|
|
// Check if variable is local.
|
|
|
|
switch (VD->getStorageClass()) {
|
|
|
|
case SC_None:
|
|
|
|
case SC_Auto:
|
|
|
|
case SC_Register:
|
|
|
|
break;
|
|
|
|
default: return Scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for const references bound to temporary. Set type to pointee.
|
|
|
|
QualType QT = VD->getType();
|
2011-11-15 23:29:30 +08:00
|
|
|
if (QT.getTypePtr()->isReferenceType()) {
|
2011-06-22 01:03:29 +08:00
|
|
|
if (!VD->extendsLifetimeOfTemporary())
|
2010-10-01 07:05:00 +08:00
|
|
|
return Scope;
|
2011-11-15 23:29:30 +08:00
|
|
|
|
|
|
|
QT = getReferenceInitTemporaryType(*Context, VD->getInit());
|
2010-10-01 07:05:00 +08:00
|
|
|
}
|
|
|
|
|
2010-10-25 15:00:40 +08:00
|
|
|
// Check for constant size array. Set type to array element type.
|
2011-11-15 23:29:30 +08:00
|
|
|
while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
|
2010-10-25 15:00:40 +08:00
|
|
|
if (AT->getSize() == 0)
|
|
|
|
return Scope;
|
|
|
|
QT = AT->getElementType();
|
|
|
|
}
|
2010-10-05 16:38:06 +08:00
|
|
|
|
2010-10-25 15:00:40 +08:00
|
|
|
// Check if type is a C++ class with non-trivial destructor.
|
2011-08-13 07:37:29 +08:00
|
|
|
if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
|
2012-01-24 12:51:48 +08:00
|
|
|
if (!CD->hasTrivialDestructor()) {
|
2010-10-05 16:38:06 +08:00
|
|
|
// Add the variable to scope
|
|
|
|
Scope = createOrReuseLocalScope(Scope);
|
|
|
|
Scope->addVar(VD);
|
|
|
|
ScopePos = Scope->begin();
|
|
|
|
}
|
2010-10-01 07:05:00 +08:00
|
|
|
return Scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// addLocalScopeAndDtors - For given statement add local scope for it and
|
|
|
|
/// add destructors that will cleanup the scope. Will reuse Scope if not NULL.
|
2011-08-13 07:37:29 +08:00
|
|
|
void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
|
2010-10-01 07:05:00 +08:00
|
|
|
if (!BuildOpts.AddImplicitDtors)
|
|
|
|
return;
|
|
|
|
|
|
|
|
LocalScope::const_iterator scopeBeginPos = ScopePos;
|
2010-10-01 11:00:16 +08:00
|
|
|
addLocalScopeForStmt(S);
|
2010-10-01 07:05:00 +08:00
|
|
|
addAutomaticObjDtors(ScopePos, scopeBeginPos, S);
|
|
|
|
}
|
|
|
|
|
2010-10-01 06:54:37 +08:00
|
|
|
/// prependAutomaticObjDtorsWithTerminator - Prepend destructor 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
|
|
|
|
/// destructors call site.
|
Enhance the CFG construction to detect no-return destructors for
temporary objects and local variables. When detected, these split the
block, marking the new one as having only the exit block as a successor.
This prevents a large number of false positives in warnings sensitive to
no-return constructs such as -Wreturn-type, and fixes the remainder of
PR10063 along with several variations of this bug that had not been
reported. The test cases are extended across the board to cover these
patterns.
This also checks in a stress test for these types of CFGs. The stress
test declares some 32k variables, a mixture of no-return and normal
destructors. Previously, this resulted in roughly 2500 CFG blocks, but
didn't model any of the no-return destructors. With this patch, it
results in over 33k blocks, many of them now unreachable.
The nice thing about how the analyzer is set up? This causes *no*
regression in performance of building the CFG. It actually in some cases
makes it faster, as best I can benchmark. The analysis for -Wreturn-type
(and any other that cares about no-return code paths) is technically
slower now as it has to look at many more candidate blocks, but it
computes the correct answer. I have more test cases to follow, I think
they all work now. Also I have further work that should dramatically
simplify analyses in the presence of no-return.
llvm-svn: 139586
2011-09-13 14:09:01 +08:00
|
|
|
/// FIXME: This mechanism for adding automatic destructors doesn't handle
|
|
|
|
/// no-return destructors properly.
|
2011-08-13 07:37:29 +08:00
|
|
|
void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
|
2010-10-01 06:54:37 +08:00
|
|
|
LocalScope::const_iterator B, LocalScope::const_iterator E) {
|
Enhance the CFG construction to detect no-return destructors for
temporary objects and local variables. When detected, these split the
block, marking the new one as having only the exit block as a successor.
This prevents a large number of false positives in warnings sensitive to
no-return constructs such as -Wreturn-type, and fixes the remainder of
PR10063 along with several variations of this bug that had not been
reported. The test cases are extended across the board to cover these
patterns.
This also checks in a stress test for these types of CFGs. The stress
test declares some 32k variables, a mixture of no-return and normal
destructors. Previously, this resulted in roughly 2500 CFG blocks, but
didn't model any of the no-return destructors. With this patch, it
results in over 33k blocks, many of them now unreachable.
The nice thing about how the analyzer is set up? This causes *no*
regression in performance of building the CFG. It actually in some cases
makes it faster, as best I can benchmark. The analysis for -Wreturn-type
(and any other that cares about no-return code paths) is technically
slower now as it has to look at many more candidate blocks, but it
computes the correct answer. I have more test cases to follow, I think
they all work now. Also I have further work that should dramatically
simplify analyses in the presence of no-return.
llvm-svn: 139586
2011-09-13 14:09:01 +08:00
|
|
|
BumpVectorContext &C = cfg->getBumpVectorContext();
|
|
|
|
CFGBlock::iterator InsertPos
|
|
|
|
= Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C);
|
|
|
|
for (LocalScope::const_iterator I = B; I != E; ++I)
|
|
|
|
InsertPos = Blk->insertAutomaticObjDtor(InsertPos, *I,
|
|
|
|
Blk->getTerminator());
|
2010-10-01 06:54:37 +08:00
|
|
|
}
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
/// Visit - Walk the subtree of a statement and add extra
|
2009-07-17 09:31:16 +08:00
|
|
|
/// blocks for ternary operators, &&, and ||. We also process "," and
|
|
|
|
/// DeclStmts (which may contain nested control-flow).
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
|
2010-05-01 06:25:53 +08:00
|
|
|
if (!S) {
|
|
|
|
badCFG = true;
|
|
|
|
return 0;
|
|
|
|
}
|
2011-06-10 16:49:37 +08:00
|
|
|
|
|
|
|
if (Expr *E = dyn_cast<Expr>(S))
|
|
|
|
S = E->IgnoreParens();
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
switch (S->getStmtClass()) {
|
|
|
|
default:
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitStmt(S, asc);
|
2009-07-18 06:18:43 +08:00
|
|
|
|
|
|
|
case Stmt::AddrLabelExprClass:
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-02-17 18:25:35 +08:00
|
|
|
case Stmt::BinaryConditionalOperatorClass:
|
|
|
|
return VisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc);
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::BinaryOperatorClass:
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::BlockExprClass:
|
2012-04-13 04:03:44 +08:00
|
|
|
return VisitNoRecurse(cast<Expr>(S), asc);
|
2009-07-18 06:18:43 +08:00
|
|
|
|
|
|
|
case Stmt::BreakStmtClass:
|
|
|
|
return VisitBreakStmt(cast<BreakStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::CallExprClass:
|
2010-09-01 02:47:34 +08:00
|
|
|
case Stmt::CXXOperatorCallExprClass:
|
2011-05-11 15:19:11 +08:00
|
|
|
case Stmt::CXXMemberCallExprClass:
|
2012-03-07 16:35:16 +08:00
|
|
|
case Stmt::UserDefinedLiteralClass:
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitCallExpr(cast<CallExpr>(S), asc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::CaseStmtClass:
|
|
|
|
return VisitCaseStmt(cast<CaseStmt>(S));
|
|
|
|
|
|
|
|
case Stmt::ChooseExprClass:
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitChooseExpr(cast<ChooseExpr>(S), asc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::CompoundStmtClass:
|
|
|
|
return VisitCompoundStmt(cast<CompoundStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ConditionalOperatorClass:
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitConditionalOperator(cast<ConditionalOperator>(S), asc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ContinueStmtClass:
|
|
|
|
return VisitContinueStmt(cast<ContinueStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-20 04:40:33 +08:00
|
|
|
case Stmt::CXXCatchStmtClass:
|
|
|
|
return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
|
|
|
|
|
2010-12-06 16:20:24 +08:00
|
|
|
case Stmt::ExprWithCleanupsClass:
|
|
|
|
return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc);
|
2010-08-28 08:19:02 +08:00
|
|
|
|
2012-08-24 02:10:53 +08:00
|
|
|
case Stmt::CXXDefaultArgExprClass:
|
|
|
|
// FIXME: The expression inside a CXXDefaultArgExpr is owned by the
|
|
|
|
// called function's declaration, not by the caller. If we simply add
|
|
|
|
// this expression to the CFG, we could end up with the same Expr
|
|
|
|
// appearing multiple times.
|
|
|
|
// PR13385 / <rdar://problem/12156507>
|
|
|
|
return VisitStmt(S, asc);
|
|
|
|
|
2010-11-01 21:04:58 +08:00
|
|
|
case Stmt::CXXBindTemporaryExprClass:
|
|
|
|
return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
|
|
|
|
|
2010-11-01 14:46:05 +08:00
|
|
|
case Stmt::CXXConstructExprClass:
|
|
|
|
return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
|
|
|
|
|
2010-11-01 21:04:58 +08:00
|
|
|
case Stmt::CXXFunctionalCastExprClass:
|
|
|
|
return VisitCXXFunctionalCastExpr(cast<CXXFunctionalCastExpr>(S), asc);
|
|
|
|
|
2010-11-01 14:46:05 +08:00
|
|
|
case Stmt::CXXTemporaryObjectExprClass:
|
|
|
|
return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc);
|
|
|
|
|
2010-01-20 04:40:33 +08:00
|
|
|
case Stmt::CXXThrowExprClass:
|
|
|
|
return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2010-01-20 04:40:33 +08:00
|
|
|
case Stmt::CXXTryStmtClass:
|
|
|
|
return VisitCXXTryStmt(cast<CXXTryStmt>(S));
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
case Stmt::CXXForRangeStmtClass:
|
|
|
|
return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::DeclStmtClass:
|
|
|
|
return VisitDeclStmt(cast<DeclStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::DefaultStmtClass:
|
|
|
|
return VisitDefaultStmt(cast<DefaultStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::DoStmtClass:
|
|
|
|
return VisitDoStmt(cast<DoStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ForStmtClass:
|
|
|
|
return VisitForStmt(cast<ForStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::GotoStmtClass:
|
|
|
|
return VisitGotoStmt(cast<GotoStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::IfStmtClass:
|
|
|
|
return VisitIfStmt(cast<IfStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-12-16 15:46:53 +08:00
|
|
|
case Stmt::ImplicitCastExprClass:
|
|
|
|
return VisitImplicitCastExpr(cast<ImplicitCastExpr>(S), asc);
|
2010-11-01 21:04:58 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::IndirectGotoStmtClass:
|
|
|
|
return VisitIndirectGotoStmt(cast<IndirectGotoStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::LabelStmtClass:
|
|
|
|
return VisitLabelStmt(cast<LabelStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-04-13 04:34:52 +08:00
|
|
|
case Stmt::LambdaExprClass:
|
|
|
|
return VisitLambdaExpr(cast<LambdaExpr>(S), asc);
|
|
|
|
|
2010-04-12 01:02:10 +08:00
|
|
|
case Stmt::MemberExprClass:
|
|
|
|
return VisitMemberExpr(cast<MemberExpr>(S), asc);
|
|
|
|
|
2011-11-05 08:10:15 +08:00
|
|
|
case Stmt::NullStmtClass:
|
|
|
|
return Block;
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ObjCAtCatchStmtClass:
|
2009-09-09 23:08:12 +08:00
|
|
|
return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
|
|
|
|
|
2012-03-07 07:40:47 +08:00
|
|
|
case Stmt::ObjCAutoreleasePoolStmtClass:
|
|
|
|
return VisitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(S));
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ObjCAtSynchronizedStmtClass:
|
|
|
|
return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ObjCAtThrowStmtClass:
|
|
|
|
return VisitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ObjCAtTryStmtClass:
|
|
|
|
return VisitObjCAtTryStmt(cast<ObjCAtTryStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ObjCForCollectionStmtClass:
|
|
|
|
return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-11-05 08:10:15 +08:00
|
|
|
case Stmt::OpaqueValueExprClass:
|
2009-07-18 06:18:43 +08:00
|
|
|
return Block;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-11-06 17:01:30 +08:00
|
|
|
case Stmt::PseudoObjectExprClass:
|
|
|
|
return VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S));
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::ReturnStmtClass:
|
|
|
|
return VisitReturnStmt(cast<ReturnStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-12 03:24:49 +08:00
|
|
|
case Stmt::UnaryExprOrTypeTraitExprClass:
|
|
|
|
return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
|
|
|
|
asc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::StmtExprClass:
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitStmtExpr(cast<StmtExpr>(S), asc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::SwitchStmtClass:
|
|
|
|
return VisitSwitchStmt(cast<SwitchStmt>(S));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-22 16:45:56 +08:00
|
|
|
case Stmt::UnaryOperatorClass:
|
|
|
|
return VisitUnaryOperator(cast<UnaryOperator>(S), asc);
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
case Stmt::WhileStmtClass:
|
|
|
|
return VisitWhileStmt(cast<WhileStmt>(S));
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, S)) {
|
2009-07-18 06:18:43 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, S);
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
return VisitChildren(S);
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
/// VisitChildren - Visit the children of a Stmt.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) {
|
2012-04-14 08:33:13 +08:00
|
|
|
CFGBlock *lastBlock = Block;
|
2011-02-22 06:11:26 +08:00
|
|
|
for (Stmt::child_range I = Terminator->children(); I; ++I)
|
|
|
|
if (Stmt *child = *I)
|
|
|
|
if (CFGBlock *b = Visit(child))
|
|
|
|
lastBlock = b;
|
|
|
|
|
|
|
|
return lastBlock;
|
2009-07-18 06:18:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
|
|
|
|
AddStmtChoice asc) {
|
2009-07-18 06:18:43 +08:00
|
|
|
AddressTakenLabels.insert(A->getLabel());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, A)) {
|
2009-07-18 06:18:43 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, A);
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
return Block;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-22 16:45:56 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U,
|
2010-12-16 15:46:53 +08:00
|
|
|
AddStmtChoice asc) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, U)) {
|
2010-11-22 16:45:56 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, U);
|
2010-11-22 16:45:56 +08:00
|
|
|
}
|
|
|
|
|
2010-12-16 15:46:53 +08:00
|
|
|
return Visit(U->getSubExpr(), AddStmtChoice());
|
2010-11-22 16:45:56 +08:00
|
|
|
}
|
|
|
|
|
2012-07-14 13:04:06 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) {
|
|
|
|
CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
|
|
|
|
appendStmt(ConfluenceBlock, B);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-07-14 13:04:06 +08:00
|
|
|
if (badCFG)
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
return VisitLogicalOperator(B, 0, ConfluenceBlock, ConfluenceBlock).first;
|
|
|
|
}
|
2010-04-29 09:10:26 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
std::pair<CFGBlock*, CFGBlock*>
|
|
|
|
CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
|
|
|
|
Stmt *Term,
|
|
|
|
CFGBlock *TrueBlock,
|
|
|
|
CFGBlock *FalseBlock) {
|
|
|
|
|
|
|
|
// Introspect the RHS. If it is a nested logical operation, we recursively
|
|
|
|
// build the CFG using this function. Otherwise, resort to default
|
|
|
|
// CFG construction behavior.
|
|
|
|
Expr *RHS = B->getRHS()->IgnoreParens();
|
|
|
|
CFGBlock *RHSBlock, *ExitBlock;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (BinaryOperator *B_RHS = dyn_cast<BinaryOperator>(RHS))
|
|
|
|
if (B_RHS->isLogicalOp()) {
|
|
|
|
llvm::tie(RHSBlock, ExitBlock) =
|
|
|
|
VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// The RHS is not a nested logical operation. Don't push the terminator
|
|
|
|
// down further, but instead visit RHS and construct the respective
|
|
|
|
// pieces of the CFG, and link up the RHSBlock with the terminator
|
|
|
|
// we have been provided.
|
|
|
|
ExitBlock = RHSBlock = createBlock(false);
|
|
|
|
|
|
|
|
if (!Term) {
|
|
|
|
assert(TrueBlock == FalseBlock);
|
|
|
|
addSuccessor(RHSBlock, TrueBlock);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
RHSBlock->setTerminator(Term);
|
|
|
|
TryResult KnownVal = tryEvaluateBool(RHS);
|
|
|
|
addSuccessor(RHSBlock, KnownVal.isFalse() ? NULL : TrueBlock);
|
|
|
|
addSuccessor(RHSBlock, KnownVal.isTrue() ? NULL : FalseBlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
Block = RHSBlock;
|
|
|
|
RHSBlock = addStmt(RHS);
|
2012-07-14 13:04:06 +08:00
|
|
|
}
|
2012-07-14 13:04:10 +08:00
|
|
|
while (false);
|
|
|
|
|
|
|
|
if (badCFG)
|
|
|
|
return std::make_pair((CFGBlock*)0, (CFGBlock*)0);
|
2012-03-23 08:59:17 +08:00
|
|
|
|
2012-07-14 13:04:06 +08:00
|
|
|
// Generate the blocks for evaluating the LHS.
|
2012-07-14 13:04:10 +08:00
|
|
|
Expr *LHS = B->getLHS()->IgnoreParens();
|
|
|
|
|
|
|
|
if (BinaryOperator *B_LHS = dyn_cast<BinaryOperator>(LHS))
|
|
|
|
if (B_LHS->isLogicalOp()) {
|
|
|
|
if (B->getOpcode() == BO_LOr)
|
|
|
|
FalseBlock = RHSBlock;
|
|
|
|
else
|
|
|
|
TrueBlock = RHSBlock;
|
|
|
|
|
|
|
|
// For the LHS, treat 'B' as the terminator that we want to sink
|
|
|
|
// into the nested branch. The RHS always gets the top-most
|
|
|
|
// terminator.
|
|
|
|
return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the block evaluating the LHS.
|
|
|
|
// This contains the '&&' or '||' as the terminator.
|
|
|
|
CFGBlock *LHSBlock = createBlock(false);
|
|
|
|
LHSBlock->setTerminator(B);
|
|
|
|
|
2012-07-14 13:04:06 +08:00
|
|
|
Block = LHSBlock;
|
2012-07-14 13:04:10 +08:00
|
|
|
CFGBlock *EntryLHSBlock = addStmt(LHS);
|
|
|
|
|
|
|
|
if (badCFG)
|
|
|
|
return std::make_pair((CFGBlock*)0, (CFGBlock*)0);
|
2012-07-14 13:04:06 +08:00
|
|
|
|
|
|
|
// See if this is a known constant.
|
2012-07-14 13:04:10 +08:00
|
|
|
TryResult KnownVal = tryEvaluateBool(LHS);
|
2012-07-14 13:04:06 +08:00
|
|
|
|
|
|
|
// Now link the LHSBlock with RHSBlock.
|
|
|
|
if (B->getOpcode() == BO_LOr) {
|
2012-07-14 13:04:10 +08:00
|
|
|
addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : TrueBlock);
|
|
|
|
addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : RHSBlock);
|
2012-07-14 13:04:06 +08:00
|
|
|
} else {
|
|
|
|
assert(B->getOpcode() == BO_LAnd);
|
|
|
|
addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
|
2012-07-14 13:04:10 +08:00
|
|
|
addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : FalseBlock);
|
2012-07-14 13:04:06 +08:00
|
|
|
}
|
2009-07-24 07:25:26 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
return std::make_pair(EntryLHSBlock, ExitBlock);
|
2012-07-14 13:04:06 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
|
2012-07-14 13:04:06 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
|
|
|
|
AddStmtChoice asc) {
|
|
|
|
// && or ||
|
|
|
|
if (B->isLogicalOp())
|
|
|
|
return VisitLogicalOperator(B);
|
2010-11-23 03:32:14 +08:00
|
|
|
|
|
|
|
if (B->getOpcode() == BO_Comma) { // ,
|
2009-07-18 06:57:50 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, B);
|
2009-07-18 06:18:43 +08:00
|
|
|
addStmt(B->getRHS());
|
|
|
|
return addStmt(B->getLHS());
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
2010-11-23 03:32:14 +08:00
|
|
|
|
|
|
|
if (B->isAssignmentOp()) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, B)) {
|
2010-06-03 14:23:18 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, B);
|
2010-06-03 14:23:18 +08:00
|
|
|
}
|
2010-12-16 15:46:53 +08:00
|
|
|
Visit(B->getLHS());
|
2010-10-24 16:21:40 +08:00
|
|
|
return Visit(B->getRHS());
|
2010-06-03 14:23:18 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, B)) {
|
2010-10-24 16:21:40 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, B);
|
2010-10-24 16:21:40 +08:00
|
|
|
}
|
|
|
|
|
2010-10-27 11:23:10 +08:00
|
|
|
CFGBlock *RBlock = Visit(B->getRHS());
|
|
|
|
CFGBlock *LBlock = Visit(B->getLHS());
|
|
|
|
// If visiting RHS causes us to finish 'Block', e.g. the RHS is a StmtExpr
|
|
|
|
// containing a DoStmt, and the LHS doesn't create a new block, then we should
|
|
|
|
// return RBlock. Otherwise we'll incorrectly return NULL.
|
|
|
|
return (LBlock ? LBlock : RBlock);
|
2009-07-18 06:18:43 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-04-13 04:03:44 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, E)) {
|
2009-11-25 09:34:30 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, E);
|
2009-11-25 09:34:30 +08:00
|
|
|
}
|
|
|
|
return Block;
|
2009-07-18 06:18:43 +08:00
|
|
|
}
|
2009-07-17 09:04:31 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
|
|
|
|
// "break" is a control-flow statement. Thus we stop processing the current
|
|
|
|
// block.
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
// Now create a new block that ends with the break statement.
|
|
|
|
Block = createBlock(false);
|
|
|
|
Block->setTerminator(B);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
// If there is no target for the break, then we are looking at an incomplete
|
|
|
|
// AST. This means that the CFG cannot be constructed.
|
2011-01-08 03:37:16 +08:00
|
|
|
if (BreakJumpTarget.block) {
|
|
|
|
addAutomaticObjDtors(ScopePos, BreakJumpTarget.scopePosition, B);
|
|
|
|
addSuccessor(Block, BreakJumpTarget.block);
|
2010-09-25 19:05:21 +08:00
|
|
|
} else
|
2009-07-18 06:18:43 +08:00
|
|
|
badCFG = true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
return Block;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-14 01:09:40 +08:00
|
|
|
static bool CanThrow(Expr *E, ASTContext &Ctx) {
|
2010-01-21 23:20:48 +08:00
|
|
|
QualType Ty = E->getType();
|
|
|
|
if (Ty->isFunctionPointerType())
|
|
|
|
Ty = Ty->getAs<PointerType>()->getPointeeType();
|
|
|
|
else if (Ty->isBlockPointerType())
|
|
|
|
Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2010-01-21 23:20:48 +08:00
|
|
|
const FunctionType *FT = Ty->getAs<FunctionType>();
|
|
|
|
if (FT) {
|
|
|
|
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
|
Final piece of core issue 1330: delay computing the exception specification of
a defaulted special member function until the exception specification is needed
(using the same criteria used for the delayed instantiation of exception
specifications for function temploids).
EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like
EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to
resolve the exception specification.
This is enabled for all C++ modes: it's a little faster in the case where the
exception specification isn't used, allows our C++11-in-C++98 extensions to
work, and is still correct for C++98, since in that mode the computation of the
exception specification can't fail.
The diagnostics here aren't great (in particular, we should include implicit
evaluation of exception specifications for defaulted special members in the
template instantiation backtraces), but they're not much worse than before.
Our approach to the problem of cycles between in-class initializers and the
exception specification for a defaulted default constructor is modified a
little by this change -- we now reject any odr-use of a defaulted default
constructor if that constructor uses an in-class initializer and the use is in
an in-class initialzer which is declared lexically earlier. This is a closer
approximation to the current draft solution in core issue 1351, but isn't an
exact match (but the current draft wording isn't reasonable, so that's to be
expected).
llvm-svn: 160847
2012-07-27 12:22:15 +08:00
|
|
|
if (!isUnresolvedExceptionSpec(Proto->getExceptionSpecType()) &&
|
Implement DR1330 in C++11 mode, to support libstdc++4.7 which uses it.
We have a new flavor of exception specification, EST_Uninstantiated. A function
type with this exception specification carries a pointer to a FunctionDecl, and
the exception specification for that FunctionDecl is instantiated (if needed)
and used in the place of the function type's exception specification.
When a function template declaration with a non-trivial exception specification
is instantiated, the specialization's exception specification is set to this
new 'uninstantiated' kind rather than being instantiated immediately.
Expr::CanThrow has migrated onto Sema, so it can instantiate exception specs
on-demand. Also, any odr-use of a function triggers the instantiation of its
exception specification (the exception specification could be needed by IRGen).
In passing, fix two places where a DeclRefExpr was created but the corresponding
function was not actually marked odr-used. We used to get away with this, but
don't any more.
Also fix a bug where instantiating an exception specification which refers to
function parameters resulted in a crash. We still have the same bug in default
arguments, which I'll be looking into next.
This, plus a tiny patch to fix libstdc++'s common_type, is enough for clang to
parse (and, in very limited testing, support) all of libstdc++4.7's standard
headers.
llvm-svn: 154886
2012-04-17 08:58:00 +08:00
|
|
|
Proto->isNothrow(Ctx))
|
2010-01-21 23:20:48 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
|
2011-05-11 15:19:11 +08:00
|
|
|
// Compute the callee type.
|
|
|
|
QualType calleeType = C->getCallee()->getType();
|
|
|
|
if (calleeType == Context->BoundMemberTy) {
|
|
|
|
QualType boundType = Expr::findBoundMemberType(C->getCallee());
|
|
|
|
|
|
|
|
// We should only get a null bound type if processing a dependent
|
|
|
|
// CFG. Recover by assuming nothing.
|
|
|
|
if (!boundType.isNull()) calleeType = boundType;
|
2009-07-26 05:26:53 +08:00
|
|
|
}
|
|
|
|
|
2011-05-11 15:19:11 +08:00
|
|
|
// If this is a call to a no-return function, this stops the block here.
|
|
|
|
bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn();
|
|
|
|
|
2010-01-21 23:20:48 +08:00
|
|
|
bool AddEHEdge = false;
|
2010-01-20 06:00:14 +08:00
|
|
|
|
|
|
|
// Languages without exceptions are assumed to not throw.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Context->getLangOpts().Exceptions) {
|
2010-09-15 07:41:16 +08:00
|
|
|
if (BuildOpts.AddEHEdges)
|
2010-01-21 23:20:48 +08:00
|
|
|
AddEHEdge = true;
|
2010-01-20 06:00:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (FunctionDecl *FD = C->getDirectCallee()) {
|
2009-07-26 05:26:53 +08:00
|
|
|
if (FD->hasAttr<NoReturnAttr>())
|
|
|
|
NoReturn = true;
|
2010-01-20 06:00:14 +08:00
|
|
|
if (FD->hasAttr<NoThrowAttr>())
|
2010-01-21 23:20:48 +08:00
|
|
|
AddEHEdge = false;
|
2010-01-20 06:00:14 +08:00
|
|
|
}
|
2009-07-26 05:26:53 +08:00
|
|
|
|
2011-03-14 01:09:40 +08:00
|
|
|
if (!CanThrow(C->getCallee(), *Context))
|
2010-01-21 23:20:48 +08:00
|
|
|
AddEHEdge = false;
|
|
|
|
|
2010-11-24 11:28:53 +08:00
|
|
|
if (!NoReturn && !AddEHEdge)
|
|
|
|
return VisitStmt(C, asc.withAlwaysAdd(true));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-01-20 06:00:14 +08:00
|
|
|
if (Block) {
|
|
|
|
Succ = Block;
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2010-01-20 06:00:14 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-09-13 17:13:49 +08:00
|
|
|
if (NoReturn)
|
|
|
|
Block = createNoReturnBlock();
|
|
|
|
else
|
|
|
|
Block = createBlock();
|
|
|
|
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, C);
|
2009-07-26 05:26:53 +08:00
|
|
|
|
2010-01-21 23:20:48 +08:00
|
|
|
if (AddEHEdge) {
|
2010-01-20 06:00:14 +08:00
|
|
|
// Add exceptional edges.
|
|
|
|
if (TryTerminatedBlock)
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, TryTerminatedBlock);
|
2010-01-20 06:00:14 +08:00
|
|
|
else
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, &cfg->getExit());
|
2010-01-20 06:00:14 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-26 05:26:53 +08:00
|
|
|
return VisitChildren(C);
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
|
|
|
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
|
|
|
|
AddStmtChoice asc) {
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(ConfluenceBlock, C);
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-18 02:20:32 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-24 11:28:53 +08:00
|
|
|
AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true);
|
2009-07-18 02:20:32 +08:00
|
|
|
Succ = ConfluenceBlock;
|
|
|
|
Block = NULL;
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *LHSBlock = Visit(C->getLHS(), alwaysAdd);
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-18 02:20:32 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 02:20:32 +08:00
|
|
|
Succ = ConfluenceBlock;
|
|
|
|
Block = NULL;
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *RHSBlock = Visit(C->getRHS(), alwaysAdd);
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-18 02:20:32 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 02:20:32 +08:00
|
|
|
Block = createBlock(false);
|
2009-07-24 07:25:26 +08:00
|
|
|
// See if this is a known constant.
|
2010-12-17 12:44:39 +08:00
|
|
|
const TryResult& KnownVal = tryEvaluateBool(C->getCond());
|
|
|
|
addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
|
|
|
|
addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
|
2009-07-18 02:20:32 +08:00
|
|
|
Block->setTerminator(C);
|
2009-09-09 23:08:12 +08:00
|
|
|
return addStmt(C->getCond());
|
2009-07-18 02:20:32 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
|
2010-10-01 08:23:17 +08:00
|
|
|
addLocalScopeAndDtors(C);
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *LastBlock = Block;
|
2009-07-18 06:18:43 +08:00
|
|
|
|
|
|
|
for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
|
|
|
|
I != E; ++I ) {
|
2010-08-18 05:00:06 +08:00
|
|
|
// If we hit a segment of code just containing ';' (NullStmts), we can
|
|
|
|
// get a null block back. In such cases, just use the LastBlock
|
|
|
|
if (CFGBlock *newBlock = addStmt(*I))
|
|
|
|
LastBlock = newBlock;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-28 07:16:26 +08:00
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2010-01-20 06:00:14 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
return LastBlock;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-02-17 18:25:35 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
AddStmtChoice asc) {
|
2011-02-17 18:25:35 +08:00
|
|
|
const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(C);
|
|
|
|
const OpaqueValueExpr *opaqueValue = (BCO ? BCO->getOpaqueValue() : NULL);
|
|
|
|
|
2009-07-18 02:15:54 +08:00
|
|
|
// Create the confluence block that will "merge" the results of the ternary
|
|
|
|
// expression.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(ConfluenceBlock, C);
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-18 02:15:54 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-24 11:28:53 +08:00
|
|
|
AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true);
|
2010-04-12 01:02:10 +08:00
|
|
|
|
2009-07-18 02:15:54 +08:00
|
|
|
// Create a block for the LHS expression if there is an LHS expression. A
|
|
|
|
// GCC extension allows LHS to be NULL, causing the condition to be the
|
|
|
|
// value that is returned instead.
|
|
|
|
// e.g: x ?: y is shorthand for: x ? x : y;
|
|
|
|
Succ = ConfluenceBlock;
|
|
|
|
Block = NULL;
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *LHSBlock = 0;
|
2011-02-17 18:25:35 +08:00
|
|
|
const Expr *trueExpr = C->getTrueExpr();
|
|
|
|
if (trueExpr != opaqueValue) {
|
|
|
|
LHSBlock = Visit(C->getTrueExpr(), alwaysAdd);
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-18 02:15:54 +08:00
|
|
|
return 0;
|
|
|
|
Block = NULL;
|
|
|
|
}
|
2011-02-24 11:09:15 +08:00
|
|
|
else
|
|
|
|
LHSBlock = ConfluenceBlock;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 02:15:54 +08:00
|
|
|
// Create the block for the RHS expression.
|
|
|
|
Succ = ConfluenceBlock;
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *RHSBlock = Visit(C->getFalseExpr(), alwaysAdd);
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-18 02:15:54 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-07-25 05:02:14 +08:00
|
|
|
// If the condition is a logical '&&' or '||', build a more accurate CFG.
|
|
|
|
if (BinaryOperator *Cond =
|
|
|
|
dyn_cast<BinaryOperator>(C->getCond()->IgnoreParens()))
|
|
|
|
if (Cond->isLogicalOp())
|
|
|
|
return VisitLogicalOperator(Cond, C, LHSBlock, RHSBlock).first;
|
|
|
|
|
2009-07-18 02:15:54 +08:00
|
|
|
// Create the block that will contain the condition.
|
|
|
|
Block = createBlock(false);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-24 07:25:26 +08:00
|
|
|
// See if this is a known constant.
|
2010-12-17 12:44:39 +08:00
|
|
|
const TryResult& KnownVal = tryEvaluateBool(C->getCond());
|
2011-02-24 11:09:15 +08:00
|
|
|
addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
|
2009-07-18 02:15:54 +08:00
|
|
|
Block->setTerminator(C);
|
2011-02-17 18:25:35 +08:00
|
|
|
Expr *condExpr = C->getCond();
|
2011-02-19 11:13:26 +08:00
|
|
|
|
2011-02-24 11:09:15 +08:00
|
|
|
if (opaqueValue) {
|
|
|
|
// Run the condition expression if it's not trivially expressed in
|
|
|
|
// terms of the opaque value (or if there is no opaque value).
|
|
|
|
if (condExpr != opaqueValue)
|
|
|
|
addStmt(condExpr);
|
2011-02-19 11:13:26 +08:00
|
|
|
|
2011-02-24 11:09:15 +08:00
|
|
|
// Before that, run the common subexpression if there was one.
|
|
|
|
// At least one of this or the above will be run.
|
|
|
|
return addStmt(BCO->getCommon());
|
|
|
|
}
|
|
|
|
|
|
|
|
return addStmt(condExpr);
|
2009-07-18 02:15:54 +08:00
|
|
|
}
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
|
2011-05-11 02:42:15 +08:00
|
|
|
// Check if the Decl is for an __label__. If so, elide it from the
|
|
|
|
// CFG entirely.
|
|
|
|
if (isa<LabelDecl>(*DS->decl_begin()))
|
|
|
|
return Block;
|
|
|
|
|
2011-05-25 04:41:31 +08:00
|
|
|
// This case also handles static_asserts.
|
2010-11-03 14:19:35 +08:00
|
|
|
if (DS->isSingleDecl())
|
|
|
|
return VisitDeclSubExpr(DS);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *B = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-07-21 02:50:48 +08:00
|
|
|
// Build an individual DeclStmt for each decl.
|
|
|
|
for (DeclStmt::reverse_decl_iterator I = DS->decl_rbegin(),
|
|
|
|
E = DS->decl_rend();
|
|
|
|
I != E; ++I) {
|
2009-07-18 06:18:43 +08:00
|
|
|
// Get the alignment of the new DeclStmt, padding out to >=8 bytes.
|
|
|
|
unsigned A = llvm::AlignOf<DeclStmt>::Alignment < 8
|
|
|
|
? 8 : llvm::AlignOf<DeclStmt>::Alignment;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
// Allocate the DeclStmt using the BumpPtrAllocator. It will get
|
|
|
|
// automatically freed with the CFG.
|
|
|
|
DeclGroupRef DG(*I);
|
|
|
|
Decl *D = *I;
|
2009-09-09 23:08:12 +08:00
|
|
|
void *Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A);
|
2009-07-18 06:18:43 +08:00
|
|
|
DeclStmt *DSNew = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
// Append the fake DeclStmt to block.
|
2010-11-03 14:19:35 +08:00
|
|
|
B = VisitDeclSubExpr(DSNew);
|
2009-07-18 06:18:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
return B;
|
2009-07-18 06:18:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
/// VisitDeclSubExpr - Utility method to add block-level expressions for
|
2010-11-03 14:19:35 +08:00
|
|
|
/// DeclStmts and initializers in them.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
|
2010-11-03 14:19:35 +08:00
|
|
|
assert(DS->isSingleDecl() && "Can handle single declarations only.");
|
2011-05-25 04:41:31 +08:00
|
|
|
Decl *D = DS->getSingleDecl();
|
|
|
|
|
|
|
|
if (isa<StaticAssertDecl>(D)) {
|
|
|
|
// static_asserts aren't added to the CFG because they do not impact
|
|
|
|
// runtime semantics.
|
|
|
|
return Block;
|
|
|
|
}
|
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
if (!VD) {
|
|
|
|
autoCreateBlock();
|
2010-12-16 15:46:53 +08:00
|
|
|
appendStmt(Block, DS);
|
2009-07-18 06:18:43 +08:00
|
|
|
return Block;
|
2010-11-03 14:19:35 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
bool IsReference = false;
|
|
|
|
bool HasTemporaries = false;
|
|
|
|
|
|
|
|
// Destructors of temporaries in initialization expression should be called
|
|
|
|
// after initialization finishes.
|
2009-07-18 06:18:43 +08:00
|
|
|
Expr *Init = VD->getInit();
|
2010-11-03 14:19:35 +08:00
|
|
|
if (Init) {
|
|
|
|
IsReference = VD->getType()->isReferenceType();
|
2010-12-06 16:20:24 +08:00
|
|
|
HasTemporaries = isa<ExprWithCleanups>(Init);
|
2010-11-03 14:19:35 +08:00
|
|
|
|
[analyzer] Always include destructors in the analysis CFG.
While destructors will continue to not be inlined (unless the analyzer
config option 'c++-inlining' is set to 'destructors'), leaving them out
of the CFG is an incomplete model of the behavior of an object, and
can cause false positive warnings (like PR13751, now working).
Destructors for temporaries are still not on by default, since
(a) we haven't actually checked this code to be sure it's fully correct
(in particular, we probably need to be very careful with regard to
lifetime-extension when a temporary is bound to a reference,
C++11 [class.temporary]p5), and
(b) ExprEngine doesn't actually do anything when it sees a temporary
destructor in the CFG -- not even invalidate the object region.
To enable temporary destructors, set the 'cfg-temporary-dtors' analyzer
config option to '1'. The old -cfg-add-implicit-dtors cc1 option, which
controlled all implicit destructors, has been removed.
llvm-svn: 163264
2012-09-06 06:55:23 +08:00
|
|
|
if (BuildOpts.AddTemporaryDtors && HasTemporaries) {
|
2010-11-03 14:19:35 +08:00
|
|
|
// Generate destructors for temporaries in initialization expression.
|
2010-12-06 16:20:24 +08:00
|
|
|
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
|
2010-11-03 14:19:35 +08:00
|
|
|
IsReference);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
autoCreateBlock();
|
2010-12-16 15:46:53 +08:00
|
|
|
appendStmt(Block, DS);
|
2012-03-22 13:57:43 +08:00
|
|
|
|
|
|
|
// Keep track of the last non-null block, as 'Block' can be nulled out
|
|
|
|
// if the initializer expression is something like a 'while' in a
|
|
|
|
// statement-expression.
|
|
|
|
CFGBlock *LastBlock = Block;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
if (Init) {
|
2012-03-22 13:57:43 +08:00
|
|
|
if (HasTemporaries) {
|
2010-11-03 14:19:35 +08:00
|
|
|
// For expression with temporaries go directly to subexpression to omit
|
|
|
|
// generating destructors for the second time.
|
2012-03-22 13:57:43 +08:00
|
|
|
ExprWithCleanups *EC = cast<ExprWithCleanups>(Init);
|
|
|
|
if (CFGBlock *newBlock = Visit(EC->getSubExpr()))
|
|
|
|
LastBlock = newBlock;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (CFGBlock *newBlock = Visit(Init))
|
|
|
|
LastBlock = newBlock;
|
|
|
|
}
|
2009-07-18 06:18:43 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
// If the type of VD is a VLA, then we must process its size expressions.
|
2011-01-19 14:33:43 +08:00
|
|
|
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
|
|
|
|
VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
|
2009-07-18 06:18:43 +08:00
|
|
|
Block = addStmt(VA->getSizeExpr());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-10-01 08:23:17 +08:00
|
|
|
// Remove variable from local scope.
|
|
|
|
if (ScopePos && VD == *ScopePos)
|
|
|
|
++ScopePos;
|
|
|
|
|
2012-03-22 13:57:43 +08:00
|
|
|
return Block ? Block : LastBlock;
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2007-08-22 05:42:03 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
|
2009-07-17 09:31:16 +08:00
|
|
|
// We may see an if statement in the middle of a basic block, or it may be the
|
|
|
|
// first statement we are processing. In either case, we create a new basic
|
|
|
|
// block. First, we create the blocks for the then...else statements, and
|
|
|
|
// then we create the block containing the if statement. If we were in the
|
2009-09-25 02:45:41 +08:00
|
|
|
// middle of a block, we stop processing that block. That block is then the
|
|
|
|
// implicit successor for the "then" and "else" clauses.
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-10-01 08:52:17 +08:00
|
|
|
// Save local scope position because in case of condition variable ScopePos
|
|
|
|
// won't be restored when traversing AST.
|
|
|
|
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
|
|
|
|
|
|
|
|
// Create local scope for possible condition variable.
|
|
|
|
// Store scope position. Add implicit destructor.
|
2011-08-13 07:37:29 +08:00
|
|
|
if (VarDecl *VD = I->getConditionVariable()) {
|
2010-10-01 08:52:17 +08:00
|
|
|
LocalScope::const_iterator BeginScopePos = ScopePos;
|
|
|
|
addLocalScopeForVarDecl(VD);
|
|
|
|
addAutomaticObjDtors(ScopePos, BeginScopePos, I);
|
|
|
|
}
|
|
|
|
|
2011-04-15 13:22:18 +08:00
|
|
|
// The block we were processing is now finished. Make it the successor
|
2009-07-17 09:31:16 +08:00
|
|
|
// block.
|
|
|
|
if (Block) {
|
2007-08-24 05:42:29 +08:00
|
|
|
Succ = Block;
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2007-08-22 06:06:14 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-07-18 02:04:55 +08:00
|
|
|
// Process the false branch.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *ElseBlock = Succ;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *Else = I->getElse()) {
|
2007-08-24 05:42:29 +08:00
|
|
|
SaveAndRestore<CFGBlock*> sv(Succ);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// NULL out Block so that the recursive call to Visit will
|
2009-07-17 09:31:16 +08:00
|
|
|
// create a new basic block.
|
2007-08-24 05:42:29 +08:00
|
|
|
Block = NULL;
|
2010-10-01 08:52:17 +08:00
|
|
|
|
|
|
|
// If branch is not a compound statement create implicit scope
|
|
|
|
// and add destructors.
|
|
|
|
if (!isa<CompoundStmt>(Else))
|
|
|
|
addLocalScopeAndDtors(Else);
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
ElseBlock = addStmt(Else);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-31 02:13:31 +08:00
|
|
|
if (!ElseBlock) // Can occur when the Else body has all NullStmts.
|
|
|
|
ElseBlock = sv.get();
|
2009-05-02 08:13:27 +08:00
|
|
|
else if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-08-22 06:06:14 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-07-18 02:04:55 +08:00
|
|
|
// Process the true branch.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *ThenBlock;
|
2007-08-24 05:42:29 +08:00
|
|
|
{
|
2011-08-13 07:37:29 +08:00
|
|
|
Stmt *Then = I->getThen();
|
2010-01-20 04:46:35 +08:00
|
|
|
assert(Then);
|
2007-08-24 05:42:29 +08:00
|
|
|
SaveAndRestore<CFGBlock*> sv(Succ);
|
2009-07-17 09:31:16 +08:00
|
|
|
Block = NULL;
|
2010-10-01 08:52:17 +08:00
|
|
|
|
|
|
|
// If branch is not a compound statement create implicit scope
|
|
|
|
// and add destructors.
|
|
|
|
if (!isa<CompoundStmt>(Then))
|
|
|
|
addLocalScopeAndDtors(Then);
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
ThenBlock = addStmt(Then);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-04-01 11:52:47 +08:00
|
|
|
if (!ThenBlock) {
|
|
|
|
// We can reach here if the "then" body has all NullStmts.
|
|
|
|
// Create an empty block so we can distinguish between true and false
|
|
|
|
// branches in path-sensitive analyses.
|
|
|
|
ThenBlock = createBlock(false);
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(ThenBlock, sv.get());
|
2009-07-17 09:31:16 +08:00
|
|
|
} else if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
2007-08-22 07:26:17 +08:00
|
|
|
}
|
2007-08-24 05:42:29 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// Specially handle "if (expr1 || ...)" and "if (expr1 && ...)" by
|
|
|
|
// having these handle the actual control-flow jump. Note that
|
|
|
|
// if we introduce a condition variable, e.g. "if (int x = exp1 || exp2)"
|
|
|
|
// we resort to the old control-flow behavior. This special handling
|
|
|
|
// removes infeasible paths from the control-flow graph by having the
|
|
|
|
// control-flow transfer of '&&' or '||' go directly into the then/else
|
|
|
|
// blocks directly.
|
|
|
|
if (!I->getConditionVariable())
|
2012-07-25 05:02:14 +08:00
|
|
|
if (BinaryOperator *Cond =
|
|
|
|
dyn_cast<BinaryOperator>(I->getCond()->IgnoreParens()))
|
2012-07-14 13:04:10 +08:00
|
|
|
if (Cond->isLogicalOp())
|
|
|
|
return VisitLogicalOperator(Cond, I, ThenBlock, ElseBlock).first;
|
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
// Now create a new block containing the if statement.
|
2007-08-24 05:42:29 +08:00
|
|
|
Block = createBlock(false);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Set the terminator of the new block to the If statement.
|
|
|
|
Block->setTerminator(I);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-07-24 07:25:26 +08:00
|
|
|
// See if this is a known constant.
|
2010-12-17 12:44:39 +08:00
|
|
|
const TryResult &KnownVal = tryEvaluateBool(I->getCond());
|
2009-07-24 07:25:26 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Now add the successors.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, KnownVal.isFalse() ? NULL : ThenBlock);
|
|
|
|
addSuccessor(Block, KnownVal.isTrue()? NULL : ElseBlock);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Add the condition as the last statement in the new block. This may create
|
|
|
|
// new blocks as the condition may contain control-flow. Any newly created
|
|
|
|
// blocks will be pointed to be "Block".
|
2009-12-23 12:49:01 +08:00
|
|
|
Block = addStmt(I->getCond());
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2009-12-23 12:49:01 +08:00
|
|
|
// Finally, if the IfStmt contains a condition variable, add both the IfStmt
|
|
|
|
// and the condition variable initialization to the CFG.
|
|
|
|
if (VarDecl *VD = I->getConditionVariable()) {
|
|
|
|
if (Expr *Init = VD->getInit()) {
|
|
|
|
autoCreateBlock();
|
2011-04-05 07:29:12 +08:00
|
|
|
appendStmt(Block, I->getConditionVariableDeclStmt());
|
2009-12-23 12:49:01 +08:00
|
|
|
addStmt(Init);
|
|
|
|
}
|
|
|
|
}
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2009-12-23 12:49:01 +08:00
|
|
|
return Block;
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
|
2009-09-25 02:45:41 +08:00
|
|
|
// If we were in the middle of a block we stop processing that block.
|
2007-08-24 05:42:29 +08:00
|
|
|
//
|
2009-07-17 09:31:16 +08:00
|
|
|
// NOTE: If a "return" appears in the middle of a block, this means that the
|
|
|
|
// code afterwards is DEAD (unreachable). We still keep a basic block
|
|
|
|
// for that code; a simple "mark-and-sweep" from the entry block will be
|
|
|
|
// able to report such dead blocks.
|
2007-08-24 05:42:29 +08:00
|
|
|
|
|
|
|
// Create the new block.
|
|
|
|
Block = createBlock(false);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// The Exit block is the only successor.
|
2010-10-01 08:23:17 +08:00
|
|
|
addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R);
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, &cfg->getExit());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Add the return statement to the block. This may create new blocks if R
|
|
|
|
// contains control-flow (short-circuit operations).
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitStmt(R, AddStmtChoice::AlwaysAdd);
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2007-08-22 07:26:17 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
|
2007-08-24 05:42:29 +08:00
|
|
|
// Get the block of the labeled statement. Add it to our map.
|
2009-07-18 06:18:43 +08:00
|
|
|
addStmt(L->getSubStmt());
|
2011-02-17 15:39:24 +08:00
|
|
|
CFGBlock *LabelBlock = Block;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
if (!LabelBlock) // This can happen when the body is empty, i.e.
|
|
|
|
LabelBlock = createBlock(); // scopes that only contains NullStmts.
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-02-17 15:39:24 +08:00
|
|
|
assert(LabelMap.find(L->getDecl()) == LabelMap.end() &&
|
|
|
|
"label already in map");
|
|
|
|
LabelMap[L->getDecl()] = JumpTarget(LabelBlock, ScopePos);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Labels partition blocks, so this is the end of the basic block we were
|
|
|
|
// processing (L is the block's label). Because this is label (and we have
|
|
|
|
// already processed the substatement) there is no extra control-flow to worry
|
|
|
|
// about.
|
2007-08-30 07:20:49 +08:00
|
|
|
LabelBlock->setLabel(L);
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// We set Block to NULL to allow lazy creation of a new block (if necessary);
|
2007-08-24 05:42:29 +08:00
|
|
|
Block = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// This block is now the implicit successor of other blocks.
|
|
|
|
Succ = LabelBlock;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
return LabelBlock;
|
|
|
|
}
|
2007-08-23 06:35:28 +08:00
|
|
|
|
2012-04-13 04:34:52 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
|
|
|
|
CFGBlock *LastBlock = VisitNoRecurse(E, asc);
|
|
|
|
for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(),
|
|
|
|
et = E->capture_init_end(); it != et; ++it) {
|
|
|
|
if (Expr *Init = *it) {
|
|
|
|
CFGBlock *Tmp = Visit(Init);
|
|
|
|
if (Tmp != 0)
|
|
|
|
LastBlock = Tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return LastBlock;
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
|
2009-07-17 09:31:16 +08:00
|
|
|
// Goto is a control-flow statement. Thus we stop processing the current
|
|
|
|
// block and create a new one.
|
2009-07-18 06:18:43 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
Block = createBlock(false);
|
|
|
|
Block->setTerminator(G);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// If we already know the mapping to the label block add the successor now.
|
2007-08-24 05:42:29 +08:00
|
|
|
LabelMapTy::iterator I = LabelMap.find(G->getLabel());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
if (I == LabelMap.end())
|
|
|
|
// We will need to backpatch this block later.
|
2010-09-25 19:05:21 +08:00
|
|
|
BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
|
|
|
|
else {
|
|
|
|
JumpTarget JT = I->second;
|
2011-01-08 03:37:16 +08:00
|
|
|
addAutomaticObjDtors(ScopePos, JT.scopePosition, G);
|
|
|
|
addSuccessor(Block, JT.block);
|
2010-09-25 19:05:21 +08:00
|
|
|
}
|
2007-08-24 05:42:29 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
return Block;
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
|
|
|
|
CFGBlock *LoopSuccessor = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-10-01 09:38:14 +08:00
|
|
|
// Save local scope position because in case of condition variable ScopePos
|
|
|
|
// won't be restored when traversing AST.
|
|
|
|
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
|
|
|
|
|
|
|
|
// Create local scope for init statement and possible condition variable.
|
|
|
|
// Add destructor for init statement and condition variable.
|
|
|
|
// Store scope position for continue statement.
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *Init = F->getInit())
|
2010-10-01 09:38:14 +08:00
|
|
|
addLocalScopeForStmt(Init);
|
2010-09-25 19:05:21 +08:00
|
|
|
LocalScope::const_iterator LoopBeginScopePos = ScopePos;
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
if (VarDecl *VD = F->getConditionVariable())
|
2010-10-01 09:38:14 +08:00
|
|
|
addLocalScopeForVarDecl(VD);
|
|
|
|
LocalScope::const_iterator ContinueScopePos = ScopePos;
|
|
|
|
|
|
|
|
addAutomaticObjDtors(ScopePos, save_scope_pos.get(), F);
|
|
|
|
|
2009-07-21 09:12:51 +08:00
|
|
|
// "for" is a control-flow statement. Thus we stop processing the current
|
|
|
|
// block.
|
2007-08-24 05:42:29 +08:00
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2007-08-24 05:42:29 +08:00
|
|
|
LoopSuccessor = Block;
|
2009-07-18 06:18:43 +08:00
|
|
|
} else
|
|
|
|
LoopSuccessor = Succ;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-05-22 04:30:15 +08:00
|
|
|
// Save the current value for the break targets.
|
|
|
|
// All breaks should go to the code following the loop.
|
2010-09-25 19:05:21 +08:00
|
|
|
SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
|
2010-10-01 09:38:14 +08:00
|
|
|
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
|
2010-05-22 04:30:15 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
CFGBlock *BodyBlock = 0, *TransitionBlock = 0;
|
2009-07-24 07:25:26 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Now create the loop body.
|
|
|
|
{
|
2010-01-20 04:46:35 +08:00
|
|
|
assert(F->getBody());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// Save the current values for Block, Succ, continue and break targets.
|
|
|
|
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
|
|
|
|
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// Create an empty block to represent the transition block for looping back
|
|
|
|
// to the head of the loop. If we have increment code, it will
|
|
|
|
// go in this block as well.
|
|
|
|
Block = Succ = TransitionBlock = createBlock(false);
|
|
|
|
TransitionBlock->setLoopTarget(F);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *I = F->getInc()) {
|
2009-07-17 09:31:16 +08:00
|
|
|
// Generate increment code in its own basic block. This is the target of
|
|
|
|
// continue statements.
|
2009-07-18 06:18:43 +08:00
|
|
|
Succ = addStmt(I);
|
2008-09-05 05:48:47 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-04-28 08:51:56 +08:00
|
|
|
// Finish up the increment (or empty) block if it hasn't been already.
|
|
|
|
if (Block) {
|
|
|
|
assert(Block == Succ);
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2009-04-28 08:51:56 +08:00
|
|
|
Block = 0;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// The starting block for the loop increment is the block that should
|
|
|
|
// represent the 'loop target' for looping back to the start of the loop.
|
|
|
|
ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
|
|
|
|
ContinueJumpTarget.block->setLoopTarget(F);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// Loop body should end with destructor of Condition variable (if any).
|
|
|
|
addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F);
|
2009-04-28 08:51:56 +08:00
|
|
|
|
2010-10-01 09:38:14 +08:00
|
|
|
// If body is not a compound statement create implicit scope
|
|
|
|
// and add destructors.
|
|
|
|
if (!isa<CompoundStmt>(F->getBody()))
|
|
|
|
addLocalScopeAndDtors(F->getBody());
|
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
// Now populate the body block, and in the process create new blocks as we
|
|
|
|
// walk the body of the loop.
|
2012-07-14 13:04:10 +08:00
|
|
|
BodyBlock = addStmt(F->getBody());
|
2007-08-31 02:39:40 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
if (!BodyBlock) {
|
|
|
|
// In the case of "for (...;...;...);" we can have a null BodyBlock.
|
|
|
|
// Use the continue jump target as the proxy for the body.
|
|
|
|
BodyBlock = ContinueJumpTarget.block;
|
|
|
|
}
|
2010-09-06 15:32:31 +08:00
|
|
|
else if (badCFG)
|
2009-07-24 12:47:11 +08:00
|
|
|
return 0;
|
2012-07-14 13:04:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Because of short-circuit evaluation, the condition of the loop can span
|
|
|
|
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
|
|
|
|
// evaluate the condition.
|
|
|
|
CFGBlock *EntryConditionBlock = 0, *ExitConditionBlock = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
Expr *C = F->getCond();
|
|
|
|
|
|
|
|
// Specially handle logical operators, which have a slightly
|
|
|
|
// more optimal CFG representation.
|
2012-07-25 05:02:14 +08:00
|
|
|
if (BinaryOperator *Cond =
|
|
|
|
dyn_cast_or_null<BinaryOperator>(C ? C->IgnoreParens() : 0))
|
2012-07-14 13:04:10 +08:00
|
|
|
if (Cond->isLogicalOp()) {
|
|
|
|
llvm::tie(EntryConditionBlock, ExitConditionBlock) =
|
|
|
|
VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor);
|
|
|
|
break;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// The default case when not handling logical operators.
|
|
|
|
EntryConditionBlock = ExitConditionBlock = createBlock(false);
|
|
|
|
ExitConditionBlock->setTerminator(F);
|
|
|
|
|
|
|
|
// See if this is a known constant.
|
|
|
|
TryResult KnownVal(true);
|
|
|
|
|
|
|
|
if (C) {
|
|
|
|
// Now add the actual condition to the condition block.
|
|
|
|
// Because the condition itself may contain control-flow, new blocks may
|
|
|
|
// be created. Thus we update "Succ" after adding the condition.
|
|
|
|
Block = ExitConditionBlock;
|
|
|
|
EntryConditionBlock = addStmt(C);
|
|
|
|
|
|
|
|
// If this block contains a condition variable, add both the condition
|
|
|
|
// variable and initializer to the CFG.
|
|
|
|
if (VarDecl *VD = F->getConditionVariable()) {
|
|
|
|
if (Expr *Init = VD->getInit()) {
|
|
|
|
autoCreateBlock();
|
|
|
|
appendStmt(Block, F->getConditionVariableDeclStmt());
|
|
|
|
EntryConditionBlock = addStmt(Init);
|
|
|
|
assert(Block == EntryConditionBlock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Block && badCFG)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
KnownVal = tryEvaluateBool(C);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the loop body entry as a successor to the condition.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
|
2012-07-14 13:04:10 +08:00
|
|
|
// Link up the condition block with the code that follows the loop. (the
|
|
|
|
// false branch).
|
|
|
|
addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
} while (false);
|
|
|
|
|
|
|
|
// Link up the loop-back block to the entry condition block.
|
|
|
|
addSuccessor(TransitionBlock, EntryConditionBlock);
|
|
|
|
|
|
|
|
// The condition block is the implicit successor for any code above the loop.
|
|
|
|
Succ = EntryConditionBlock;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// If the loop contains initialization, create a new block for those
|
2009-07-17 09:31:16 +08:00
|
|
|
// statements. This block can also contain statements that precede the loop.
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *I = F->getInit()) {
|
2007-08-24 05:42:29 +08:00
|
|
|
Block = createBlock();
|
2007-08-28 03:46:09 +08:00
|
|
|
return addStmt(I);
|
2007-08-23 05:05:42 +08:00
|
|
|
}
|
2010-11-23 03:32:14 +08:00
|
|
|
|
|
|
|
// There is no loop initialization. We are thus basically a while loop.
|
|
|
|
// NULL out Block to force lazy block construction.
|
|
|
|
Block = NULL;
|
|
|
|
Succ = EntryConditionBlock;
|
|
|
|
return EntryConditionBlock;
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
|
|
|
|
2010-04-12 01:02:10 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, M)) {
|
2010-04-12 01:02:10 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, M);
|
2010-04-12 01:02:10 +08:00
|
|
|
}
|
2010-12-16 15:46:53 +08:00
|
|
|
return Visit(M->getBase());
|
2010-04-12 01:02:10 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
|
2008-11-12 01:10:00 +08:00
|
|
|
// Objective-C fast enumeration 'for' statements:
|
|
|
|
// http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
|
|
|
|
//
|
|
|
|
// for ( Type newVariable in collection_expression ) { statements }
|
|
|
|
//
|
|
|
|
// becomes:
|
|
|
|
//
|
|
|
|
// prologue:
|
|
|
|
// 1. collection_expression
|
|
|
|
// T. jump to loop_entry
|
|
|
|
// loop_entry:
|
2008-11-14 09:57:41 +08:00
|
|
|
// 1. side-effects of element expression
|
2008-11-12 01:10:00 +08:00
|
|
|
// 1. ObjCForCollectionStmt [performs binding to newVariable]
|
|
|
|
// T. ObjCForCollectionStmt TB, FB [jumps to TB if newVariable != nil]
|
|
|
|
// TB:
|
|
|
|
// statements
|
|
|
|
// T. jump to loop_entry
|
|
|
|
// FB:
|
|
|
|
// what comes after
|
|
|
|
//
|
|
|
|
// and
|
|
|
|
//
|
|
|
|
// Type existingItem;
|
|
|
|
// for ( existingItem in expression ) { statements }
|
|
|
|
//
|
|
|
|
// becomes:
|
|
|
|
//
|
2009-07-17 09:31:16 +08:00
|
|
|
// the same with newVariable replaced with existingItem; the binding works
|
|
|
|
// the same except that for one ObjCForCollectionStmt::getElement() returns
|
|
|
|
// a DeclStmt and the other returns a DeclRefExpr.
|
2008-11-12 01:10:00 +08:00
|
|
|
//
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *LoopSuccessor = 0;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-12 01:10:00 +08:00
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2008-11-12 01:10:00 +08:00
|
|
|
LoopSuccessor = Block;
|
|
|
|
Block = 0;
|
2009-07-18 06:18:43 +08:00
|
|
|
} else
|
|
|
|
LoopSuccessor = Succ;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-14 09:57:41 +08:00
|
|
|
// Build the condition blocks.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *ExitConditionBlock = createBlock(false);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-14 09:57:41 +08:00
|
|
|
// Set the terminator for the "exit" condition block.
|
2009-07-17 09:31:16 +08:00
|
|
|
ExitConditionBlock->setTerminator(S);
|
|
|
|
|
|
|
|
// The last statement in the block should be the ObjCForCollectionStmt, which
|
|
|
|
// performs the actual binding to 'element' and determines if there are any
|
|
|
|
// more items in the collection.
|
2010-12-16 15:46:53 +08:00
|
|
|
appendStmt(ExitConditionBlock, S);
|
2008-11-14 09:57:41 +08:00
|
|
|
Block = ExitConditionBlock;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-14 09:57:41 +08:00
|
|
|
// Walk the 'element' expression to see if there are any side-effects. We
|
2011-04-15 13:22:18 +08:00
|
|
|
// generate new blocks as necessary. We DON'T add the statement by default to
|
2009-07-17 09:31:16 +08:00
|
|
|
// the CFG unless it contains control-flow.
|
2011-08-18 05:04:19 +08:00
|
|
|
CFGBlock *EntryConditionBlock = Visit(S->getElement(),
|
|
|
|
AddStmtChoice::NotAlwaysAdd);
|
2009-07-17 09:31:16 +08:00
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
|
|
|
Block = 0;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// The condition block is the implicit successor for the loop body as well as
|
|
|
|
// any code above the loop.
|
2008-11-14 09:57:41 +08:00
|
|
|
Succ = EntryConditionBlock;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-14 09:57:41 +08:00
|
|
|
// Now create the true branch.
|
2009-07-17 09:31:16 +08:00
|
|
|
{
|
2008-11-14 09:57:41 +08:00
|
|
|
// Save the current values for Succ, continue and break targets.
|
2010-09-25 19:05:21 +08:00
|
|
|
SaveAndRestore<CFGBlock*> save_Succ(Succ);
|
|
|
|
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
|
|
|
|
save_break(BreakJumpTarget);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-25 19:05:21 +08:00
|
|
|
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
|
|
|
|
ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *BodyBlock = addStmt(S->getBody());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-14 09:57:41 +08:00
|
|
|
if (!BodyBlock)
|
|
|
|
BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;"
|
2009-05-02 08:13:27 +08:00
|
|
|
else if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-14 09:57:41 +08:00
|
|
|
// This new body block is a successor to our "exit" condition block.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(ExitConditionBlock, BodyBlock);
|
2008-11-14 09:57:41 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-14 09:57:41 +08:00
|
|
|
// Link up the condition block with the code that follows the loop.
|
|
|
|
// (the false branch).
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(ExitConditionBlock, LoopSuccessor);
|
2008-11-14 09:57:41 +08:00
|
|
|
|
2008-11-12 01:10:00 +08:00
|
|
|
// Now create a prologue block to contain the collection expression.
|
2008-11-14 09:57:41 +08:00
|
|
|
Block = createBlock();
|
2008-11-12 01:10:00 +08:00
|
|
|
return addStmt(S->getCollection());
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
|
|
|
|
2012-03-07 07:40:47 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
|
|
|
|
// Inline the body.
|
|
|
|
return addStmt(S->getSubStmt());
|
|
|
|
// TODO: consider adding cleanups for the end of @autoreleasepool scope.
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
|
2009-05-02 09:49:13 +08:00
|
|
|
// FIXME: Add locking 'primitives' to CFG for @synchronized.
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-05-02 09:49:13 +08:00
|
|
|
// Inline the body.
|
2009-07-18 06:18:43 +08:00
|
|
|
CFGBlock *SyncBlock = addStmt(S->getSynchBody());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-05-06 07:11:51 +08:00
|
|
|
// The sync body starts its own basic block. This makes it a little easier
|
|
|
|
// for diagnostic clients.
|
|
|
|
if (SyncBlock) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-06 07:11:51 +08:00
|
|
|
return 0;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-05-06 07:11:51 +08:00
|
|
|
Block = 0;
|
2010-05-14 00:38:08 +08:00
|
|
|
Succ = SyncBlock;
|
2009-05-06 07:11:51 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-10 11:05:33 +08:00
|
|
|
// Add the @synchronized to the CFG.
|
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, S);
|
2010-09-10 11:05:33 +08:00
|
|
|
|
2009-05-02 09:49:13 +08:00
|
|
|
// Inline the sync expression.
|
2009-07-18 06:18:43 +08:00
|
|
|
return addStmt(S->getSynchExpr());
|
2009-05-02 09:49:13 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
|
2009-07-18 06:18:43 +08:00
|
|
|
// FIXME
|
2009-04-07 12:26:02 +08:00
|
|
|
return NYS();
|
2009-03-31 06:29:21 +08:00
|
|
|
}
|
2008-11-12 01:10:00 +08:00
|
|
|
|
2011-11-06 17:01:30 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
|
|
|
|
autoCreateBlock();
|
|
|
|
|
|
|
|
// Add the PseudoObject as the last thing.
|
|
|
|
appendStmt(Block, E);
|
|
|
|
|
|
|
|
CFGBlock *lastBlock = Block;
|
|
|
|
|
|
|
|
// Before that, evaluate all of the semantics in order. In
|
|
|
|
// CFG-land, that means appending them in reverse order.
|
|
|
|
for (unsigned i = E->getNumSemanticExprs(); i != 0; ) {
|
|
|
|
Expr *Semantic = E->getSemanticExpr(--i);
|
|
|
|
|
|
|
|
// If the semantic is an opaque value, we're being asked to bind
|
|
|
|
// it to its source expression.
|
|
|
|
if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
|
|
|
|
Semantic = OVE->getSourceExpr();
|
|
|
|
|
|
|
|
if (CFGBlock *B = Visit(Semantic))
|
|
|
|
lastBlock = B;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lastBlock;
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
|
|
|
|
CFGBlock *LoopSuccessor = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-10-01 09:14:17 +08:00
|
|
|
// Save local scope position because in case of condition variable ScopePos
|
|
|
|
// won't be restored when traversing AST.
|
|
|
|
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
|
|
|
|
|
|
|
|
// Create local scope for possible condition variable.
|
|
|
|
// Store scope position for continue statement.
|
2010-09-25 19:05:21 +08:00
|
|
|
LocalScope::const_iterator LoopBeginScopePos = ScopePos;
|
2011-08-13 07:37:29 +08:00
|
|
|
if (VarDecl *VD = W->getConditionVariable()) {
|
2010-10-01 09:14:17 +08:00
|
|
|
addLocalScopeForVarDecl(VD);
|
|
|
|
addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
|
|
|
|
}
|
2010-09-25 19:05:21 +08:00
|
|
|
|
2009-07-21 09:12:51 +08:00
|
|
|
// "while" is a control-flow statement. Thus we stop processing the current
|
|
|
|
// block.
|
2007-08-24 05:42:29 +08:00
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2007-08-24 05:42:29 +08:00
|
|
|
LoopSuccessor = Block;
|
2011-02-22 06:11:26 +08:00
|
|
|
Block = 0;
|
2012-07-14 13:04:10 +08:00
|
|
|
} else {
|
2009-07-18 06:18:43 +08:00
|
|
|
LoopSuccessor = Succ;
|
2007-08-28 03:46:09 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
CFGBlock *BodyBlock = 0, *TransitionBlock = 0;
|
2009-07-24 07:25:26 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Process the loop body.
|
|
|
|
{
|
2009-04-28 11:09:44 +08:00
|
|
|
assert(W->getBody());
|
2007-08-24 05:42:29 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// Save the current values for Block, Succ, continue and break targets.
|
2010-09-25 19:05:21 +08:00
|
|
|
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
|
|
|
|
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
|
2012-07-14 13:04:10 +08:00
|
|
|
save_break(BreakJumpTarget);
|
2009-04-28 11:09:44 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
// Create an empty block to represent the transition block for looping back
|
|
|
|
// to the head of the loop.
|
2012-07-14 13:04:10 +08:00
|
|
|
Succ = TransitionBlock = createBlock(false);
|
|
|
|
TransitionBlock->setLoopTarget(W);
|
2010-09-25 19:05:21 +08:00
|
|
|
ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// All breaks should go to the code following the loop.
|
2010-10-01 09:14:17 +08:00
|
|
|
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-10-01 09:14:17 +08:00
|
|
|
// Loop body should end with destructor of Condition variable (if any).
|
|
|
|
addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W);
|
|
|
|
|
|
|
|
// If body is not a compound statement create implicit scope
|
|
|
|
// and add destructors.
|
|
|
|
if (!isa<CompoundStmt>(W->getBody()))
|
|
|
|
addLocalScopeAndDtors(W->getBody());
|
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Create the body. The returned block is the entry to the loop body.
|
2012-07-14 13:04:10 +08:00
|
|
|
BodyBlock = addStmt(W->getBody());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-31 02:39:40 +08:00
|
|
|
if (!BodyBlock)
|
2011-01-08 03:37:16 +08:00
|
|
|
BodyBlock = ContinueJumpTarget.block; // can happen for "while(...) ;"
|
2012-07-14 13:04:10 +08:00
|
|
|
else if (Block && badCFG)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Because of short-circuit evaluation, the condition of the loop can span
|
|
|
|
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
|
|
|
|
// evaluate the condition.
|
|
|
|
CFGBlock *EntryConditionBlock = 0, *ExitConditionBlock = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
Expr *C = W->getCond();
|
|
|
|
|
|
|
|
// Specially handle logical operators, which have a slightly
|
|
|
|
// more optimal CFG representation.
|
2012-07-25 05:02:14 +08:00
|
|
|
if (BinaryOperator *Cond = dyn_cast<BinaryOperator>(C->IgnoreParens()))
|
2012-07-14 13:04:10 +08:00
|
|
|
if (Cond->isLogicalOp()) {
|
|
|
|
llvm::tie(EntryConditionBlock, ExitConditionBlock) =
|
|
|
|
VisitLogicalOperator(Cond, W, BodyBlock,
|
|
|
|
LoopSuccessor);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The default case when not handling logical operators.
|
2012-10-13 06:56:26 +08:00
|
|
|
ExitConditionBlock = createBlock(false);
|
2012-07-14 13:04:10 +08:00
|
|
|
ExitConditionBlock->setTerminator(W);
|
|
|
|
|
|
|
|
// Now add the actual condition to the condition block.
|
|
|
|
// Because the condition itself may contain control-flow, new blocks may
|
|
|
|
// be created. Thus we update "Succ" after adding the condition.
|
|
|
|
Block = ExitConditionBlock;
|
|
|
|
Block = EntryConditionBlock = addStmt(C);
|
|
|
|
|
|
|
|
// If this block contains a condition variable, add both the condition
|
|
|
|
// variable and initializer to the CFG.
|
|
|
|
if (VarDecl *VD = W->getConditionVariable()) {
|
|
|
|
if (Expr *Init = VD->getInit()) {
|
|
|
|
autoCreateBlock();
|
|
|
|
appendStmt(Block, W->getConditionVariableDeclStmt());
|
|
|
|
EntryConditionBlock = addStmt(Init);
|
|
|
|
assert(Block == EntryConditionBlock);
|
|
|
|
}
|
2009-05-02 08:13:27 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
if (Block && badCFG)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// See if this is a known constant.
|
|
|
|
const TryResult& KnownVal = tryEvaluateBool(C);
|
|
|
|
|
2009-07-24 12:47:11 +08:00
|
|
|
// Add the loop body entry as a successor to the condition.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
|
2012-07-14 13:04:10 +08:00
|
|
|
// Link up the condition block with the code that follows the loop. (the
|
|
|
|
// false branch).
|
|
|
|
addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
|
|
|
|
|
|
|
|
} while(false);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-07-14 13:04:10 +08:00
|
|
|
// Link up the loop-back block to the entry condition block.
|
|
|
|
addSuccessor(TransitionBlock, EntryConditionBlock);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// There can be no more statements in the condition block since we loop back
|
|
|
|
// to this block. NULL out Block to force lazy creation of another block.
|
2007-08-24 05:42:29 +08:00
|
|
|
Block = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-12-24 09:34:10 +08:00
|
|
|
// Return the condition block, which is the dominating block for the loop.
|
2008-02-27 15:20:00 +08:00
|
|
|
Succ = EntryConditionBlock;
|
2007-08-28 03:46:09 +08:00
|
|
|
return EntryConditionBlock;
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
|
2009-07-18 06:18:43 +08:00
|
|
|
// FIXME: For now we pretend that @catch and the code it contains does not
|
|
|
|
// exit.
|
|
|
|
return Block;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
|
2008-12-10 04:20:09 +08:00
|
|
|
// FIXME: This isn't complete. We basically treat @throw like a return
|
|
|
|
// statement.
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-09-25 02:45:41 +08:00
|
|
|
// If we were in the middle of a block we stop processing that block.
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-18 06:18:43 +08:00
|
|
|
return 0;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-12-10 04:20:09 +08:00
|
|
|
// Create the new block.
|
|
|
|
Block = createBlock(false);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-12-10 04:20:09 +08:00
|
|
|
// The Exit block is the only successor.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, &cfg->getExit());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Add the statement to the block. This may create new blocks if S contains
|
|
|
|
// control-flow (short-circuit operations).
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitStmt(S, AddStmtChoice::AlwaysAdd);
|
2008-12-10 04:20:09 +08:00
|
|
|
}
|
2007-08-24 01:29:58 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
|
2009-09-25 02:45:41 +08:00
|
|
|
// If we were in the middle of a block we stop processing that block.
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-23 06:56:04 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Create the new block.
|
|
|
|
Block = createBlock(false);
|
|
|
|
|
2010-01-19 10:20:09 +08:00
|
|
|
if (TryTerminatedBlock)
|
|
|
|
// The current try statement is the only successor.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, TryTerminatedBlock);
|
2010-08-03 07:46:59 +08:00
|
|
|
else
|
2010-01-19 10:20:09 +08:00
|
|
|
// otherwise the Exit block is the only successor.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, &cfg->getExit());
|
2009-07-23 06:56:04 +08:00
|
|
|
|
|
|
|
// Add the statement to the block. This may create new blocks if S contains
|
|
|
|
// control-flow (short-circuit operations).
|
Add (initial?) static analyzer support for handling C++ references.
This change was a lot bigger than I originally anticipated; among
other things it requires us storing more information in the CFG to
record what block-level expressions need to be evaluated as lvalues.
The big change is that CFGBlocks no longer contain Stmt*'s by
CFGElements. Currently CFGElements just wrap Stmt*, but they also
store a bit indicating whether the block-level expression should be
evalauted as an lvalue. DeclStmts involving the initialization of a
reference require us treating the initialization expression as an
lvalue, even though that information isn't recorded in the AST.
Conceptually this change isn't that complicated, but it required
bubbling up the data through the CFGBuilder, to GRCoreEngine, and
eventually to GRExprEngine.
The addition of CFGElement is also useful for when we want to handle
more control-flow constructs or other data we want to keep in the CFG
that isn't represented well with just a block of statements.
In GRExprEngine, this patch introduces logic for evaluating the
lvalues of references, which currently retrieves the internal "pointer
value" that the reference represents. EvalLoad does a two stage load
to catch null dereferences involving an invalid reference (although
this could possibly be caught earlier during the initialization of a
reference).
Symbols are currently symbolicated using the reference type, instead
of a pointer type, and special handling is required creating
ElementRegions that layer on SymbolicRegions (see the changes to
RegionStoreManager).
Along the way, the DeadStoresChecker also silences warnings involving
dead stores to references. This was the original change I introduced
(which I wrote test cases for) that I realized caused GRExprEngine to
crash.
llvm-svn: 91501
2009-12-16 11:18:58 +08:00
|
|
|
return VisitStmt(T, AddStmtChoice::AlwaysAdd);
|
2009-07-23 06:56:04 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
|
|
|
|
CFGBlock *LoopSuccessor = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-07-21 09:27:50 +08:00
|
|
|
// "do...while" is a control-flow statement. Thus we stop processing the
|
|
|
|
// current block.
|
2007-08-24 05:42:29 +08:00
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2007-08-24 05:42:29 +08:00
|
|
|
LoopSuccessor = Block;
|
2009-07-18 06:18:43 +08:00
|
|
|
} else
|
|
|
|
LoopSuccessor = Succ;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Because of short-circuit evaluation, the condition of the loop can span
|
|
|
|
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
|
|
|
|
// evaluate the condition.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *ExitConditionBlock = createBlock(false);
|
|
|
|
CFGBlock *EntryConditionBlock = ExitConditionBlock;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-28 03:46:09 +08:00
|
|
|
// Set the terminator for the "exit" condition block.
|
2009-07-17 09:31:16 +08:00
|
|
|
ExitConditionBlock->setTerminator(D);
|
|
|
|
|
|
|
|
// Now add the actual condition to the condition block. Because the condition
|
|
|
|
// itself may contain control-flow, new blocks may be created.
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *C = D->getCond()) {
|
2007-08-28 03:46:09 +08:00
|
|
|
Block = ExitConditionBlock;
|
|
|
|
EntryConditionBlock = addStmt(C);
|
2009-05-02 08:13:27 +08:00
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-08-28 03:46:09 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-02-27 15:20:00 +08:00
|
|
|
// The condition block is the implicit successor for the loop body.
|
2007-08-28 03:46:09 +08:00
|
|
|
Succ = EntryConditionBlock;
|
|
|
|
|
2009-07-24 07:25:26 +08:00
|
|
|
// See if this is a known constant.
|
2010-12-17 12:44:39 +08:00
|
|
|
const TryResult &KnownVal = tryEvaluateBool(D->getCond());
|
2009-07-24 07:25:26 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Process the loop body.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *BodyBlock = NULL;
|
2007-08-24 05:42:29 +08:00
|
|
|
{
|
2010-01-20 04:46:35 +08:00
|
|
|
assert(D->getBody());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Save the current values for Block, Succ, and continue and break targets
|
2010-09-25 19:05:21 +08:00
|
|
|
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
|
|
|
|
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
|
|
|
|
save_break(BreakJumpTarget);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// All continues within this loop should go to the condition block
|
2010-09-25 19:05:21 +08:00
|
|
|
ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// All breaks should go to the code following the loop.
|
2010-09-25 19:05:21 +08:00
|
|
|
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// NULL out Block to force lazy instantiation of blocks for the body.
|
2007-08-24 02:43:24 +08:00
|
|
|
Block = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-10-01 09:14:17 +08:00
|
|
|
// If body is not a compound statement create implicit scope
|
|
|
|
// and add destructors.
|
|
|
|
if (!isa<CompoundStmt>(D->getBody()))
|
|
|
|
addLocalScopeAndDtors(D->getBody());
|
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Create the body. The returned block is the entry to the loop body.
|
2009-07-18 06:18:43 +08:00
|
|
|
BodyBlock = addStmt(D->getBody());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-31 02:39:40 +08:00
|
|
|
if (!BodyBlock)
|
2008-02-27 08:28:17 +08:00
|
|
|
BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)"
|
2009-05-02 08:13:27 +08:00
|
|
|
else if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-08-18 04:59:56 +08:00
|
|
|
if (!KnownVal.isFalse()) {
|
|
|
|
// Add an intermediate block between the BodyBlock and the
|
|
|
|
// ExitConditionBlock to represent the "loop back" transition. Create an
|
|
|
|
// empty block to represent the transition block for looping back to the
|
|
|
|
// head of the loop.
|
|
|
|
// FIXME: Can we do this more efficiently without adding another block?
|
|
|
|
Block = NULL;
|
|
|
|
Succ = BodyBlock;
|
|
|
|
CFGBlock *LoopBackBlock = createBlock();
|
|
|
|
LoopBackBlock->setLoopTarget(D);
|
|
|
|
|
|
|
|
// Add the loop body entry as a successor to the condition.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(ExitConditionBlock, LoopBackBlock);
|
2010-08-18 04:59:56 +08:00
|
|
|
}
|
|
|
|
else
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(ExitConditionBlock, NULL);
|
2007-08-24 02:43:24 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-07-24 12:47:11 +08:00
|
|
|
// Link up the condition block with the code that follows the loop.
|
|
|
|
// (the false branch).
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// There can be no more statements in the body block(s) since we loop back to
|
|
|
|
// the body. NULL out Block to force lazy creation of another block.
|
2007-08-24 05:42:29 +08:00
|
|
|
Block = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Return the loop body, which is the dominating block for the loop.
|
2008-02-27 15:20:00 +08:00
|
|
|
Succ = BodyBlock;
|
2007-08-24 05:42:29 +08:00
|
|
|
return BodyBlock;
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) {
|
2007-08-24 05:42:29 +08:00
|
|
|
// "continue" is a control-flow statement. Thus we stop processing the
|
|
|
|
// current block.
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
|
|
|
return 0;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Now create a new block that ends with the continue statement.
|
|
|
|
Block = createBlock(false);
|
|
|
|
Block->setTerminator(C);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// If there is no target for the continue, then we are looking at an
|
2009-04-08 02:53:24 +08:00
|
|
|
// incomplete AST. This means the CFG cannot be constructed.
|
2011-01-08 03:37:16 +08:00
|
|
|
if (ContinueJumpTarget.block) {
|
|
|
|
addAutomaticObjDtors(ScopePos, ContinueJumpTarget.scopePosition, C);
|
|
|
|
addSuccessor(Block, ContinueJumpTarget.block);
|
2010-09-25 19:05:21 +08:00
|
|
|
} else
|
2009-04-08 02:53:24 +08:00
|
|
|
badCFG = true;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
return Block;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-03-12 03:24:49 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
|
|
|
|
AddStmtChoice asc) {
|
2009-07-18 08:47:21 +08:00
|
|
|
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, E)) {
|
2009-07-18 08:47:21 +08:00
|
|
|
autoCreateBlock();
|
2010-12-16 15:46:53 +08:00
|
|
|
appendStmt(Block, E);
|
2009-07-18 08:47:21 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
// VLA types have expressions that must be evaluated.
|
2011-04-14 09:50:50 +08:00
|
|
|
CFGBlock *lastBlock = Block;
|
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
if (E->isArgumentType()) {
|
2011-01-19 14:33:43 +08:00
|
|
|
for (const VariableArrayType *VA =FindVA(E->getArgumentType().getTypePtr());
|
2009-07-18 06:18:43 +08:00
|
|
|
VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
|
2011-04-14 09:50:50 +08:00
|
|
|
lastBlock = addStmt(VA->getSizeExpr());
|
2011-08-06 08:30:00 +08:00
|
|
|
}
|
2011-04-14 09:50:50 +08:00
|
|
|
return lastBlock;
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 06:18:43 +08:00
|
|
|
/// VisitStmtExpr - Utility method to handle (nested) statement
|
|
|
|
/// expressions (a GCC extension).
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, SE)) {
|
2009-07-18 08:47:21 +08:00
|
|
|
autoCreateBlock();
|
2010-12-16 15:46:53 +08:00
|
|
|
appendStmt(Block, SE);
|
2009-07-18 08:47:21 +08:00
|
|
|
}
|
2009-07-18 06:18:43 +08:00
|
|
|
return VisitCompoundStmt(SE->getSubStmt());
|
|
|
|
}
|
2007-08-24 05:42:29 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
|
2009-07-17 09:31:16 +08:00
|
|
|
// "switch" is a control-flow statement. Thus we stop processing the current
|
|
|
|
// block.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *SwitchSuccessor = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-10-01 09:24:41 +08:00
|
|
|
// Save local scope position because in case of condition variable ScopePos
|
|
|
|
// won't be restored when traversing AST.
|
|
|
|
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
|
|
|
|
|
|
|
|
// Create local scope for possible condition variable.
|
|
|
|
// Store scope position. Add implicit destructor.
|
2011-08-13 07:37:29 +08:00
|
|
|
if (VarDecl *VD = Terminator->getConditionVariable()) {
|
2010-10-01 09:24:41 +08:00
|
|
|
LocalScope::const_iterator SwitchBeginScopePos = ScopePos;
|
|
|
|
addLocalScopeForVarDecl(VD);
|
|
|
|
addAutomaticObjDtors(ScopePos, SwitchBeginScopePos, Terminator);
|
|
|
|
}
|
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2007-08-24 05:42:29 +08:00
|
|
|
SwitchSuccessor = Block;
|
2009-07-17 09:31:16 +08:00
|
|
|
} else SwitchSuccessor = Succ;
|
2007-08-24 05:42:29 +08:00
|
|
|
|
|
|
|
// Save the current "switch" context.
|
|
|
|
SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
|
2008-02-14 06:05:39 +08:00
|
|
|
save_default(DefaultCaseBlock);
|
2010-09-25 19:05:21 +08:00
|
|
|
SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
|
2008-02-14 06:05:39 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
// Set the "default" case to be the block after the switch statement. If the
|
|
|
|
// switch statement contains a "default:", this value will be overwritten with
|
|
|
|
// the block for that code.
|
2008-02-14 06:05:39 +08:00
|
|
|
DefaultCaseBlock = SwitchSuccessor;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Create a new block that will contain the switch statement.
|
|
|
|
SwitchTerminatedBlock = createBlock(false);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Now process the switch body. The code after the switch is the implicit
|
|
|
|
// successor.
|
|
|
|
Succ = SwitchSuccessor;
|
2010-09-25 19:05:21 +08:00
|
|
|
BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// When visiting the body, the case statements should automatically get linked
|
|
|
|
// up to the switch. We also don't keep a pointer to the body, since all
|
|
|
|
// control-flow from the switch goes to case/default statements.
|
2010-01-20 04:46:35 +08:00
|
|
|
assert(Terminator->getBody() && "switch must contain a non-NULL body");
|
2007-08-28 03:46:09 +08:00
|
|
|
Block = NULL;
|
2010-10-01 09:24:41 +08:00
|
|
|
|
2011-03-02 07:12:55 +08:00
|
|
|
// For pruning unreachable case statements, save the current state
|
|
|
|
// for tracking the condition value.
|
|
|
|
SaveAndRestore<bool> save_switchExclusivelyCovered(switchExclusivelyCovered,
|
|
|
|
false);
|
2011-03-04 09:03:41 +08:00
|
|
|
|
2011-03-02 07:12:55 +08:00
|
|
|
// Determine if the switch condition can be explicitly evaluated.
|
|
|
|
assert(Terminator->getCond() && "switch condition must be non-NULL");
|
2011-03-04 09:03:41 +08:00
|
|
|
Expr::EvalResult result;
|
2011-03-13 11:48:04 +08:00
|
|
|
bool b = tryEvaluate(Terminator->getCond(), result);
|
|
|
|
SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond,
|
|
|
|
b ? &result : 0);
|
2011-03-04 09:03:41 +08:00
|
|
|
|
2010-10-01 09:24:41 +08:00
|
|
|
// If body is not a compound statement create implicit scope
|
|
|
|
// and add destructors.
|
|
|
|
if (!isa<CompoundStmt>(Terminator->getBody()))
|
|
|
|
addLocalScopeAndDtors(Terminator->getBody());
|
|
|
|
|
2010-09-06 15:32:31 +08:00
|
|
|
addStmt(Terminator->getBody());
|
2009-05-02 08:13:27 +08:00
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-08-28 03:46:09 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
// If we have no "default:" case, the default transition is to the code
|
2011-03-16 12:32:01 +08:00
|
|
|
// following the switch body. Moreover, take into account if all the
|
|
|
|
// cases of a switch are covered (e.g., switching on an enum value).
|
2011-03-02 07:12:55 +08:00
|
|
|
addSuccessor(SwitchTerminatedBlock,
|
2011-03-16 12:32:01 +08:00
|
|
|
switchExclusivelyCovered || Terminator->isAllEnumCasesCovered()
|
|
|
|
? 0 : DefaultCaseBlock);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-28 03:46:09 +08:00
|
|
|
// Add the terminator and condition in the switch block.
|
2008-04-17 05:10:48 +08:00
|
|
|
SwitchTerminatedBlock->setTerminator(Terminator);
|
2007-08-24 05:42:29 +08:00
|
|
|
Block = SwitchTerminatedBlock;
|
2009-12-24 08:39:26 +08:00
|
|
|
Block = addStmt(Terminator->getCond());
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2009-12-24 08:39:26 +08:00
|
|
|
// Finally, if the SwitchStmt contains a condition variable, add both the
|
|
|
|
// SwitchStmt and the condition variable initialization to the CFG.
|
|
|
|
if (VarDecl *VD = Terminator->getConditionVariable()) {
|
|
|
|
if (Expr *Init = VD->getInit()) {
|
|
|
|
autoCreateBlock();
|
2011-04-05 07:29:12 +08:00
|
|
|
appendStmt(Block, Terminator->getConditionVariableDeclStmt());
|
2009-12-24 08:39:26 +08:00
|
|
|
addStmt(Init);
|
|
|
|
}
|
|
|
|
}
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2009-12-24 08:39:26 +08:00
|
|
|
return Block;
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2011-03-02 07:12:55 +08:00
|
|
|
|
|
|
|
static bool shouldAddCase(bool &switchExclusivelyCovered,
|
2011-03-13 11:48:04 +08:00
|
|
|
const Expr::EvalResult *switchCond,
|
2011-03-02 07:12:55 +08:00
|
|
|
const CaseStmt *CS,
|
|
|
|
ASTContext &Ctx) {
|
2011-03-13 11:48:04 +08:00
|
|
|
if (!switchCond)
|
|
|
|
return true;
|
|
|
|
|
2011-03-02 07:12:55 +08:00
|
|
|
bool addCase = false;
|
2011-03-04 09:03:41 +08:00
|
|
|
|
2011-03-02 07:12:55 +08:00
|
|
|
if (!switchExclusivelyCovered) {
|
2011-03-13 11:48:04 +08:00
|
|
|
if (switchCond->Val.isInt()) {
|
2011-03-02 07:12:55 +08:00
|
|
|
// Evaluate the LHS of the case value.
|
2011-10-15 04:22:00 +08:00
|
|
|
const llvm::APSInt &lhsInt = CS->getLHS()->EvaluateKnownConstInt(Ctx);
|
2011-03-13 11:48:04 +08:00
|
|
|
const llvm::APSInt &condInt = switchCond->Val.getInt();
|
2011-03-02 07:12:55 +08:00
|
|
|
|
|
|
|
if (condInt == lhsInt) {
|
|
|
|
addCase = true;
|
|
|
|
switchExclusivelyCovered = true;
|
|
|
|
}
|
|
|
|
else if (condInt < lhsInt) {
|
|
|
|
if (const Expr *RHS = CS->getRHS()) {
|
|
|
|
// Evaluate the RHS of the case value.
|
2011-10-15 04:22:00 +08:00
|
|
|
const llvm::APSInt &V2 = RHS->EvaluateKnownConstInt(Ctx);
|
|
|
|
if (V2 <= condInt) {
|
2011-03-02 07:12:55 +08:00
|
|
|
addCase = true;
|
|
|
|
switchExclusivelyCovered = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
addCase = true;
|
|
|
|
}
|
|
|
|
return addCase;
|
|
|
|
}
|
2007-08-24 05:42:29 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
|
2009-07-17 09:31:16 +08:00
|
|
|
// CaseStmts are essentially labels, so they are the first statement in a
|
|
|
|
// block.
|
2010-08-05 07:54:30 +08:00
|
|
|
CFGBlock *TopBlock = 0, *LastBlock = 0;
|
2011-03-04 09:03:41 +08:00
|
|
|
|
2010-08-05 07:54:30 +08:00
|
|
|
if (Stmt *Sub = CS->getSubStmt()) {
|
|
|
|
// For deeply nested chains of CaseStmts, instead of doing a recursion
|
|
|
|
// (which can blow out the stack), manually unroll and create blocks
|
|
|
|
// along the way.
|
|
|
|
while (isa<CaseStmt>(Sub)) {
|
2010-12-17 12:44:39 +08:00
|
|
|
CFGBlock *currentBlock = createBlock(false);
|
|
|
|
currentBlock->setLabel(CS);
|
2010-08-05 07:54:30 +08:00
|
|
|
|
|
|
|
if (TopBlock)
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(LastBlock, currentBlock);
|
2010-08-05 07:54:30 +08:00
|
|
|
else
|
2010-12-17 12:44:39 +08:00
|
|
|
TopBlock = currentBlock;
|
2010-08-05 07:54:30 +08:00
|
|
|
|
2011-03-02 07:12:55 +08:00
|
|
|
addSuccessor(SwitchTerminatedBlock,
|
2011-03-13 11:48:04 +08:00
|
|
|
shouldAddCase(switchExclusivelyCovered, switchCond,
|
2011-03-02 07:12:55 +08:00
|
|
|
CS, *Context)
|
|
|
|
? currentBlock : 0);
|
2010-08-05 07:54:30 +08:00
|
|
|
|
2011-03-02 07:12:55 +08:00
|
|
|
LastBlock = currentBlock;
|
2010-08-05 07:54:30 +08:00
|
|
|
CS = cast<CaseStmt>(Sub);
|
|
|
|
Sub = CS->getSubStmt();
|
|
|
|
}
|
2007-08-31 02:48:11 +08:00
|
|
|
|
2010-08-05 07:54:30 +08:00
|
|
|
addStmt(Sub);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CaseBlock = Block;
|
2009-07-18 06:18:43 +08:00
|
|
|
if (!CaseBlock)
|
|
|
|
CaseBlock = createBlock();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Cases statements partition blocks, so this is the top of the basic block we
|
|
|
|
// were processing (the "case XXX:" is the label).
|
2009-07-18 06:18:43 +08:00
|
|
|
CaseBlock->setLabel(CS);
|
|
|
|
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Add this block to the list of successors for the block with the switch
|
|
|
|
// statement.
|
2009-07-18 06:18:43 +08:00
|
|
|
assert(SwitchTerminatedBlock);
|
2011-03-02 07:12:55 +08:00
|
|
|
addSuccessor(SwitchTerminatedBlock,
|
2011-03-13 11:48:04 +08:00
|
|
|
shouldAddCase(switchExclusivelyCovered, switchCond,
|
2011-03-02 07:12:55 +08:00
|
|
|
CS, *Context)
|
|
|
|
? CaseBlock : 0);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// We set Block to NULL to allow lazy creation of a new block (if necessary)
|
|
|
|
Block = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-08-05 07:54:30 +08:00
|
|
|
if (TopBlock) {
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(LastBlock, CaseBlock);
|
2010-08-05 07:54:30 +08:00
|
|
|
Succ = TopBlock;
|
2010-11-23 03:32:14 +08:00
|
|
|
} else {
|
2010-08-05 07:54:30 +08:00
|
|
|
// This block is now the implicit successor of other blocks.
|
|
|
|
Succ = CaseBlock;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-08-05 07:54:30 +08:00
|
|
|
return Succ;
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
|
2009-07-18 06:18:43 +08:00
|
|
|
if (Terminator->getSubStmt())
|
|
|
|
addStmt(Terminator->getSubStmt());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-02-14 06:05:39 +08:00
|
|
|
DefaultCaseBlock = Block;
|
2009-07-18 06:18:43 +08:00
|
|
|
|
|
|
|
if (!DefaultCaseBlock)
|
|
|
|
DefaultCaseBlock = createBlock();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Default statements partition blocks, so this is the top of the basic block
|
|
|
|
// we were processing (the "default:" is the label).
|
2008-04-17 05:10:48 +08:00
|
|
|
DefaultCaseBlock->setLabel(Terminator);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-05-02 08:13:27 +08:00
|
|
|
return 0;
|
2008-02-14 06:05:39 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
// Unlike case statements, we don't add the default block to the successors
|
|
|
|
// for the switch statement immediately. This is done when we finish
|
|
|
|
// processing the switch statement. This allows for the default case
|
|
|
|
// (including a fall-through to the code after the switch statement) to always
|
|
|
|
// be the last successor of a switch-terminated block.
|
|
|
|
|
2008-02-14 06:05:39 +08:00
|
|
|
// We set Block to NULL to allow lazy creation of a new block (if necessary)
|
|
|
|
Block = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-02-14 06:05:39 +08:00
|
|
|
// This block is now the implicit successor of other blocks.
|
|
|
|
Succ = DefaultCaseBlock;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
return DefaultCaseBlock;
|
2008-02-14 05:46:34 +08:00
|
|
|
}
|
2007-08-24 05:42:29 +08:00
|
|
|
|
2010-01-19 10:20:09 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
|
|
|
|
// "try"/"catch" is a control-flow statement. Thus we stop processing the
|
|
|
|
// current block.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *TrySuccessor = NULL;
|
2010-01-19 10:20:09 +08:00
|
|
|
|
|
|
|
if (Block) {
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2010-01-19 10:20:09 +08:00
|
|
|
return 0;
|
|
|
|
TrySuccessor = Block;
|
|
|
|
} else TrySuccessor = Succ;
|
|
|
|
|
2010-01-20 09:15:34 +08:00
|
|
|
CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
|
2010-01-19 10:20:09 +08:00
|
|
|
|
|
|
|
// Create a new block that will contain the try statement.
|
2010-01-20 09:30:58 +08:00
|
|
|
CFGBlock *NewTryTerminatedBlock = createBlock(false);
|
2010-01-19 10:20:09 +08:00
|
|
|
// Add the terminator in the try block.
|
2010-01-20 09:30:58 +08:00
|
|
|
NewTryTerminatedBlock->setTerminator(Terminator);
|
2010-01-19 10:20:09 +08:00
|
|
|
|
2010-01-20 09:15:34 +08:00
|
|
|
bool HasCatchAll = false;
|
2010-01-19 10:20:09 +08:00
|
|
|
for (unsigned h = 0; h <Terminator->getNumHandlers(); ++h) {
|
|
|
|
// The code after the try is the implicit successor.
|
|
|
|
Succ = TrySuccessor;
|
|
|
|
CXXCatchStmt *CS = Terminator->getHandler(h);
|
2010-01-20 09:15:34 +08:00
|
|
|
if (CS->getExceptionDecl() == 0) {
|
|
|
|
HasCatchAll = true;
|
|
|
|
}
|
2010-01-19 10:20:09 +08:00
|
|
|
Block = NULL;
|
|
|
|
CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
|
|
|
|
if (CatchBlock == 0)
|
|
|
|
return 0;
|
|
|
|
// Add this block to the list of successors for the block with the try
|
|
|
|
// statement.
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(NewTryTerminatedBlock, CatchBlock);
|
2010-01-19 10:20:09 +08:00
|
|
|
}
|
2010-01-20 09:15:34 +08:00
|
|
|
if (!HasCatchAll) {
|
|
|
|
if (PrevTryTerminatedBlock)
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
|
2010-01-20 09:15:34 +08:00
|
|
|
else
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
|
2010-01-20 09:15:34 +08:00
|
|
|
}
|
2010-01-19 10:20:09 +08:00
|
|
|
|
|
|
|
// The code after the try is the implicit successor.
|
|
|
|
Succ = TrySuccessor;
|
|
|
|
|
2010-01-20 09:30:58 +08:00
|
|
|
// Save the current "try" context.
|
2011-08-24 07:05:07 +08:00
|
|
|
SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock, NewTryTerminatedBlock);
|
|
|
|
cfg->addTryDispatchBlock(TryTerminatedBlock);
|
2010-01-20 09:30:58 +08:00
|
|
|
|
2010-01-20 04:46:35 +08:00
|
|
|
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
|
2010-01-19 10:20:09 +08:00
|
|
|
Block = NULL;
|
2010-01-20 04:52:05 +08:00
|
|
|
Block = addStmt(Terminator->getTryBlock());
|
2010-01-19 10:20:09 +08:00
|
|
|
return Block;
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
|
2010-01-19 10:20:09 +08:00
|
|
|
// CXXCatchStmt are treated like labels, so they are the first statement in a
|
|
|
|
// block.
|
|
|
|
|
2010-10-01 09:46:52 +08:00
|
|
|
// Save local scope position because in case of exception variable ScopePos
|
|
|
|
// won't be restored when traversing AST.
|
|
|
|
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
|
|
|
|
|
|
|
|
// Create local scope for possible exception variable.
|
|
|
|
// Store scope position. Add implicit destructor.
|
2011-08-13 07:37:29 +08:00
|
|
|
if (VarDecl *VD = CS->getExceptionDecl()) {
|
2010-10-01 09:46:52 +08:00
|
|
|
LocalScope::const_iterator BeginScopePos = ScopePos;
|
|
|
|
addLocalScopeForVarDecl(VD);
|
|
|
|
addAutomaticObjDtors(ScopePos, BeginScopePos, CS);
|
|
|
|
}
|
|
|
|
|
2010-01-19 10:20:09 +08:00
|
|
|
if (CS->getHandlerBlock())
|
|
|
|
addStmt(CS->getHandlerBlock());
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CatchBlock = Block;
|
2010-01-19 10:20:09 +08:00
|
|
|
if (!CatchBlock)
|
|
|
|
CatchBlock = createBlock();
|
2012-03-10 09:34:17 +08:00
|
|
|
|
|
|
|
// CXXCatchStmt is more than just a label. They have semantic meaning
|
|
|
|
// as well, as they implicitly "initialize" the catch variable. Add
|
|
|
|
// it to the CFG as a CFGElement so that the control-flow of these
|
|
|
|
// semantics gets captured.
|
|
|
|
appendStmt(CatchBlock, CS);
|
|
|
|
|
|
|
|
// Also add the CXXCatchStmt as a label, to mirror handling of regular
|
|
|
|
// labels.
|
2010-01-19 10:20:09 +08:00
|
|
|
CatchBlock->setLabel(CS);
|
|
|
|
|
2012-03-10 09:34:17 +08:00
|
|
|
// Bail out if the CFG is bad.
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2010-01-19 10:20:09 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// We set Block to NULL to allow lazy creation of a new block (if necessary)
|
|
|
|
Block = NULL;
|
|
|
|
|
|
|
|
return CatchBlock;
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
2011-04-15 06:09:26 +08:00
|
|
|
// C++0x for-range statements are specified as [stmt.ranged]:
|
|
|
|
//
|
|
|
|
// {
|
|
|
|
// auto && __range = range-init;
|
|
|
|
// for ( auto __begin = begin-expr,
|
|
|
|
// __end = end-expr;
|
|
|
|
// __begin != __end;
|
|
|
|
// ++__begin ) {
|
|
|
|
// for-range-declaration = *__begin;
|
|
|
|
// statement
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// Save local scope position before the addition of the implicit variables.
|
|
|
|
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
|
|
|
|
|
|
|
|
// Create local scopes and destructors for range, begin and end variables.
|
|
|
|
if (Stmt *Range = S->getRangeStmt())
|
|
|
|
addLocalScopeForStmt(Range);
|
|
|
|
if (Stmt *BeginEnd = S->getBeginEndStmt())
|
|
|
|
addLocalScopeForStmt(BeginEnd);
|
|
|
|
addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
|
|
|
|
|
|
|
|
LocalScope::const_iterator ContinueScopePos = ScopePos;
|
|
|
|
|
|
|
|
// "for" is a control-flow statement. Thus we stop processing the current
|
|
|
|
// block.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *LoopSuccessor = NULL;
|
2011-04-15 06:09:26 +08:00
|
|
|
if (Block) {
|
|
|
|
if (badCFG)
|
|
|
|
return 0;
|
|
|
|
LoopSuccessor = Block;
|
|
|
|
} else
|
|
|
|
LoopSuccessor = Succ;
|
|
|
|
|
|
|
|
// Save the current value for the break targets.
|
|
|
|
// All breaks should go to the code following the loop.
|
|
|
|
SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
|
|
|
|
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
|
|
|
|
|
|
|
|
// The block for the __begin != __end expression.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *ConditionBlock = createBlock(false);
|
2011-04-15 06:09:26 +08:00
|
|
|
ConditionBlock->setTerminator(S);
|
|
|
|
|
|
|
|
// Now add the actual condition to the condition block.
|
|
|
|
if (Expr *C = S->getCond()) {
|
|
|
|
Block = ConditionBlock;
|
|
|
|
CFGBlock *BeginConditionBlock = addStmt(C);
|
|
|
|
if (badCFG)
|
|
|
|
return 0;
|
|
|
|
assert(BeginConditionBlock == ConditionBlock &&
|
|
|
|
"condition block in for-range was unexpectedly complex");
|
|
|
|
(void)BeginConditionBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The condition block is the implicit successor for the loop body as well as
|
|
|
|
// any code above the loop.
|
|
|
|
Succ = ConditionBlock;
|
|
|
|
|
|
|
|
// See if this is a known constant.
|
|
|
|
TryResult KnownVal(true);
|
|
|
|
|
|
|
|
if (S->getCond())
|
|
|
|
KnownVal = tryEvaluateBool(S->getCond());
|
|
|
|
|
|
|
|
// Now create the loop body.
|
|
|
|
{
|
|
|
|
assert(S->getBody());
|
|
|
|
|
|
|
|
// Save the current values for Block, Succ, and continue targets.
|
|
|
|
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
|
|
|
|
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
|
|
|
|
|
|
|
|
// Generate increment code in its own basic block. This is the target of
|
|
|
|
// continue statements.
|
|
|
|
Block = 0;
|
|
|
|
Succ = addStmt(S->getInc());
|
|
|
|
ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
|
|
|
|
|
|
|
|
// The starting block for the loop increment is the block that should
|
|
|
|
// represent the 'loop target' for looping back to the start of the loop.
|
|
|
|
ContinueJumpTarget.block->setLoopTarget(S);
|
|
|
|
|
|
|
|
// Finish up the increment block and prepare to start the loop body.
|
|
|
|
assert(Block);
|
|
|
|
if (badCFG)
|
|
|
|
return 0;
|
|
|
|
Block = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Add implicit scope and dtors for loop variable.
|
|
|
|
addLocalScopeAndDtors(S->getLoopVarStmt());
|
|
|
|
|
|
|
|
// Populate a new block to contain the loop body and loop variable.
|
|
|
|
Block = addStmt(S->getBody());
|
|
|
|
if (badCFG)
|
|
|
|
return 0;
|
|
|
|
Block = addStmt(S->getLoopVarStmt());
|
|
|
|
if (badCFG)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// This new body block is a successor to our condition block.
|
|
|
|
addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Link up the condition block with the code that follows the loop (the
|
|
|
|
// false branch).
|
|
|
|
addSuccessor(ConditionBlock, KnownVal.isTrue() ? 0 : LoopSuccessor);
|
|
|
|
|
|
|
|
// Add the initialization statements.
|
|
|
|
Block = createBlock();
|
2011-04-18 23:49:25 +08:00
|
|
|
addStmt(S->getBeginEndStmt());
|
|
|
|
return addStmt(S->getRangeStmt());
|
2011-04-15 06:09:26 +08:00
|
|
|
}
|
|
|
|
|
2010-12-06 16:20:24 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
|
2010-11-03 14:19:35 +08:00
|
|
|
AddStmtChoice asc) {
|
[analyzer] Always include destructors in the analysis CFG.
While destructors will continue to not be inlined (unless the analyzer
config option 'c++-inlining' is set to 'destructors'), leaving them out
of the CFG is an incomplete model of the behavior of an object, and
can cause false positive warnings (like PR13751, now working).
Destructors for temporaries are still not on by default, since
(a) we haven't actually checked this code to be sure it's fully correct
(in particular, we probably need to be very careful with regard to
lifetime-extension when a temporary is bound to a reference,
C++11 [class.temporary]p5), and
(b) ExprEngine doesn't actually do anything when it sees a temporary
destructor in the CFG -- not even invalidate the object region.
To enable temporary destructors, set the 'cfg-temporary-dtors' analyzer
config option to '1'. The old -cfg-add-implicit-dtors cc1 option, which
controlled all implicit destructors, has been removed.
llvm-svn: 163264
2012-09-06 06:55:23 +08:00
|
|
|
if (BuildOpts.AddTemporaryDtors) {
|
2010-11-03 14:19:35 +08:00
|
|
|
// If adding implicit destructors visit the full expression for adding
|
|
|
|
// destructors of temporaries.
|
|
|
|
VisitForTemporaryDtors(E->getSubExpr());
|
|
|
|
|
|
|
|
// Full expression has to be added as CFGStmt so it will be sequenced
|
|
|
|
// before destructors of it's temporaries.
|
2010-11-24 11:28:53 +08:00
|
|
|
asc = asc.withAlwaysAdd(true);
|
2010-11-03 14:19:35 +08:00
|
|
|
}
|
|
|
|
return Visit(E->getSubExpr(), asc);
|
|
|
|
}
|
|
|
|
|
2010-11-01 21:04:58 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
|
|
|
|
AddStmtChoice asc) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, E)) {
|
2010-11-01 21:04:58 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, E);
|
2010-11-01 21:04:58 +08:00
|
|
|
|
|
|
|
// We do not want to propagate the AlwaysAdd property.
|
2010-11-24 11:28:53 +08:00
|
|
|
asc = asc.withAlwaysAdd(false);
|
2010-11-01 21:04:58 +08:00
|
|
|
}
|
|
|
|
return Visit(E->getSubExpr(), asc);
|
|
|
|
}
|
|
|
|
|
2010-11-01 14:46:05 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
|
|
|
|
AddStmtChoice asc) {
|
|
|
|
autoCreateBlock();
|
2012-01-11 10:39:07 +08:00
|
|
|
appendStmt(Block, C);
|
2010-11-24 11:28:53 +08:00
|
|
|
|
2010-11-01 14:46:05 +08:00
|
|
|
return VisitChildren(C);
|
|
|
|
}
|
|
|
|
|
2010-11-01 21:04:58 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
|
|
|
|
AddStmtChoice asc) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, E)) {
|
2010-11-01 21:04:58 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, E);
|
2010-11-01 21:04:58 +08:00
|
|
|
// We do not want to propagate the AlwaysAdd property.
|
2010-11-24 11:28:53 +08:00
|
|
|
asc = asc.withAlwaysAdd(false);
|
2010-11-01 21:04:58 +08:00
|
|
|
}
|
|
|
|
return Visit(E->getSubExpr(), asc);
|
|
|
|
}
|
|
|
|
|
2010-11-01 14:46:05 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
|
|
|
|
AddStmtChoice asc) {
|
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, C);
|
2010-11-01 14:46:05 +08:00
|
|
|
return VisitChildren(C);
|
|
|
|
}
|
|
|
|
|
2010-11-01 21:04:58 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
|
|
|
|
AddStmtChoice asc) {
|
2011-03-10 09:14:11 +08:00
|
|
|
if (asc.alwaysAdd(*this, E)) {
|
2010-11-01 21:04:58 +08:00
|
|
|
autoCreateBlock();
|
2011-03-10 09:14:08 +08:00
|
|
|
appendStmt(Block, E);
|
2010-11-01 21:04:58 +08:00
|
|
|
}
|
2010-12-16 15:46:53 +08:00
|
|
|
return Visit(E->getSubExpr(), AddStmtChoice());
|
2010-11-01 21:04:58 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
|
2009-07-17 09:31:16 +08:00
|
|
|
// Lazily create the indirect-goto dispatch block if there isn't one already.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *IBlock = cfg->getIndirectGotoBlock();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-29 03:26:49 +08:00
|
|
|
if (!IBlock) {
|
|
|
|
IBlock = createBlock(false);
|
|
|
|
cfg->setIndirectGotoBlock(IBlock);
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-29 03:26:49 +08:00
|
|
|
// IndirectGoto is a control-flow statement. Thus we stop processing the
|
|
|
|
// current block and create a new one.
|
2010-09-06 15:32:31 +08:00
|
|
|
if (badCFG)
|
2009-07-18 06:18:43 +08:00
|
|
|
return 0;
|
|
|
|
|
2007-08-29 03:26:49 +08:00
|
|
|
Block = createBlock(false);
|
|
|
|
Block->setTerminator(I);
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, IBlock);
|
2007-08-29 03:26:49 +08:00
|
|
|
return addStmt(I->getTarget());
|
|
|
|
}
|
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) {
|
[analyzer] Always include destructors in the analysis CFG.
While destructors will continue to not be inlined (unless the analyzer
config option 'c++-inlining' is set to 'destructors'), leaving them out
of the CFG is an incomplete model of the behavior of an object, and
can cause false positive warnings (like PR13751, now working).
Destructors for temporaries are still not on by default, since
(a) we haven't actually checked this code to be sure it's fully correct
(in particular, we probably need to be very careful with regard to
lifetime-extension when a temporary is bound to a reference,
C++11 [class.temporary]p5), and
(b) ExprEngine doesn't actually do anything when it sees a temporary
destructor in the CFG -- not even invalidate the object region.
To enable temporary destructors, set the 'cfg-temporary-dtors' analyzer
config option to '1'. The old -cfg-add-implicit-dtors cc1 option, which
controlled all implicit destructors, has been removed.
llvm-svn: 163264
2012-09-06 06:55:23 +08:00
|
|
|
assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors);
|
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
tryAgain:
|
|
|
|
if (!E) {
|
|
|
|
badCFG = true;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
switch (E->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
return VisitChildrenForTemporaryDtors(E);
|
|
|
|
|
|
|
|
case Stmt::BinaryOperatorClass:
|
|
|
|
return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(E));
|
|
|
|
|
|
|
|
case Stmt::CXXBindTemporaryExprClass:
|
|
|
|
return VisitCXXBindTemporaryExprForTemporaryDtors(
|
|
|
|
cast<CXXBindTemporaryExpr>(E), BindToTemporary);
|
|
|
|
|
2011-02-17 18:25:35 +08:00
|
|
|
case Stmt::BinaryConditionalOperatorClass:
|
2010-11-03 14:19:35 +08:00
|
|
|
case Stmt::ConditionalOperatorClass:
|
|
|
|
return VisitConditionalOperatorForTemporaryDtors(
|
2011-02-17 18:25:35 +08:00
|
|
|
cast<AbstractConditionalOperator>(E), BindToTemporary);
|
2010-11-03 14:19:35 +08:00
|
|
|
|
|
|
|
case Stmt::ImplicitCastExprClass:
|
|
|
|
// For implicit cast we want BindToTemporary to be passed further.
|
|
|
|
E = cast<CastExpr>(E)->getSubExpr();
|
|
|
|
goto tryAgain;
|
|
|
|
|
|
|
|
case Stmt::ParenExprClass:
|
|
|
|
E = cast<ParenExpr>(E)->getSubExpr();
|
|
|
|
goto tryAgain;
|
2011-06-22 01:03:29 +08:00
|
|
|
|
|
|
|
case Stmt::MaterializeTemporaryExprClass:
|
|
|
|
E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
|
|
|
|
goto tryAgain;
|
2010-11-03 14:19:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) {
|
|
|
|
// When visiting children for destructors we want to visit them in reverse
|
|
|
|
// order. Because there's no reverse iterator for children must to reverse
|
|
|
|
// them in helper vector.
|
2011-07-23 18:55:15 +08:00
|
|
|
typedef SmallVector<Stmt *, 4> ChildrenVect;
|
2010-11-03 14:19:35 +08:00
|
|
|
ChildrenVect ChildrenRev;
|
2011-02-13 12:07:26 +08:00
|
|
|
for (Stmt::child_range I = E->children(); I; ++I) {
|
2010-11-03 14:19:35 +08:00
|
|
|
if (*I) ChildrenRev.push_back(*I);
|
|
|
|
}
|
|
|
|
|
|
|
|
CFGBlock *B = Block;
|
|
|
|
for (ChildrenVect::reverse_iterator I = ChildrenRev.rbegin(),
|
|
|
|
L = ChildrenRev.rend(); I != L; ++I) {
|
|
|
|
if (CFGBlock *R = VisitForTemporaryDtors(*I))
|
|
|
|
B = R;
|
|
|
|
}
|
|
|
|
return B;
|
|
|
|
}
|
|
|
|
|
|
|
|
CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E) {
|
|
|
|
if (E->isLogicalOp()) {
|
|
|
|
// Destructors for temporaries in LHS expression should be called after
|
|
|
|
// those for RHS expression. Even if this will unnecessarily create a block,
|
|
|
|
// this block will be used at least by the full expression.
|
|
|
|
autoCreateBlock();
|
|
|
|
CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getLHS());
|
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
Succ = ConfluenceBlock;
|
|
|
|
Block = NULL;
|
|
|
|
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS());
|
|
|
|
|
|
|
|
if (RHSBlock) {
|
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
// If RHS expression did produce destructors we need to connect created
|
|
|
|
// blocks to CFG in same manner as for binary operator itself.
|
|
|
|
CFGBlock *LHSBlock = createBlock(false);
|
|
|
|
LHSBlock->setTerminator(CFGTerminator(E, true));
|
|
|
|
|
|
|
|
// For binary operator LHS block is before RHS in list of predecessors
|
|
|
|
// of ConfluenceBlock.
|
|
|
|
std::reverse(ConfluenceBlock->pred_begin(),
|
|
|
|
ConfluenceBlock->pred_end());
|
|
|
|
|
|
|
|
// See if this is a known constant.
|
2010-12-17 12:44:39 +08:00
|
|
|
TryResult KnownVal = tryEvaluateBool(E->getLHS());
|
2010-11-03 14:19:35 +08:00
|
|
|
if (KnownVal.isKnown() && (E->getOpcode() == BO_LOr))
|
|
|
|
KnownVal.negate();
|
|
|
|
|
|
|
|
// Link LHSBlock with RHSBlock exactly the same way as for binary operator
|
|
|
|
// itself.
|
|
|
|
if (E->getOpcode() == BO_LOr) {
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
|
|
|
|
addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
|
2010-11-03 14:19:35 +08:00
|
|
|
} else {
|
|
|
|
assert (E->getOpcode() == BO_LAnd);
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
|
|
|
|
addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
|
2010-11-03 14:19:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Block = LHSBlock;
|
|
|
|
return LHSBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
Block = ConfluenceBlock;
|
|
|
|
return ConfluenceBlock;
|
|
|
|
}
|
|
|
|
|
2010-11-23 03:32:14 +08:00
|
|
|
if (E->isAssignmentOp()) {
|
2010-11-03 14:19:35 +08:00
|
|
|
// For assignment operator (=) LHS expression is visited
|
|
|
|
// before RHS expression. For destructors visit them in reverse order.
|
|
|
|
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS());
|
|
|
|
CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS());
|
|
|
|
return LHSBlock ? LHSBlock : RHSBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For any other binary operator RHS expression is visited before
|
|
|
|
// LHS expression (order of children). For destructors visit them in reverse
|
|
|
|
// order.
|
|
|
|
CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS());
|
|
|
|
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS());
|
|
|
|
return RHSBlock ? RHSBlock : LHSBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
|
|
|
|
CXXBindTemporaryExpr *E, bool BindToTemporary) {
|
|
|
|
// First add destructors for temporaries in subexpression.
|
|
|
|
CFGBlock *B = VisitForTemporaryDtors(E->getSubExpr());
|
2010-11-14 23:23:50 +08:00
|
|
|
if (!BindToTemporary) {
|
2010-11-03 14:19:35 +08:00
|
|
|
// If lifetime of temporary is not prolonged (by assigning to constant
|
|
|
|
// reference) add destructor for it.
|
Enhance the CFG construction to detect no-return destructors for
temporary objects and local variables. When detected, these split the
block, marking the new one as having only the exit block as a successor.
This prevents a large number of false positives in warnings sensitive to
no-return constructs such as -Wreturn-type, and fixes the remainder of
PR10063 along with several variations of this bug that had not been
reported. The test cases are extended across the board to cover these
patterns.
This also checks in a stress test for these types of CFGs. The stress
test declares some 32k variables, a mixture of no-return and normal
destructors. Previously, this resulted in roughly 2500 CFG blocks, but
didn't model any of the no-return destructors. With this patch, it
results in over 33k blocks, many of them now unreachable.
The nice thing about how the analyzer is set up? This causes *no*
regression in performance of building the CFG. It actually in some cases
makes it faster, as best I can benchmark. The analysis for -Wreturn-type
(and any other that cares about no-return code paths) is technically
slower now as it has to look at many more candidate blocks, but it
computes the correct answer. I have more test cases to follow, I think
they all work now. Also I have further work that should dramatically
simplify analyses in the presence of no-return.
llvm-svn: 139586
2011-09-13 14:09:01 +08:00
|
|
|
|
|
|
|
// If the destructor is marked as a no-return destructor, we need to create
|
|
|
|
// a new block for the destructor which does not have as a successor
|
|
|
|
// anything built thus far. Control won't flow out of this block.
|
|
|
|
const CXXDestructorDecl *Dtor = E->getTemporary()->getDestructor();
|
2011-09-13 17:13:49 +08:00
|
|
|
if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr())
|
|
|
|
Block = createNoReturnBlock();
|
|
|
|
else
|
Enhance the CFG construction to detect no-return destructors for
temporary objects and local variables. When detected, these split the
block, marking the new one as having only the exit block as a successor.
This prevents a large number of false positives in warnings sensitive to
no-return constructs such as -Wreturn-type, and fixes the remainder of
PR10063 along with several variations of this bug that had not been
reported. The test cases are extended across the board to cover these
patterns.
This also checks in a stress test for these types of CFGs. The stress
test declares some 32k variables, a mixture of no-return and normal
destructors. Previously, this resulted in roughly 2500 CFG blocks, but
didn't model any of the no-return destructors. With this patch, it
results in over 33k blocks, many of them now unreachable.
The nice thing about how the analyzer is set up? This causes *no*
regression in performance of building the CFG. It actually in some cases
makes it faster, as best I can benchmark. The analysis for -Wreturn-type
(and any other that cares about no-return code paths) is technically
slower now as it has to look at many more candidate blocks, but it
computes the correct answer. I have more test cases to follow, I think
they all work now. Also I have further work that should dramatically
simplify analyses in the presence of no-return.
llvm-svn: 139586
2011-09-13 14:09:01 +08:00
|
|
|
autoCreateBlock();
|
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
appendTemporaryDtor(Block, E);
|
|
|
|
B = Block;
|
|
|
|
}
|
|
|
|
return B;
|
|
|
|
}
|
|
|
|
|
|
|
|
CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
|
2011-02-17 18:25:35 +08:00
|
|
|
AbstractConditionalOperator *E, bool BindToTemporary) {
|
2010-11-03 14:19:35 +08:00
|
|
|
// First add destructors for condition expression. Even if this will
|
|
|
|
// unnecessarily create a block, this block will be used at least by the full
|
|
|
|
// expression.
|
|
|
|
autoCreateBlock();
|
|
|
|
CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getCond());
|
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
2011-02-17 18:25:35 +08:00
|
|
|
if (BinaryConditionalOperator *BCO
|
|
|
|
= dyn_cast<BinaryConditionalOperator>(E)) {
|
|
|
|
ConfluenceBlock = VisitForTemporaryDtors(BCO->getCommon());
|
2010-11-03 14:19:35 +08:00
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:25:35 +08:00
|
|
|
// Try to add block with destructors for LHS expression.
|
|
|
|
CFGBlock *LHSBlock = NULL;
|
|
|
|
Succ = ConfluenceBlock;
|
|
|
|
Block = NULL;
|
|
|
|
LHSBlock = VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary);
|
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
|
|
|
|
2010-11-03 14:19:35 +08:00
|
|
|
// Try to add block with destructors for RHS expression;
|
|
|
|
Succ = ConfluenceBlock;
|
|
|
|
Block = NULL;
|
2011-02-17 18:25:35 +08:00
|
|
|
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getFalseExpr(),
|
|
|
|
BindToTemporary);
|
2010-11-03 14:19:35 +08:00
|
|
|
if (badCFG)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!RHSBlock && !LHSBlock) {
|
|
|
|
// If neither LHS nor RHS expression had temporaries to destroy don't create
|
|
|
|
// more blocks.
|
|
|
|
Block = ConfluenceBlock;
|
|
|
|
return Block;
|
|
|
|
}
|
|
|
|
|
|
|
|
Block = createBlock(false);
|
|
|
|
Block->setTerminator(CFGTerminator(E, true));
|
|
|
|
|
|
|
|
// See if this is a known constant.
|
2010-12-17 12:44:39 +08:00
|
|
|
const TryResult &KnownVal = tryEvaluateBool(E->getCond());
|
2010-11-03 14:19:35 +08:00
|
|
|
|
|
|
|
if (LHSBlock) {
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
|
2010-11-03 14:19:35 +08:00
|
|
|
} else if (KnownVal.isFalse()) {
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, NULL);
|
2010-11-03 14:19:35 +08:00
|
|
|
} else {
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, ConfluenceBlock);
|
2010-11-03 14:19:35 +08:00
|
|
|
std::reverse(ConfluenceBlock->pred_begin(), ConfluenceBlock->pred_end());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!RHSBlock)
|
|
|
|
RHSBlock = ConfluenceBlock;
|
2010-12-17 12:44:39 +08:00
|
|
|
addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
|
2010-11-03 14:19:35 +08:00
|
|
|
|
|
|
|
return Block;
|
|
|
|
}
|
|
|
|
|
2007-08-24 05:26:19 +08:00
|
|
|
} // end anonymous namespace
|
2007-08-24 00:51:22 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
/// createBlock - Constructs and adds a new CFGBlock to the CFG. The block has
|
|
|
|
/// no successors or predecessors. If this is the first block created in the
|
|
|
|
/// CFG, it is automatically set to be the Entry and Exit of the CFG.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlock *CFG::createBlock() {
|
2007-08-24 00:51:22 +08:00
|
|
|
bool first_block = begin() == end();
|
|
|
|
|
|
|
|
// Create the block.
|
2009-10-13 04:55:07 +08:00
|
|
|
CFGBlock *Mem = getAllocator().Allocate<CFGBlock>();
|
2011-12-06 05:33:11 +08:00
|
|
|
new (Mem) CFGBlock(NumBlockIDs++, BlkBVC, this);
|
2009-10-13 04:55:07 +08:00
|
|
|
Blocks.push_back(Mem, BlkBVC);
|
2007-08-24 00:51:22 +08:00
|
|
|
|
|
|
|
// If this is the first block, set it as the Entry and Exit.
|
2009-10-13 04:55:07 +08:00
|
|
|
if (first_block)
|
|
|
|
Entry = Exit = &back();
|
2007-08-24 00:51:22 +08:00
|
|
|
|
|
|
|
// Return the block.
|
2009-10-13 04:55:07 +08:00
|
|
|
return &back();
|
2007-08-24 00:51:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
|
|
|
|
/// CFG is returned to the caller.
|
2011-08-13 07:37:29 +08:00
|
|
|
CFG* CFG::buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
|
2011-03-10 09:14:05 +08:00
|
|
|
const BuildOptions &BO) {
|
|
|
|
CFGBuilder Builder(C, BO);
|
|
|
|
return Builder.buildCFG(D, Statement);
|
2007-08-22 05:42:03 +08:00
|
|
|
}
|
|
|
|
|
2011-03-03 09:21:32 +08:00
|
|
|
const CXXDestructorDecl *
|
|
|
|
CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
|
2011-03-03 04:32:29 +08:00
|
|
|
switch (getKind()) {
|
|
|
|
case CFGElement::Invalid:
|
|
|
|
case CFGElement::Statement:
|
|
|
|
case CFGElement::Initializer:
|
|
|
|
llvm_unreachable("getDestructorDecl should only be used with "
|
|
|
|
"ImplicitDtors");
|
|
|
|
case CFGElement::AutomaticObjectDtor: {
|
|
|
|
const VarDecl *var = cast<CFGAutomaticObjDtor>(this)->getVarDecl();
|
|
|
|
QualType ty = var->getType();
|
2011-03-03 09:01:03 +08:00
|
|
|
ty = ty.getNonReferenceType();
|
2012-03-20 07:48:41 +08:00
|
|
|
while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
|
2011-03-03 09:21:32 +08:00
|
|
|
ty = arrayType->getElementType();
|
|
|
|
}
|
2011-03-03 04:32:29 +08:00
|
|
|
const RecordType *recordType = ty->getAs<RecordType>();
|
|
|
|
const CXXRecordDecl *classDecl =
|
2011-03-03 09:01:03 +08:00
|
|
|
cast<CXXRecordDecl>(recordType->getDecl());
|
2011-03-03 04:32:29 +08:00
|
|
|
return classDecl->getDestructor();
|
|
|
|
}
|
|
|
|
case CFGElement::TemporaryDtor: {
|
|
|
|
const CXXBindTemporaryExpr *bindExpr =
|
|
|
|
cast<CFGTemporaryDtor>(this)->getBindTemporaryExpr();
|
|
|
|
const CXXTemporary *temp = bindExpr->getTemporary();
|
|
|
|
return temp->getDestructor();
|
|
|
|
}
|
|
|
|
case CFGElement::BaseDtor:
|
|
|
|
case CFGElement::MemberDtor:
|
|
|
|
|
|
|
|
// Not yet supported.
|
|
|
|
return 0;
|
|
|
|
}
|
2011-03-03 09:01:03 +08:00
|
|
|
llvm_unreachable("getKind() returned bogus value");
|
2011-03-03 04:32:29 +08:00
|
|
|
}
|
|
|
|
|
2011-03-03 09:21:32 +08:00
|
|
|
bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
|
2012-06-06 20:00:10 +08:00
|
|
|
if (const CXXDestructorDecl *decl = getDestructorDecl(astContext)) {
|
|
|
|
QualType ty = decl->getType();
|
2011-03-03 04:32:29 +08:00
|
|
|
return cast<FunctionType>(ty)->getNoReturnAttr();
|
|
|
|
}
|
|
|
|
return false;
|
2011-03-01 11:15:10 +08:00
|
|
|
}
|
|
|
|
|
2007-10-02 03:33:33 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// CFG: Queries for BlkExprs.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
2008-01-18 04:48:37 +08:00
|
|
|
typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
|
2007-10-02 03:33:33 +08:00
|
|
|
}
|
|
|
|
|
2011-08-24 07:05:04 +08:00
|
|
|
static void FindSubExprAssignments(const Stmt *S,
|
|
|
|
llvm::SmallPtrSet<const Expr*,50>& Set) {
|
2009-12-24 07:37:10 +08:00
|
|
|
if (!S)
|
2008-01-26 08:03:27 +08:00
|
|
|
return;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-24 07:05:04 +08:00
|
|
|
for (Stmt::const_child_range I = S->children(); I; ++I) {
|
|
|
|
const Stmt *child = *I;
|
2009-12-24 07:37:10 +08:00
|
|
|
if (!child)
|
|
|
|
continue;
|
2010-08-03 07:46:59 +08:00
|
|
|
|
2011-08-24 07:05:04 +08:00
|
|
|
if (const BinaryOperator* B = dyn_cast<BinaryOperator>(child))
|
2008-01-26 08:03:27 +08:00
|
|
|
if (B->isAssignmentOp()) Set.insert(B);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-12-24 07:37:10 +08:00
|
|
|
FindSubExprAssignments(child, Set);
|
2008-01-26 08:03:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-02 03:33:33 +08:00
|
|
|
static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
|
|
|
|
BlkExprMapTy* M = new BlkExprMapTy();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Look for assignments that are used as subexpressions. These are the only
|
|
|
|
// assignments that we want to *possibly* register as a block-level
|
|
|
|
// expression. Basically, if an assignment occurs both in a subexpression and
|
|
|
|
// at the block-level, it is a block-level expression.
|
2011-08-24 07:05:04 +08:00
|
|
|
llvm::SmallPtrSet<const Expr*,50> SubExprAssignments;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-10-02 03:33:33 +08:00
|
|
|
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
|
2009-10-13 04:55:07 +08:00
|
|
|
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
|
2011-03-01 11:15:10 +08:00
|
|
|
if (const CFGStmt *S = BI->getAs<CFGStmt>())
|
|
|
|
FindSubExprAssignments(S->getStmt(), SubExprAssignments);
|
2008-01-18 04:48:37 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
|
2009-07-17 09:31:16 +08:00
|
|
|
|
|
|
|
// Iterate over the statements again on identify the Expr* and Stmt* at the
|
|
|
|
// block-level that are block-level expressions.
|
2008-04-17 05:10:48 +08:00
|
|
|
|
2010-09-16 09:25:47 +08:00
|
|
|
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) {
|
2011-03-01 11:15:10 +08:00
|
|
|
const CFGStmt *CS = BI->getAs<CFGStmt>();
|
|
|
|
if (!CS)
|
2010-09-16 09:25:47 +08:00
|
|
|
continue;
|
2011-08-24 07:05:04 +08:00
|
|
|
if (const Expr *Exp = dyn_cast<Expr>(CS->getStmt())) {
|
2011-06-10 16:49:37 +08:00
|
|
|
assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps");
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-24 07:05:04 +08:00
|
|
|
if (const BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
|
2008-01-26 08:03:27 +08:00
|
|
|
// Assignment expressions that are not nested within another
|
2009-07-17 09:31:16 +08:00
|
|
|
// expression are really "statements" whose value is never used by
|
|
|
|
// another expression.
|
2008-04-17 05:10:48 +08:00
|
|
|
if (B->isAssignmentOp() && !SubExprAssignments.count(Exp))
|
2008-01-26 08:03:27 +08:00
|
|
|
continue;
|
2011-08-13 07:37:29 +08:00
|
|
|
} else if (const StmtExpr *SE = dyn_cast<StmtExpr>(Exp)) {
|
2009-07-17 09:31:16 +08:00
|
|
|
// Special handling for statement expressions. The last statement in
|
|
|
|
// the statement expression is also a block-level expr.
|
2011-08-13 07:37:29 +08:00
|
|
|
const CompoundStmt *C = SE->getSubStmt();
|
2008-01-18 04:48:37 +08:00
|
|
|
if (!C->body_empty()) {
|
2011-06-10 16:49:37 +08:00
|
|
|
const Stmt *Last = C->body_back();
|
|
|
|
if (const Expr *LastEx = dyn_cast<Expr>(Last))
|
|
|
|
Last = LastEx->IgnoreParens();
|
2008-01-26 08:03:27 +08:00
|
|
|
unsigned x = M->size();
|
2011-06-10 16:49:37 +08:00
|
|
|
(*M)[Last] = x;
|
2008-01-18 04:48:37 +08:00
|
|
|
}
|
|
|
|
}
|
2008-01-26 07:22:27 +08:00
|
|
|
|
2008-01-26 08:03:27 +08:00
|
|
|
unsigned x = M->size();
|
2008-04-17 05:10:48 +08:00
|
|
|
(*M)[Exp] = x;
|
2008-01-26 08:03:27 +08:00
|
|
|
}
|
2010-09-16 09:25:47 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
// Look at terminators. The condition is a block-level expression.
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
Stmt *S = (*I)->getTerminatorCondition();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-13 05:11:49 +08:00
|
|
|
if (S && M->find(S) == M->end()) {
|
2011-06-10 16:49:37 +08:00
|
|
|
unsigned x = M->size();
|
|
|
|
(*M)[S] = x;
|
2008-04-17 05:10:48 +08:00
|
|
|
}
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-01-18 04:48:37 +08:00
|
|
|
return M;
|
2007-10-02 03:33:33 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt *S) {
|
2008-01-18 04:48:37 +08:00
|
|
|
assert(S != NULL);
|
2007-10-02 03:33:33 +08:00
|
|
|
if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-10-02 03:33:33 +08:00
|
|
|
BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
|
2008-01-18 04:48:37 +08:00
|
|
|
BlkExprMapTy::iterator I = M->find(S);
|
2010-01-20 04:52:05 +08:00
|
|
|
return (I == M->end()) ? CFG::BlkExprNumTy() : CFG::BlkExprNumTy(I->second);
|
2007-10-02 03:33:33 +08:00
|
|
|
}
|
2007-08-30 05:56:09 +08:00
|
|
|
|
2007-10-02 03:33:33 +08:00
|
|
|
unsigned CFG::getNumBlkExprs() {
|
|
|
|
if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap))
|
|
|
|
return M->size();
|
2010-11-23 03:32:14 +08:00
|
|
|
|
|
|
|
// We assume callers interested in the number of BlkExprs will want
|
|
|
|
// the map constructed if it doesn't already exist.
|
|
|
|
BlkExprMap = (void*) PopulateBlkExprMap(*this);
|
|
|
|
return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size();
|
2007-10-02 03:33:33 +08:00
|
|
|
}
|
|
|
|
|
2010-09-09 08:06:04 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Filtered walking of the CFG.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
|
2010-09-09 10:57:48 +08:00
|
|
|
const CFGBlock *From, const CFGBlock *To) {
|
2010-09-09 08:06:04 +08:00
|
|
|
|
2011-03-08 06:04:39 +08:00
|
|
|
if (To && F.IgnoreDefaultsWithCoveredEnums) {
|
2010-09-09 08:06:04 +08:00
|
|
|
// If the 'To' has no label or is labeled but the label isn't a
|
|
|
|
// CaseStmt then filter this edge.
|
|
|
|
if (const SwitchStmt *S =
|
2011-03-08 06:04:39 +08:00
|
|
|
dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) {
|
2010-09-09 08:06:04 +08:00
|
|
|
if (S->isAllEnumCasesCovered()) {
|
2011-03-08 06:04:39 +08:00
|
|
|
const Stmt *L = To->getLabel();
|
|
|
|
if (!L || !isa<CaseStmt>(L))
|
|
|
|
return true;
|
2010-09-09 08:06:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-04-29 02:00:46 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Cleanup: CFG dstor.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2007-10-02 03:33:33 +08:00
|
|
|
CFG::~CFG() {
|
|
|
|
delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 05:56:09 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// CFG pretty printing
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
namespace {
|
2007-08-23 05:05:42 +08:00
|
|
|
|
2009-11-28 14:07:30 +08:00
|
|
|
class StmtPrinterHelper : public PrinterHelper {
|
2011-03-01 11:15:10 +08:00
|
|
|
typedef llvm::DenseMap<const Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
|
|
|
|
typedef llvm::DenseMap<const Decl*,std::pair<unsigned,unsigned> > DeclMapTy;
|
2007-09-01 05:30:12 +08:00
|
|
|
StmtMapTy StmtMap;
|
2010-09-21 13:58:15 +08:00
|
|
|
DeclMapTy DeclMap;
|
2010-12-17 12:44:39 +08:00
|
|
|
signed currentBlock;
|
2012-08-22 14:26:15 +08:00
|
|
|
unsigned currStmt;
|
2009-06-30 09:26:17 +08:00
|
|
|
const LangOptions &LangOpts;
|
2007-09-01 05:30:12 +08:00
|
|
|
public:
|
2007-09-01 06:26:13 +08:00
|
|
|
|
2009-06-30 09:26:17 +08:00
|
|
|
StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
|
2012-08-22 14:26:15 +08:00
|
|
|
: currentBlock(0), currStmt(0), LangOpts(LO)
|
2011-03-01 11:15:10 +08:00
|
|
|
{
|
2007-09-01 05:30:12 +08:00
|
|
|
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
|
|
|
|
unsigned j = 1;
|
2009-10-13 04:55:07 +08:00
|
|
|
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
|
2010-09-21 13:58:15 +08:00
|
|
|
BI != BEnd; ++BI, ++j ) {
|
2011-03-01 11:15:10 +08:00
|
|
|
if (const CFGStmt *SE = BI->getAs<CFGStmt>()) {
|
|
|
|
const Stmt *stmt= SE->getStmt();
|
2010-09-21 13:58:15 +08:00
|
|
|
std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
|
2011-03-01 11:15:10 +08:00
|
|
|
StmtMap[stmt] = P;
|
|
|
|
|
|
|
|
switch (stmt->getStmtClass()) {
|
|
|
|
case Stmt::DeclStmtClass:
|
|
|
|
DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
|
|
|
|
break;
|
|
|
|
case Stmt::IfStmtClass: {
|
|
|
|
const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
|
|
|
|
if (var)
|
|
|
|
DeclMap[var] = P;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Stmt::ForStmtClass: {
|
|
|
|
const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
|
|
|
|
if (var)
|
|
|
|
DeclMap[var] = P;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Stmt::WhileStmtClass: {
|
|
|
|
const VarDecl *var =
|
|
|
|
cast<WhileStmt>(stmt)->getConditionVariable();
|
|
|
|
if (var)
|
|
|
|
DeclMap[var] = P;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Stmt::SwitchStmtClass: {
|
|
|
|
const VarDecl *var =
|
|
|
|
cast<SwitchStmt>(stmt)->getConditionVariable();
|
|
|
|
if (var)
|
|
|
|
DeclMap[var] = P;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Stmt::CXXCatchStmtClass: {
|
|
|
|
const VarDecl *var =
|
|
|
|
cast<CXXCatchStmt>(stmt)->getExceptionDecl();
|
|
|
|
if (var)
|
|
|
|
DeclMap[var] = P;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
2010-09-21 13:58:15 +08:00
|
|
|
}
|
|
|
|
}
|
2007-09-01 05:30:12 +08:00
|
|
|
}
|
2010-09-16 09:25:47 +08:00
|
|
|
}
|
2007-08-22 05:42:03 +08:00
|
|
|
}
|
2011-03-01 11:15:10 +08:00
|
|
|
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
virtual ~StmtPrinterHelper() {}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-06-30 09:26:17 +08:00
|
|
|
const LangOptions &getLangOpts() const { return LangOpts; }
|
2010-12-17 12:44:39 +08:00
|
|
|
void setBlockID(signed i) { currentBlock = i; }
|
2012-08-22 14:26:15 +08:00
|
|
|
void setStmtID(unsigned i) { currStmt = i; }
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
virtual bool handledStmt(Stmt *S, raw_ostream &OS) {
|
2010-09-21 13:58:15 +08:00
|
|
|
StmtMapTy::iterator I = StmtMap.find(S);
|
2007-08-22 05:42:03 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
if (I == StmtMap.end())
|
|
|
|
return false;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-12-17 12:44:39 +08:00
|
|
|
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
|
2012-08-22 14:26:15 +08:00
|
|
|
&& I->second.second == currStmt) {
|
2007-09-01 05:30:12 +08:00
|
|
|
return false;
|
2010-01-20 04:52:05 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-01-20 04:52:05 +08:00
|
|
|
OS << "[B" << I->second.first << "." << I->second.second << "]";
|
2007-09-01 06:26:13 +08:00
|
|
|
return true;
|
2007-09-01 05:30:12 +08:00
|
|
|
}
|
2010-09-21 13:58:15 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
bool handleDecl(const Decl *D, raw_ostream &OS) {
|
2010-09-21 13:58:15 +08:00
|
|
|
DeclMapTy::iterator I = DeclMap.find(D);
|
|
|
|
|
|
|
|
if (I == DeclMap.end())
|
|
|
|
return false;
|
|
|
|
|
2010-12-17 12:44:39 +08:00
|
|
|
if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock
|
2012-08-22 14:26:15 +08:00
|
|
|
&& I->second.second == currStmt) {
|
2010-09-21 13:58:15 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << "[B" << I->second.first << "." << I->second.second << "]";
|
|
|
|
return true;
|
|
|
|
}
|
2007-09-01 05:30:12 +08:00
|
|
|
};
|
2009-06-30 09:26:17 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2007-08-23 02:22:34 +08:00
|
|
|
|
2009-06-30 09:26:17 +08:00
|
|
|
namespace {
|
2009-11-28 14:07:30 +08:00
|
|
|
class CFGBlockTerminatorPrint
|
2008-01-09 02:15:10 +08:00
|
|
|
: public StmtVisitor<CFGBlockTerminatorPrint,void> {
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
raw_ostream &OS;
|
2007-09-01 05:30:12 +08:00
|
|
|
StmtPrinterHelper* Helper;
|
2009-05-30 04:38:28 +08:00
|
|
|
PrintingPolicy Policy;
|
2007-08-24 05:42:29 +08:00
|
|
|
public:
|
2011-08-13 07:37:29 +08:00
|
|
|
CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
|
2009-06-30 09:26:17 +08:00
|
|
|
const PrintingPolicy &Policy)
|
2009-05-30 04:38:28 +08:00
|
|
|
: OS(os), Helper(helper), Policy(Policy) {}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitIfStmt(IfStmt *I) {
|
2007-08-24 05:42:29 +08:00
|
|
|
OS << "if ";
|
2009-05-30 04:38:28 +08:00
|
|
|
I->getCond()->printPretty(OS,Helper,Policy);
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-24 05:42:29 +08:00
|
|
|
// Default case.
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitStmt(Stmt *Terminator) {
|
2009-07-17 09:31:16 +08:00
|
|
|
Terminator->printPretty(OS, Helper, Policy);
|
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitForStmt(ForStmt *F) {
|
2007-08-24 05:42:29 +08:00
|
|
|
OS << "for (" ;
|
2010-01-20 04:52:05 +08:00
|
|
|
if (F->getInit())
|
|
|
|
OS << "...";
|
2007-08-31 05:28:02 +08:00
|
|
|
OS << "; ";
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *C = F->getCond())
|
2010-01-20 04:52:05 +08:00
|
|
|
C->printPretty(OS, Helper, Policy);
|
2007-08-31 05:28:02 +08:00
|
|
|
OS << "; ";
|
2010-01-20 04:52:05 +08:00
|
|
|
if (F->getInc())
|
|
|
|
OS << "...";
|
2008-01-31 07:02:42 +08:00
|
|
|
OS << ")";
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitWhileStmt(WhileStmt *W) {
|
2007-08-24 05:42:29 +08:00
|
|
|
OS << "while " ;
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *C = W->getCond())
|
2010-01-20 04:52:05 +08:00
|
|
|
C->printPretty(OS, Helper, Policy);
|
2007-08-24 05:42:29 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitDoStmt(DoStmt *D) {
|
2007-08-24 05:42:29 +08:00
|
|
|
OS << "do ... while ";
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *C = D->getCond())
|
2010-01-20 04:52:05 +08:00
|
|
|
C->printPretty(OS, Helper, Policy);
|
2007-08-28 05:27:44 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitSwitchStmt(SwitchStmt *Terminator) {
|
2007-08-28 05:27:44 +08:00
|
|
|
OS << "switch ";
|
2009-05-30 04:38:28 +08:00
|
|
|
Terminator->getCond()->printPretty(OS, Helper, Policy);
|
2007-08-28 05:27:44 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitCXXTryStmt(CXXTryStmt *CS) {
|
2010-01-19 10:20:09 +08:00
|
|
|
OS << "try ...";
|
|
|
|
}
|
|
|
|
|
2011-02-17 18:25:35 +08:00
|
|
|
void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) {
|
2009-05-30 04:38:28 +08:00
|
|
|
C->getCond()->printPretty(OS, Helper, Policy);
|
2009-07-17 09:31:16 +08:00
|
|
|
OS << " ? ... : ...";
|
2007-09-01 05:49:40 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitChooseExpr(ChooseExpr *C) {
|
2007-09-01 06:29:13 +08:00
|
|
|
OS << "__builtin_choose_expr( ";
|
2009-05-30 04:38:28 +08:00
|
|
|
C->getCond()->printPretty(OS, Helper, Policy);
|
2008-01-31 07:02:42 +08:00
|
|
|
OS << " )";
|
2007-09-01 06:29:13 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitIndirectGotoStmt(IndirectGotoStmt *I) {
|
2007-09-01 06:26:13 +08:00
|
|
|
OS << "goto *";
|
2009-05-30 04:38:28 +08:00
|
|
|
I->getTarget()->printPretty(OS, Helper, Policy);
|
2007-09-01 06:26:13 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:49:40 +08:00
|
|
|
void VisitBinaryOperator(BinaryOperator* B) {
|
|
|
|
if (!B->isLogicalOp()) {
|
|
|
|
VisitExpr(B);
|
|
|
|
return;
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2009-05-30 04:38:28 +08:00
|
|
|
B->getLHS()->printPretty(OS, Helper, Policy);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:49:40 +08:00
|
|
|
switch (B->getOpcode()) {
|
2010-08-25 19:45:40 +08:00
|
|
|
case BO_LOr:
|
2008-01-31 07:02:42 +08:00
|
|
|
OS << " || ...";
|
2007-09-01 05:49:40 +08:00
|
|
|
return;
|
2010-08-25 19:45:40 +08:00
|
|
|
case BO_LAnd:
|
2008-01-31 07:02:42 +08:00
|
|
|
OS << " && ...";
|
2007-09-01 05:49:40 +08:00
|
|
|
return;
|
|
|
|
default:
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Invalid logical operator.");
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
2007-09-01 05:49:40 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
void VisitExpr(Expr *E) {
|
2009-05-30 04:38:28 +08:00
|
|
|
E->printPretty(OS, Helper, Policy);
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
2007-08-24 05:42:29 +08:00
|
|
|
};
|
2009-06-30 09:26:17 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
|
2010-01-20 06:00:14 +08:00
|
|
|
const CFGElement &E) {
|
2011-03-01 11:15:10 +08:00
|
|
|
if (const CFGStmt *CS = E.getAs<CFGStmt>()) {
|
2011-08-24 07:05:04 +08:00
|
|
|
const Stmt *S = CS->getStmt();
|
2010-09-21 13:58:15 +08:00
|
|
|
|
|
|
|
if (Helper) {
|
|
|
|
|
|
|
|
// special printing for statement-expressions.
|
2011-08-24 07:05:04 +08:00
|
|
|
if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
|
|
|
|
const CompoundStmt *Sub = SE->getSubStmt();
|
2010-09-21 13:58:15 +08:00
|
|
|
|
2011-02-13 12:07:26 +08:00
|
|
|
if (Sub->children()) {
|
2010-09-21 13:58:15 +08:00
|
|
|
OS << "({ ... ; ";
|
|
|
|
Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS);
|
|
|
|
OS << " })\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// special printing for comma expressions.
|
2011-08-24 07:05:04 +08:00
|
|
|
if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
|
2010-09-21 13:58:15 +08:00
|
|
|
if (B->getOpcode() == BO_Comma) {
|
|
|
|
OS << "... , ";
|
|
|
|
Helper->handledStmt(B->getRHS(),OS);
|
|
|
|
OS << '\n';
|
|
|
|
return;
|
|
|
|
}
|
2007-09-01 06:26:13 +08:00
|
|
|
}
|
|
|
|
}
|
2010-09-21 13:58:15 +08:00
|
|
|
S->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts()));
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-21 13:58:15 +08:00
|
|
|
if (isa<CXXOperatorCallExpr>(S)) {
|
2010-11-23 03:32:14 +08:00
|
|
|
OS << " (OperatorCall)";
|
2011-12-22 03:32:38 +08:00
|
|
|
}
|
|
|
|
else if (isa<CXXBindTemporaryExpr>(S)) {
|
2010-11-23 03:32:14 +08:00
|
|
|
OS << " (BindTemporary)";
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
2011-12-22 03:39:59 +08:00
|
|
|
else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
|
|
|
|
OS << " (CXXConstructExpr, " << CCE->getType().getAsString() << ")";
|
|
|
|
}
|
2011-12-22 03:32:38 +08:00
|
|
|
else if (const CastExpr *CE = dyn_cast<CastExpr>(S)) {
|
|
|
|
OS << " (" << CE->getStmtClassName() << ", "
|
|
|
|
<< CE->getCastKindName()
|
|
|
|
<< ", " << CE->getType().getAsString()
|
|
|
|
<< ")";
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-21 13:58:15 +08:00
|
|
|
// Expressions need a newline.
|
|
|
|
if (isa<Expr>(S))
|
|
|
|
OS << '\n';
|
2010-09-01 02:47:37 +08:00
|
|
|
|
2011-03-01 11:15:10 +08:00
|
|
|
} else if (const CFGInitializer *IE = E.getAs<CFGInitializer>()) {
|
|
|
|
const CXXCtorInitializer *I = IE->getInitializer();
|
2010-09-21 13:58:15 +08:00
|
|
|
if (I->isBaseInitializer())
|
|
|
|
OS << I->getBaseClass()->getAsCXXRecordDecl()->getName();
|
2010-12-04 17:14:42 +08:00
|
|
|
else OS << I->getAnyMember()->getName();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2010-09-21 13:58:15 +08:00
|
|
|
OS << "(";
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Expr *IE = I->getInit())
|
2010-09-21 13:58:15 +08:00
|
|
|
IE->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts()));
|
|
|
|
OS << ")";
|
|
|
|
|
|
|
|
if (I->isBaseInitializer())
|
|
|
|
OS << " (Base initializer)\n";
|
|
|
|
else OS << " (Member initializer)\n";
|
|
|
|
|
2011-03-01 11:15:10 +08:00
|
|
|
} else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){
|
2011-08-13 07:37:29 +08:00
|
|
|
const VarDecl *VD = DE->getVarDecl();
|
2010-09-21 13:58:15 +08:00
|
|
|
Helper->handleDecl(VD, OS);
|
|
|
|
|
2010-10-25 15:00:40 +08:00
|
|
|
const Type* T = VD->getType().getTypePtr();
|
2010-09-21 13:58:15 +08:00
|
|
|
if (const ReferenceType* RT = T->getAs<ReferenceType>())
|
|
|
|
T = RT->getPointeeType().getTypePtr();
|
2012-07-25 05:02:14 +08:00
|
|
|
T = T->getBaseElementTypeUnsafe();
|
2010-09-21 13:58:15 +08:00
|
|
|
|
|
|
|
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
|
|
|
|
OS << " (Implicit destructor)\n";
|
2010-10-05 13:37:00 +08:00
|
|
|
|
2011-03-01 11:15:10 +08:00
|
|
|
} else if (const CFGBaseDtor *BE = E.getAs<CFGBaseDtor>()) {
|
|
|
|
const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
|
2010-10-05 13:37:00 +08:00
|
|
|
OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
|
2010-10-05 16:38:06 +08:00
|
|
|
OS << " (Base object destructor)\n";
|
2010-10-05 13:37:00 +08:00
|
|
|
|
2011-03-01 11:15:10 +08:00
|
|
|
} else if (const CFGMemberDtor *ME = E.getAs<CFGMemberDtor>()) {
|
|
|
|
const FieldDecl *FD = ME->getFieldDecl();
|
2012-07-25 05:02:14 +08:00
|
|
|
const Type *T = FD->getType()->getBaseElementTypeUnsafe();
|
2010-10-05 13:37:00 +08:00
|
|
|
OS << "this->" << FD->getName();
|
2010-10-25 15:05:54 +08:00
|
|
|
OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()";
|
2010-10-05 16:38:06 +08:00
|
|
|
OS << " (Member object destructor)\n";
|
2010-11-03 14:19:35 +08:00
|
|
|
|
2011-03-01 11:15:10 +08:00
|
|
|
} else if (const CFGTemporaryDtor *TE = E.getAs<CFGTemporaryDtor>()) {
|
|
|
|
const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
|
2010-11-03 14:19:35 +08:00
|
|
|
OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()";
|
|
|
|
OS << " (Temporary object destructor)\n";
|
2010-09-21 13:58:15 +08:00
|
|
|
}
|
2010-11-01 14:46:05 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
static void print_block(raw_ostream &OS, const CFG* cfg,
|
|
|
|
const CFGBlock &B,
|
2011-12-23 07:33:52 +08:00
|
|
|
StmtPrinterHelper* Helper, bool print_edges,
|
|
|
|
bool ShowColors) {
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-12-23 07:33:52 +08:00
|
|
|
if (Helper)
|
|
|
|
Helper->setBlockID(B.getBlockID());
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 05:56:09 +08:00
|
|
|
// Print the header.
|
2011-12-23 07:33:52 +08:00
|
|
|
if (ShowColors)
|
|
|
|
OS.changeColor(raw_ostream::YELLOW, true);
|
|
|
|
|
|
|
|
OS << "\n [B" << B.getBlockID();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
if (&B == &cfg->getEntry())
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << " (ENTRY)]\n";
|
2007-09-01 05:30:12 +08:00
|
|
|
else if (&B == &cfg->getExit())
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << " (EXIT)]\n";
|
2007-09-01 05:30:12 +08:00
|
|
|
else if (&B == cfg->getIndirectGotoBlock())
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << " (INDIRECT GOTO DISPATCH)]\n";
|
2007-09-01 05:30:12 +08:00
|
|
|
else
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << "]\n";
|
|
|
|
|
|
|
|
if (ShowColors)
|
|
|
|
OS.resetColor();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 07:20:49 +08:00
|
|
|
// Print the label of this block.
|
2011-08-13 07:37:29 +08:00
|
|
|
if (Stmt *Label = const_cast<Stmt*>(B.getLabel())) {
|
2007-09-01 05:30:12 +08:00
|
|
|
|
|
|
|
if (print_edges)
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << " ";
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
if (LabelStmt *L = dyn_cast<LabelStmt>(Label))
|
2007-08-30 07:20:49 +08:00
|
|
|
OS << L->getName();
|
2011-08-13 07:37:29 +08:00
|
|
|
else if (CaseStmt *C = dyn_cast<CaseStmt>(Label)) {
|
2007-08-30 07:20:49 +08:00
|
|
|
OS << "case ";
|
2009-06-30 09:26:17 +08:00
|
|
|
C->getLHS()->printPretty(OS, Helper,
|
|
|
|
PrintingPolicy(Helper->getLangOpts()));
|
2007-08-30 07:20:49 +08:00
|
|
|
if (C->getRHS()) {
|
|
|
|
OS << " ... ";
|
2009-06-30 09:26:17 +08:00
|
|
|
C->getRHS()->printPretty(OS, Helper,
|
|
|
|
PrintingPolicy(Helper->getLangOpts()));
|
2007-08-30 07:20:49 +08:00
|
|
|
}
|
2010-01-20 06:00:14 +08:00
|
|
|
} else if (isa<DefaultStmt>(Label))
|
2007-08-30 07:20:49 +08:00
|
|
|
OS << "default";
|
2010-01-20 06:00:14 +08:00
|
|
|
else if (CXXCatchStmt *CS = dyn_cast<CXXCatchStmt>(Label)) {
|
2010-01-19 10:20:09 +08:00
|
|
|
OS << "catch (";
|
2010-01-20 09:15:34 +08:00
|
|
|
if (CS->getExceptionDecl())
|
|
|
|
CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper->getLangOpts()),
|
|
|
|
0);
|
|
|
|
else
|
|
|
|
OS << "...";
|
2010-01-19 10:20:09 +08:00
|
|
|
OS << ")";
|
|
|
|
|
|
|
|
} else
|
2011-09-23 13:06:16 +08:00
|
|
|
llvm_unreachable("Invalid label statement in CFGBlock.");
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 07:20:49 +08:00
|
|
|
OS << ":\n";
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-22 05:42:03 +08:00
|
|
|
// Iterate through the statements in the block and print them.
|
|
|
|
unsigned j = 1;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
for (CFGBlock::const_iterator I = B.begin(), E = B.end() ;
|
|
|
|
I != E ; ++I, ++j ) {
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 07:20:49 +08:00
|
|
|
// Print the statement # in the basic block and the statement itself.
|
2007-09-01 05:30:12 +08:00
|
|
|
if (print_edges)
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << " ";
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-09-13 13:16:45 +08:00
|
|
|
OS << llvm::format("%3d", j) << ": ";
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
if (Helper)
|
|
|
|
Helper->setStmtID(j);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-12-23 07:33:52 +08:00
|
|
|
print_elem(OS, Helper, *I);
|
2007-08-22 05:42:03 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 07:20:49 +08:00
|
|
|
// Print the terminator of this block.
|
2007-09-01 05:30:12 +08:00
|
|
|
if (B.getTerminator()) {
|
2011-12-23 07:33:52 +08:00
|
|
|
if (ShowColors)
|
|
|
|
OS.changeColor(raw_ostream::GREEN);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << " T: ";
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
if (Helper) Helper->setBlockID(-1);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2012-10-13 06:56:31 +08:00
|
|
|
PrintingPolicy PP(Helper ? Helper->getLangOpts() : LangOptions());
|
|
|
|
CFGBlockTerminatorPrint TPrinter(OS, Helper, PP);
|
2010-10-29 13:21:47 +08:00
|
|
|
TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt()));
|
2008-01-31 07:02:42 +08:00
|
|
|
OS << '\n';
|
2011-12-23 07:33:52 +08:00
|
|
|
|
|
|
|
if (ShowColors)
|
|
|
|
OS.resetColor();
|
2007-08-22 05:42:03 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 07:20:49 +08:00
|
|
|
if (print_edges) {
|
|
|
|
// Print the predecessors of this block.
|
2011-12-23 07:33:52 +08:00
|
|
|
if (!B.pred_empty()) {
|
|
|
|
const raw_ostream::Colors Color = raw_ostream::BLUE;
|
|
|
|
if (ShowColors)
|
|
|
|
OS.changeColor(Color);
|
|
|
|
OS << " Preds " ;
|
|
|
|
if (ShowColors)
|
|
|
|
OS.resetColor();
|
|
|
|
OS << '(' << B.pred_size() << "):";
|
|
|
|
unsigned i = 0;
|
|
|
|
|
|
|
|
if (ShowColors)
|
|
|
|
OS.changeColor(Color);
|
|
|
|
|
|
|
|
for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
|
|
|
|
I != E; ++I, ++i) {
|
2007-09-01 05:30:12 +08:00
|
|
|
|
2011-12-23 07:33:52 +08:00
|
|
|
if (i == 8 || (i-8) == 0)
|
|
|
|
OS << "\n ";
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << " B" << (*I)->getBlockID();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ShowColors)
|
|
|
|
OS.resetColor();
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-12-23 07:33:52 +08:00
|
|
|
OS << '\n';
|
2007-08-30 07:20:49 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 07:20:49 +08:00
|
|
|
// Print the successors of this block.
|
2011-12-23 07:33:52 +08:00
|
|
|
if (!B.succ_empty()) {
|
|
|
|
const raw_ostream::Colors Color = raw_ostream::MAGENTA;
|
|
|
|
if (ShowColors)
|
|
|
|
OS.changeColor(Color);
|
|
|
|
OS << " Succs ";
|
|
|
|
if (ShowColors)
|
|
|
|
OS.resetColor();
|
|
|
|
OS << '(' << B.succ_size() << "):";
|
|
|
|
unsigned i = 0;
|
|
|
|
|
|
|
|
if (ShowColors)
|
|
|
|
OS.changeColor(Color);
|
|
|
|
|
|
|
|
for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
|
|
|
|
I != E; ++I, ++i) {
|
|
|
|
|
|
|
|
if (i == 8 || (i-8) % 10 == 0)
|
|
|
|
OS << "\n ";
|
|
|
|
|
|
|
|
if (*I)
|
|
|
|
OS << " B" << (*I)->getBlockID();
|
|
|
|
else
|
|
|
|
OS << " NULL";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ShowColors)
|
|
|
|
OS.resetColor();
|
|
|
|
OS << '\n';
|
2007-08-22 05:42:03 +08:00
|
|
|
}
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
2007-09-01 05:30:12 +08:00
|
|
|
|
|
|
|
|
|
|
|
/// dump - A simple pretty printer of a CFG that outputs to stderr.
|
2011-12-23 07:33:52 +08:00
|
|
|
void CFG::dump(const LangOptions &LO, bool ShowColors) const {
|
|
|
|
print(llvm::errs(), LO, ShowColors);
|
|
|
|
}
|
2007-09-01 05:30:12 +08:00
|
|
|
|
|
|
|
/// print - A simple pretty printer of a CFG that outputs to an ostream.
|
2011-12-23 07:33:52 +08:00
|
|
|
void CFG::print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const {
|
2009-06-30 09:26:17 +08:00
|
|
|
StmtPrinterHelper Helper(this, LO);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
// Print the entry block.
|
2011-12-23 07:33:52 +08:00
|
|
|
print_block(OS, this, getEntry(), &Helper, true, ShowColors);
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
// Iterate through the CFGBlocks and print them one by one.
|
|
|
|
for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
|
|
|
|
// Skip the entry block, because we already printed it.
|
2009-10-13 04:55:07 +08:00
|
|
|
if (&(**I) == &getEntry() || &(**I) == &getExit())
|
2007-09-01 05:30:12 +08:00
|
|
|
continue;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-12-23 07:33:52 +08:00
|
|
|
print_block(OS, this, **I, &Helper, true, ShowColors);
|
2007-09-01 05:30:12 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
// Print the exit block.
|
2011-12-23 07:33:52 +08:00
|
|
|
print_block(OS, this, getExit(), &Helper, true, ShowColors);
|
|
|
|
OS << '\n';
|
2008-11-25 04:50:24 +08:00
|
|
|
OS.flush();
|
2009-07-17 09:31:16 +08:00
|
|
|
}
|
2007-09-01 05:30:12 +08:00
|
|
|
|
|
|
|
/// dump - A simply pretty printer of a CFGBlock that outputs to stderr.
|
2011-12-23 07:33:52 +08:00
|
|
|
void CFGBlock::dump(const CFG* cfg, const LangOptions &LO,
|
|
|
|
bool ShowColors) const {
|
|
|
|
print(llvm::errs(), cfg, LO, ShowColors);
|
2009-06-30 09:26:17 +08:00
|
|
|
}
|
2007-09-01 05:30:12 +08:00
|
|
|
|
|
|
|
/// print - A simple pretty printer of a CFGBlock that outputs to an ostream.
|
|
|
|
/// Generally this will only be called from CFG::print.
|
2011-08-13 07:37:29 +08:00
|
|
|
void CFGBlock::print(raw_ostream &OS, const CFG* cfg,
|
2011-12-23 07:33:52 +08:00
|
|
|
const LangOptions &LO, bool ShowColors) const {
|
2009-06-30 09:26:17 +08:00
|
|
|
StmtPrinterHelper Helper(cfg, LO);
|
2011-12-23 07:33:52 +08:00
|
|
|
print_block(OS, cfg, *this, &Helper, true, ShowColors);
|
|
|
|
OS << '\n';
|
2007-08-24 00:51:22 +08:00
|
|
|
}
|
2007-08-30 05:56:09 +08:00
|
|
|
|
2008-01-31 07:02:42 +08:00
|
|
|
/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
|
2011-07-23 18:55:15 +08:00
|
|
|
void CFGBlock::printTerminator(raw_ostream &OS,
|
2009-07-17 09:31:16 +08:00
|
|
|
const LangOptions &LO) const {
|
2009-06-30 09:26:17 +08:00
|
|
|
CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO));
|
2010-10-29 13:21:47 +08:00
|
|
|
TPrinter.Visit(const_cast<Stmt*>(getTerminator().getStmt()));
|
2008-01-31 07:02:42 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
Stmt *CFGBlock::getTerminatorCondition() {
|
2010-10-29 13:21:47 +08:00
|
|
|
Stmt *Terminator = this->Terminator;
|
2008-04-17 05:10:48 +08:00
|
|
|
if (!Terminator)
|
|
|
|
return NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
Expr *E = NULL;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
switch (Terminator->getStmtClass()) {
|
|
|
|
default:
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::ForStmtClass:
|
|
|
|
E = cast<ForStmt>(Terminator)->getCond();
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::WhileStmtClass:
|
|
|
|
E = cast<WhileStmt>(Terminator)->getCond();
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::DoStmtClass:
|
|
|
|
E = cast<DoStmt>(Terminator)->getCond();
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::IfStmtClass:
|
|
|
|
E = cast<IfStmt>(Terminator)->getCond();
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::ChooseExprClass:
|
|
|
|
E = cast<ChooseExpr>(Terminator)->getCond();
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::IndirectGotoStmtClass:
|
|
|
|
E = cast<IndirectGotoStmt>(Terminator)->getTarget();
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::SwitchStmtClass:
|
|
|
|
E = cast<SwitchStmt>(Terminator)->getCond();
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2011-02-17 18:25:35 +08:00
|
|
|
case Stmt::BinaryConditionalOperatorClass:
|
|
|
|
E = cast<BinaryConditionalOperator>(Terminator)->getCond();
|
|
|
|
break;
|
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::ConditionalOperatorClass:
|
|
|
|
E = cast<ConditionalOperator>(Terminator)->getCond();
|
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
case Stmt::BinaryOperatorClass: // '&&' and '||'
|
|
|
|
E = cast<BinaryOperator>(Terminator)->getLHS();
|
2008-11-13 05:11:49 +08:00
|
|
|
break;
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-11-13 05:11:49 +08:00
|
|
|
case Stmt::ObjCForCollectionStmtClass:
|
2009-07-17 09:31:16 +08:00
|
|
|
return Terminator;
|
2008-04-17 05:10:48 +08:00
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2008-04-17 05:10:48 +08:00
|
|
|
return E ? E->IgnoreParens() : NULL;
|
|
|
|
}
|
|
|
|
|
2007-08-30 05:56:09 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// CFG Graphviz Visualization
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2007-09-01 05:30:12 +08:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2009-07-17 09:31:16 +08:00
|
|
|
static StmtPrinterHelper* GraphHelper;
|
2007-09-01 05:30:12 +08:00
|
|
|
#endif
|
|
|
|
|
2009-06-30 09:26:17 +08:00
|
|
|
void CFG::viewCFG(const LangOptions &LO) const {
|
2007-09-01 05:30:12 +08:00
|
|
|
#ifndef NDEBUG
|
2009-06-30 09:26:17 +08:00
|
|
|
StmtPrinterHelper H(this, LO);
|
2007-09-01 05:30:12 +08:00
|
|
|
GraphHelper = &H;
|
|
|
|
llvm::ViewGraph(this,"CFG");
|
|
|
|
GraphHelper = NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-08-30 05:56:09 +08:00
|
|
|
namespace llvm {
|
|
|
|
template<>
|
|
|
|
struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
|
2009-11-30 22:16:05 +08:00
|
|
|
|
|
|
|
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
static std::string getNodeLabel(const CFGBlock *Node, const CFG* Graph) {
|
2007-08-30 05:56:09 +08:00
|
|
|
|
2007-09-16 08:28:28 +08:00
|
|
|
#ifndef NDEBUG
|
2008-09-13 13:16:45 +08:00
|
|
|
std::string OutSStr;
|
|
|
|
llvm::raw_string_ostream Out(OutSStr);
|
2011-12-23 07:33:52 +08:00
|
|
|
print_block(Out,Graph, *Node, GraphHelper, false, false);
|
2008-09-13 13:16:45 +08:00
|
|
|
std::string& OutStr = Out.str();
|
2007-08-30 05:56:09 +08:00
|
|
|
|
|
|
|
if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
|
|
|
|
|
|
|
|
// Process string output to make it nicer...
|
|
|
|
for (unsigned i = 0; i != OutStr.length(); ++i)
|
|
|
|
if (OutStr[i] == '\n') { // Left justify
|
|
|
|
OutStr[i] = '\\';
|
|
|
|
OutStr.insert(OutStr.begin()+i+1, 'l');
|
|
|
|
}
|
2009-07-17 09:31:16 +08:00
|
|
|
|
2007-08-30 05:56:09 +08:00
|
|
|
return OutStr;
|
2007-09-16 08:28:28 +08:00
|
|
|
#else
|
|
|
|
return "";
|
|
|
|
#endif
|
2007-08-30 05:56:09 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end namespace llvm
|