summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis')
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp17
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/CFG.cpp187
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp127
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp135
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp53
6 files changed, 277 insertions, 247 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp
index d7fb7e9..52c7f26 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -148,6 +148,23 @@ const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
}
}
+ auto *CXXMethod = dyn_cast<CXXMethodDecl>(D);
+ if (!CXXMethod)
+ return nullptr;
+
+ const CXXRecordDecl *parent = CXXMethod->getParent();
+ if (!parent->isLambda())
+ return nullptr;
+
+ for (const LambdaCapture &LC : parent->captures()) {
+ if (!LC.capturesVariable())
+ continue;
+
+ VarDecl *VD = LC.getCapturedVar();
+ if (VD->getName() == "self")
+ return dyn_cast<ImplicitParamDecl>(VD);
+ }
+
return nullptr;
}
diff --git a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp
index 7d1b235..0990436 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/BodyFarm.cpp
@@ -36,10 +36,7 @@ static bool isDispatchBlock(QualType Ty) {
// returns void.
const FunctionProtoType *FT =
BPT->getPointeeType()->getAs<FunctionProtoType>();
- if (!FT || !FT->getReturnType()->isVoidType() || FT->getNumParams() != 0)
- return false;
-
- return true;
+ return FT && FT->getReturnType()->isVoidType() && FT->getNumParams() == 0;
}
namespace {
diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp
index 54d15bd..ed2239f 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp
@@ -39,6 +39,78 @@ static SourceLocation GetEndLoc(Decl *D) {
return D->getLocation();
}
+/// Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral
+/// or EnumConstantDecl from the given Expr. If it fails, returns nullptr.
+const Expr *tryTransformToIntOrEnumConstant(const Expr *E) {
+ E = E->IgnoreParens();
+ if (isa<IntegerLiteral>(E))
+ return E;
+ if (auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
+ return isa<EnumConstantDecl>(DR->getDecl()) ? DR : nullptr;
+ return nullptr;
+}
+
+/// Tries to interpret a binary operator into `Decl Op Expr` form, if Expr is
+/// an integer literal or an enum constant.
+///
+/// If this fails, at least one of the returned DeclRefExpr or Expr will be
+/// null.
+static std::tuple<const DeclRefExpr *, BinaryOperatorKind, const Expr *>
+tryNormalizeBinaryOperator(const BinaryOperator *B) {
+ BinaryOperatorKind Op = B->getOpcode();
+
+ const Expr *MaybeDecl = B->getLHS();
+ const Expr *Constant = tryTransformToIntOrEnumConstant(B->getRHS());
+ // Expr looked like `0 == Foo` instead of `Foo == 0`
+ if (Constant == nullptr) {
+ // Flip the operator
+ if (Op == BO_GT)
+ Op = BO_LT;
+ else if (Op == BO_GE)
+ Op = BO_LE;
+ else if (Op == BO_LT)
+ Op = BO_GT;
+ else if (Op == BO_LE)
+ Op = BO_GE;
+
+ MaybeDecl = B->getRHS();
+ Constant = tryTransformToIntOrEnumConstant(B->getLHS());
+ }
+
+ auto *D = dyn_cast<DeclRefExpr>(MaybeDecl->IgnoreParenImpCasts());
+ return std::make_tuple(D, Op, Constant);
+}
+
+/// For an expression `x == Foo && x == Bar`, this determines whether the
+/// `Foo` and `Bar` are either of the same enumeration type, or both integer
+/// literals.
+///
+/// It's an error to pass this arguments that are not either IntegerLiterals
+/// or DeclRefExprs (that have decls of type EnumConstantDecl)
+static bool areExprTypesCompatible(const Expr *E1, const Expr *E2) {
+ // User intent isn't clear if they're mixing int literals with enum
+ // constants.
+ if (isa<IntegerLiteral>(E1) != isa<IntegerLiteral>(E2))
+ return false;
+
+ // Integer literal comparisons, regardless of literal type, are acceptable.
+ if (isa<IntegerLiteral>(E1))
+ return true;
+
+ // IntegerLiterals are handled above and only EnumConstantDecls are expected
+ // beyond this point
+ assert(isa<DeclRefExpr>(E1) && isa<DeclRefExpr>(E2));
+ auto *Decl1 = cast<DeclRefExpr>(E1)->getDecl();
+ auto *Decl2 = cast<DeclRefExpr>(E2)->getDecl();
+
+ assert(isa<EnumConstantDecl>(Decl1) && isa<EnumConstantDecl>(Decl2));
+ const DeclContext *DC1 = Decl1->getDeclContext();
+ const DeclContext *DC2 = Decl2->getDeclContext();
+
+ assert(isa<EnumDecl>(DC1) && isa<EnumDecl>(DC2));
+ return DC1 == DC2;
+}
+
class CFGBuilder;
/// The CFG builder uses a recursive algorithm to build the CFG. When
@@ -176,8 +248,8 @@ private:
public:
/// Constructs empty scope linked to previous scope in specified place.
- LocalScope(BumpVectorContext &ctx, const_iterator P)
- : ctx(ctx), Vars(ctx, 4), Prev(P) {}
+ LocalScope(BumpVectorContext ctx, const_iterator P)
+ : ctx(std::move(ctx)), Vars(this->ctx, 4), Prev(P) {}
/// Begin of scope in direction of CFG building (backwards).
const_iterator begin() const { return const_iterator(*this, Vars.size()); }
@@ -284,7 +356,7 @@ reverse_children::reverse_children(Stmt *S) {
/// Example usage:
///
/// CFGBuilder builder;
-/// CFG* cfg = builder.BuildAST(stmt1);
+/// std::unique_ptr<CFG> cfg = builder.buildCFG(decl, stmt1);
///
/// CFG construction is done via a recursive walk of an AST. We actually parse
/// the AST in reverse order so that the successor of a basic block is
@@ -388,6 +460,7 @@ private:
CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
CFGBlock *VisitLabelStmt(LabelStmt *L);
+ CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc);
CFGBlock *VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc);
CFGBlock *VisitLogicalOperator(BinaryOperator *B);
std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(BinaryOperator *B,
@@ -694,56 +767,35 @@ private:
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());
- }
+ const DeclRefExpr *Decl1;
+ const Expr *Expr1;
+ BinaryOperatorKind BO1;
+ std::tie(Decl1, BO1, Expr1) = tryNormalizeBinaryOperator(LHS);
- if (!Decl1 || !Literal1)
+ if (!Decl1 || !Expr1)
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());
- }
+ const DeclRefExpr *Decl2;
+ const Expr *Expr2;
+ BinaryOperatorKind BO2;
+ std::tie(Decl2, BO2, Expr2) = tryNormalizeBinaryOperator(RHS);
- if (!Decl2 || !Literal2)
+ if (!Decl2 || !Expr2)
return TryResult();
// Check that it is the same variable on both sides.
if (Decl1->getDecl() != Decl2->getDecl())
return TryResult();
+ // Make sure the user's intent is clear (e.g. they're comparing against two
+ // int literals, or two things from the same enum)
+ if (!areExprTypesCompatible(Expr1, Expr2))
+ return TryResult();
+
llvm::APSInt L1, L2;
- if (!Literal1->EvaluateAsInt(L1, *Context) ||
- !Literal2->EvaluateAsInt(L2, *Context))
+ if (!Expr1->EvaluateAsInt(L1, *Context) ||
+ !Expr2->EvaluateAsInt(L2, *Context))
return TryResult();
// Can't compare signed with unsigned or with different bit width.
@@ -773,10 +825,7 @@ private:
// * 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];
+ for (llvm::APSInt Value : Values) {
TryResult Res1, Res2;
Res1 = analyzeLogicOperatorCondition(BO1, Value, L1);
Res2 = analyzeLogicOperatorCondition(BO2, Value, L2);
@@ -994,9 +1043,8 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
// For C++ constructor add initializers to CFG.
if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
- for (CXXConstructorDecl::init_const_reverse_iterator I = CD->init_rbegin(),
- E = CD->init_rend(); I != E; ++I) {
- B = addInitializer(*I);
+ for (auto *I : llvm::reverse(CD->inits())) {
+ B = addInitializer(I);
if (badCFG)
return nullptr;
}
@@ -1248,13 +1296,11 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
/// createOrReuseLocalScope - If Scope is NULL create new LocalScope. Either
/// way return valid LocalScope object.
LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
- if (!Scope) {
- llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
- Scope = alloc.Allocate<LocalScope>();
- BumpVectorContext ctx(alloc);
- new (Scope) LocalScope(ctx, ScopePos);
- }
- return Scope;
+ if (Scope)
+ return Scope;
+ llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
+ return new (alloc.Allocate<LocalScope>())
+ LocalScope(BumpVectorContext(alloc), ScopePos);
}
/// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement
@@ -1405,7 +1451,7 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
case Stmt::BlockExprClass:
- return VisitNoRecurse(cast<Expr>(S), asc);
+ return VisitBlockExpr(cast<BlockExpr>(S), asc);
case Stmt::BreakStmtClass:
return VisitBreakStmt(cast<BreakStmt>(S));
@@ -1894,7 +1940,15 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
- addLocalScopeAndDtors(C);
+ LocalScope::const_iterator scopeBeginPos = ScopePos;
+ if (BuildOpts.AddImplicitDtors) {
+ addLocalScopeForStmt(C);
+ }
+ if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) {
+ // If the body ends with a ReturnStmt, the dtors will be added in VisitReturnStmt
+ addAutomaticObjDtors(ScopePos, scopeBeginPos, C);
+ }
+
CFGBlock *LastBlock = Block;
for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
@@ -2277,6 +2331,18 @@ CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
return LabelBlock;
}
+CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
+ CFGBlock *LastBlock = VisitNoRecurse(E, asc);
+ for (const BlockDecl::Capture &CI : E->getBlockDecl()->captures()) {
+ if (Expr *CopyExpr = CI.getCopyExpr()) {
+ CFGBlock *Tmp = Visit(CopyExpr);
+ if (Tmp)
+ LastBlock = Tmp;
+ }
+ }
+ return LastBlock;
+}
+
CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
CFGBlock *LastBlock = VisitNoRecurse(E, asc);
for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(),
@@ -3104,11 +3170,11 @@ static bool shouldAddCase(bool &switchExclusivelyCovered,
addCase = true;
switchExclusivelyCovered = true;
}
- else if (condInt < lhsInt) {
+ else if (condInt > lhsInt) {
if (const Expr *RHS = CS->getRHS()) {
// Evaluate the RHS of the case value.
const llvm::APSInt &V2 = RHS->EvaluateKnownConstInt(Ctx);
- if (V2 <= condInt) {
+ if (V2 >= condInt) {
addCase = true;
switchExclusivelyCovered = true;
}
@@ -4128,7 +4194,8 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
const CompoundStmt *Sub = SE->getSubStmt();
- if (Sub->children()) {
+ auto Children = Sub->children();
+ if (Children.begin() != Children.end()) {
OS << "({ ... ; ";
Helper.handledStmt(*SE->getSubStmt()->body_rbegin(),OS);
OS << " })\n";
diff --git a/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp b/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp
index fa985ee..9df2392 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/Consumed.cpp
@@ -1038,65 +1038,54 @@ bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
return true;
}
-void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
- ConsumedStateMap *StateMap,
- bool &AlreadyOwned) {
-
+void ConsumedBlockInfo::addInfo(
+ const CFGBlock *Block, ConsumedStateMap *StateMap,
+ std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
+
assert(Block && "Block pointer must not be NULL");
-
- ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
-
+
+ auto &Entry = StateMapsArray[Block->getBlockID()];
+
if (Entry) {
- Entry->intersect(StateMap);
-
- } else if (AlreadyOwned) {
- StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap);
-
- } else {
- StateMapsArray[Block->getBlockID()] = StateMap;
- AlreadyOwned = true;
- }
+ Entry->intersect(*StateMap);
+ } else if (OwnedStateMap)
+ Entry = std::move(OwnedStateMap);
+ else
+ Entry = llvm::make_unique<ConsumedStateMap>(*StateMap);
}
void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
- ConsumedStateMap *StateMap) {
+ std::unique_ptr<ConsumedStateMap> StateMap) {
assert(Block && "Block pointer must not be NULL");
- ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
-
+ auto &Entry = StateMapsArray[Block->getBlockID()];
+
if (Entry) {
- Entry->intersect(StateMap);
- delete StateMap;
-
+ Entry->intersect(*StateMap);
} else {
- StateMapsArray[Block->getBlockID()] = StateMap;
+ Entry = std::move(StateMap);
}
}
ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
assert(Block && "Block pointer must not be NULL");
assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
-
- return StateMapsArray[Block->getBlockID()];
+
+ return StateMapsArray[Block->getBlockID()].get();
}
void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
- unsigned int BlockID = Block->getBlockID();
- delete StateMapsArray[BlockID];
- StateMapsArray[BlockID] = nullptr;
+ StateMapsArray[Block->getBlockID()] = nullptr;
}
-ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
+std::unique_ptr<ConsumedStateMap>
+ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
assert(Block && "Block pointer must not be NULL");
-
- ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()];
- if (isBackEdgeTarget(Block)) {
- return new ConsumedStateMap(*StateMap);
- } else {
- StateMapsArray[Block->getBlockID()] = nullptr;
- return StateMap;
- }
+
+ auto &Entry = StateMapsArray[Block->getBlockID()];
+ return isBackEdgeTarget(Block) ? llvm::make_unique<ConsumedStateMap>(*Entry)
+ : std::move(Entry);
}
bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
@@ -1166,15 +1155,15 @@ ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
return CS_None;
}
-void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
+void ConsumedStateMap::intersect(const ConsumedStateMap &Other) {
ConsumedState LocalState;
-
- if (this->From && this->From == Other->From && !Other->Reachable) {
+
+ if (this->From && this->From == Other.From && !Other.Reachable) {
this->markUnreachable();
return;
}
-
- for (const auto &DM : Other->VarMap) {
+
+ for (const auto &DM : Other.VarMap) {
LocalState = this->getState(DM.first);
if (LocalState == CS_None)
@@ -1282,14 +1271,14 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
if (PInfo.isVarTest()) {
CurrStates->setSource(Cond);
FalseStates->setSource(Cond);
- splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates,
+ splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates.get(),
FalseStates.get());
-
+
} else if (PInfo.isBinTest()) {
CurrStates->setSource(PInfo.testSourceNode());
FalseStates->setSource(PInfo.testSourceNode());
- splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates.get());
-
+ splitVarStateForIfBinOp(PInfo, CurrStates.get(), FalseStates.get());
+
} else {
return false;
}
@@ -1337,14 +1326,13 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
if (*SI)
- BlockInfo.addInfo(*SI, CurrStates);
+ BlockInfo.addInfo(*SI, std::move(CurrStates));
else
- delete CurrStates;
-
+ CurrStates = nullptr;
+
if (*++SI)
- BlockInfo.addInfo(*SI, FalseStates.release());
+ BlockInfo.addInfo(*SI, std::move(FalseStates));
- CurrStates = nullptr;
return true;
}
@@ -1363,10 +1351,10 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
// AC.getCFG()->viewCFG(LangOptions());
BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
-
- CurrStates = new ConsumedStateMap();
- ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
-
+
+ CurrStates = llvm::make_unique<ConsumedStateMap>();
+ ConsumedStmtVisitor Visitor(AC, *this, CurrStates.get());
+
// Add all trackable parameters to the state map.
for (const auto *PI : D->params())
Visitor.VisitParmVarDecl(PI);
@@ -1380,13 +1368,12 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
continue;
} else if (!CurrStates->isReachable()) {
- delete CurrStates;
CurrStates = nullptr;
continue;
}
-
- Visitor.reset(CurrStates);
-
+
+ Visitor.reset(CurrStates.get());
+
// Visit all of the basic block's statements.
for (const auto &B : *CurrBlock) {
switch (B.getKind()) {
@@ -1429,28 +1416,24 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
if (CurrBlock->succ_size() > 1 ||
(CurrBlock->succ_size() == 1 &&
(*CurrBlock->succ_begin())->pred_size() > 1)) {
-
- bool OwnershipTaken = false;
-
+
+ auto *RawState = CurrStates.get();
+
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
if (*SI == nullptr) continue;
if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
- BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
- CurrStates,
- WarningsHandler);
-
+ BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
+ *SI, CurrBlock, RawState, WarningsHandler);
+
if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
BlockInfo.discardInfo(*SI);
} else {
- BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken);
+ BlockInfo.addInfo(*SI, RawState, CurrStates);
}
}
-
- if (!OwnershipTaken)
- delete CurrStates;
CurrStates = nullptr;
}
@@ -1463,8 +1446,8 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
} // End of block iterator.
// Delete the last existing state map.
- delete CurrStates;
-
+ CurrStates = nullptr;
+
WarningsHandler.emitDiagnostics();
}
}} // end namespace clang::consumed
diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp
index e2c6ab5..b282a5b 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp
@@ -258,16 +258,15 @@ private:
typedef SmallVector<const ValueDecl*, 4> BeforeVect;
struct BeforeInfo {
- BeforeInfo() : Vect(nullptr), Visited(false) { }
- BeforeInfo(BeforeInfo &&O)
- : Vect(std::move(O.Vect)), Visited(O.Visited)
- {}
+ BeforeInfo() : Visited(0) {}
+ BeforeInfo(BeforeInfo &&O) : Vect(std::move(O.Vect)), Visited(O.Visited) {}
- std::unique_ptr<BeforeVect> Vect;
- int Visited;
+ BeforeVect Vect;
+ int Visited;
};
- typedef llvm::DenseMap<const ValueDecl*, BeforeInfo> BeforeMap;
+ typedef llvm::DenseMap<const ValueDecl *, std::unique_ptr<BeforeInfo>>
+ BeforeMap;
typedef llvm::DenseMap<const ValueDecl*, bool> CycleMap;
public:
@@ -276,6 +275,9 @@ public:
BeforeInfo* insertAttrExprs(const ValueDecl* Vd,
ThreadSafetyAnalyzer& Analyzer);
+ BeforeInfo *getBeforeInfoForDecl(const ValueDecl *Vd,
+ ThreadSafetyAnalyzer &Analyzer);
+
void checkBeforeAfter(const ValueDecl* Vd,
const FactSet& FSet,
ThreadSafetyAnalyzer& Analyzer,
@@ -787,7 +789,7 @@ static void findBlockLocations(CFG *CFGraph,
}
}
- if (!CurrBlockInfo->ExitLoc.isInvalid()) {
+ if (CurrBlockInfo->ExitLoc.isValid()) {
// This block contains at least one statement. Find the source location
// of the first statement in the block.
for (CFGBlock::const_iterator BI = CurrBlock->begin(),
@@ -965,26 +967,27 @@ public:
BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd,
ThreadSafetyAnalyzer& Analyzer) {
// Create a new entry for Vd.
- auto& Entry = BMap.FindAndConstruct(Vd);
- BeforeInfo* Info = &Entry.second;
- BeforeVect* Bv = nullptr;
+ BeforeInfo *Info = nullptr;
+ {
+ // Keep InfoPtr in its own scope in case BMap is modified later and the
+ // reference becomes invalid.
+ std::unique_ptr<BeforeInfo> &InfoPtr = BMap[Vd];
+ if (!InfoPtr)
+ InfoPtr.reset(new BeforeInfo());
+ Info = InfoPtr.get();
+ }
for (Attr* At : Vd->attrs()) {
switch (At->getKind()) {
case attr::AcquiredBefore: {
auto *A = cast<AcquiredBeforeAttr>(At);
- // Create a new BeforeVect for Vd if necessary.
- if (!Bv) {
- Bv = new BeforeVect;
- Info->Vect.reset(Bv);
- }
// Read exprs from the attribute, and add them to BeforeVect.
for (const auto *Arg : A->args()) {
CapabilityExpr Cp =
Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr);
if (const ValueDecl *Cpvd = Cp.valueDecl()) {
- Bv->push_back(Cpvd);
+ Info->Vect.push_back(Cpvd);
auto It = BMap.find(Cpvd);
if (It == BMap.end())
insertAttrExprs(Cpvd, Analyzer);
@@ -1001,20 +1004,8 @@ BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd,
Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr);
if (const ValueDecl *ArgVd = Cp.valueDecl()) {
// Get entry for mutex listed in attribute
- BeforeInfo* ArgInfo;
- auto It = BMap.find(ArgVd);
- if (It == BMap.end())
- ArgInfo = insertAttrExprs(ArgVd, Analyzer);
- else
- ArgInfo = &It->second;
-
- // Create a new BeforeVect if necessary.
- BeforeVect* ArgBv = ArgInfo->Vect.get();
- if (!ArgBv) {
- ArgBv = new BeforeVect;
- ArgInfo->Vect.reset(ArgBv);
- }
- ArgBv->push_back(Vd);
+ BeforeInfo *ArgInfo = getBeforeInfoForDecl(ArgVd, Analyzer);
+ ArgInfo->Vect.push_back(Vd);
}
}
break;
@@ -1027,6 +1018,18 @@ BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd,
return Info;
}
+BeforeSet::BeforeInfo *
+BeforeSet::getBeforeInfoForDecl(const ValueDecl *Vd,
+ ThreadSafetyAnalyzer &Analyzer) {
+ auto It = BMap.find(Vd);
+ BeforeInfo *Info = nullptr;
+ if (It == BMap.end())
+ Info = insertAttrExprs(Vd, Analyzer);
+ else
+ Info = It->second.get();
+ assert(Info && "BMap contained nullptr?");
+ return Info;
+}
/// Return true if any mutexes in FSet are in the acquired_before set of Vd.
void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd,
@@ -1041,12 +1044,7 @@ void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd,
if (!Vd)
return false;
- BeforeSet::BeforeInfo* Info;
- auto It = BMap.find(Vd);
- if (It == BMap.end())
- Info = insertAttrExprs(Vd, Analyzer);
- else
- Info = &It->second;
+ BeforeSet::BeforeInfo *Info = getBeforeInfoForDecl(Vd, Analyzer);
if (Info->Visited == 1)
return true;
@@ -1054,13 +1052,12 @@ void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd,
if (Info->Visited == 2)
return false;
- BeforeVect* Bv = Info->Vect.get();
- if (!Bv)
+ if (Info->Vect.empty())
return false;
InfoVect.push_back(Info);
Info->Visited = 1;
- for (auto *Vdb : *Bv) {
+ for (auto *Vdb : Info->Vect) {
// Exclude mutexes in our immediate before set.
if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) {
StringRef L1 = StartVd->getName();
@@ -1926,34 +1923,42 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
}
}
-
if (ExamineArgs) {
if (FunctionDecl *FD = Exp->getDirectCallee()) {
- unsigned Fn = FD->getNumParams();
- unsigned Cn = Exp->getNumArgs();
- unsigned Skip = 0;
-
- unsigned i = 0;
- if (OperatorFun) {
- if (isa<CXXMethodDecl>(FD)) {
- // First arg in operator call is implicit self argument,
- // and doesn't appear in the FunctionDecl.
- Skip = 1;
- Cn--;
- } else {
- // Ignore the first argument of operators; it's been checked above.
- i = 1;
+
+ // NO_THREAD_SAFETY_ANALYSIS does double duty here. Normally it
+ // only turns off checking within the body of a function, but we also
+ // use it to turn off checking in arguments to the function. This
+ // could result in some false negatives, but the alternative is to
+ // create yet another attribute.
+ //
+ if (!FD->hasAttr<NoThreadSafetyAnalysisAttr>()) {
+ unsigned Fn = FD->getNumParams();
+ unsigned Cn = Exp->getNumArgs();
+ unsigned Skip = 0;
+
+ unsigned i = 0;
+ if (OperatorFun) {
+ if (isa<CXXMethodDecl>(FD)) {
+ // First arg in operator call is implicit self argument,
+ // and doesn't appear in the FunctionDecl.
+ Skip = 1;
+ Cn--;
+ } else {
+ // Ignore the first argument of operators; it's been checked above.
+ i = 1;
+ }
+ }
+ // Ignore default arguments
+ unsigned n = (Fn < Cn) ? Fn : Cn;
+
+ for (; i < n; ++i) {
+ ParmVarDecl* Pvd = FD->getParamDecl(i);
+ Expr* Arg = Exp->getArg(i+Skip);
+ QualType Qt = Pvd->getType();
+ if (Qt->isReferenceType())
+ checkAccess(Arg, AK_Read, POK_PassByRef);
}
- }
- // Ignore default arguments
- unsigned n = (Fn < Cn) ? Fn : Cn;
-
- for (; i < n; ++i) {
- ParmVarDecl* Pvd = FD->getParamDecl(i);
- Expr* Arg = Exp->getArg(i+Skip);
- QualType Qt = Pvd->getType();
- if (Qt->isReferenceType())
- checkAccess(Arg, AK_Read, POK_PassByRef);
}
}
}
diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp
index d4b1ce2..ffe95ea 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -1,4 +1,4 @@
-//===- ThreadSafetyCommon.cpp ----------------------------------*- C++ --*-===//
+//===- ThreadSafetyCommon.cpp -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -31,6 +31,7 @@
#include <algorithm>
#include <climits>
#include <vector>
+
using namespace clang;
using namespace threadSafety;
@@ -66,7 +67,6 @@ static bool isIncompletePhi(const til::SExpr *E) {
typedef SExprBuilder::CallingContext CallingContext;
-
til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
auto It = SMap.find(S);
if (It != SMap.end())
@@ -74,7 +74,6 @@ til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
return nullptr;
}
-
til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
Walker.walk(*this);
return Scfg;
@@ -85,7 +84,6 @@ static bool isCalleeArrow(const Expr *E) {
return ME ? ME->isArrow() : false;
}
-
/// \brief Translate a clang expression in an attribute to a til::SExpr.
/// Constructs the context from D, DeclExp, and SelfDecl.
///
@@ -148,7 +146,6 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
return translateAttrExpr(AttrExp, &Ctx);
}
-
/// \brief Translate a clang expression in an attribute to a til::SExpr.
// This assumes a CallingContext has already been created.
CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
@@ -195,8 +192,6 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
return CapabilityExpr(E, Neg);
}
-
-
// 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.
@@ -268,8 +263,6 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
return new (Arena) til::Undefined(S);
}
-
-
til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
CallingContext *Ctx) {
const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
@@ -290,11 +283,10 @@ til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
VD = FD->getParamDecl(I);
}
- // For non-local variables, treat it as a referenced to a named object.
+ // For non-local variables, treat it as a reference to a named object.
return new (Arena) til::LiteralPtr(VD);
}
-
til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
CallingContext *Ctx) {
// Substitute for 'this'
@@ -313,7 +305,7 @@ static const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) {
return P->clangDecl();
if (auto *L = dyn_cast<til::LiteralPtr>(E))
return L->clangDecl();
- return 0;
+ return nullptr;
}
static bool hasCppPointerType(const til::SExpr *E) {
@@ -344,7 +336,8 @@ til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
til::SExpr *BE = translate(ME->getBase(), Ctx);
til::SExpr *E = new (Arena) til::SApply(BE);
- const ValueDecl *D = ME->getMemberDecl();
+ const ValueDecl *D =
+ cast<ValueDecl>(ME->getMemberDecl()->getCanonicalDecl());
if (auto *VD = dyn_cast<CXXMethodDecl>(D))
D = getFirstVirtualDecl(VD);
@@ -354,7 +347,6 @@ til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
return P;
}
-
til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
CallingContext *Ctx,
const Expr *SelfE) {
@@ -380,7 +372,6 @@ til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
return new (Arena) til::Call(E, CE);
}
-
til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
const CXXMemberCallExpr *ME, CallingContext *Ctx) {
if (CapabilityExprMode) {
@@ -396,7 +387,6 @@ til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
ME->getImplicitObjectArgument());
}
-
til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
if (CapabilityExprMode) {
@@ -411,7 +401,6 @@ til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
return translateCallExpr(cast<CallExpr>(OCE), Ctx);
}
-
til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
CallingContext *Ctx) {
switch (UO->getOpcode()) {
@@ -456,12 +445,12 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
case UO_Real:
case UO_Imag:
case UO_Extension:
+ case UO_Coawait:
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) {
@@ -473,7 +462,6 @@ til::SExpr *SExprBuilder::translateBinOp(til::TIL_BinaryOpcode Op,
return new (Arena) til::BinaryOp(Op, E0, E1);
}
-
til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,
const BinaryOperator *BO,
CallingContext *Ctx,
@@ -500,7 +488,6 @@ til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,
return new (Arena) til::Store(E0, E1);
}
-
til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
CallingContext *Ctx) {
switch (BO->getOpcode()) {
@@ -546,7 +533,6 @@ til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
return new (Arena) til::Undefined(BO);
}
-
til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
CallingContext *Ctx) {
clang::CastKind K = CE->getCastKind();
@@ -580,7 +566,6 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
}
}
-
til::SExpr *
SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
CallingContext *Ctx) {
@@ -589,7 +574,6 @@ SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
return new (Arena) til::ArrayIndex(E0, E1);
}
-
til::SExpr *
SExprBuilder::translateAbstractConditionalOperator(
const AbstractConditionalOperator *CO, CallingContext *Ctx) {
@@ -599,7 +583,6 @@ SExprBuilder::translateAbstractConditionalOperator(
return new (Arena) til::IfThenElse(C, T, E);
}
-
til::SExpr *
SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
DeclGroupRef DGrp = S->getDeclGroup();
@@ -621,8 +604,6 @@ SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
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.
@@ -639,7 +620,6 @@ til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,
return E;
}
-
// Returns the current value of VD, if known, and nullptr otherwise.
til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {
auto It = LVarIdxMap.find(VD);
@@ -650,7 +630,6 @@ til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {
return nullptr;
}
-
// if E is a til::Variable, update its clangDecl.
static void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
if (!E)
@@ -670,7 +649,6 @@ til::SExpr *SExprBuilder::addVarDecl(const ValueDecl *VD, til::SExpr *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);
@@ -685,7 +663,6 @@ til::SExpr *SExprBuilder::updateVarDecl(const ValueDecl *VD, til::SExpr *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.
@@ -728,7 +705,6 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
CurrentLVarMap.elem(i).second = Ph;
}
-
// 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) {
@@ -763,7 +739,6 @@ void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {
}
}
-
// Merge a back edge into the current variable map.
// This will create phi nodes for all variables in the variable map.
void SExprBuilder::mergeEntryMapBackEdge() {
@@ -790,7 +765,6 @@ void SExprBuilder::mergeEntryMapBackEdge() {
}
}
-
// 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.
@@ -843,7 +817,6 @@ void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,
}
}
-
void SExprBuilder::enterCFGBlock(const CFGBlock *B) {
// Intialize TIL basic block and add it to the CFG.
CurrentBB = lookupBlock(B);
@@ -857,7 +830,6 @@ void SExprBuilder::enterCFGBlock(const CFGBlock *B) {
// assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
}
-
void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
// Compute CurrentLVarMap on entry from ExitMaps of predecessors
@@ -873,12 +845,10 @@ void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
++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.
@@ -888,13 +858,11 @@ void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
CurrentBB->addArgument(A);
}
-
void SExprBuilder::handleStatement(const Stmt *S) {
til::SExpr *E = translate(S, nullptr);
addStatement(E, S);
}
-
void SExprBuilder::handleDestructorCall(const VarDecl *VD,
const CXXDestructorDecl *DD) {
til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
@@ -904,8 +872,6 @@ void SExprBuilder::handleDestructorCall(const VarDecl *VD,
addStatement(E, nullptr);
}
-
-
void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
CurrentBB->instructions().reserve(
static_cast<unsigned>(CurrentInstructions.size()), Arena);
@@ -933,18 +899,15 @@ void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
}
}
-
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();
@@ -953,7 +916,6 @@ void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
CurrentBlockInfo = nullptr;
}
-
void SExprBuilder::exitCFG(const CFGBlock *Last) {
for (auto *Ph : IncompleteArgs) {
if (Ph->status() == til::Phi::PH_Incomplete)
@@ -965,7 +927,6 @@ void SExprBuilder::exitCFG(const CFGBlock *Last) {
IncompleteArgs.clear();
}
-
/*
void printSCFG(CFGWalker &Walker) {
llvm::BumpPtrAllocator Bpa;
OpenPOWER on IntegriCloud