Update Clang for 3.5 rebase (r209713).
Change-Id: I8c9133b0f8f776dc915f270b60f94962e771bc83
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index c90d947..90d4b13 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -41,11 +41,11 @@
: Manager(Mgr),
D(d),
cfgBuildOptions(buildOptions),
- forcedBlkExprs(0),
+ forcedBlkExprs(nullptr),
builtCFG(false),
builtCompleteCFG(false),
- ReferencedBlockVars(0),
- ManagedAnalyses(0)
+ ReferencedBlockVars(nullptr),
+ ManagedAnalyses(nullptr)
{
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
@@ -54,11 +54,11 @@
const Decl *d)
: Manager(Mgr),
D(d),
- forcedBlkExprs(0),
+ forcedBlkExprs(nullptr),
builtCFG(false),
builtCompleteCFG(false),
- ReferencedBlockVars(0),
- ManagedAnalyses(0)
+ ReferencedBlockVars(nullptr),
+ ManagedAnalyses(nullptr)
{
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
@@ -140,7 +140,7 @@
}
}
- return NULL;
+ return nullptr;
}
void AnalysisDeclContext::registerForcedBlockExpression(const Stmt *stmt) {
@@ -189,6 +189,9 @@
if (PM)
addParentsForSyntheticStmts(cfg.get(), *PM);
+
+ // The Observer should only observe one build of the CFG.
+ getCFGBuildOptions().Observer = nullptr;
}
return cfg.get();
}
@@ -205,6 +208,9 @@
if (PM)
addParentsForSyntheticStmts(completeCFG.get(), *PM);
+
+ // The Observer should only observe one build of the CFG.
+ getCFGBuildOptions().Observer = nullptr;
}
return completeCFG.get();
}
@@ -217,8 +223,8 @@
cfgStmtMap.reset(CFGStmtMap::Build(c, &getParentMap()));
return cfgStmtMap.get();
}
-
- return 0;
+
+ return nullptr;
}
CFGReverseBlockReachabilityAnalysis *AnalysisDeclContext::getCFGReachablityAnalysis() {
@@ -229,8 +235,8 @@
CFA.reset(new CFGReverseBlockReachabilityAnalysis(*c));
return CFA.get();
}
-
- return 0;
+
+ return nullptr;
}
void AnalysisDeclContext::dumpCFG(bool ShowColors) {
@@ -395,7 +401,7 @@
return SFC;
LC = LC->getParent();
}
- return NULL;
+ return nullptr;
}
bool LocationContext::inTopFrame() const {
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 039911e..316a18b 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -128,20 +128,20 @@
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
- const_cast<Expr*>(Arg), 0, VK_RValue);
+ const_cast<Expr*>(Arg), nullptr, VK_RValue);
}
Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
if (Arg->getType() == Ty)
return const_cast<Expr*>(Arg);
-
+
return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
- const_cast<Expr*>(Arg), 0, VK_RValue);
+ const_cast<Expr*>(Arg), nullptr, VK_RValue);
}
ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
- const_cast<Expr*>(Arg), 0, VK_RValue);
+ const_cast<Expr*>(Arg), nullptr, VK_RValue);
}
ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
@@ -159,7 +159,8 @@
ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
- return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0);
+ return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal),
+ nullptr);
}
//===----------------------------------------------------------------------===//
@@ -172,24 +173,24 @@
static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
// Check if we have at least two parameters.
if (D->param_size() != 2)
- return 0;
+ return nullptr;
// Check if the first parameter is a pointer to integer type.
const ParmVarDecl *Predicate = D->getParamDecl(0);
QualType PredicateQPtrTy = Predicate->getType();
const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
if (!PredicatePtrTy)
- return 0;
+ return nullptr;
QualType PredicateTy = PredicatePtrTy->getPointeeType();
if (!PredicateTy->isIntegerType())
- return 0;
-
+ return nullptr;
+
// Check if the second parameter is the proper block type.
const ParmVarDecl *Block = D->getParamDecl(1);
QualType Ty = Block->getType();
if (!isDispatchBlock(Ty))
- return 0;
-
+ return nullptr;
+
// Everything checks out. Create a fakse body that checks the predicate,
// sets it, and calls the block. Basically, an AST dump of:
//
@@ -242,7 +243,7 @@
SourceLocation());
// (5) Create the 'if' statement.
- IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
+ IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, CS);
return If;
}
@@ -250,14 +251,14 @@
static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
// Check if we have at least two parameters.
if (D->param_size() != 2)
- return 0;
-
+ return nullptr;
+
// Check if the second parameter is a block.
const ParmVarDecl *PV = D->getParamDecl(1);
QualType Ty = PV->getType();
if (!isDispatchBlock(Ty))
- return 0;
-
+ return nullptr;
+
// Everything checks out. Create a fake body that just calls the block.
// This is basically just an AST dump of:
//
@@ -277,8 +278,8 @@
{
// There are exactly 3 arguments.
if (D->param_size() != 3)
- return 0;
-
+ return nullptr;
+
// Signature:
// _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
// void *__newValue,
@@ -293,8 +294,8 @@
QualType ResultTy = D->getReturnType();
bool isBoolean = ResultTy->isBooleanType();
if (!isBoolean && !ResultTy->isIntegralType(C))
- return 0;
-
+ return nullptr;
+
const ParmVarDecl *OldValue = D->getParamDecl(0);
QualType OldValueTy = OldValue->getType();
@@ -307,7 +308,7 @@
QualType TheValueTy = TheValue->getType();
const PointerType *PT = TheValueTy->getAs<PointerType>();
if (!PT)
- return 0;
+ return nullptr;
QualType PointeeTy = PT->getPointeeType();
ASTMaker M(C);
@@ -346,9 +347,9 @@
/// Construct the If.
Stmt *If =
- new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body,
+ new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, Body,
SourceLocation(), Else);
-
+
return If;
}
@@ -358,15 +359,15 @@
Optional<Stmt *> &Val = Bodies[D];
if (Val.hasValue())
return Val.getValue();
-
- Val = 0;
-
- if (D->getIdentifier() == 0)
- return 0;
+
+ Val = nullptr;
+
+ if (D->getIdentifier() == nullptr)
+ return nullptr;
StringRef Name = D->getName();
if (Name.empty())
- return 0;
+ return nullptr;
FunctionFarmer FF;
@@ -378,7 +379,7 @@
FF = llvm::StringSwitch<FunctionFarmer>(Name)
.Case("dispatch_sync", create_dispatch_sync)
.Case("dispatch_once", create_dispatch_once)
- .Default(NULL);
+ .Default(nullptr);
}
if (FF) { Val = FF(C, D); }
@@ -390,11 +391,11 @@
// First, find the backing ivar.
const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
if (!IVar)
- return 0;
+ return nullptr;
// Ignore weak variables, which have special behavior.
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
- return 0;
+ return nullptr;
// Look to see if Sema has synthesized a body for us. This happens in
// Objective-C++ because the return value may be a C++ class type with a
@@ -420,10 +421,10 @@
// copyable.
if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
Prop->getType().getNonReferenceType()))
- return 0;
+ return nullptr;
if (!IVar->getType()->isObjCLifetimeType() &&
!IVar->getType().isTriviallyCopyableType(Ctx))
- return 0;
+ return nullptr;
// Generate our body:
// return self->_ivar;
@@ -447,22 +448,22 @@
Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
// We currently only know how to synthesize property accessors.
if (!D->isPropertyAccessor())
- return 0;
+ return nullptr;
D = D->getCanonicalDecl();
Optional<Stmt *> &Val = Bodies[D];
if (Val.hasValue())
return Val.getValue();
- Val = 0;
+ Val = nullptr;
const ObjCPropertyDecl *Prop = D->findPropertyDecl();
if (!Prop)
- return 0;
+ return nullptr;
// For now, we only synthesize getters.
if (D->param_size() != 0)
- return 0;
+ return nullptr;
Val = createObjCPropertyGetter(C, Prop);
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 400c202..5d2926c 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -112,7 +112,7 @@
/// Incrementing invalid iterator is allowed and will result in invalid
/// iterator.
const_iterator()
- : Scope(NULL), VarIter(0) {}
+ : Scope(nullptr), 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.
@@ -207,7 +207,7 @@
/// build process. It consists of CFGBlock that specifies position in CFG graph
/// and LocalScope::const_iterator that specifies position in LocalScope graph.
struct BlockScopePosPair {
- BlockScopePosPair() : block(0) {}
+ BlockScopePosPair() : block(nullptr) {}
BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos)
: block(b), scopePosition(scopePos) {}
@@ -336,11 +336,11 @@
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),
- switchExclusivelyCovered(false), switchCond(0),
- cachedEntry(0), lastLookup(0) {}
+ Block(nullptr), Succ(nullptr),
+ SwitchTerminatedBlock(nullptr), DefaultCaseBlock(nullptr),
+ TryTerminatedBlock(nullptr), badCFG(false), BuildOpts(buildOpts),
+ switchExclusivelyCovered(false), switchCond(nullptr),
+ cachedEntry(nullptr), lastLookup(nullptr) {}
// buildCFG - Used by external clients to construct the CFG.
CFG* buildCFG(const Decl *D, Stmt *Statement);
@@ -443,8 +443,9 @@
LocalScope* createOrReuseLocalScope(LocalScope* Scope);
void addLocalScopeForStmt(Stmt *S);
- LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope = NULL);
- LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = NULL);
+ LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS,
+ LocalScope* Scope = nullptr);
+ LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = nullptr);
void addLocalScopeAndDtors(Stmt *S);
@@ -495,6 +496,242 @@
cfg->getBumpVectorContext());
}
+ /// \brief Find a relational comparison with an expression evaluating to a
+ /// boolean and a constant other than 0 and 1.
+ /// e.g. if ((x < y) == 10)
+ TryResult checkIncorrectRelationalOperator(const BinaryOperator *B) {
+ const Expr *LHSExpr = B->getLHS()->IgnoreParens();
+ const Expr *RHSExpr = B->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
+ const Expr *BoolExpr = RHSExpr;
+ bool IntFirst = true;
+ if (!IntLiteral) {
+ IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
+ BoolExpr = LHSExpr;
+ IntFirst = false;
+ }
+
+ if (!IntLiteral || !BoolExpr->isKnownToHaveBooleanValue())
+ return TryResult();
+
+ llvm::APInt IntValue = IntLiteral->getValue();
+ if ((IntValue == 1) || (IntValue == 0))
+ return TryResult();
+
+ bool IntLarger = IntLiteral->getType()->isUnsignedIntegerType() ||
+ !IntValue.isNegative();
+
+ BinaryOperatorKind Bok = B->getOpcode();
+ if (Bok == BO_GT || Bok == BO_GE) {
+ // Always true for 10 > bool and bool > -1
+ // Always false for -1 > bool and bool > 10
+ return TryResult(IntFirst == IntLarger);
+ } else {
+ // Always true for -1 < bool and bool < 10
+ // Always false for 10 < bool and bool < -1
+ return TryResult(IntFirst != IntLarger);
+ }
+ }
+
+ /// Find an incorrect equality comparison. Either with an expression
+ /// evaluating to a boolean and a constant other than 0 and 1.
+ /// e.g. if (!x == 10) or a bitwise and/or operation that always evaluates to
+ /// true/false e.q. (x & 8) == 4.
+ TryResult checkIncorrectEqualityOperator(const BinaryOperator *B) {
+ const Expr *LHSExpr = B->getLHS()->IgnoreParens();
+ const Expr *RHSExpr = B->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
+ const Expr *BoolExpr = RHSExpr;
+
+ if (!IntLiteral) {
+ IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
+ BoolExpr = LHSExpr;
+ }
+
+ if (!IntLiteral)
+ return TryResult();
+
+ const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
+ if (BitOp && (BitOp->getOpcode() == BO_And ||
+ BitOp->getOpcode() == BO_Or)) {
+ const Expr *LHSExpr2 = BitOp->getLHS()->IgnoreParens();
+ const Expr *RHSExpr2 = BitOp->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral2 = dyn_cast<IntegerLiteral>(LHSExpr2);
+
+ if (!IntLiteral2)
+ IntLiteral2 = dyn_cast<IntegerLiteral>(RHSExpr2);
+
+ if (!IntLiteral2)
+ return TryResult();
+
+ llvm::APInt L1 = IntLiteral->getValue();
+ llvm::APInt L2 = IntLiteral2->getValue();
+ if ((BitOp->getOpcode() == BO_And && (L2 & L1) != L1) ||
+ (BitOp->getOpcode() == BO_Or && (L2 | L1) != L1)) {
+ if (BuildOpts.Observer)
+ BuildOpts.Observer->compareBitwiseEquality(B,
+ B->getOpcode() != BO_EQ);
+ TryResult(B->getOpcode() != BO_EQ);
+ }
+ } else if (BoolExpr->isKnownToHaveBooleanValue()) {
+ llvm::APInt IntValue = IntLiteral->getValue();
+ if ((IntValue == 1) || (IntValue == 0)) {
+ return TryResult();
+ }
+ return TryResult(B->getOpcode() != BO_EQ);
+ }
+
+ return TryResult();
+ }
+
+ TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
+ const llvm::APSInt &Value1,
+ const llvm::APSInt &Value2) {
+ assert(Value1.isSigned() == Value2.isSigned());
+ switch (Relation) {
+ default:
+ return TryResult();
+ case BO_EQ:
+ return TryResult(Value1 == Value2);
+ case BO_NE:
+ return TryResult(Value1 != Value2);
+ case BO_LT:
+ return TryResult(Value1 < Value2);
+ case BO_LE:
+ return TryResult(Value1 <= Value2);
+ case BO_GT:
+ return TryResult(Value1 > Value2);
+ case BO_GE:
+ return TryResult(Value1 >= Value2);
+ }
+ }
+
+ /// \brief Find a pair of comparison expressions with or without parentheses
+ /// with a shared variable and constants and a logical operator between them
+ /// that always evaluates to either true or false.
+ /// e.g. if (x != 3 || x != 4)
+ TryResult checkIncorrectLogicOperator(const BinaryOperator *B) {
+ assert(B->isLogicalOp());
+ const BinaryOperator *LHS =
+ dyn_cast<BinaryOperator>(B->getLHS()->IgnoreParens());
+ const BinaryOperator *RHS =
+ dyn_cast<BinaryOperator>(B->getRHS()->IgnoreParens());
+ if (!LHS || !RHS)
+ return TryResult();
+
+ if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
+ return TryResult();
+
+ BinaryOperatorKind BO1 = LHS->getOpcode();
+ const DeclRefExpr *Decl1 =
+ dyn_cast<DeclRefExpr>(LHS->getLHS()->IgnoreParenImpCasts());
+ const IntegerLiteral *Literal1 =
+ dyn_cast<IntegerLiteral>(LHS->getRHS()->IgnoreParens());
+ if (!Decl1 && !Literal1) {
+ if (BO1 == BO_GT)
+ BO1 = BO_LT;
+ else if (BO1 == BO_GE)
+ BO1 = BO_LE;
+ else if (BO1 == BO_LT)
+ BO1 = BO_GT;
+ else if (BO1 == BO_LE)
+ BO1 = BO_GE;
+ Decl1 = dyn_cast<DeclRefExpr>(LHS->getRHS()->IgnoreParenImpCasts());
+ Literal1 = dyn_cast<IntegerLiteral>(LHS->getLHS()->IgnoreParens());
+ }
+
+ if (!Decl1 || !Literal1)
+ return TryResult();
+
+ BinaryOperatorKind BO2 = RHS->getOpcode();
+ const DeclRefExpr *Decl2 =
+ dyn_cast<DeclRefExpr>(RHS->getLHS()->IgnoreParenImpCasts());
+ const IntegerLiteral *Literal2 =
+ dyn_cast<IntegerLiteral>(RHS->getRHS()->IgnoreParens());
+ if (!Decl2 && !Literal2) {
+ if (BO2 == BO_GT)
+ BO2 = BO_LT;
+ else if (BO2 == BO_GE)
+ BO2 = BO_LE;
+ else if (BO2 == BO_LT)
+ BO2 = BO_GT;
+ else if (BO2 == BO_LE)
+ BO2 = BO_GE;
+ Decl2 = dyn_cast<DeclRefExpr>(RHS->getRHS()->IgnoreParenImpCasts());
+ Literal2 = dyn_cast<IntegerLiteral>(RHS->getLHS()->IgnoreParens());
+ }
+
+ if (!Decl2 || !Literal2)
+ return TryResult();
+
+ // Check that it is the same variable on both sides.
+ if (Decl1->getDecl() != Decl2->getDecl())
+ return TryResult();
+
+ llvm::APSInt L1, L2;
+
+ if (!Literal1->EvaluateAsInt(L1, *Context) ||
+ !Literal2->EvaluateAsInt(L2, *Context))
+ return TryResult();
+
+ // Can't compare signed with unsigned or with different bit width.
+ if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth())
+ return TryResult();
+
+ // Values that will be used to determine if result of logical
+ // operator is always true/false
+ const llvm::APSInt Values[] = {
+ // Value less than both Value1 and Value2
+ llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
+ // L1
+ L1,
+ // Value between Value1 and Value2
+ ((L1 < L2) ? L1 : L2) + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1),
+ L1.isUnsigned()),
+ // L2
+ L2,
+ // Value greater than both Value1 and Value2
+ llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
+ };
+
+ // Check whether expression is always true/false by evaluating the following
+ // * variable x is less than the smallest literal.
+ // * variable x is equal to the smallest literal.
+ // * Variable x is between smallest and largest literal.
+ // * Variable x is equal to the largest literal.
+ // * Variable x is greater than largest literal.
+ bool AlwaysTrue = true, AlwaysFalse = true;
+ for (unsigned int ValueIndex = 0;
+ ValueIndex < sizeof(Values) / sizeof(Values[0]);
+ ++ValueIndex) {
+ llvm::APSInt Value = Values[ValueIndex];
+ TryResult Res1, Res2;
+ Res1 = analyzeLogicOperatorCondition(BO1, Value, L1);
+ Res2 = analyzeLogicOperatorCondition(BO2, Value, L2);
+
+ if (!Res1.isKnown() || !Res2.isKnown())
+ return TryResult();
+
+ if (B->getOpcode() == BO_LAnd) {
+ AlwaysTrue &= (Res1.isTrue() && Res2.isTrue());
+ AlwaysFalse &= !(Res1.isTrue() && Res2.isTrue());
+ } else {
+ AlwaysTrue &= (Res1.isTrue() || Res2.isTrue());
+ AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue());
+ }
+ }
+
+ if (AlwaysTrue || AlwaysFalse) {
+ if (BuildOpts.Observer)
+ BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue);
+ return TryResult(AlwaysTrue);
+ }
+ return TryResult();
+ }
+
/// Try and evaluate an expression to an integer constant.
bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
if (!BuildOpts.PruneTriviallyFalseEdges)
@@ -577,10 +814,22 @@
// is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
return RHS.isTrue();
+ } else {
+ TryResult BopRes = checkIncorrectLogicOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
}
}
return TryResult();
+ } else if (Bop->isEqualityOp()) {
+ TryResult BopRes = checkIncorrectEqualityOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
+ } else if (Bop->isRelationalOp()) {
+ TryResult BopRes = checkIncorrectRelationalOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
}
}
@@ -619,13 +868,13 @@
if (!fb) {
// No need to update 'cachedEntry', since it will always be null.
- assert(cachedEntry == 0);
+ assert(!cachedEntry);
return shouldAdd;
}
CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt);
if (itr == fb->end()) {
- cachedEntry = 0;
+ cachedEntry = nullptr;
return shouldAdd;
}
@@ -644,7 +893,7 @@
t = vt->getElementType().getTypePtr();
}
- return 0;
+ return nullptr;
}
/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can represent an
@@ -655,14 +904,14 @@
CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
assert(cfg.get());
if (!Statement)
- return NULL;
+ return nullptr;
// 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.
Succ = createBlock();
assert(Succ == &cfg->getExit());
- Block = NULL; // the EXIT block is empty. Create all other blocks lazily.
+ Block = nullptr; // the EXIT block is empty. Create all other blocks lazily.
if (BuildOpts.AddImplicitDtors)
if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
@@ -672,7 +921,7 @@
CFGBlock *B = addStmt(Statement);
if (badCFG)
- return NULL;
+ return nullptr;
// For C++ constructor add initializers to CFG.
if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
@@ -680,7 +929,7 @@
E = CD->init_rend(); I != E; ++I) {
B = addInitializer(*I);
if (badCFG)
- return NULL;
+ return nullptr;
}
}
@@ -935,7 +1184,7 @@
if (!BuildOpts.AddImplicitDtors)
return;
- LocalScope *Scope = 0;
+ LocalScope *Scope = nullptr;
// For compound statement we will be creating explicit scope.
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
@@ -1057,7 +1306,7 @@
CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
if (!S) {
badCFG = true;
- return 0;
+ return nullptr;
}
if (Expr *E = dyn_cast<Expr>(S))
@@ -1282,9 +1531,10 @@
appendStmt(ConfluenceBlock, B);
if (badCFG)
- return 0;
+ return nullptr;
- return VisitLogicalOperator(B, 0, ConfluenceBlock, ConfluenceBlock).first;
+ return VisitLogicalOperator(B, nullptr, ConfluenceBlock,
+ ConfluenceBlock).first;
}
std::pair<CFGBlock*, CFGBlock*>
@@ -1320,6 +1570,8 @@
else {
RHSBlock->setTerminator(Term);
TryResult KnownVal = tryEvaluateBool(RHS);
+ if (!KnownVal.isKnown())
+ KnownVal = tryEvaluateBool(B);
addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
}
@@ -1330,7 +1582,7 @@
while (false);
if (badCFG)
- return std::make_pair((CFGBlock*)0, (CFGBlock*)0);
+ return std::make_pair(nullptr, nullptr);
// Generate the blocks for evaluating the LHS.
Expr *LHS = B->getLHS()->IgnoreParens();
@@ -1357,7 +1609,7 @@
CFGBlock *EntryLHSBlock = addStmt(LHS);
if (badCFG)
- return std::make_pair((CFGBlock*)0, (CFGBlock*)0);
+ return std::make_pair(nullptr, nullptr);
// See if this is a known constant.
TryResult KnownVal = tryEvaluateBool(LHS);
@@ -1423,7 +1675,7 @@
// "break" is a control-flow statement. Thus we stop processing the current
// block.
if (badCFG)
- return 0;
+ return nullptr;
// Now create a new block that ends with the break statement.
Block = createBlock(false);
@@ -1511,7 +1763,7 @@
if (Block) {
Succ = Block;
if (badCFG)
- return 0;
+ return nullptr;
}
if (NoReturn)
@@ -1537,26 +1789,26 @@
CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
appendStmt(ConfluenceBlock, C);
if (badCFG)
- return 0;
+ return nullptr;
AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true);
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
CFGBlock *LHSBlock = Visit(C->getLHS(), alwaysAdd);
if (badCFG)
- return 0;
+ return nullptr;
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
CFGBlock *RHSBlock = Visit(C->getRHS(), alwaysAdd);
if (badCFG)
- return 0;
+ return nullptr;
Block = createBlock(false);
// See if this is a known constant.
const TryResult& KnownVal = tryEvaluateBool(C->getCond());
- addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
- addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
+ addSuccessor(Block, KnownVal.isFalse() ? nullptr : LHSBlock);
+ addSuccessor(Block, KnownVal.isTrue() ? nullptr : RHSBlock);
Block->setTerminator(C);
return addStmt(C->getCond());
}
@@ -1574,7 +1826,7 @@
LastBlock = newBlock;
if (badCFG)
- return NULL;
+ return nullptr;
}
return LastBlock;
@@ -1583,14 +1835,14 @@
CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
AddStmtChoice asc) {
const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(C);
- const OpaqueValueExpr *opaqueValue = (BCO ? BCO->getOpaqueValue() : NULL);
+ const OpaqueValueExpr *opaqueValue = (BCO ? BCO->getOpaqueValue() : nullptr);
// Create the confluence block that will "merge" the results of the ternary
// expression.
CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
appendStmt(ConfluenceBlock, C);
if (badCFG)
- return 0;
+ return nullptr;
AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true);
@@ -1599,14 +1851,14 @@
// value that is returned instead.
// e.g: x ?: y is shorthand for: x ? x : y;
Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock *LHSBlock = 0;
+ Block = nullptr;
+ CFGBlock *LHSBlock = nullptr;
const Expr *trueExpr = C->getTrueExpr();
if (trueExpr != opaqueValue) {
LHSBlock = Visit(C->getTrueExpr(), alwaysAdd);
if (badCFG)
- return 0;
- Block = NULL;
+ return nullptr;
+ Block = nullptr;
}
else
LHSBlock = ConfluenceBlock;
@@ -1615,7 +1867,7 @@
Succ = ConfluenceBlock;
CFGBlock *RHSBlock = Visit(C->getFalseExpr(), alwaysAdd);
if (badCFG)
- return 0;
+ return nullptr;
// If the condition is a logical '&&' or '||', build a more accurate CFG.
if (BinaryOperator *Cond =
@@ -1657,7 +1909,7 @@
if (DS->isSingleDecl())
return VisitDeclSubExpr(DS);
- CFGBlock *B = 0;
+ CFGBlock *B = nullptr;
// Build an individual DeclStmt for each decl.
for (DeclStmt::reverse_decl_iterator I = DS->decl_rbegin(),
@@ -1698,16 +1950,16 @@
bool HasTemporaries = false;
// Guard static initializers under a branch.
- CFGBlock *blockAfterStaticInit = 0;
+ CFGBlock *blockAfterStaticInit = nullptr;
if (BuildOpts.AddStaticInitBranches && VD->isStaticLocal()) {
// For static variables, we need to create a branch to track
// whether or not they are initialized.
if (Block) {
Succ = Block;
- Block = 0;
+ Block = nullptr;
if (badCFG)
- return 0;
+ return nullptr;
}
blockAfterStaticInit = Succ;
}
@@ -1750,7 +2002,7 @@
// If the type of VD is a VLA, then we must process its size expressions.
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) {
+ VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr())) {
if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
LastBlock = newBlock;
}
@@ -1797,7 +2049,7 @@
if (Block) {
Succ = Block;
if (badCFG)
- return 0;
+ return nullptr;
}
// Process the false branch.
@@ -1808,7 +2060,7 @@
// NULL out Block so that the recursive call to Visit will
// create a new basic block.
- Block = NULL;
+ Block = nullptr;
// If branch is not a compound statement create implicit scope
// and add destructors.
@@ -1821,7 +2073,7 @@
ElseBlock = sv.get();
else if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
}
@@ -1831,7 +2083,7 @@
Stmt *Then = I->getThen();
assert(Then);
SaveAndRestore<CFGBlock*> sv(Succ);
- Block = NULL;
+ Block = nullptr;
// If branch is not a compound statement create implicit scope
// and add destructors.
@@ -1848,7 +2100,7 @@
addSuccessor(ThenBlock, sv.get());
} else if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
}
@@ -1884,14 +2136,11 @@
// blocks will be pointed to be "Block".
CFGBlock *LastBlock = addStmt(I->getCond());
- // 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();
- appendStmt(Block, I->getConditionVariableDeclStmt());
- LastBlock = addStmt(Init);
- }
+ // Finally, if the IfStmt contains a condition variable, add it and its
+ // initializer to the CFG.
+ if (const DeclStmt* DS = I->getConditionVariableDeclStmt()) {
+ autoCreateBlock();
+ LastBlock = addStmt(const_cast<DeclStmt *>(DS));
}
return LastBlock;
@@ -1939,10 +2188,10 @@
// about.
LabelBlock->setLabel(L);
if (badCFG)
- return 0;
+ return nullptr;
// We set Block to NULL to allow lazy creation of a new block (if necessary);
- Block = NULL;
+ Block = nullptr;
// This block is now the implicit successor of other blocks.
Succ = LabelBlock;
@@ -1956,7 +2205,7 @@
et = E->capture_init_end(); it != et; ++it) {
if (Expr *Init = *it) {
CFGBlock *Tmp = Visit(Init);
- if (Tmp != 0)
+ if (Tmp)
LastBlock = Tmp;
}
}
@@ -1986,7 +2235,7 @@
}
CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
- CFGBlock *LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = nullptr;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -2009,7 +2258,7 @@
// block.
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
} else
LoopSuccessor = Succ;
@@ -2019,7 +2268,7 @@
SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
- CFGBlock *BodyBlock = 0, *TransitionBlock = 0;
+ CFGBlock *BodyBlock = nullptr, *TransitionBlock = nullptr;
// Now create the loop body.
{
@@ -2045,8 +2294,8 @@
if (Block) {
assert(Block == Succ);
if (badCFG)
- return 0;
- Block = 0;
+ return nullptr;
+ Block = nullptr;
}
// The starting block for the loop increment is the block that should
@@ -2072,13 +2321,13 @@
BodyBlock = ContinueJumpTarget.block;
}
else if (badCFG)
- return 0;
+ return nullptr;
}
// 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;
+ CFGBlock *EntryConditionBlock = nullptr, *ExitConditionBlock = nullptr;
do {
Expr *C = F->getCond();
@@ -2086,7 +2335,7 @@
// Specially handle logical operators, which have a slightly
// more optimal CFG representation.
if (BinaryOperator *Cond =
- dyn_cast_or_null<BinaryOperator>(C ? C->IgnoreParens() : 0))
+ dyn_cast_or_null<BinaryOperator>(C ? C->IgnoreParens() : nullptr))
if (Cond->isLogicalOp()) {
std::tie(EntryConditionBlock, ExitConditionBlock) =
VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor);
@@ -2119,16 +2368,17 @@
}
if (Block && badCFG)
- return 0;
+ return nullptr;
KnownVal = tryEvaluateBool(C);
}
// Add the loop body entry as a successor to the condition.
- addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
+ addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? nullptr : BodyBlock);
// Link up the condition block with the code that follows the loop. (the
// false branch).
- addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
+ addSuccessor(ExitConditionBlock,
+ KnownVal.isTrue() ? nullptr : LoopSuccessor);
} while (false);
@@ -2147,7 +2397,7 @@
// There is no loop initialization. We are thus basically a while loop.
// NULL out Block to force lazy block construction.
- Block = NULL;
+ Block = nullptr;
Succ = EntryConditionBlock;
return EntryConditionBlock;
}
@@ -2193,13 +2443,13 @@
// a DeclStmt and the other returns a DeclRefExpr.
//
- CFGBlock *LoopSuccessor = 0;
+ CFGBlock *LoopSuccessor = nullptr;
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
- Block = 0;
+ Block = nullptr;
} else
LoopSuccessor = Succ;
@@ -2222,8 +2472,8 @@
AddStmtChoice::NotAlwaysAdd);
if (Block) {
if (badCFG)
- return 0;
- Block = 0;
+ return nullptr;
+ Block = nullptr;
}
// The condition block is the implicit successor for the loop body as well as
@@ -2240,7 +2490,7 @@
// Add an intermediate block between the BodyBlock and the
// EntryConditionBlock to represent the "loop back" transition, for looping
// back to the head of the loop.
- CFGBlock *LoopBackBlock = 0;
+ CFGBlock *LoopBackBlock = nullptr;
Succ = LoopBackBlock = createBlock();
LoopBackBlock->setLoopTarget(S);
@@ -2253,7 +2503,7 @@
BodyBlock = ContinueJumpTarget.block; // can happen for "for (X in Y) ;"
else if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
// This new body block is a successor to our "exit" condition block.
@@ -2285,9 +2535,9 @@
// for diagnostic clients.
if (SyncBlock) {
if (badCFG)
- return 0;
+ return nullptr;
- Block = 0;
+ Block = nullptr;
Succ = SyncBlock;
}
@@ -2330,7 +2580,7 @@
}
CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
- CFGBlock *LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = nullptr;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -2348,14 +2598,14 @@
// block.
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
- Block = 0;
+ Block = nullptr;
} else {
LoopSuccessor = Succ;
}
- CFGBlock *BodyBlock = 0, *TransitionBlock = 0;
+ CFGBlock *BodyBlock = nullptr, *TransitionBlock = nullptr;
// Process the loop body.
{
@@ -2389,13 +2639,13 @@
if (!BodyBlock)
BodyBlock = ContinueJumpTarget.block; // can happen for "while(...) ;"
else if (Block && badCFG)
- return 0;
+ return nullptr;
}
// 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;
+ CFGBlock *EntryConditionBlock = nullptr, *ExitConditionBlock = nullptr;
do {
Expr *C = W->getCond();
@@ -2431,16 +2681,17 @@
}
if (Block && badCFG)
- return 0;
+ return nullptr;
// See if this is a known constant.
const TryResult& KnownVal = tryEvaluateBool(C);
// Add the loop body entry as a successor to the condition.
- addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
+ addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? nullptr : BodyBlock);
// Link up the condition block with the code that follows the loop. (the
// false branch).
- addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
+ addSuccessor(ExitConditionBlock,
+ KnownVal.isTrue() ? nullptr : LoopSuccessor);
} while(false);
@@ -2449,7 +2700,7 @@
// 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.
- Block = NULL;
+ Block = nullptr;
// Return the condition block, which is the dominating block for the loop.
Succ = EntryConditionBlock;
@@ -2469,7 +2720,7 @@
// If we were in the middle of a block we stop processing that block.
if (badCFG)
- return 0;
+ return nullptr;
// Create the new block.
Block = createBlock(false);
@@ -2485,7 +2736,7 @@
CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
// If we were in the middle of a block we stop processing that block.
if (badCFG)
- return 0;
+ return nullptr;
// Create the new block.
Block = createBlock(false);
@@ -2503,13 +2754,13 @@
}
CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
- CFGBlock *LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = nullptr;
// "do...while" is a control-flow statement. Thus we stop processing the
// current block.
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
} else
LoopSuccessor = Succ;
@@ -2530,7 +2781,7 @@
EntryConditionBlock = addStmt(C);
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
}
@@ -2541,7 +2792,7 @@
const TryResult &KnownVal = tryEvaluateBool(D->getCond());
// Process the loop body.
- CFGBlock *BodyBlock = NULL;
+ CFGBlock *BodyBlock = nullptr;
{
assert(D->getBody());
@@ -2557,7 +2808,7 @@
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// NULL out Block to force lazy instantiation of blocks for the body.
- Block = NULL;
+ Block = nullptr;
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -2571,7 +2822,7 @@
BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)"
else if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
if (!KnownVal.isFalse()) {
@@ -2580,7 +2831,7 @@
// 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;
+ Block = nullptr;
Succ = BodyBlock;
CFGBlock *LoopBackBlock = createBlock();
LoopBackBlock->setLoopTarget(D);
@@ -2589,16 +2840,16 @@
addSuccessor(ExitConditionBlock, LoopBackBlock);
}
else
- addSuccessor(ExitConditionBlock, NULL);
+ addSuccessor(ExitConditionBlock, nullptr);
}
// Link up the condition block with the code that follows the loop.
// (the false branch).
- addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
+ addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? nullptr : LoopSuccessor);
// 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.
- Block = NULL;
+ Block = nullptr;
// Return the loop body, which is the dominating block for the loop.
Succ = BodyBlock;
@@ -2609,7 +2860,7 @@
// "continue" is a control-flow statement. Thus we stop processing the
// current block.
if (badCFG)
- return 0;
+ return nullptr;
// Now create a new block that ends with the continue statement.
Block = createBlock(false);
@@ -2639,7 +2890,7 @@
if (E->isArgumentType()) {
for (const VariableArrayType *VA =FindVA(E->getArgumentType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
+ VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr()))
lastBlock = addStmt(VA->getSizeExpr());
}
return lastBlock;
@@ -2658,7 +2909,7 @@
CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// "switch" is a control-flow statement. Thus we stop processing the current
// block.
- CFGBlock *SwitchSuccessor = NULL;
+ CFGBlock *SwitchSuccessor = nullptr;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -2674,7 +2925,7 @@
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
SwitchSuccessor = Block;
} else SwitchSuccessor = Succ;
@@ -2700,7 +2951,7 @@
// 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.
assert(Terminator->getBody() && "switch must contain a non-NULL body");
- Block = NULL;
+ Block = nullptr;
// For pruning unreachable case statements, save the current state
// for tracking the condition value.
@@ -2712,7 +2963,7 @@
Expr::EvalResult result;
bool b = tryEvaluate(Terminator->getCond(), result);
SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond,
- b ? &result : 0);
+ b ? &result : nullptr);
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -2722,7 +2973,7 @@
addStmt(Terminator->getBody());
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
// If we have no "default:" case, the default transition is to the code
@@ -2795,7 +3046,7 @@
CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
// CaseStmts are essentially labels, so they are the first statement in a
// block.
- CFGBlock *TopBlock = 0, *LastBlock = 0;
+ CFGBlock *TopBlock = nullptr, *LastBlock = nullptr;
if (Stmt *Sub = CS->getSubStmt()) {
// For deeply nested chains of CaseStmts, instead of doing a recursion
@@ -2813,7 +3064,7 @@
addSuccessor(SwitchTerminatedBlock,
shouldAddCase(switchExclusivelyCovered, switchCond,
CS, *Context)
- ? currentBlock : 0);
+ ? currentBlock : nullptr);
LastBlock = currentBlock;
CS = cast<CaseStmt>(Sub);
@@ -2832,7 +3083,7 @@
CaseBlock->setLabel(CS);
if (badCFG)
- return 0;
+ return nullptr;
// Add this block to the list of successors for the block with the switch
// statement.
@@ -2842,7 +3093,7 @@
CS, *Context));
// We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
+ Block = nullptr;
if (TopBlock) {
addSuccessor(LastBlock, CaseBlock);
@@ -2869,7 +3120,7 @@
DefaultCaseBlock->setLabel(Terminator);
if (badCFG)
- return 0;
+ return nullptr;
// Unlike case statements, we don't add the default block to the successors
// for the switch statement immediately. This is done when we finish
@@ -2878,7 +3129,7 @@
// be the last successor of a switch-terminated block.
// We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
+ Block = nullptr;
// This block is now the implicit successor of other blocks.
Succ = DefaultCaseBlock;
@@ -2889,11 +3140,11 @@
CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
// "try"/"catch" is a control-flow statement. Thus we stop processing the
// current block.
- CFGBlock *TrySuccessor = NULL;
+ CFGBlock *TrySuccessor = nullptr;
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
TrySuccessor = Block;
} else TrySuccessor = Succ;
@@ -2909,13 +3160,13 @@
// The code after the try is the implicit successor.
Succ = TrySuccessor;
CXXCatchStmt *CS = Terminator->getHandler(h);
- if (CS->getExceptionDecl() == 0) {
+ if (CS->getExceptionDecl() == nullptr) {
HasCatchAll = true;
}
- Block = NULL;
+ Block = nullptr;
CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
- if (CatchBlock == 0)
- return 0;
+ if (!CatchBlock)
+ return nullptr;
// Add this block to the list of successors for the block with the try
// statement.
addSuccessor(NewTryTerminatedBlock, CatchBlock);
@@ -2935,7 +3186,7 @@
cfg->addTryDispatchBlock(TryTerminatedBlock);
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
- Block = NULL;
+ Block = nullptr;
return addStmt(Terminator->getTryBlock());
}
@@ -2974,10 +3225,10 @@
// Bail out if the CFG is bad.
if (badCFG)
- return 0;
+ return nullptr;
// We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
+ Block = nullptr;
return CatchBlock;
}
@@ -3010,10 +3261,10 @@
// "for" is a control-flow statement. Thus we stop processing the current
// block.
- CFGBlock *LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = nullptr;
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
} else
LoopSuccessor = Succ;
@@ -3032,7 +3283,7 @@
Block = ConditionBlock;
CFGBlock *BeginConditionBlock = addStmt(C);
if (badCFG)
- return 0;
+ return nullptr;
assert(BeginConditionBlock == ConditionBlock &&
"condition block in for-range was unexpectedly complex");
(void)BeginConditionBlock;
@@ -3058,7 +3309,7 @@
// Generate increment code in its own basic block. This is the target of
// continue statements.
- Block = 0;
+ Block = nullptr;
Succ = addStmt(S->getInc());
ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
@@ -3069,9 +3320,8 @@
// Finish up the increment block and prepare to start the loop body.
assert(Block);
if (badCFG)
- return 0;
- Block = 0;
-
+ return nullptr;
+ Block = nullptr;
// Add implicit scope and dtors for loop variable.
addLocalScopeAndDtors(S->getLoopVarStmt());
@@ -3079,18 +3329,19 @@
// Populate a new block to contain the loop body and loop variable.
addStmt(S->getBody());
if (badCFG)
- return 0;
+ return nullptr;
CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
if (badCFG)
- return 0;
-
+ return nullptr;
+
// This new body block is a successor to our condition block.
- addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : LoopVarStmtBlock);
+ addSuccessor(ConditionBlock,
+ KnownVal.isFalse() ? nullptr : LoopVarStmtBlock);
}
// Link up the condition block with the code that follows the loop (the
// false branch).
- addSuccessor(ConditionBlock, KnownVal.isTrue() ? 0 : LoopSuccessor);
+ addSuccessor(ConditionBlock, KnownVal.isTrue() ? nullptr : LoopSuccessor);
// Add the initialization statements.
Block = createBlock();
@@ -3204,7 +3455,7 @@
// IndirectGoto is a control-flow statement. Thus we stop processing the
// current block and create a new one.
if (badCFG)
- return 0;
+ return nullptr;
Block = createBlock(false);
Block->setTerminator(I);
@@ -3218,7 +3469,7 @@
tryAgain:
if (!E) {
badCFG = true;
- return NULL;
+ return nullptr;
}
switch (E->getStmtClass()) {
default:
@@ -3273,15 +3524,15 @@
autoCreateBlock();
CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getLHS());
if (badCFG)
- return NULL;
+ return nullptr;
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS());
if (RHSBlock) {
if (badCFG)
- return NULL;
+ return nullptr;
// If RHS expression did produce destructors we need to connect created
// blocks to CFG in same manner as for binary operator itself.
@@ -3301,12 +3552,12 @@
// Link LHSBlock with RHSBlock exactly the same way as for binary operator
// itself.
if (E->getOpcode() == BO_LOr) {
- addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
- addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
+ addSuccessor(LHSBlock, KnownVal.isTrue() ? nullptr : ConfluenceBlock);
+ addSuccessor(LHSBlock, KnownVal.isFalse() ? nullptr : RHSBlock);
} else {
assert (E->getOpcode() == BO_LAnd);
- addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
- addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
+ addSuccessor(LHSBlock, KnownVal.isFalse() ? nullptr : RHSBlock);
+ addSuccessor(LHSBlock, KnownVal.isTrue() ? nullptr : ConfluenceBlock);
}
Block = LHSBlock;
@@ -3366,29 +3617,29 @@
autoCreateBlock();
CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getCond());
if (badCFG)
- return NULL;
+ return nullptr;
if (BinaryConditionalOperator *BCO
= dyn_cast<BinaryConditionalOperator>(E)) {
ConfluenceBlock = VisitForTemporaryDtors(BCO->getCommon());
if (badCFG)
- return NULL;
+ return nullptr;
}
// Try to add block with destructors for LHS expression.
- CFGBlock *LHSBlock = NULL;
+ CFGBlock *LHSBlock = nullptr;
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
LHSBlock = VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary);
if (badCFG)
- return NULL;
+ return nullptr;
// Try to add block with destructors for RHS expression;
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getFalseExpr(),
BindToTemporary);
if (badCFG)
- return NULL;
+ return nullptr;
if (!RHSBlock && !LHSBlock) {
// If neither LHS nor RHS expression had temporaries to destroy don't create
@@ -3407,7 +3658,7 @@
if (LHSBlock) {
addSuccessor(Block, LHSBlock, !KnownVal.isFalse());
} else if (KnownVal.isFalse()) {
- addSuccessor(Block, NULL);
+ addSuccessor(Block, nullptr);
} else {
addSuccessor(Block, ConfluenceBlock);
std::reverse(ConfluenceBlock->pred_begin(), ConfluenceBlock->pred_end());
@@ -3488,7 +3739,7 @@
case CFGElement::MemberDtor:
// Not yet supported.
- return 0;
+ return nullptr;
}
llvm_unreachable("getKind() returned bogus value");
}
@@ -3504,13 +3755,13 @@
//===----------------------------------------------------------------------===//
CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, bool IsReachable)
- : ReachableBlock(IsReachable ? B : 0),
- UnreachableBlock(!IsReachable ? B : 0,
+ : ReachableBlock(IsReachable ? B : nullptr),
+ UnreachableBlock(!IsReachable ? B : nullptr,
B && IsReachable ? AB_Normal : AB_Unreachable) {}
CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock)
: ReachableBlock(B),
- UnreachableBlock(B == AlternateBlock ? 0 : AlternateBlock,
+ UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock,
B == AlternateBlock ? AB_Alternate : AB_Normal) {}
void CFGBlock::addSuccessor(AdjacentBlock Succ,
@@ -4110,16 +4361,16 @@
/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
void CFGBlock::printTerminator(raw_ostream &OS,
const LangOptions &LO) const {
- CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO));
+ CFGBlockTerminatorPrint TPrinter(OS, nullptr, PrintingPolicy(LO));
TPrinter.print(getTerminator());
}
Stmt *CFGBlock::getTerminatorCondition(bool StripParens) {
Stmt *Terminator = this->Terminator;
if (!Terminator)
- return NULL;
+ return nullptr;
- Expr *E = NULL;
+ Expr *E = nullptr;
switch (Terminator->getStmtClass()) {
default:
@@ -4176,7 +4427,7 @@
if (!StripParens)
return E;
- return E ? E->IgnoreParens() : NULL;
+ return E ? E->IgnoreParens() : nullptr;
}
//===----------------------------------------------------------------------===//
@@ -4193,7 +4444,7 @@
StmtPrinterHelper H(this, LO);
GraphHelper = &H;
llvm::ViewGraph(this,"CFG");
- GraphHelper = NULL;
+ GraphHelper = nullptr;
#endif
}
diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp
index 87c2f5b..19b8019 100644
--- a/lib/Analysis/CFGStmtMap.cpp
+++ b/lib/Analysis/CFGStmtMap.cpp
@@ -42,8 +42,8 @@
X = PM->getParentIgnoreParens(X);
}
-
- return 0;
+
+ return nullptr;
}
static void Accumulate(SMap &SM, CFGBlock *B) {
@@ -77,7 +77,7 @@
CFGStmtMap *CFGStmtMap::Build(CFG *C, ParentMap *PM) {
if (!C || !PM)
- return 0;
+ return nullptr;
SMap *SM = new SMap();
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 9630bc0..5e97ce2 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -23,6 +23,9 @@
ReachableCode.cpp
ScanfFormatString.cpp
ThreadSafety.cpp
+ ThreadSafetyCommon.cpp
+ ThreadSafetyLogical.cpp
+ ThreadSafetyTIL.cpp
UninitializedValues.cpp
LINK_LIBS
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 649ba57..f41a96d 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -10,8 +10,6 @@
// This file defines the AST-based CallGraph.
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "CallGraph"
-
#include "clang/Analysis/CallGraph.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -22,6 +20,8 @@
using namespace clang;
+#define DEBUG_TYPE "CallGraph"
+
STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
STATISTIC(NumBlockCallEdges, "Number of block call edges");
@@ -49,7 +49,7 @@
return Block->getBlockDecl();
}
- return 0;
+ return nullptr;
}
void addCalledDecl(Decl *D) {
@@ -70,7 +70,7 @@
Selector Sel = ME->getSelector();
// Find the callee definition within the same translation unit.
- Decl *D = 0;
+ Decl *D = nullptr;
if (ME->isInstanceMessage())
D = IDecl->lookupPrivateMethod(Sel);
else
@@ -101,7 +101,7 @@
}
CallGraph::CallGraph() {
- Root = getOrInsertNode(0);
+ Root = getOrInsertNode(nullptr);
}
CallGraph::~CallGraph() {
@@ -147,7 +147,7 @@
CallGraphNode *CallGraph::getNode(const Decl *F) const {
FunctionMapTy::const_iterator I = FunctionMap.find(F);
- if (I == FunctionMap.end()) return 0;
+ if (I == FunctionMap.end()) return nullptr;
return I->second;
}
@@ -158,7 +158,7 @@
Node = new CallGraphNode(F);
// Make Root node a parent of all functions to make sure all are reachable.
- if (F != 0)
+ if (F)
Root->addCallee(Node, this);
return Node;
}
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index 7b6ad57..2b2da2c 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -57,11 +57,9 @@
static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
// Find the source location of the first statement in the block, if the block
// is not empty.
- for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
- BI != BE; ++BI) {
- if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
+ for (const auto &B : *Block)
+ if (Optional<CFGStmt> CS = B.getAs<CFGStmt>())
return CS->getStmt()->getLocStart();
- }
// Block is empty.
// If we have one successor, return the first statement in that block
@@ -115,14 +113,10 @@
static bool isCallableInState(const CallableWhenAttr *CWAttr,
ConsumedState State) {
- CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
- E = CWAttr->callableState_end();
-
- for (; I != E; ++I) {
-
+ for (const auto &S : CWAttr->callableStates()) {
ConsumedState MappedAttrState = CS_None;
-
- switch (*I) {
+
+ switch (S) {
case CallableWhenAttr::Unknown:
MappedAttrState = CS_Unknown;
break;
@@ -716,7 +710,7 @@
LTest = LEntry->second.getVarTest();
} else {
- LTest.Var = NULL;
+ LTest.Var = nullptr;
LTest.TestsFor = CS_None;
}
@@ -724,11 +718,11 @@
RTest = REntry->second.getVarTest();
} else {
- RTest.Var = NULL;
+ RTest.Var = nullptr;
RTest.TestsFor = CS_None;
}
-
- if (!(LTest.Var == NULL && RTest.Var == NULL))
+
+ if (!(LTest.Var == nullptr && RTest.Var == nullptr))
PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
@@ -745,16 +739,6 @@
}
}
-static bool isStdNamespace(const DeclContext *DC) {
- if (!DC->isNamespace()) return false;
- while (DC->getParent()->isNamespace())
- DC = DC->getParent();
- const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
-
- return ND && ND->getName() == "std" &&
- ND->getDeclContext()->isTranslationUnit();
-}
-
void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
const FunctionDecl *FunDecl = Call->getDirectCallee();
if (!FunDecl)
@@ -762,14 +746,13 @@
// Special case for the std::move function.
// TODO: Make this more specific. (Deferred)
- if (Call->getNumArgs() == 1 &&
- FunDecl->getNameAsString() == "move" &&
- isStdNamespace(FunDecl->getDeclContext())) {
+ if (Call->getNumArgs() == 1 && FunDecl->getNameAsString() == "move" &&
+ FunDecl->isInStdNamespace()) {
copyInfo(Call->getArg(0), Call, CS_Consumed);
return;
}
- handleCall(Call, 0, FunDecl);
+ handleCall(Call, nullptr, FunDecl);
propagateReturnType(Call, FunDecl);
}
@@ -1078,9 +1061,9 @@
void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
ConsumedStateMap *StateMap) {
-
- assert(Block != NULL && "Block pointer must not be NULL");
-
+
+ assert(Block && "Block pointer must not be NULL");
+
ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
if (Entry) {
@@ -1102,7 +1085,7 @@
void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
unsigned int BlockID = Block->getBlockID();
delete StateMapsArray[BlockID];
- StateMapsArray[BlockID] = NULL;
+ StateMapsArray[BlockID] = nullptr;
}
ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
@@ -1112,7 +1095,7 @@
if (isBackEdgeTarget(Block)) {
return new ConsumedStateMap(*StateMap);
} else {
- StateMapsArray[Block->getBlockID()] = NULL;
+ StateMapsArray[Block->getBlockID()] = nullptr;
return StateMap;
}
}
@@ -1125,8 +1108,8 @@
}
bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
- assert(Block != NULL && "Block pointer must not be NULL");
-
+ assert(Block && "Block pointer must not be NULL");
+
// Anything with less than two predecessors can't be the target of a back
// edge.
if (Block->pred_size() < 2)
@@ -1144,21 +1127,19 @@
void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
ConsumedWarningsHandlerBase &WarningsHandler) const {
- for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
- DMI != DME; ++DMI) {
-
- if (isa<ParmVarDecl>(DMI->first)) {
- const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
+ for (const auto &DM : VarMap) {
+ if (isa<ParmVarDecl>(DM.first)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first);
const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
if (!RTA)
continue;
ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
- if (DMI->second != ExpectedState)
+ if (DM.second != ExpectedState)
WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
Param->getNameAsString(), stateToString(ExpectedState),
- stateToString(DMI->second));
+ stateToString(DM.second));
}
}
}
@@ -1194,16 +1175,14 @@
return;
}
- for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
- DME = Other->VarMap.end(); DMI != DME; ++DMI) {
-
- LocalState = this->getState(DMI->first);
+ for (const auto &DM : Other->VarMap) {
+ LocalState = this->getState(DM.first);
if (LocalState == CS_None)
continue;
- if (LocalState != DMI->second)
- VarMap[DMI->first] = CS_Unknown;
+ if (LocalState != DM.second)
+ VarMap[DM.first] = CS_Unknown;
}
}
@@ -1214,18 +1193,16 @@
ConsumedState LocalState;
SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
- for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
- DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
-
- LocalState = this->getState(DMI->first);
+ for (const auto &DM : LoopBackStates->VarMap) {
+ LocalState = this->getState(DM.first);
if (LocalState == CS_None)
continue;
- if (LocalState != DMI->second) {
- VarMap[DMI->first] = CS_Unknown;
- WarningsHandler.warnLoopStateMismatch(
- BlameLoc, DMI->first->getNameAsString());
+ if (LocalState != DM.second) {
+ VarMap[DM.first] = CS_Unknown;
+ WarningsHandler.warnLoopStateMismatch(BlameLoc,
+ DM.first->getNameAsString());
}
}
}
@@ -1245,18 +1222,14 @@
TmpMap[Tmp] = State;
}
-void ConsumedStateMap::remove(const VarDecl *Var) {
- VarMap.erase(Var);
+void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
+ TmpMap.erase(Tmp);
}
bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
- for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
- DME = Other->VarMap.end(); DMI != DME; ++DMI) {
-
- if (this->getState(DMI->first) != DMI->second)
- return true;
- }
-
+ for (const auto &DM : Other->VarMap)
+ if (this->getState(DM.first) != DM.second)
+ return true;
return false;
}
@@ -1372,7 +1345,7 @@
if (*++SI)
BlockInfo.addInfo(*SI, FalseStates.release());
- CurrStates = NULL;
+ CurrStates = nullptr;
return true;
}
@@ -1396,17 +1369,12 @@
ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
// Add all trackable parameters to the state map.
- for (auto PI : D->params()) {
+ for (const auto *PI : D->params())
Visitor.VisitParmVarDecl(PI);
- }
// Visit all of the function's basic blocks.
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I != E; ++I) {
-
- const CFGBlock *CurrBlock = *I;
-
- if (CurrStates == NULL)
+ for (const auto *CurrBlock : *SortedGraph) {
+ if (!CurrStates)
CurrStates = BlockInfo.getInfo(CurrBlock);
if (!CurrStates) {
@@ -1414,33 +1382,32 @@
} else if (!CurrStates->isReachable()) {
delete CurrStates;
- CurrStates = NULL;
+ CurrStates = nullptr;
continue;
}
Visitor.reset(CurrStates);
// Visit all of the basic block's statements.
- for (CFGBlock::const_iterator BI = CurrBlock->begin(),
- BE = CurrBlock->end(); BI != BE; ++BI) {
-
- switch (BI->getKind()) {
+ for (const auto &B : *CurrBlock) {
+ switch (B.getKind()) {
case CFGElement::Statement:
- Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
+ Visitor.Visit(B.castAs<CFGStmt>().getStmt());
break;
case CFGElement::TemporaryDtor: {
- const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
+ const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
Visitor.checkCallability(PropagationInfo(BTE),
DTor.getDestructorDecl(AC.getASTContext()),
BTE->getExprLoc());
+ CurrStates->remove(BTE);
break;
}
case CFGElement::AutomaticObjectDtor: {
- const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
+ const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
const VarDecl *Var = DTor.getVarDecl();
@@ -1455,13 +1422,11 @@
}
}
- CurrStates->clearTemporaries();
-
// TODO: Handle other forms of branching with precision, including while-
// and for-loops. (Deferred)
if (!splitState(CurrBlock, Visitor)) {
- CurrStates->setSource(NULL);
-
+ CurrStates->setSource(nullptr);
+
if (CurrBlock->succ_size() > 1 ||
(CurrBlock->succ_size() == 1 &&
(*CurrBlock->succ_begin())->pred_size() > 1)) {
@@ -1470,9 +1435,9 @@
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
-
- if (*SI == NULL) continue;
-
+
+ if (*SI == nullptr) continue;
+
if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
CurrStates,
@@ -1487,8 +1452,8 @@
if (!OwnershipTaken)
delete CurrStates;
-
- CurrStates = NULL;
+
+ CurrStates = nullptr;
}
}
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 43ecc66..851b97e 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -507,7 +507,7 @@
case None:
return "";
}
- return NULL;
+ return nullptr;
}
//===----------------------------------------------------------------------===//
@@ -539,7 +539,7 @@
case nArg: return "n";
case PercentArg: return "%";
case ScanListArg: return "[";
- case InvalidSpecifier: return NULL;
+ case InvalidSpecifier: return nullptr;
// POSIX unicode extensions.
case CArg: return "C";
@@ -551,7 +551,7 @@
// GlibC specific specifiers.
case PrintErrno: return "m";
}
- return NULL;
+ return nullptr;
}
Optional<ConversionSpecifier>
diff --git a/lib/Analysis/FormatStringParsing.h b/lib/Analysis/FormatStringParsing.h
index 6b25123..fba3180 100644
--- a/lib/Analysis/FormatStringParsing.h
+++ b/lib/Analysis/FormatStringParsing.h
@@ -53,14 +53,14 @@
bool Stop;
public:
SpecifierResult(bool stop = false)
- : Start(0), Stop(stop) {}
+ : Start(nullptr), Stop(stop) {}
SpecifierResult(const char *start,
const T &fs)
: FS(fs), Start(start), Stop(false) {}
const char *getStart() const { return Start; }
bool shouldStop() const { return Stop; }
- bool hasValue() const { return Start != 0; }
+ bool hasValue() const { return Start != nullptr; }
const T &getValue() const {
assert(hasValue());
return FS;
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index b26d4fb..3d6fc03 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -72,7 +72,7 @@
const CFGBlock *DataflowWorklist::dequeue() {
if (worklist.empty())
- return 0;
+ return nullptr;
const CFGBlock *b = worklist.pop_back_val();
enqueuedBlocks[b->getBlockID()] = false;
return b;
@@ -94,10 +94,10 @@
LiveVariables::LivenessValues
merge(LiveVariables::LivenessValues valsA,
LiveVariables::LivenessValues valsB);
-
- LiveVariables::LivenessValues runOnBlock(const CFGBlock *block,
- LiveVariables::LivenessValues val,
- LiveVariables::Observer *obs = 0);
+
+ LiveVariables::LivenessValues
+ runOnBlock(const CFGBlock *block, LiveVariables::LivenessValues val,
+ LiveVariables::Observer *obs = nullptr);
void dumpBlockLiveness(const SourceManager& M);
@@ -224,8 +224,8 @@
ty = VT->getElementType().getTypePtr();
}
-
- return 0;
+
+ return nullptr;
}
static const Stmt *LookThroughStmt(const Stmt *S) {
@@ -291,7 +291,7 @@
const DeclStmt *DS = cast<DeclStmt>(S);
if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) {
for (const VariableArrayType* VA = FindVA(VD->getType());
- VA != 0; VA = FindVA(VA->getElementType())) {
+ VA != nullptr; VA = FindVA(VA->getElementType())) {
AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr());
}
}
@@ -384,8 +384,8 @@
void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
// Kill the iteration variable.
- DeclRefExpr *DR = 0;
- const VarDecl *VD = 0;
+ DeclRefExpr *DR = nullptr;
+ const VarDecl *VD = nullptr;
Stmt *element = OS->getElement();
if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
@@ -493,12 +493,12 @@
// No CFG? Bail out.
CFG *cfg = AC.getCFG();
if (!cfg)
- return 0;
+ return nullptr;
// The analysis currently has scalability issues for very large CFGs.
// Bail out if it looks too large.
if (cfg->getNumBlockIDs() > 300000)
- return 0;
+ return nullptr;
LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign);
diff --git a/lib/Analysis/PostOrderCFGView.cpp b/lib/Analysis/PostOrderCFGView.cpp
index cfd66f7..5a3c8182 100644
--- a/lib/Analysis/PostOrderCFGView.cpp
+++ b/lib/Analysis/PostOrderCFGView.cpp
@@ -31,7 +31,7 @@
PostOrderCFGView *PostOrderCFGView::create(AnalysisDeclContext &ctx) {
const CFG *cfg = ctx.getCFG();
if (!cfg)
- return 0;
+ return nullptr;
return new PostOrderCFGView(cfg);
}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index f21b407..082a832 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -60,7 +60,7 @@
using namespace clang::analyze_printf;
const char *I = Beg;
- const char *Start = 0;
+ const char *Start = nullptr;
UpdateOnReturn <const char*> UpdateBeg(Beg, I);
// Look for a '%' character that indicates the start of a format specifier.
@@ -124,7 +124,7 @@
// Look for the field width (if any).
if (ParseFieldWidth(H, FS, Start, I, E,
- FS.usesPositionalArg() ? 0 : &argIndex))
+ FS.usesPositionalArg() ? nullptr : &argIndex))
return true;
if (I == E) {
@@ -142,7 +142,7 @@
}
if (ParsePrecision(H, FS, Start, I, E,
- FS.usesPositionalArg() ? 0 : &argIndex))
+ FS.usesPositionalArg() ? nullptr : &argIndex))
return true;
if (I == E) {
diff --git a/lib/Analysis/PseudoConstantAnalysis.cpp b/lib/Analysis/PseudoConstantAnalysis.cpp
index 314ce7c..3f96ca8 100644
--- a/lib/Analysis/PseudoConstantAnalysis.cpp
+++ b/lib/Analysis/PseudoConstantAnalysis.cpp
@@ -70,7 +70,7 @@
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
return DR->getDecl();
else
- return 0;
+ return nullptr;
}
void PseudoConstantAnalysis::RunAnalysis() {
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 3cc8ae4..b4a72a7 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -59,32 +59,57 @@
}
static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
- // Look to see if the block ends with a 'return', and see if 'S'
- // is a substatement. The 'return' may not be the last element in
- // the block because of destructors.
- for (CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend();
- I != E; ++I) {
- if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
- if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
- if (RS == S)
- return true;
- if (const Expr *RE = RS->getRetValue()) {
- RE = RE->IgnoreParenCasts();
- if (RE == S)
+ // Look to see if the current control flow ends with a 'return', and see if
+ // 'S' is a substatement. The 'return' may not be the last element in the
+ // block, or may be in a subsequent block because of destructors.
+ const CFGBlock *Current = B;
+ while (true) {
+ for (CFGBlock::const_reverse_iterator I = Current->rbegin(),
+ E = Current->rend();
+ I != E; ++I) {
+ if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
+ if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
+ if (RS == S)
return true;
- ParentMap PM(const_cast<Expr*>(RE));
- // If 'S' is in the ParentMap, it is a subexpression of
- // the return statement. Note also that we are restricting
- // to looking at return statements in the same CFGBlock,
- // so this will intentionally not catch cases where the
- // return statement contains nested control-flow.
- return PM.getParent(S);
+ if (const Expr *RE = RS->getRetValue()) {
+ RE = RE->IgnoreParenCasts();
+ if (RE == S)
+ return true;
+ ParentMap PM(const_cast<Expr *>(RE));
+ // If 'S' is in the ParentMap, it is a subexpression of
+ // the return statement.
+ return PM.getParent(S);
+ }
}
+ break;
}
- break;
+ }
+ // Note also that we are restricting the search for the return statement
+ // to stop at control-flow; only part of a return statement may be dead,
+ // without the whole return statement being dead.
+ if (Current->getTerminator().isTemporaryDtorsBranch()) {
+ // Temporary destructors have a predictable control flow, thus we want to
+ // look into the next block for the return statement.
+ // We look into the false branch, as we know the true branch only contains
+ // the call to the destructor.
+ assert(Current->succ_size() == 2);
+ Current = *(Current->succ_begin() + 1);
+ } else if (!Current->getTerminator() && Current->succ_size() == 1) {
+ // If there is only one successor, we're not dealing with outgoing control
+ // flow. Thus, look into the next block.
+ Current = *Current->succ_begin();
+ if (Current->pred_size() > 1) {
+ // If there is more than one predecessor, we're dealing with incoming
+ // control flow - if the return statement is in that block, it might
+ // well be reachable via a different control flow, thus it's not dead.
+ return false;
+ }
+ } else {
+ // We hit control flow or a dead end. Stop searching.
+ return false;
}
}
- return false;
+ llvm_unreachable("Broke out of infinite loop.");
}
static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM) {
@@ -139,6 +164,9 @@
if (!S)
return false;
+ if (const Expr *Ex = dyn_cast<Expr>(S))
+ S = Ex->IgnoreCasts();
+
// Special case looking for the sigil '()' around an integer literal.
if (const ParenExpr *PE = dyn_cast<ParenExpr>(S))
if (!PE->getLocStart().isMacroID())
@@ -146,7 +174,7 @@
IncludeIntegers, true);
if (const Expr *Ex = dyn_cast<Expr>(S))
- S = Ex->IgnoreParenCasts();
+ S = Ex->IgnoreCasts();
bool IgnoreYES_NO = false;
@@ -399,7 +427,7 @@
}
}
- return 0;
+ return nullptr;
}
static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1,
@@ -603,7 +631,7 @@
unsigned ScanReachableFromBlock(const CFGBlock *Start,
llvm::BitVector &Reachable) {
- return scanFromBlock(Start, Reachable, /* SourceManager* */ 0, false);
+ return scanFromBlock(Start, Reachable, /* SourceManager* */ nullptr, false);
}
void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 3ff7f0a..ed28627 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -50,6 +50,15 @@
}
}
+ // Special case: "^]" are the first characters.
+ if (I + 1 != E && I[0] == '^' && I[1] == ']') {
+ I += 2;
+ if (I == E) {
+ H.HandleIncompleteScanList(start, I - 1);
+ return true;
+ }
+ }
+
// Look for a ']' character which denotes the end of the scan list.
while (*I != ']') {
if (++I == E) {
@@ -73,7 +82,7 @@
using namespace clang::analyze_scanf;
const char *I = Beg;
- const char *Start = 0;
+ const char *Start = nullptr;
UpdateOnReturn <const char*> UpdateBeg(Beg, I);
// Look for a '%' character that indicates the start of a format specifier.
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index fd804eb..11df61f 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -10,18 +10,22 @@
// A intra-procedural analysis for thread safety (e.g. deadlocks and race
// conditions), based off of an annotation system.
//
-// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking
+// See http://clang.llvm.org/docs/ThreadSafetyAnalysis.html
// for more information.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/Analyses/ThreadSafety.h"
+#include "clang/Analysis/Analyses/ThreadSafetyLogical.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
@@ -173,8 +177,8 @@
CallingContext* PrevCtx; // The previous context; or 0 if none.
CallingContext(const NamedDecl *D)
- : AttrDecl(D), SelfArg(0), SelfArrow(false), NumArgs(0), FunArgs(0),
- PrevCtx(0) {}
+ : AttrDecl(D), SelfArg(nullptr), SelfArrow(false), NumArgs(0),
+ FunArgs(nullptr), PrevCtx(nullptr) {}
};
typedef SmallVector<SExprNode, 4> NodeVector;
@@ -185,7 +189,7 @@
NodeVector NodeVec;
private:
- unsigned make(ExprOp O, unsigned F = 0, const void *D = 0) {
+ unsigned make(ExprOp O, unsigned F = 0, const void *D = nullptr) {
NodeVec.push_back(SExprNode(O, F, D));
return NodeVec.size() - 1;
}
@@ -232,7 +236,7 @@
return D; // Method does not override anything
D = *I; // FIXME: this does not work with multiple inheritance.
}
- return 0;
+ return nullptr;
}
unsigned makeMCall(unsigned NumArgs, const CXXMethodDecl *D) {
@@ -268,8 +272,8 @@
/// NDeref returns the number of Derefence and AddressOf operations
/// preceding the Expr; this is used to decide whether to pretty-print
/// SExprs with . or ->.
- unsigned buildSExpr(const Expr *Exp, CallingContext* CallCtx,
- int* NDeref = 0) {
+ unsigned buildSExpr(const Expr *Exp, CallingContext *CallCtx,
+ int *NDeref = nullptr) {
if (!Exp)
return 0;
@@ -366,7 +370,7 @@
}
}
unsigned NumCallArgs = CE->getNumArgs();
- unsigned Root = makeCall(NumCallArgs, 0);
+ unsigned Root = makeCall(NumCallArgs, nullptr);
unsigned Sz = buildSExpr(CE->getCallee(), CallCtx);
const Expr* const* CallArgs = CE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
@@ -459,7 +463,7 @@
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
void buildSExprFromExpr(const Expr *MutexExp, const Expr *DeclExp,
- const NamedDecl *D, VarDecl *SelfDecl = 0) {
+ const NamedDecl *D, VarDecl *SelfDecl = nullptr) {
CallingContext CallCtx(D);
if (MutexExp) {
@@ -476,8 +480,8 @@
}
// If we are processing a raw attribute expression, with no substitutions.
- if (DeclExp == 0) {
- buildSExpr(MutexExp, 0);
+ if (!DeclExp) {
+ buildSExpr(MutexExp, nullptr);
return;
}
@@ -497,7 +501,7 @@
CallCtx.FunArgs = CE->getArgs();
} else if (const CXXConstructExpr *CE =
dyn_cast<CXXConstructExpr>(DeclExp)) {
- CallCtx.SelfArg = 0; // Will be set below
+ CallCtx.SelfArg = nullptr; // Will be set below
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (D && isa<CXXDestructorDecl>(D)) {
@@ -513,16 +517,16 @@
CallCtx.SelfArg = &SelfDRE;
// If the attribute has no arguments, then assume the argument is "this".
- if (MutexExp == 0)
- buildSExpr(CallCtx.SelfArg, 0);
+ if (!MutexExp)
+ buildSExpr(CallCtx.SelfArg, nullptr);
else // For most attributes.
buildSExpr(MutexExp, &CallCtx);
return;
}
// If the attribute has no arguments, then assume the argument is "this".
- if (MutexExp == 0)
- buildSExpr(CallCtx.SelfArg, 0);
+ if (!MutexExp)
+ buildSExpr(CallCtx.SelfArg, nullptr);
else // For most attributes.
buildSExpr(MutexExp, &CallCtx);
}
@@ -540,8 +544,8 @@
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
/// Caller must check isValid() after construction.
- SExpr(const Expr* MutexExp, const Expr *DeclExp, const NamedDecl* D,
- VarDecl *SelfDecl=0) {
+ SExpr(const Expr *MutexExp, const Expr *DeclExp, const NamedDecl *D,
+ VarDecl *SelfDecl = nullptr) {
buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl);
}
@@ -845,45 +849,38 @@
return false;
}
- // Returns an iterator
iterator findLockIter(FactManager &FM, const SExpr &M) {
- for (iterator I = begin(), E = end(); I != E; ++I) {
- const SExpr &Exp = FM[*I].MutID;
- if (Exp.matches(M))
- return I;
- }
- return end();
+ return std::find_if(begin(), end(), [&](FactID ID) {
+ return FM[ID].MutID.matches(M);
+ });
}
- LockData* findLock(FactManager &FM, const SExpr &M) const {
- for (const_iterator I = begin(), E = end(); I != E; ++I) {
- const SExpr &Exp = FM[*I].MutID;
- if (Exp.matches(M))
- return &FM[*I].LDat;
- }
- return 0;
+ LockData *findLock(FactManager &FM, const SExpr &M) const {
+ auto I = std::find_if(begin(), end(), [&](FactID ID) {
+ return FM[ID].MutID.matches(M);
+ });
+
+ return I != end() ? &FM[*I].LDat : nullptr;
}
- LockData* findLockUniv(FactManager &FM, const SExpr &M) const {
- for (const_iterator I = begin(), E = end(); I != E; ++I) {
- const SExpr &Exp = FM[*I].MutID;
- if (Exp.matches(M) || Exp.isUniversal())
- return &FM[*I].LDat;
- }
- return 0;
+ LockData *findLockUniv(FactManager &FM, const SExpr &M) const {
+ auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool {
+ const SExpr &Expr = FM[ID].MutID;
+ return Expr.isUniversal() || Expr.matches(M);
+ });
+
+ return I != end() ? &FM[*I].LDat : nullptr;
}
- FactEntry* findPartialMatch(FactManager &FM, const SExpr &M) const {
- for (const_iterator I=begin(), E=end(); I != E; ++I) {
- const SExpr& Exp = FM[*I].MutID;
- if (Exp.partiallyMatches(M)) return &FM[*I];
- }
- return 0;
+ FactEntry *findPartialMatch(FactManager &FM, const SExpr &M) const {
+ auto I = std::find_if(begin(), end(), [&](FactID ID) {
+ return FM[ID].MutID.partiallyMatches(M);
+ });
+
+ return I != end() ? &FM[*I] : nullptr;
}
};
-
-
/// A Lockset maps each SExpr (defined above) to information about how it has
/// been locked.
typedef llvm::ImmutableMap<SExpr, LockData> Lockset;
@@ -965,7 +962,7 @@
// Create reference to previous definition
VarDefinition(const NamedDecl *D, unsigned R, Context C)
- : Dec(D), Exp(0), Ref(R), Ctx(C)
+ : Dec(D), Exp(nullptr), Ref(R), Ctx(C)
{ }
};
@@ -978,14 +975,14 @@
public:
LocalVariableMap() {
// index 0 is a placeholder for undefined variables (aka phi-nodes).
- VarDefinitions.push_back(VarDefinition(0, 0u, getEmptyContext()));
+ VarDefinitions.push_back(VarDefinition(nullptr, 0u, getEmptyContext()));
}
/// Look up a definition, within the given context.
const VarDefinition* lookup(const NamedDecl *D, Context Ctx) {
const unsigned *i = Ctx.lookup(D);
if (!i)
- return 0;
+ return nullptr;
assert(*i < VarDefinitions.size());
return &VarDefinitions[*i];
}
@@ -996,7 +993,7 @@
const Expr* lookupExpr(const NamedDecl *D, Context &Ctx) {
const unsigned *P = Ctx.lookup(D);
if (!P)
- return 0;
+ return nullptr;
unsigned i = *P;
while (i > 0) {
@@ -1006,7 +1003,7 @@
}
i = VarDefinitions[i].Ref;
}
- return 0;
+ return nullptr;
}
Context getEmptyContext() { return ContextFactory.getEmptyMap(); }
@@ -1066,8 +1063,8 @@
}
/// Builds the variable map.
- void traverseCFG(CFG *CFGraph, PostOrderCFGView *SortedGraph,
- std::vector<CFGBlockInfo> &BlockInfo);
+ void traverseCFG(CFG *CFGraph, const PostOrderCFGView *SortedGraph,
+ std::vector<CFGBlockInfo> &BlockInfo);
protected:
// Get the current context index
@@ -1080,7 +1077,7 @@
// Adds a new definition to the given context, and returns a new context.
// This method should be called when declaring a new variable.
- Context addDefinition(const NamedDecl *D, Expr *Exp, Context Ctx) {
+ Context addDefinition(const NamedDecl *D, const Expr *Exp, Context Ctx) {
assert(!Ctx.contains(D));
unsigned newID = VarDefinitions.size();
Context NewCtx = ContextFactory.add(Ctx, D, newID);
@@ -1161,9 +1158,9 @@
void VarMapBuilder::VisitDeclStmt(DeclStmt *S) {
bool modifiedCtx = false;
DeclGroupRef DGrp = S->getDeclGroup();
- for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
- if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
- Expr *E = VD->getInit();
+ for (const auto *D : DGrp) {
+ if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
+ const Expr *E = VD->getInit();
// Add local variables with trivial type to the variable map
QualType T = VD->getType();
@@ -1205,13 +1202,12 @@
LocalVariableMap::Context
LocalVariableMap::intersectContexts(Context C1, Context C2) {
Context Result = C1;
- for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) {
- const NamedDecl *Dec = I.getKey();
- unsigned i1 = I.getData();
+ for (const auto &P : C1) {
+ const NamedDecl *Dec = P.first;
const unsigned *i2 = C2.lookup(Dec);
if (!i2) // variable doesn't exist on second path
Result = removeDefinition(Dec, Result);
- else if (*i2 != i1) // variable exists, but has different definition
+ else if (*i2 != P.second) // variable exists, but has different definition
Result = clearDefinition(Dec, Result);
}
return Result;
@@ -1222,11 +1218,8 @@
// (We use this for a naive implementation of SSA on loop back-edges.)
LocalVariableMap::Context LocalVariableMap::createReferenceContext(Context C) {
Context Result = getEmptyContext();
- for (Context::iterator I = C.begin(), E = C.end(); I != E; ++I) {
- const NamedDecl *Dec = I.getKey();
- unsigned i = I.getData();
- Result = addReference(Dec, i, Result);
- }
+ for (const auto &P : C)
+ Result = addReference(P.first, P.second, Result);
return Result;
}
@@ -1234,13 +1227,12 @@
// altering the VarDefinitions. C1 must be the result of an earlier call to
// createReferenceContext.
void LocalVariableMap::intersectBackEdge(Context C1, Context C2) {
- for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) {
- const NamedDecl *Dec = I.getKey();
- unsigned i1 = I.getData();
+ for (const auto &P : C1) {
+ unsigned i1 = P.second;
VarDefinition *VDef = &VarDefinitions[i1];
assert(VDef->isReference());
- const unsigned *i2 = C2.lookup(Dec);
+ const unsigned *i2 = C2.lookup(P.first);
if (!i2 || (*i2 != i1))
VDef->Ref = 0; // Mark this variable as undefined
}
@@ -1286,15 +1278,13 @@
// ... { y -> y1 | x3 = 2, x2 = 1, ... }
//
void LocalVariableMap::traverseCFG(CFG *CFGraph,
- PostOrderCFGView *SortedGraph,
+ const PostOrderCFGView *SortedGraph,
std::vector<CFGBlockInfo> &BlockInfo) {
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
CtxIndices.resize(CFGraph->getNumBlockIDs());
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
int CurrBlockID = CurrBlock->getBlockID();
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
@@ -1306,7 +1296,7 @@
for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
// if *PI -> CurrBlock is a back edge, so skip it
- if (*PI == 0 || !VisitedBlocks.alreadySet(*PI)) {
+ if (*PI == nullptr || !VisitedBlocks.alreadySet(*PI)) {
HasBackEdges = true;
continue;
}
@@ -1332,7 +1322,7 @@
createReferenceContext(CurrBlockInfo->EntryContext);
// Create a starting context index for the current block
- saveContext(0, CurrBlockInfo->EntryContext);
+ saveContext(nullptr, CurrBlockInfo->EntryContext);
CurrBlockInfo->EntryIndex = getContextIndex();
// Visit all the statements in the basic block.
@@ -1355,7 +1345,7 @@
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
// if CurrBlock -> *SI is *not* a back edge
- if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
+ if (*SI == nullptr || !VisitedBlocks.alreadySet(*SI))
continue;
CFGBlock *FirstLoopBlock = *SI;
@@ -1367,17 +1357,15 @@
// Put an extra entry at the end of the indexed context array
unsigned exitID = CFGraph->getExit().getBlockID();
- saveContext(0, BlockInfo[exitID].ExitContext);
+ saveContext(nullptr, BlockInfo[exitID].ExitContext);
}
/// Find the appropriate source locations to use when producing diagnostics for
/// each block in the CFG.
static void findBlockLocations(CFG *CFGraph,
- PostOrderCFGView *SortedGraph,
+ const PostOrderCFGView *SortedGraph,
std::vector<CFGBlockInfo> &BlockInfo) {
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()];
// Find the source location of the last statement in the block, if the
@@ -1435,7 +1423,7 @@
template <typename AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
- const NamedDecl *D, VarDecl *SelfDecl=0);
+ const NamedDecl *D, VarDecl *SelfDecl = nullptr);
template <class AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
@@ -1479,12 +1467,12 @@
}
template <typename Ty>
-class has_arg_iterator {
+class has_arg_iterator_range {
typedef char yes[1];
typedef char no[2];
template <typename Inner>
- static yes& test(Inner *I, decltype(I->args_begin()) * = nullptr);
+ static yes& test(Inner *I, decltype(I->args()) * = nullptr);
template <typename>
static no& test(...);
@@ -1523,7 +1511,7 @@
}
template <typename AttrTy>
-static typename std::enable_if<!has_arg_iterator<AttrTy>::value,
+static typename std::enable_if<!has_arg_iterator_range<AttrTy>::value,
StringRef>::type
ClassifyDiagnostic(const AttrTy *A) {
if (const ValueDecl *VD = getValueDecl(A->getArg()))
@@ -1532,11 +1520,11 @@
}
template <typename AttrTy>
-static typename std::enable_if<has_arg_iterator<AttrTy>::value,
+static typename std::enable_if<has_arg_iterator_range<AttrTy>::value,
StringRef>::type
ClassifyDiagnostic(const AttrTy *A) {
- for (auto I = A->args_begin(), E = A->args_end(); I != E; ++I) {
- if (const ValueDecl *VD = getValueDecl(*I))
+ for (const auto *Arg : A->args()) {
+ if (const ValueDecl *VD = getValueDecl(Arg))
return ClassifyDiagnostic(VD);
}
return "mutex";
@@ -1613,22 +1601,21 @@
void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
Expr *Exp, const NamedDecl *D,
VarDecl *SelfDecl) {
- typedef typename AttrType::args_iterator iterator_type;
-
if (Attr->args_size() == 0) {
// The mutex held is the "this" object.
- SExpr Mu(0, Exp, D, SelfDecl);
+ SExpr Mu(nullptr, Exp, D, SelfDecl);
if (!Mu.isValid())
- SExpr::warnInvalidLock(Handler, 0, Exp, D, ClassifyDiagnostic(Attr));
+ SExpr::warnInvalidLock(Handler, nullptr, Exp, D,
+ ClassifyDiagnostic(Attr));
else
Mtxs.push_back_nodup(Mu);
return;
}
- for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
- SExpr Mu(*I, Exp, D, SelfDecl);
+ for (const auto *Arg : Attr->args()) {
+ SExpr Mu(Arg, Exp, D, SelfDecl);
if (!Mu.isValid())
- SExpr::warnInvalidLock(Handler, *I, Exp, D, ClassifyDiagnostic(Attr));
+ SExpr::warnInvalidLock(Handler, Arg, Exp, D, ClassifyDiagnostic(Attr));
else
Mtxs.push_back_nodup(Mu);
}
@@ -1645,23 +1632,22 @@
const CFGBlock *CurrBlock,
Expr *BrE, bool Neg) {
// Find out which branch has the lock
- bool branch = 0;
- if (CXXBoolLiteralExpr *BLE = dyn_cast_or_null<CXXBoolLiteralExpr>(BrE)) {
+ bool branch = false;
+ if (CXXBoolLiteralExpr *BLE = dyn_cast_or_null<CXXBoolLiteralExpr>(BrE))
branch = BLE->getValue();
- }
- else if (IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE)) {
+ else if (IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE))
branch = ILE->getValue().getBoolValue();
- }
+
int branchnum = branch ? 0 : 1;
- if (Neg) branchnum = !branchnum;
+ if (Neg)
+ branchnum = !branchnum;
// If we've taken the trylock branch, then add the lock
int i = 0;
for (CFGBlock::const_succ_iterator SI = PredBlock->succ_begin(),
SE = PredBlock->succ_end(); SI != SE && i < 2; ++SI, ++i) {
- if (*SI == CurrBlock && i == branchnum) {
+ if (*SI == CurrBlock && i == branchnum)
getMutexIDs(Mtxs, Attr, Exp, D);
- }
}
}
@@ -1690,7 +1676,7 @@
LocalVarContext C,
bool &Negate) {
if (!Cond)
- return 0;
+ return nullptr;
if (const CallExpr *CallExp = dyn_cast<CallExpr>(Cond)) {
return CallExp;
@@ -1713,7 +1699,7 @@
Negate = !Negate;
return getTrylockCallExpr(UOP->getSubExpr(), C, Negate);
}
- return 0;
+ return nullptr;
}
else if (const BinaryOperator *BOP = dyn_cast<BinaryOperator>(Cond)) {
if (BOP->getOpcode() == BO_EQ || BOP->getOpcode() == BO_NE) {
@@ -1730,7 +1716,7 @@
if (!TCond) Negate = !Negate;
return getTrylockCallExpr(BOP->getRHS(), C, Negate);
}
- return 0;
+ return nullptr;
}
if (BOP->getOpcode() == BO_LAnd) {
// LHS must have been evaluated in a different block.
@@ -1739,9 +1725,9 @@
if (BOP->getOpcode() == BO_LOr) {
return getTrylockCallExpr(BOP->getRHS(), C, Negate);
}
- return 0;
+ return nullptr;
}
- return 0;
+ return nullptr;
}
@@ -1776,9 +1762,7 @@
MutexIDList SharedLocksToAdd;
// If the condition is a call to a Trylock function, then grab the attributes
- AttrVec &ArgAttrs = FunDecl->getAttrs();
- for (unsigned i = 0; i < ArgAttrs.size(); ++i) {
- Attr *Attr = ArgAttrs[i];
+ for (auto *Attr : FunDecl->getAttrs()) {
switch (Attr->getKind()) {
case attr::ExclusiveTrylockFunction: {
ExclusiveTrylockFunctionAttr *A =
@@ -1834,7 +1818,7 @@
void checkAccess(const Expr *Exp, AccessKind AK);
void checkPtAccess(const Expr *Exp, AccessKind AK);
- void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);
+ void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = nullptr);
public:
BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
@@ -2059,21 +2043,16 @@
case attr::RequiresCapability: {
RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
-
- for (RequiresCapabilityAttr::args_iterator I = A->args_begin(),
- E = A->args_end(); I != E; ++I)
- warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, *I,
+ for (auto *Arg : A->args())
+ warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, Arg,
POK_FunctionCall, ClassifyDiagnostic(A));
break;
}
case attr::LocksExcluded: {
LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
-
- for (LocksExcludedAttr::args_iterator I = A->args_begin(),
- E = A->args_end(); I != E; ++I) {
- warnIfMutexHeld(D, Exp, *I, ClassifyDiagnostic(A));
- }
+ for (auto *Arg : A->args())
+ warnIfMutexHeld(D, Exp, Arg, ClassifyDiagnostic(A));
break;
}
@@ -2106,7 +2085,7 @@
if (isScopedVar) {
SourceLocation MLoc = VD->getLocation();
DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation());
- SExpr SMutex(&DRE, 0, 0);
+ SExpr SMutex(&DRE, nullptr, nullptr);
for (const auto &M : ExclusiveLocksToAdd)
Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Exclusive, M),
@@ -2232,9 +2211,7 @@
// adjust the context
LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, S, LVarCtx);
- DeclGroupRef DGrp = S->getDeclGroup();
- for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
- Decl *D = *I;
+ for (auto *D : S->getDeclGroup()) {
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) {
Expr *E = VD->getInit();
// handle constructors that involve temporaries
@@ -2276,10 +2253,9 @@
FactSet FSet1Orig = FSet1;
// Find locks in FSet2 that conflict or are not in FSet1, and warn.
- for (FactSet::const_iterator I = FSet2.begin(), E = FSet2.end();
- I != E; ++I) {
- const SExpr &FSet2Mutex = FactMan[*I].MutID;
- const LockData &LDat2 = FactMan[*I].LDat;
+ for (const auto &Fact : FSet2) {
+ const SExpr &FSet2Mutex = FactMan[Fact].MutID;
+ const LockData &LDat2 = FactMan[Fact].LDat;
FactSet::iterator I1 = FSet1.findLockIter(FactMan, FSet2Mutex);
if (I1 != FSet1.end()) {
@@ -2289,12 +2265,12 @@
LDat2.AcquireLoc, LDat1->AcquireLoc);
if (Modify && LDat1->LKind != LK_Exclusive) {
// Take the exclusive lock, which is the one in FSet2.
- *I1 = *I;
+ *I1 = Fact;
}
}
else if (LDat1->Asserted && !LDat2.Asserted) {
// The non-asserted lock in FSet2 is the one we want to track.
- *I1 = *I;
+ *I1 = Fact;
}
} else {
if (LDat2.UnderlyingMutex.isValid()) {
@@ -2314,10 +2290,9 @@
}
// Find locks in FSet1 that are not in FSet2, and remove them.
- for (FactSet::const_iterator I = FSet1Orig.begin(), E = FSet1Orig.end();
- I != E; ++I) {
- const SExpr &FSet1Mutex = FactMan[*I].MutID;
- const LockData &LDat1 = FactMan[*I].LDat;
+ for (const auto &Fact : FSet1Orig) {
+ const SExpr &FSet1Mutex = FactMan[Fact].MutID;
+ const LockData &LDat1 = FactMan[Fact].LDat;
if (!FSet2.findLock(FactMan, FSet1Mutex)) {
if (LDat1.UnderlyingMutex.isValid()) {
@@ -2362,16 +2337,21 @@
/// at the end of each block, and issue warnings for thread safety violations.
/// Each block in the CFG is traversed exactly once.
void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
- CFG *CFGraph = AC.getCFG();
- if (!CFGraph) return;
- const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl());
+ // TODO: this whole function needs be rewritten as a visitor for CFGWalker.
+ // For now, we just use the walker to set things up.
+ threadSafety::CFGWalker walker;
+ if (!walker.init(AC))
+ return;
// AC.dumpCFG(true);
+ // threadSafety::printSCFG(walker);
- if (!D)
- return; // Ignore anonymous functions for now.
+ CFG *CFGraph = walker.getGraph();
+ const NamedDecl *D = walker.getDecl();
+
if (D->hasAttr<NoThreadSafetyAnalysisAttr>())
return;
+
// FIXME: Do something a bit more intelligent inside constructor and
// destructor code. Constructors and destructors must assume unique access
// to 'this', so checks on member variable access is disabled, but we should
@@ -2387,7 +2367,7 @@
// We need to explore the CFG via a "topological" ordering.
// That way, we will be guaranteed to have information about required
// predecessor locksets when exploring a new block.
- PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+ const PostOrderCFGView *SortedGraph = walker.getSortedGraph();
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
// Mark entry block as reachable
@@ -2416,23 +2396,22 @@
StringRef CapDiagKind = "mutex";
SourceLocation Loc = D->getLocation();
- for (unsigned i = 0; i < ArgAttrs.size(); ++i) {
- Attr *Attr = ArgAttrs[i];
+ for (const auto *Attr : ArgAttrs) {
Loc = Attr->getLocation();
- if (RequiresCapabilityAttr *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
+ if (const auto *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
- 0, D);
+ nullptr, D);
CapDiagKind = ClassifyDiagnostic(A);
- } else if (auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) {
+ } else if (const auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) {
// UNLOCK_FUNCTION() is used to hide the underlying lock implementation.
// We must ignore such methods.
if (A->args_size() == 0)
return;
// FIXME -- deal with exclusive vs. shared unlock functions?
- getMutexIDs(ExclusiveLocksToAdd, A, (Expr*) 0, D);
- getMutexIDs(LocksReleased, A, (Expr*) 0, D);
+ getMutexIDs(ExclusiveLocksToAdd, A, nullptr, D);
+ getMutexIDs(LocksReleased, A, nullptr, D);
CapDiagKind = ClassifyDiagnostic(A);
- } else if (auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) {
+ } else if (const auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) {
if (A->args_size() == 0)
return;
getMutexIDs(A->isShared() ? SharedLocksAcquired
@@ -2457,9 +2436,7 @@
CapDiagKind);
}
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
int CurrBlockID = CurrBlock->getBlockID();
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
@@ -2485,7 +2462,7 @@
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
// if *PI -> CurrBlock is a back edge
- if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
+ if (*PI == nullptr || !VisitedBlocks.alreadySet(*PI))
continue;
int PrevBlockID = (*PI)->getBlockID();
@@ -2528,9 +2505,7 @@
// Process continue and break blocks. Assume that the lockset for the
// resulting block is unaffected by any discrepancies in them.
- for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size();
- SpecialI < SpecialN; ++SpecialI) {
- CFGBlock *PrevBlock = SpecialBlocks[SpecialI];
+ for (const auto *PrevBlock : SpecialBlocks) {
int PrevBlockID = PrevBlock->getBlockID();
CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
@@ -2599,7 +2574,7 @@
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
// if CurrBlock -> *SI is *not* a back edge
- if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
+ if (*SI == nullptr || !VisitedBlocks.alreadySet(*SI))
continue;
CFGBlock *FirstLoopBlock = *SI;
@@ -2626,17 +2601,14 @@
// by *-LOCK_FUNCTION and UNLOCK_FUNCTION. The intersect below will then
// issue the appropriate warning.
// FIXME: the location here is not quite right.
- for (unsigned i=0,n=ExclusiveLocksAcquired.size(); i<n; ++i) {
- ExpectedExitSet.addLock(FactMan, ExclusiveLocksAcquired[i],
+ for (const auto &Lock : ExclusiveLocksAcquired)
+ ExpectedExitSet.addLock(FactMan, Lock,
LockData(D->getLocation(), LK_Exclusive));
- }
- for (unsigned i=0,n=SharedLocksAcquired.size(); i<n; ++i) {
- ExpectedExitSet.addLock(FactMan, SharedLocksAcquired[i],
+ for (const auto &Lock : SharedLocksAcquired)
+ ExpectedExitSet.addLock(FactMan, Lock,
LockData(D->getLocation(), LK_Shared));
- }
- for (unsigned i=0,n=LocksReleased.size(); i<n; ++i) {
- ExpectedExitSet.removeLock(FactMan, LocksReleased[i]);
- }
+ for (const auto &Lock : LocksReleased)
+ ExpectedExitSet.removeLock(FactMan, Lock);
// FIXME: Should we call this function for all blocks which exit the function?
intersectAndWarn(ExpectedExitSet, Final->ExitSet,
diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp
new file mode 100644
index 0000000..91cf849
--- /dev/null
+++ b/lib/Analysis/ThreadSafetyCommon.cpp
@@ -0,0 +1,791 @@
+//===- ThreadSafetyCommon.cpp ----------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the interfaces declared in ThreadSafetyCommon.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <algorithm>
+#include <climits>
+#include <vector>
+
+
+namespace clang {
+namespace threadSafety {
+
+// From ThreadSafetyUtil.h
+std::string getSourceLiteralString(const clang::Expr *CE) {
+ switch (CE->getStmtClass()) {
+ case Stmt::IntegerLiteralClass:
+ return cast<IntegerLiteral>(CE)->getValue().toString(10, true);
+ case Stmt::StringLiteralClass: {
+ std::string ret("\"");
+ ret += cast<StringLiteral>(CE)->getString();
+ ret += "\"";
+ return ret;
+ }
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::ObjCStringLiteralClass:
+ default:
+ return "#lit";
+ }
+}
+
+namespace til {
+
+// Return true if E is a variable that points to an incomplete Phi node.
+static bool isIncompleteVar(const SExpr *E) {
+ if (const auto *V = dyn_cast<Variable>(E)) {
+ if (const auto *Ph = dyn_cast<Phi>(V->definition()))
+ return Ph->status() == Phi::PH_Incomplete;
+ }
+ return false;
+}
+
+} // end namespace til
+
+
+typedef SExprBuilder::CallingContext CallingContext;
+
+
+til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
+ auto It = SMap.find(S);
+ if (It != SMap.end())
+ return It->second;
+ return nullptr;
+}
+
+
+til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
+ Walker.walk(*this);
+ return Scfg;
+}
+
+
+// Translate a clang statement or expression to a TIL expression.
+// Also performs substitution of variables; Ctx provides the context.
+// Dispatches on the type of S.
+til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
+ if (!S)
+ return nullptr;
+
+ // Check if S has already been translated and cached.
+ // This handles the lookup of SSA names for DeclRefExprs here.
+ if (til::SExpr *E = lookupStmt(S))
+ return E;
+
+ switch (S->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ return translateDeclRefExpr(cast<DeclRefExpr>(S), Ctx);
+ case Stmt::CXXThisExprClass:
+ return translateCXXThisExpr(cast<CXXThisExpr>(S), Ctx);
+ case Stmt::MemberExprClass:
+ return translateMemberExpr(cast<MemberExpr>(S), Ctx);
+ case Stmt::CallExprClass:
+ return translateCallExpr(cast<CallExpr>(S), Ctx);
+ case Stmt::CXXMemberCallExprClass:
+ return translateCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), Ctx);
+ case Stmt::CXXOperatorCallExprClass:
+ return translateCXXOperatorCallExpr(cast<CXXOperatorCallExpr>(S), Ctx);
+ case Stmt::UnaryOperatorClass:
+ return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
+ case Stmt::BinaryOperatorClass:
+ case Stmt::CompoundAssignOperatorClass:
+ return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
+
+ case Stmt::ArraySubscriptExprClass:
+ return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
+ case Stmt::ConditionalOperatorClass:
+ return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
+ case Stmt::BinaryConditionalOperatorClass:
+ return translateBinaryConditionalOperator(
+ cast<BinaryConditionalOperator>(S), Ctx);
+
+ // We treat these as no-ops
+ case Stmt::ParenExprClass:
+ return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);
+ case Stmt::ExprWithCleanupsClass:
+ return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);
+ case Stmt::CXXBindTemporaryExprClass:
+ return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
+
+ // Collect all literals
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::StringLiteralClass:
+ case Stmt::ObjCStringLiteralClass:
+ return new (Arena) til::Literal(cast<Expr>(S));
+
+ case Stmt::DeclStmtClass:
+ return translateDeclStmt(cast<DeclStmt>(S), Ctx);
+ default:
+ break;
+ }
+ if (const CastExpr *CE = dyn_cast<CastExpr>(S))
+ return translateCastExpr(CE, Ctx);
+
+ return new (Arena) til::Undefined(S);
+}
+
+
+til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
+ CallingContext *Ctx) {
+ const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
+
+ // Function parameters require substitution and/or renaming.
+ if (const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
+ const FunctionDecl *FD =
+ cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
+ unsigned I = PV->getFunctionScopeIndex();
+
+ if (Ctx && Ctx->FunArgs && FD == Ctx->AttrDecl->getCanonicalDecl()) {
+ // Substitute call arguments for references to function parameters
+ assert(I < Ctx->NumArgs);
+ return translate(Ctx->FunArgs[I], Ctx->Prev);
+ }
+ // Map the param back to the param of the original function declaration
+ // for consistent comparisons.
+ VD = FD->getParamDecl(I);
+ }
+
+ // For non-local variables, treat it as a referenced to a named object.
+ return new (Arena) til::LiteralPtr(VD);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
+ CallingContext *Ctx) {
+ // Substitute for 'this'
+ if (Ctx && Ctx->SelfArg)
+ return translate(Ctx->SelfArg, Ctx->Prev);
+ assert(SelfVar && "We have no variable for 'this'!");
+ return SelfVar;
+}
+
+
+til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
+ CallingContext *Ctx) {
+ til::SExpr *E = translate(ME->getBase(), Ctx);
+ E = new (Arena) til::SApply(E);
+ return new (Arena) til::Project(E, ME->getMemberDecl());
+}
+
+
+til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
+ CallingContext *Ctx) {
+ // TODO -- Lock returned
+ til::SExpr *E = translate(CE->getCallee(), Ctx);
+ for (const auto *Arg : CE->arguments()) {
+ til::SExpr *A = translate(Arg, Ctx);
+ E = new (Arena) til::Apply(E, A);
+ }
+ return new (Arena) til::Call(E, CE);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
+ const CXXMemberCallExpr *ME, CallingContext *Ctx) {
+ return translateCallExpr(cast<CallExpr>(ME), Ctx);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
+ const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
+ return translateCallExpr(cast<CallExpr>(OCE), Ctx);
+}
+
+
+til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
+ CallingContext *Ctx) {
+ switch (UO->getOpcode()) {
+ case UO_PostInc:
+ case UO_PostDec:
+ case UO_PreInc:
+ case UO_PreDec:
+ return new (Arena) til::Undefined(UO);
+
+ // We treat these as no-ops
+ case UO_AddrOf:
+ case UO_Deref:
+ case UO_Plus:
+ return translate(UO->getSubExpr(), Ctx);
+
+ case UO_Minus:
+ return new (Arena)
+ til::UnaryOp(til::UOP_Minus, translate(UO->getSubExpr(), Ctx));
+ case UO_Not:
+ return new (Arena)
+ til::UnaryOp(til::UOP_BitNot, translate(UO->getSubExpr(), Ctx));
+ case UO_LNot:
+ return new (Arena)
+ til::UnaryOp(til::UOP_LogicNot, translate(UO->getSubExpr(), Ctx));
+
+ // Currently unsupported
+ case UO_Real:
+ case UO_Imag:
+ case UO_Extension:
+ return new (Arena) til::Undefined(UO);
+ }
+ return new (Arena) til::Undefined(UO);
+}
+
+
+til::SExpr *SExprBuilder::translateBinOp(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx, bool Reverse) {
+ til::SExpr *E0 = translate(BO->getLHS(), Ctx);
+ til::SExpr *E1 = translate(BO->getRHS(), Ctx);
+ if (Reverse)
+ return new (Arena) til::BinaryOp(Op, E1, E0);
+ else
+ return new (Arena) til::BinaryOp(Op, E0, E1);
+}
+
+
+til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx,
+ bool Assign) {
+ const Expr *LHS = BO->getLHS();
+ const Expr *RHS = BO->getRHS();
+ til::SExpr *E0 = translate(LHS, Ctx);
+ til::SExpr *E1 = translate(RHS, Ctx);
+
+ const ValueDecl *VD = nullptr;
+ til::SExpr *CV = nullptr;
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
+ VD = DRE->getDecl();
+ CV = lookupVarDecl(VD);
+ }
+
+ if (!Assign) {
+ til::SExpr *Arg = CV ? CV : new (Arena) til::Load(E0);
+ E1 = new (Arena) til::BinaryOp(Op, Arg, E1);
+ E1 = addStatement(E1, nullptr, VD);
+ }
+ if (VD && CV)
+ return updateVarDecl(VD, E1);
+ return new (Arena) til::Store(E0, E1);
+}
+
+
+til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
+ CallingContext *Ctx) {
+ switch (BO->getOpcode()) {
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ return new (Arena) til::Undefined(BO);
+
+ case BO_Mul: return translateBinOp(til::BOP_Mul, BO, Ctx);
+ case BO_Div: return translateBinOp(til::BOP_Div, BO, Ctx);
+ case BO_Rem: return translateBinOp(til::BOP_Rem, BO, Ctx);
+ case BO_Add: return translateBinOp(til::BOP_Add, BO, Ctx);
+ case BO_Sub: return translateBinOp(til::BOP_Sub, BO, Ctx);
+ case BO_Shl: return translateBinOp(til::BOP_Shl, BO, Ctx);
+ case BO_Shr: return translateBinOp(til::BOP_Shr, BO, Ctx);
+ case BO_LT: return translateBinOp(til::BOP_Lt, BO, Ctx);
+ case BO_GT: return translateBinOp(til::BOP_Lt, BO, Ctx, true);
+ case BO_LE: return translateBinOp(til::BOP_Leq, BO, Ctx);
+ case BO_GE: return translateBinOp(til::BOP_Leq, BO, Ctx, true);
+ case BO_EQ: return translateBinOp(til::BOP_Eq, BO, Ctx);
+ case BO_NE: return translateBinOp(til::BOP_Neq, BO, Ctx);
+ case BO_And: return translateBinOp(til::BOP_BitAnd, BO, Ctx);
+ case BO_Xor: return translateBinOp(til::BOP_BitXor, BO, Ctx);
+ case BO_Or: return translateBinOp(til::BOP_BitOr, BO, Ctx);
+ case BO_LAnd: return translateBinOp(til::BOP_LogicAnd, BO, Ctx);
+ case BO_LOr: return translateBinOp(til::BOP_LogicOr, BO, Ctx);
+
+ case BO_Assign: return translateBinAssign(til::BOP_Eq, BO, Ctx, true);
+ case BO_MulAssign: return translateBinAssign(til::BOP_Mul, BO, Ctx);
+ case BO_DivAssign: return translateBinAssign(til::BOP_Div, BO, Ctx);
+ case BO_RemAssign: return translateBinAssign(til::BOP_Rem, BO, Ctx);
+ case BO_AddAssign: return translateBinAssign(til::BOP_Add, BO, Ctx);
+ case BO_SubAssign: return translateBinAssign(til::BOP_Sub, BO, Ctx);
+ case BO_ShlAssign: return translateBinAssign(til::BOP_Shl, BO, Ctx);
+ case BO_ShrAssign: return translateBinAssign(til::BOP_Shr, BO, Ctx);
+ case BO_AndAssign: return translateBinAssign(til::BOP_BitAnd, BO, Ctx);
+ case BO_XorAssign: return translateBinAssign(til::BOP_BitXor, BO, Ctx);
+ case BO_OrAssign: return translateBinAssign(til::BOP_BitOr, BO, Ctx);
+
+ case BO_Comma:
+ // The clang CFG should have already processed both sides.
+ return translate(BO->getRHS(), Ctx);
+ }
+ return new (Arena) til::Undefined(BO);
+}
+
+
+til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
+ CallingContext *Ctx) {
+ clang::CastKind K = CE->getCastKind();
+ switch (K) {
+ case CK_LValueToRValue: {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
+ til::SExpr *E0 = lookupVarDecl(DRE->getDecl());
+ if (E0)
+ return E0;
+ }
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return new (Arena) til::Load(E0);
+ }
+ case CK_NoOp:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay: {
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return E0;
+ }
+ default: {
+ // FIXME: handle different kinds of casts.
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return new (Arena) til::Cast(til::CAST_none, E0);
+ }
+ }
+}
+
+
+til::SExpr *
+SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
+ CallingContext *Ctx) {
+ til::SExpr *E0 = translate(E->getBase(), Ctx);
+ til::SExpr *E1 = translate(E->getIdx(), Ctx);
+ auto *AA = new (Arena) til::ArrayAdd(E0, E1);
+ return new (Arena) til::ArrayFirst(AA);
+}
+
+
+til::SExpr *
+SExprBuilder::translateConditionalOperator(const ConditionalOperator *C,
+ CallingContext *Ctx) {
+ return new (Arena) til::Undefined(C);
+}
+
+
+til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
+ const BinaryConditionalOperator *C, CallingContext *Ctx) {
+ return new (Arena) til::Undefined(C);
+}
+
+
+til::SExpr *
+SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
+ DeclGroupRef DGrp = S->getDeclGroup();
+ for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
+ if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
+ Expr *E = VD->getInit();
+ til::SExpr* SE = translate(E, Ctx);
+
+ // Add local variables with trivial type to the variable map
+ QualType T = VD->getType();
+ if (T.isTrivialType(VD->getASTContext())) {
+ return addVarDecl(VD, SE);
+ }
+ else {
+ // TODO: add alloca
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+
+// If (E) is non-trivial, then add it to the current basic block, and
+// update the statement map so that S refers to E. Returns a new variable
+// that refers to E.
+// If E is trivial returns E.
+til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,
+ const ValueDecl *VD) {
+ if (!E)
+ return nullptr;
+ if (til::ThreadSafetyTIL::isTrivial(E))
+ return E;
+
+ til::Variable *V = new (Arena) til::Variable(E, VD);
+ CurrentInstructions.push_back(V);
+ if (S)
+ insertStmt(S, V);
+ return V;
+}
+
+
+// Returns the current value of VD, if known, and nullptr otherwise.
+til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {
+ auto It = LVarIdxMap.find(VD);
+ if (It != LVarIdxMap.end()) {
+ assert(CurrentLVarMap[It->second].first == VD);
+ return CurrentLVarMap[It->second].second;
+ }
+ return nullptr;
+}
+
+
+// if E is a til::Variable, update its clangDecl.
+inline void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
+ if (!E)
+ return;
+ if (til::Variable *V = dyn_cast<til::Variable>(E)) {
+ if (!V->clangDecl())
+ V->setClangDecl(VD);
+ }
+}
+
+// Adds a new variable declaration.
+til::SExpr *SExprBuilder::addVarDecl(const ValueDecl *VD, til::SExpr *E) {
+ maybeUpdateVD(E, VD);
+ LVarIdxMap.insert(std::make_pair(VD, CurrentLVarMap.size()));
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.push_back(std::make_pair(VD, E));
+ return E;
+}
+
+
+// Updates a current variable declaration. (E.g. by assignment)
+til::SExpr *SExprBuilder::updateVarDecl(const ValueDecl *VD, til::SExpr *E) {
+ maybeUpdateVD(E, VD);
+ auto It = LVarIdxMap.find(VD);
+ if (It == LVarIdxMap.end()) {
+ til::SExpr *Ptr = new (Arena) til::LiteralPtr(VD);
+ til::SExpr *St = new (Arena) til::Store(Ptr, E);
+ return St;
+ }
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.elem(It->second).second = E;
+ return E;
+}
+
+
+// Make a Phi node in the current block for the i^th variable in CurrentVarMap.
+// If E != null, sets Phi[CurrentBlockInfo->ArgIndex] = E.
+// If E == null, this is a backedge and will be set later.
+void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
+ unsigned ArgIndex = CurrentBlockInfo->ProcessedPredecessors;
+ assert(ArgIndex > 0 && ArgIndex < NPreds);
+
+ til::Variable *V = dyn_cast<til::Variable>(CurrentLVarMap[i].second);
+ if (V && V->getBlockID() == CurrentBB->blockID()) {
+ // We already have a Phi node in the current block,
+ // so just add the new variable to the Phi node.
+ til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+ assert(Ph && "Expecting Phi node.");
+ if (E)
+ Ph->values()[ArgIndex] = E;
+ return;
+ }
+
+ // Make a new phi node: phi(..., E)
+ // All phi args up to the current index are set to the current value.
+ til::SExpr *CurrE = CurrentLVarMap[i].second;
+ til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
+ Ph->values().setValues(NPreds, nullptr);
+ for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
+ Ph->values()[PIdx] = CurrE;
+ if (E)
+ Ph->values()[ArgIndex] = E;
+ // If E is from a back-edge, or either E or CurrE are incomplete, then
+ // mark this node as incomplete; we may need to remove it later.
+ if (!E || isIncompleteVar(E) || isIncompleteVar(CurrE)) {
+ Ph->setStatus(til::Phi::PH_Incomplete);
+ }
+
+ // Add Phi node to current block, and update CurrentLVarMap[i]
+ auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first);
+ CurrentArguments.push_back(Var);
+ if (Ph->status() == til::Phi::PH_Incomplete)
+ IncompleteArgs.push_back(Var);
+
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.elem(i).second = Var;
+}
+
+
+// Merge values from Map into the current variable map.
+// This will construct Phi nodes in the current basic block as necessary.
+void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {
+ assert(CurrentBlockInfo && "Not processing a block!");
+
+ if (!CurrentLVarMap.valid()) {
+ // Steal Map, using copy-on-write.
+ CurrentLVarMap = std::move(Map);
+ return;
+ }
+ if (CurrentLVarMap.sameAs(Map))
+ return; // Easy merge: maps from different predecessors are unchanged.
+
+ unsigned NPreds = CurrentBB->numPredecessors();
+ unsigned ESz = CurrentLVarMap.size();
+ unsigned MSz = Map.size();
+ unsigned Sz = std::min(ESz, MSz);
+
+ for (unsigned i=0; i<Sz; ++i) {
+ if (CurrentLVarMap[i].first != Map[i].first) {
+ // We've reached the end of variables in common.
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.downsize(i);
+ break;
+ }
+ if (CurrentLVarMap[i].second != Map[i].second)
+ makePhiNodeVar(i, NPreds, Map[i].second);
+ }
+ if (ESz > MSz) {
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.downsize(Map.size());
+ }
+}
+
+
+// Merge a back edge into the current variable map.
+// This will create phi nodes for all variables in the variable map.
+void SExprBuilder::mergeEntryMapBackEdge() {
+ // We don't have definitions for variables on the backedge, because we
+ // haven't gotten that far in the CFG. Thus, when encountering a back edge,
+ // we conservatively create Phi nodes for all variables. Unnecessary Phi
+ // nodes will be marked as incomplete, and stripped out at the end.
+ //
+ // An Phi node is unnecessary if it only refers to itself and one other
+ // variable, e.g. x = Phi(y, y, x) can be reduced to x = y.
+
+ assert(CurrentBlockInfo && "Not processing a block!");
+
+ if (CurrentBlockInfo->HasBackEdges)
+ return;
+ CurrentBlockInfo->HasBackEdges = true;
+
+ CurrentLVarMap.makeWritable();
+ unsigned Sz = CurrentLVarMap.size();
+ unsigned NPreds = CurrentBB->numPredecessors();
+
+ for (unsigned i=0; i < Sz; ++i) {
+ makePhiNodeVar(i, NPreds, nullptr);
+ }
+}
+
+
+// Update the phi nodes that were initially created for a back edge
+// once the variable definitions have been computed.
+// I.e., merge the current variable map into the phi nodes for Blk.
+void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
+ til::BasicBlock *BB = lookupBlock(Blk);
+ unsigned ArgIndex = BBInfo[Blk->getBlockID()].ProcessedPredecessors;
+ assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());
+
+ for (til::Variable *V : BB->arguments()) {
+ til::Phi *Ph = dyn_cast_or_null<til::Phi>(V->definition());
+ assert(Ph && "Expecting Phi Node.");
+ assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");
+ assert(V->clangDecl() && "No local variable for Phi node.");
+
+ til::SExpr *E = lookupVarDecl(V->clangDecl());
+ assert(E && "Couldn't find local variable for Phi node.");
+
+ Ph->values()[ArgIndex] = E;
+ }
+}
+
+void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,
+ const CFGBlock *First) {
+ // Perform initial setup operations.
+ unsigned NBlocks = Cfg->getNumBlockIDs();
+ Scfg = new (Arena) til::SCFG(Arena, NBlocks);
+
+ // allocate all basic blocks immediately, to handle forward references.
+ BBInfo.resize(NBlocks);
+ BlockMap.resize(NBlocks, nullptr);
+ // create map from clang blockID to til::BasicBlocks
+ for (auto *B : *Cfg) {
+ auto *BB = new (Arena) til::BasicBlock(Arena, 0, B->size());
+ BlockMap[B->getBlockID()] = BB;
+ }
+ CallCtx.reset(new SExprBuilder::CallingContext(D));
+
+ CurrentBB = lookupBlock(&Cfg->getEntry());
+ auto Parms = isa<ObjCMethodDecl>(D) ? cast<ObjCMethodDecl>(D)->parameters()
+ : cast<FunctionDecl>(D)->parameters();
+ for (auto *Pm : Parms) {
+ QualType T = Pm->getType();
+ if (!T.isTrivialType(Pm->getASTContext()))
+ continue;
+
+ // Add parameters to local variable map.
+ // FIXME: right now we emulate params with loads; that should be fixed.
+ til::SExpr *Lp = new (Arena) til::LiteralPtr(Pm);
+ til::SExpr *Ld = new (Arena) til::Load(Lp);
+ til::SExpr *V = addStatement(Ld, nullptr, Pm);
+ addVarDecl(Pm, V);
+ }
+}
+
+
+void SExprBuilder::enterCFGBlock(const CFGBlock *B) {
+ // Intialize TIL basic block and add it to the CFG.
+ CurrentBB = lookupBlock(B);
+ CurrentBB->setNumPredecessors(B->pred_size());
+ Scfg->add(CurrentBB);
+
+ CurrentBlockInfo = &BBInfo[B->getBlockID()];
+
+ // CurrentLVarMap is moved to ExitMap on block exit.
+ // FIXME: the entry block will hold function parameters.
+ // assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
+}
+
+
+void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
+ // Compute CurrentLVarMap on entry from ExitMaps of predecessors
+
+ BlockInfo *PredInfo = &BBInfo[Pred->getBlockID()];
+ assert(PredInfo->UnprocessedSuccessors > 0);
+
+ if (--PredInfo->UnprocessedSuccessors == 0)
+ mergeEntryMap(std::move(PredInfo->ExitMap));
+ else
+ mergeEntryMap(PredInfo->ExitMap.clone());
+
+ ++CurrentBlockInfo->ProcessedPredecessors;
+}
+
+
+void SExprBuilder::handlePredecessorBackEdge(const CFGBlock *Pred) {
+ mergeEntryMapBackEdge();
+}
+
+
+void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
+ // The merge*() methods have created arguments.
+ // Push those arguments onto the basic block.
+ CurrentBB->arguments().reserve(
+ static_cast<unsigned>(CurrentArguments.size()), Arena);
+ for (auto *V : CurrentArguments)
+ CurrentBB->addArgument(V);
+}
+
+
+void SExprBuilder::handleStatement(const Stmt *S) {
+ til::SExpr *E = translate(S, CallCtx.get());
+ addStatement(E, S);
+}
+
+
+void SExprBuilder::handleDestructorCall(const VarDecl *VD,
+ const CXXDestructorDecl *DD) {
+ til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
+ til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
+ til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
+ til::SExpr *E = new (Arena) til::Call(Ap);
+ addStatement(E, nullptr);
+}
+
+
+
+void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
+ CurrentBB->instructions().reserve(
+ static_cast<unsigned>(CurrentInstructions.size()), Arena);
+ for (auto *V : CurrentInstructions)
+ CurrentBB->addInstruction(V);
+
+ // Create an appropriate terminator
+ unsigned N = B->succ_size();
+ auto It = B->succ_begin();
+ if (N == 1) {
+ til::BasicBlock *BB = *It ? lookupBlock(*It) : nullptr;
+ // TODO: set index
+ til::SExpr *Tm = new (Arena) til::Goto(BB, 0);
+ CurrentBB->setTerminator(Tm);
+ }
+ else if (N == 2) {
+ til::SExpr *C = translate(B->getTerminatorCondition(true), CallCtx.get());
+ til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;
+ ++It;
+ til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;
+ // TODO: set conditional, set index
+ til::SExpr *Tm = new (Arena) til::Branch(C, BB1, BB2);
+ CurrentBB->setTerminator(Tm);
+ }
+}
+
+
+void SExprBuilder::handleSuccessor(const CFGBlock *Succ) {
+ ++CurrentBlockInfo->UnprocessedSuccessors;
+}
+
+
+void SExprBuilder::handleSuccessorBackEdge(const CFGBlock *Succ) {
+ mergePhiNodesBackEdge(Succ);
+ ++BBInfo[Succ->getBlockID()].ProcessedPredecessors;
+}
+
+
+void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
+ CurrentBlockInfo->ExitMap = std::move(CurrentLVarMap);
+ CurrentBB = nullptr;
+ CurrentBlockInfo = nullptr;
+}
+
+
+void SExprBuilder::exitCFG(const CFGBlock *Last) {
+ for (auto *V : IncompleteArgs) {
+ til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+ if (Ph && Ph->status() == til::Phi::PH_Incomplete)
+ simplifyIncompleteArg(V, Ph);
+ }
+
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
+ IncompleteArgs.clear();
+}
+
+
+
+class TILPrinter : public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {};
+
+
+void printSCFG(CFGWalker &Walker) {
+ llvm::BumpPtrAllocator Bpa;
+ til::MemRegionRef Arena(&Bpa);
+ SExprBuilder builder(Arena);
+ til::SCFG *Cfg = builder.buildCFG(Walker);
+ TILPrinter::print(Cfg, llvm::errs());
+}
+
+
+
+} // end namespace threadSafety
+
+} // end namespace clang
diff --git a/lib/Analysis/ThreadSafetyLogical.cpp b/lib/Analysis/ThreadSafetyLogical.cpp
new file mode 100644
index 0000000..51a8077
--- /dev/null
+++ b/lib/Analysis/ThreadSafetyLogical.cpp
@@ -0,0 +1,112 @@
+//===- ThreadSafetyLogical.cpp ---------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file defines a representation for logical expressions with SExpr leaves
+// that are used as part of fact-checking capability expressions.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafetyLogical.h"
+
+using namespace llvm;
+using namespace clang::threadSafety::lexpr;
+
+// Implication. We implement De Morgan's Laws by maintaining LNeg and RNeg
+// to keep track of whether LHS and RHS are negated.
+static bool implies(const LExpr *LHS, bool LNeg, const LExpr *RHS, bool RNeg) {
+ // In comments below, we write => for implication.
+
+ // Calculates the logical AND implication operator.
+ const auto LeftAndOperator = [=](const BinOp *A) {
+ return implies(A->left(), LNeg, RHS, RNeg) &&
+ implies(A->right(), LNeg, RHS, RNeg);
+ };
+ const auto RightAndOperator = [=](const BinOp *A) {
+ return implies(LHS, LNeg, A->left(), RNeg) &&
+ implies(LHS, LNeg, A->right(), RNeg);
+ };
+
+ // Calculates the logical OR implication operator.
+ const auto LeftOrOperator = [=](const BinOp *A) {
+ return implies(A->left(), LNeg, RHS, RNeg) ||
+ implies(A->right(), LNeg, RHS, RNeg);
+ };
+ const auto RightOrOperator = [=](const BinOp *A) {
+ return implies(LHS, LNeg, A->left(), RNeg) ||
+ implies(LHS, LNeg, A->right(), RNeg);
+ };
+
+ // Recurse on right.
+ switch (RHS->kind()) {
+ case LExpr::And:
+ // When performing right recursion:
+ // C => A & B [if] C => A and C => B
+ // When performing right recursion (negated):
+ // C => !(A & B) [if] C => !A | !B [===] C => !A or C => !B
+ return RNeg ? RightOrOperator(cast<And>(RHS))
+ : RightAndOperator(cast<And>(RHS));
+ case LExpr::Or:
+ // When performing right recursion:
+ // C => (A | B) [if] C => A or C => B
+ // When performing right recursion (negated):
+ // C => !(A | B) [if] C => !A & !B [===] C => !A and C => !B
+ return RNeg ? RightAndOperator(cast<Or>(RHS))
+ : RightOrOperator(cast<Or>(RHS));
+ case LExpr::Not:
+ // Note that C => !A is very different from !(C => A). It would be incorrect
+ // to return !implies(LHS, RHS).
+ return implies(LHS, LNeg, cast<Not>(RHS)->exp(), !RNeg);
+ case LExpr::Terminal:
+ // After reaching the terminal, it's time to recurse on the left.
+ break;
+ }
+
+ // RHS is now a terminal. Recurse on Left.
+ switch (LHS->kind()) {
+ case LExpr::And:
+ // When performing left recursion:
+ // A & B => C [if] A => C or B => C
+ // When performing left recursion (negated):
+ // !(A & B) => C [if] !A | !B => C [===] !A => C and !B => C
+ return LNeg ? LeftAndOperator(cast<And>(LHS))
+ : LeftOrOperator(cast<And>(LHS));
+ case LExpr::Or:
+ // When performing left recursion:
+ // A | B => C [if] A => C and B => C
+ // When performing left recursion (negated):
+ // !(A | B) => C [if] !A & !B => C [===] !A => C or !B => C
+ return LNeg ? LeftOrOperator(cast<Or>(LHS))
+ : LeftAndOperator(cast<Or>(LHS));
+ case LExpr::Not:
+ // Note that A => !C is very different from !(A => C). It would be incorrect
+ // to return !implies(LHS, RHS).
+ return implies(cast<Not>(LHS)->exp(), !LNeg, RHS, RNeg);
+ case LExpr::Terminal:
+ // After reaching the terminal, it's time to perform identity comparisons.
+ break;
+ }
+
+ // A => A
+ // !A => !A
+ if (LNeg != RNeg)
+ return false;
+
+ // FIXME -- this should compare SExprs for equality, not pointer equality.
+ return cast<Terminal>(LHS)->expr() == cast<Terminal>(RHS)->expr();
+}
+
+namespace clang {
+namespace threadSafety {
+namespace lexpr {
+
+bool implies(const LExpr *LHS, const LExpr *RHS) {
+ // Start out by assuming that LHS and RHS are not negated.
+ return ::implies(LHS, false, RHS, false);
+}
+}
+}
+}
diff --git a/lib/Analysis/ThreadSafetyTIL.cpp b/lib/Analysis/ThreadSafetyTIL.cpp
new file mode 100644
index 0000000..f4da8d4
--- /dev/null
+++ b/lib/Analysis/ThreadSafetyTIL.cpp
@@ -0,0 +1,113 @@
+//===- ThreadSafetyTIL.cpp -------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT in the llvm repository for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+
+namespace clang {
+namespace threadSafety {
+namespace til {
+
+
+StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) {
+ switch (Op) {
+ case UOP_Minus: return "-";
+ case UOP_BitNot: return "~";
+ case UOP_LogicNot: return "!";
+ }
+ return "";
+}
+
+
+StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op) {
+ switch (Op) {
+ case BOP_Mul: return "*";
+ case BOP_Div: return "/";
+ case BOP_Rem: return "%";
+ case BOP_Add: return "+";
+ case BOP_Sub: return "-";
+ case BOP_Shl: return "<<";
+ case BOP_Shr: return ">>";
+ case BOP_BitAnd: return "&";
+ case BOP_BitXor: return "^";
+ case BOP_BitOr: return "|";
+ case BOP_Eq: return "==";
+ case BOP_Neq: return "!=";
+ case BOP_Lt: return "<";
+ case BOP_Leq: return "<=";
+ case BOP_LogicAnd: return "&&";
+ case BOP_LogicOr: return "||";
+ }
+ return "";
+}
+
+
+
+// If E is a variable, then trace back through any aliases or redundant
+// Phi nodes to find the canonical definition.
+SExpr *getCanonicalVal(SExpr *E) {
+ while (auto *V = dyn_cast<Variable>(E)) {
+ SExpr *D;
+ do {
+ if (V->kind() != Variable::VK_Let)
+ return V;
+ D = V->definition();
+ auto *V2 = dyn_cast<Variable>(D);
+ if (V2)
+ V = V2;
+ else
+ break;
+ } while (true);
+
+ if (ThreadSafetyTIL::isTrivial(D))
+ return D;
+
+ if (Phi *Ph = dyn_cast<Phi>(D)) {
+ if (Ph->status() == Phi::PH_Incomplete)
+ simplifyIncompleteArg(V, Ph);
+
+ if (Ph->status() == Phi::PH_SingleVal) {
+ E = Ph->values()[0];
+ continue;
+ }
+ }
+ return V;
+ }
+ return E;
+}
+
+
+// Trace the arguments of an incomplete Phi node to see if they have the same
+// canonical definition. If so, mark the Phi node as redundant.
+// getCanonicalVal() will recursively call simplifyIncompletePhi().
+void simplifyIncompleteArg(Variable *V, til::Phi *Ph) {
+ assert(Ph && Ph->status() == Phi::PH_Incomplete);
+
+ // eliminate infinite recursion -- assume that this node is not redundant.
+ Ph->setStatus(Phi::PH_MultiVal);
+
+ SExpr *E0 = getCanonicalVal(Ph->values()[0]);
+ for (unsigned i=1, n=Ph->values().size(); i<n; ++i) {
+ SExpr *Ei = getCanonicalVal(Ph->values()[i]);
+ if (Ei == V)
+ continue; // Recursive reference to itself. Don't count.
+ if (Ei != E0) {
+ return; // Status is already set to MultiVal.
+ }
+ }
+ Ph->setStatus(Phi::PH_SingleVal);
+ // Eliminate Redundant Phi node.
+ V->setDefinition(Ph->values()[0]);
+}
+
+
+} // end namespace til
+} // end namespace threadSafety
+} // end namespace clang
+
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 29c17c3..4b8a59c 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -236,7 +236,7 @@
}
const CFGBlock *DataflowWorklist::dequeue() {
- const CFGBlock *B = 0;
+ const CFGBlock *B = nullptr;
// First dequeue from the worklist. This can represent
// updates along backedges that we want propagated as quickly as possible.
@@ -250,7 +250,7 @@
++PO_I;
}
else {
- return 0;
+ return nullptr;
}
assert(enqueuedBlocks[B->getBlockID()] == true);
@@ -295,7 +295,7 @@
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
if (isTrackedVar(VD, DC))
return FindVarResult(VD, DRE);
- return FindVarResult(0, 0);
+ return FindVarResult(nullptr, nullptr);
}
/// \brief Classify each DeclRefExpr as an initialization or a use. Any
@@ -353,7 +353,7 @@
if (DRE && DRE->getDecl() == VD)
return DRE;
}
- return 0;
+ return nullptr;
}
void ClassifyRefs::classify(const Expr *E, Class C) {
@@ -542,7 +542,7 @@
// This block initializes the variable.
continue;
if (AtPredExit == MayUninitialized &&
- vals.getValue(B, 0, vd) == Uninitialized) {
+ vals.getValue(B, nullptr, vd) == Uninitialized) {
// This block declares the variable (uninitialized), and is reachable
// from a block that initializes the variable. We can't guarantee to
// give an earlier location for the diagnostic (and it appears that