summaryrefslogtreecommitdiff
path: root/clang/lib/Analysis
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /clang/lib/Analysis
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'clang/lib/Analysis')
-rw-r--r--clang/lib/Analysis/AnalysisDeclContext.cpp117
-rw-r--r--clang/lib/Analysis/BodyFarm.cpp44
-rw-r--r--clang/lib/Analysis/CFG.cpp40
-rw-r--r--clang/lib/Analysis/CallGraph.cpp24
-rw-r--r--clang/lib/Analysis/CloneDetection.cpp1
-rw-r--r--clang/lib/Analysis/ExprMutationAnalyzer.cpp43
-rw-r--r--clang/lib/Analysis/LiveVariables.cpp62
-rw-r--r--clang/lib/Analysis/PathDiagnostic.cpp7
-rw-r--r--clang/lib/Analysis/PostOrderCFGView.cpp5
-rw-r--r--clang/lib/Analysis/ProgramPoint.cpp1
-rw-r--r--clang/lib/Analysis/ReachableCode.cpp4
-rw-r--r--clang/lib/Analysis/RetainSummaryManager.cpp8
-rw-r--r--clang/lib/Analysis/ThreadSafety.cpp59
-rw-r--r--clang/lib/Analysis/UninitializedValues.cpp142
-rw-r--r--clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp2
15 files changed, 256 insertions, 303 deletions
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
index 9f58b5079c760..783de64426458 100644
--- a/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -50,18 +50,18 @@
using namespace clang;
-using ManagedAnalysisMap = llvm::DenseMap<const void *, ManagedAnalysis *>;
+using ManagedAnalysisMap = llvm::DenseMap<const void *, std::unique_ptr<ManagedAnalysis>>;
-AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *d,
- const CFG::BuildOptions &buildOptions)
- : Manager(Mgr), D(d), cfgBuildOptions(buildOptions) {
+AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *ADCMgr,
+ const Decl *D,
+ const CFG::BuildOptions &Options)
+ : ADCMgr(ADCMgr), D(D), cfgBuildOptions(Options) {
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
-AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
- const Decl *d)
- : Manager(Mgr), D(d) {
+AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *ADCMgr,
+ const Decl *D)
+ : ADCMgr(ADCMgr), D(D) {
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
@@ -96,8 +96,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
Stmt *Body = FD->getBody();
if (auto *CoroBody = dyn_cast_or_null<CoroutineBodyStmt>(Body))
Body = CoroBody->getBody();
- if (Manager && Manager->synthesizeBodies()) {
- Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(FD);
+ if (ADCMgr && ADCMgr->synthesizeBodies()) {
+ Stmt *SynthesizedBody = ADCMgr->getBodyFarm().getBody(FD);
if (SynthesizedBody) {
Body = SynthesizedBody;
IsAutosynthesized = true;
@@ -107,8 +107,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
}
else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
Stmt *Body = MD->getBody();
- if (Manager && Manager->synthesizeBodies()) {
- Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(MD);
+ if (ADCMgr && ADCMgr->synthesizeBodies()) {
+ Stmt *SynthesizedBody = ADCMgr->getBodyFarm().getBody(MD);
if (SynthesizedBody) {
Body = SynthesizedBody;
IsAutosynthesized = true;
@@ -309,19 +309,17 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; }
const StackFrameContext *
-AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S,
- const CFGBlock *Blk, unsigned BlockCount,
- unsigned Idx) {
- return getLocationContextManager().getStackFrame(this, Parent, S, Blk,
- BlockCount, Idx);
+AnalysisDeclContext::getStackFrame(const LocationContext *ParentLC,
+ const Stmt *S, const CFGBlock *Blk,
+ unsigned BlockCount, unsigned Index) {
+ return getLocationContextManager().getStackFrame(this, ParentLC, S, Blk,
+ BlockCount, Index);
}
-const BlockInvocationContext *
-AnalysisDeclContext::getBlockInvocationContext(const LocationContext *parent,
- const BlockDecl *BD,
- const void *ContextData) {
- return getLocationContextManager().getBlockInvocationContext(this, parent,
- BD, ContextData);
+const BlockInvocationContext *AnalysisDeclContext::getBlockInvocationContext(
+ const LocationContext *ParentLC, const BlockDecl *BD, const void *Data) {
+ return getLocationContextManager().getBlockInvocationContext(this, ParentLC,
+ BD, Data);
}
bool AnalysisDeclContext::isInStdNamespace(const Decl *D) {
@@ -340,9 +338,10 @@ bool AnalysisDeclContext::isInStdNamespace(const Decl *D) {
}
LocationContextManager &AnalysisDeclContext::getLocationContextManager() {
- assert(Manager &&
- "Cannot create LocationContexts without an AnalysisDeclContextManager!");
- return Manager->getLocationContextManager();
+ assert(
+ ADCMgr &&
+ "Cannot create LocationContexts without an AnalysisDeclContextManager!");
+ return ADCMgr->getLocationContextManager();
}
//===----------------------------------------------------------------------===//
@@ -365,36 +364,14 @@ void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
BlockCount, Index);
}
-void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAnalysisDeclContext(), getParent(), Enter);
-}
-
void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAnalysisDeclContext(), getParent(), BD, ContextData);
+ Profile(ID, getAnalysisDeclContext(), getParent(), BD, Data);
}
//===----------------------------------------------------------------------===//
// LocationContext creation.
//===----------------------------------------------------------------------===//
-template <typename LOC, typename DATA>
-const LOC*
-LocationContextManager::getLocationContext(AnalysisDeclContext *ctx,
- const LocationContext *parent,
- const DATA *d) {
- llvm::FoldingSetNodeID ID;
- LOC::Profile(ID, ctx, parent, d);
- void *InsertPos;
-
- LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
-
- if (!L) {
- L = new LOC(ctx, parent, d, ++NewID);
- Contexts.InsertNode(L, InsertPos);
- }
- return L;
-}
-
const StackFrameContext *LocationContextManager::getStackFrame(
AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s,
const CFGBlock *blk, unsigned blockCount, unsigned idx) {
@@ -410,26 +387,17 @@ const StackFrameContext *LocationContextManager::getStackFrame(
return L;
}
-const ScopeContext *
-LocationContextManager::getScope(AnalysisDeclContext *ctx,
- const LocationContext *parent,
- const Stmt *s) {
- return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
-}
-
-const BlockInvocationContext *
-LocationContextManager::getBlockInvocationContext(AnalysisDeclContext *ctx,
- const LocationContext *parent,
- const BlockDecl *BD,
- const void *ContextData) {
+const BlockInvocationContext *LocationContextManager::getBlockInvocationContext(
+ AnalysisDeclContext *ADC, const LocationContext *ParentLC,
+ const BlockDecl *BD, const void *Data) {
llvm::FoldingSetNodeID ID;
- BlockInvocationContext::Profile(ID, ctx, parent, BD, ContextData);
+ BlockInvocationContext::Profile(ID, ADC, ParentLC, BD, Data);
void *InsertPos;
auto *L =
cast_or_null<BlockInvocationContext>(Contexts.FindNodeOrInsertPos(ID,
InsertPos));
if (!L) {
- L = new BlockInvocationContext(ctx, parent, BD, ContextData, ++NewID);
+ L = new BlockInvocationContext(ADC, ParentLC, BD, Data, ++NewID);
Contexts.InsertNode(L, InsertPos);
}
return L;
@@ -473,9 +441,7 @@ static void printLocation(raw_ostream &Out, const SourceManager &SM,
Loc.print(Out, SM);
}
-void LocationContext::dumpStack(raw_ostream &Out, const char *NL,
- std::function<void(const LocationContext *)>
- printMoreInfoPerContext) const {
+void LocationContext::dumpStack(raw_ostream &Out) const {
ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
PrintingPolicy PP(Ctx.getLangOpts());
PP.TerseOutput = 1;
@@ -498,9 +464,6 @@ void LocationContext::dumpStack(raw_ostream &Out, const char *NL,
printLocation(Out, SM, S->getBeginLoc());
}
break;
- case Scope:
- Out << "Entering scope";
- break;
case Block:
Out << "Invoking block";
if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
@@ -509,9 +472,7 @@ void LocationContext::dumpStack(raw_ostream &Out, const char *NL,
}
break;
}
- Out << NL;
-
- printMoreInfoPerContext(LCtx);
+ Out << '\n';
}
}
@@ -548,9 +509,6 @@ void LocationContext::printJson(raw_ostream &Out, const char *NL,
Out << ", \"items\": ";
break;
- case Scope:
- Out << "Entering scope\" ";
- break;
case Block:
Out << "Invoking block\" ";
if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
@@ -659,7 +617,7 @@ AnalysisDeclContext::getReferencedBlockVars(const BlockDecl *BD) {
return llvm::make_range(V->begin(), V->end());
}
-ManagedAnalysis *&AnalysisDeclContext::getAnalysisImpl(const void *tag) {
+std::unique_ptr<ManagedAnalysis> &AnalysisDeclContext::getAnalysisImpl(const void *tag) {
if (!ManagedAnalyses)
ManagedAnalyses = new ManagedAnalysisMap();
ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses;
@@ -675,12 +633,7 @@ ManagedAnalysis::~ManagedAnalysis() = default;
AnalysisDeclContext::~AnalysisDeclContext() {
delete forcedBlkExprs;
delete ReferencedBlockVars;
- // Release the managed analyses.
- if (ManagedAnalyses) {
- ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses;
- llvm::DeleteContainerSeconds(*M);
- delete M;
- }
+ delete (ManagedAnalysisMap*) ManagedAnalyses;
}
LocationContext::~LocationContext() = default;
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 1a7891550542d..f9f0553d28f05 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -114,21 +114,19 @@ private:
BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
QualType Ty) {
- return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
- BO_Assign, Ty, VK_RValue,
- OK_Ordinary, SourceLocation(), FPOptions());
+ return BinaryOperator::Create(
+ C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty,
+ VK_RValue, OK_Ordinary, SourceLocation(), FPOptionsOverride());
}
BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
BinaryOperator::Opcode Op) {
assert(BinaryOperator::isLogicalOp(Op) ||
BinaryOperator::isComparisonOp(Op));
- return new (C) BinaryOperator(const_cast<Expr*>(LHS),
- const_cast<Expr*>(RHS),
- Op,
- C.getLogicalOperationType(),
- VK_RValue,
- OK_Ordinary, SourceLocation(), FPOptions());
+ return BinaryOperator::Create(
+ C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), Op,
+ C.getLogicalOperationType(), VK_RValue, OK_Ordinary, SourceLocation(),
+ FPOptionsOverride());
}
CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
@@ -147,9 +145,9 @@ DeclRefExpr *ASTMaker::makeDeclRefExpr(
}
UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
- return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
+ return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty,
VK_LValue, OK_Ordinary, SourceLocation(),
- /*CanOverflow*/ false);
+ /*CanOverflow*/ false, FPOptionsOverride());
}
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
@@ -296,7 +294,8 @@ static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
/*Args=*/CallArgs,
/*QualType=*/C.VoidTy,
/*ExprValueType=*/VK_RValue,
- /*SourceLocation=*/SourceLocation(), FPOptions());
+ /*SourceLocation=*/SourceLocation(),
+ /*FPFeatures=*/FPOptionsOverride());
}
/// Create a fake body for std::call_once.
@@ -447,15 +446,16 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
QualType DerefType = Deref->getType();
// Negation predicate.
- UnaryOperator *FlagCheck = new (C) UnaryOperator(
+ UnaryOperator *FlagCheck = UnaryOperator::Create(
+ C,
/* input=*/
M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,
CK_IntegralToBoolean),
- /* opc=*/ UO_LNot,
- /* QualType=*/ C.IntTy,
- /* ExprValueKind=*/ VK_RValue,
- /* ExprObjectKind=*/ OK_Ordinary, SourceLocation(),
- /* CanOverflow*/ false);
+ /* opc=*/UO_LNot,
+ /* QualType=*/C.IntTy,
+ /* ExprValueKind=*/VK_RValue,
+ /* ExprObjectKind=*/OK_Ordinary, SourceLocation(),
+ /* CanOverflow*/ false, FPOptionsOverride());
// Create assignment.
BinaryOperator *FlagAssignment = M.makeAssignment(
@@ -518,9 +518,9 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
// (2) Create the assignment to the predicate.
Expr *DoneValue =
- new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy,
- VK_RValue, OK_Ordinary, SourceLocation(),
- /*CanOverflow*/false);
+ UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,
+ C.LongTy, VK_RValue, OK_Ordinary, SourceLocation(),
+ /*CanOverflow*/ false, FPOptionsOverride());
BinaryOperator *B =
M.makeAssignment(
@@ -762,7 +762,7 @@ static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
return nullptr;
// Ignore weak variables, which have special behavior.
- if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
+ if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)
return nullptr;
// Look to see if Sema has synthesized a body for us. This happens in
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 4c1ea8995f9f6..fc74226951a4b 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -223,8 +223,6 @@ private:
///
class LocalScope {
public:
- friend class const_iterator;
-
using AutomaticVarsTy = BumpVector<VarDecl *>;
/// const_iterator - Iterates local scope backwards and jumps to previous
@@ -720,10 +718,10 @@ private:
// These sorts of call expressions don't have a common superclass,
// hence strict duck-typing.
template <typename CallLikeExpr,
- typename = typename std::enable_if<
- std::is_same<CallLikeExpr, CallExpr>::value ||
- std::is_same<CallLikeExpr, CXXConstructExpr>::value ||
- std::is_same<CallLikeExpr, ObjCMessageExpr>::value>>
+ typename = std::enable_if_t<
+ std::is_base_of<CallExpr, CallLikeExpr>::value ||
+ std::is_base_of<CXXConstructExpr, CallLikeExpr>::value ||
+ std::is_base_of<ObjCMessageExpr, CallLikeExpr>::value>>
void findConstructionContextsForArguments(CallLikeExpr *E) {
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
Expr *Arg = E->getArg(i);
@@ -2839,11 +2837,30 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
/// DeclStmts and initializers in them.
CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
assert(DS->isSingleDecl() && "Can handle single declarations only.");
+
+ if (const auto *TND = dyn_cast<TypedefNameDecl>(DS->getSingleDecl())) {
+ // If we encounter a VLA, process its size expressions.
+ const Type *T = TND->getUnderlyingType().getTypePtr();
+ if (!T->isVariablyModifiedType())
+ return Block;
+
+ autoCreateBlock();
+ appendStmt(Block, DS);
+
+ CFGBlock *LastBlock = Block;
+ for (const VariableArrayType *VA = FindVA(T); VA != nullptr;
+ VA = FindVA(VA->getElementType().getTypePtr())) {
+ if (CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
+ LastBlock = NewBlock;
+ }
+ return LastBlock;
+ }
+
VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
if (!VD) {
- // Of everything that can be declared in a DeclStmt, only VarDecls impact
- // runtime semantics.
+ // Of everything that can be declared in a DeclStmt, only VarDecls and the
+ // exceptions above impact runtime semantics.
return Block;
}
@@ -2905,6 +2922,8 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
}
// If the type of VD is a VLA, then we must process its size expressions.
+ // FIXME: This does not find the VLA if it is embedded in other types,
+ // like here: `int (*p_vla)[x];`
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr())) {
if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
@@ -3997,6 +4016,11 @@ CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
}
// VLA types have expressions that must be evaluated.
+ // Evaluation is done only for `sizeof`.
+
+ if (E->getKind() != UETT_SizeOf)
+ return Block;
+
CFGBlock *lastBlock = Block;
if (E->isArgumentType()) {
diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp
index 76be292dad8d2..59cc939b6fd15 100644
--- a/clang/lib/Analysis/CallGraph.cpp
+++ b/clang/lib/Analysis/CallGraph.cpp
@@ -66,16 +66,16 @@ public:
return nullptr;
}
- void addCalledDecl(Decl *D) {
- if (G->includeInGraph(D)) {
+ void addCalledDecl(Decl *D, Expr *CallExpr) {
+ if (G->includeCalleeInGraph(D)) {
CallGraphNode *CalleeNode = G->getOrInsertNode(D);
- CallerNode->addCallee(CalleeNode);
+ CallerNode->addCallee({CalleeNode, CallExpr});
}
}
void VisitCallExpr(CallExpr *CE) {
if (Decl *D = getDeclFromCall(CE))
- addCalledDecl(D);
+ addCalledDecl(D, CE);
VisitChildren(CE);
}
@@ -89,14 +89,14 @@ public:
void VisitCXXNewExpr(CXXNewExpr *E) {
if (FunctionDecl *FD = E->getOperatorNew())
- addCalledDecl(FD);
+ addCalledDecl(FD, E);
VisitChildren(E);
}
void VisitCXXConstructExpr(CXXConstructExpr *E) {
CXXConstructorDecl *Ctor = E->getConstructor();
if (FunctionDecl *Def = Ctor->getDefinition())
- addCalledDecl(Def);
+ addCalledDecl(Def, E);
VisitChildren(E);
}
@@ -122,7 +122,7 @@ public:
else
D = IDecl->lookupPrivateClassMethod(Sel);
if (D) {
- addCalledDecl(D);
+ addCalledDecl(D, ME);
NumObjCCallEdges++;
}
}
@@ -157,6 +157,10 @@ bool CallGraph::includeInGraph(const Decl *D) {
if (!D->hasBody())
return false;
+ return includeCalleeInGraph(D);
+}
+
+bool CallGraph::includeCalleeInGraph(const Decl *D) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
@@ -207,7 +211,7 @@ CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
Node = std::make_unique<CallGraphNode>(F);
// Make Root node a parent of all functions to make sure all are reachable.
if (F)
- Root->addCallee(Node.get());
+ Root->addCallee({Node.get(), /*Call=*/nullptr});
return Node.get();
}
@@ -230,8 +234,8 @@ void CallGraph::print(raw_ostream &OS) const {
OS << " calls: ";
for (CallGraphNode::const_iterator CI = N->begin(),
CE = N->end(); CI != CE; ++CI) {
- assert(*CI != Root && "No one can call the root node.");
- (*CI)->print(OS);
+ assert(CI->Callee != Root && "No one can call the root node.");
+ CI->Callee->print(OS);
OS << " ";
}
OS << '\n';
diff --git a/clang/lib/Analysis/CloneDetection.cpp b/clang/lib/Analysis/CloneDetection.cpp
index 5fb5840ce293a..0a1122bd5a4af 100644
--- a/clang/lib/Analysis/CloneDetection.cpp
+++ b/clang/lib/Analysis/CloneDetection.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/DataCollection.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/Path.h"
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index fb5a139e82ab2..2f80285f17b4d 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -43,9 +43,6 @@ AST_MATCHER(CXXTypeidExpr, isPotentiallyEvaluated) {
return Node.isPotentiallyEvaluated();
}
-const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXNoexceptExpr>
- cxxNoexceptExpr;
-
const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt,
GenericSelectionExpr>
genericSelectionExpr;
@@ -76,10 +73,10 @@ const auto isMoveOnly = [] {
};
template <class T> struct NodeID;
-template <> struct NodeID<Expr> { static const std::string value; };
-template <> struct NodeID<Decl> { static const std::string value; };
-const std::string NodeID<Expr>::value = "expr";
-const std::string NodeID<Decl>::value = "decl";
+template <> struct NodeID<Expr> { static constexpr StringRef value = "expr"; };
+template <> struct NodeID<Decl> { static constexpr StringRef value = "decl"; };
+constexpr StringRef NodeID<Expr>::value;
+constexpr StringRef NodeID<Decl>::value;
template <class T, class F = const Stmt *(ExprMutationAnalyzer::*)(const T *)>
const Stmt *tryEachMatch(ArrayRef<ast_matchers::BoundNodes> Matches,
@@ -204,14 +201,15 @@ const Stmt *ExprMutationAnalyzer::findDeclPointeeMutation(
const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
// LHS of any assignment operators.
- const auto AsAssignmentLhs =
- binaryOperator(isAssignmentOperator(),
- hasLHS(maybeEvalCommaExpr(equalsNode(Exp))));
+ const auto AsAssignmentLhs = binaryOperator(
+ isAssignmentOperator(),
+ hasLHS(maybeEvalCommaExpr(ignoringParenImpCasts(equalsNode(Exp)))));
// Operand of increment/decrement operators.
const auto AsIncDecOperand =
unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")),
- hasUnaryOperand(maybeEvalCommaExpr(equalsNode(Exp))));
+ hasUnaryOperand(maybeEvalCommaExpr(
+ ignoringParenImpCasts(equalsNode(Exp)))));
// Invoking non-const member function.
// A member function is assumed to be non-const when it is unresolved.
@@ -283,13 +281,15 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
const auto AsNonConstRefReturn = returnStmt(hasReturnValue(
maybeEvalCommaExpr(equalsNode(Exp))));
- const auto Matches =
- match(findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, AsNonConstThis,
- AsAmpersandOperand, AsPointerFromArrayDecay,
- AsOperatorArrowThis, AsNonConstRefArg,
- AsLambdaRefCaptureInit, AsNonConstRefReturn))
- .bind("stmt")),
- Stm, Context);
+ const auto Matches = match(
+ traverse(
+ ast_type_traits::TK_AsIs,
+ findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, AsNonConstThis,
+ AsAmpersandOperand, AsPointerFromArrayDecay,
+ AsOperatorArrowThis, AsNonConstRefArg,
+ AsLambdaRefCaptureInit, AsNonConstRefReturn))
+ .bind("stmt"))),
+ Stm, Context);
return selectFirst<Stmt>("stmt", Matches);
}
@@ -388,12 +388,15 @@ const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(const Expr *Exp) {
const auto IsInstantiated = hasDeclaration(isInstantiated());
const auto FuncDecl = hasDeclaration(functionDecl().bind("func"));
const auto Matches = match(
- findAll(expr(anyOf(callExpr(NonConstRefParam, IsInstantiated, FuncDecl,
+ traverse(
+ ast_type_traits::TK_AsIs,
+ findAll(
+ expr(anyOf(callExpr(NonConstRefParam, IsInstantiated, FuncDecl,
unless(callee(namedDecl(hasAnyName(
"::std::move", "::std::forward"))))),
cxxConstructExpr(NonConstRefParam, IsInstantiated,
FuncDecl)))
- .bind(NodeID<Expr>::value)),
+ .bind(NodeID<Expr>::value))),
Stm, Context);
for (const auto &Nodes : Matches) {
const auto *Exp = Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp
index 2cd607d8a4932..d24c40b457b4b 100644
--- a/clang/lib/Analysis/LiveVariables.cpp
+++ b/clang/lib/Analysis/LiveVariables.cpp
@@ -13,12 +13,10 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/PostOrderIterator.h"
-#include "llvm/ADT/PriorityQueue.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <vector>
@@ -26,51 +24,6 @@
using namespace clang;
namespace {
-
-class DataflowWorklist {
- llvm::BitVector enqueuedBlocks;
- PostOrderCFGView *POV;
- llvm::PriorityQueue<const CFGBlock *, SmallVector<const CFGBlock *, 20>,
- PostOrderCFGView::BlockOrderCompare> worklist;
-
-public:
- DataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx)
- : enqueuedBlocks(cfg.getNumBlockIDs()),
- POV(Ctx.getAnalysis<PostOrderCFGView>()),
- worklist(POV->getComparator()) {}
-
- void enqueueBlock(const CFGBlock *block);
- void enqueuePredecessors(const CFGBlock *block);
-
- const CFGBlock *dequeue();
-};
-
-}
-
-void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
- if (block && !enqueuedBlocks[block->getBlockID()]) {
- enqueuedBlocks[block->getBlockID()] = true;
- worklist.push(block);
- }
-}
-
-void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) {
- for (CFGBlock::const_pred_iterator I = block->pred_begin(),
- E = block->pred_end(); I != E; ++I) {
- enqueueBlock(*I);
- }
-}
-
-const CFGBlock *DataflowWorklist::dequeue() {
- if (worklist.empty())
- return nullptr;
- const CFGBlock *b = worklist.top();
- worklist.pop();
- enqueuedBlocks[b->getBlockID()] = false;
- return b;
-}
-
-namespace {
class LiveVariablesImpl {
public:
AnalysisDeclContext &analysisContext;
@@ -136,7 +89,7 @@ namespace {
}
return A;
}
-}
+} // namespace
void LiveVariables::Observer::anchor() { }
@@ -218,7 +171,7 @@ public:
void VisitUnaryOperator(UnaryOperator *UO);
void Visit(Stmt *S);
};
-}
+} // namespace
static const VariableArrayType *FindVA(QualType Ty) {
const Type *ty = Ty.getTypePtr();
@@ -537,9 +490,8 @@ LiveVariables::~LiveVariables() {
delete (LiveVariablesImpl*) impl;
}
-LiveVariables *
-LiveVariables::computeLiveness(AnalysisDeclContext &AC,
- bool killAtAssign) {
+std::unique_ptr<LiveVariables>
+LiveVariables::computeLiveness(AnalysisDeclContext &AC, bool killAtAssign) {
// No CFG? Bail out.
CFG *cfg = AC.getCFG();
@@ -555,7 +507,7 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
// Construct the dataflow worklist. Enqueue the exit block as the
// start of the analysis.
- DataflowWorklist worklist(*cfg, AC);
+ BackwardDataflowWorklist worklist(*cfg, AC);
llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs());
// FIXME: we should enqueue using post order.
@@ -612,7 +564,7 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
worklist.enqueuePredecessors(block);
}
- return new LiveVariables(LV);
+ return std::unique_ptr<LiveVariables>(new LiveVariables(LV));
}
void LiveVariables::dumpBlockLiveness(const SourceManager &M) {
diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp
index 53235ba076994..c88e6c1e1535f 100644
--- a/clang/lib/Analysis/PathDiagnostic.cpp
+++ b/clang/lib/Analysis/PathDiagnostic.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/AnalysisDeclContext.h"
@@ -909,7 +910,7 @@ static void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
Out << Prefix << '\'' << *D;
if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D))
describeTemplateParameters(Out, T->getTemplateArgs().asArray(),
- D->getASTContext().getLangOpts(), "<", ">");
+ D->getLangOpts(), "<", ">");
Out << '\'';
}
@@ -975,8 +976,8 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
if (const auto FD = dyn_cast<FunctionDecl>(D))
if (const TemplateArgumentList *TAList =
FD->getTemplateSpecializationArgs())
- describeTemplateParameters(Out, TAList->asArray(),
- FD->getASTContext().getLangOpts(), "<", ">");
+ describeTemplateParameters(Out, TAList->asArray(), FD->getLangOpts(), "<",
+ ">");
Out << '\'';
return true;
diff --git a/clang/lib/Analysis/PostOrderCFGView.cpp b/clang/lib/Analysis/PostOrderCFGView.cpp
index f79d0007cb3d9..0c09c0f97ff68 100644
--- a/clang/lib/Analysis/PostOrderCFGView.cpp
+++ b/clang/lib/Analysis/PostOrderCFGView.cpp
@@ -29,11 +29,12 @@ PostOrderCFGView::PostOrderCFGView(const CFG *cfg) {
}
}
-PostOrderCFGView *PostOrderCFGView::create(AnalysisDeclContext &ctx) {
+std::unique_ptr<PostOrderCFGView>
+PostOrderCFGView::create(AnalysisDeclContext &ctx) {
const CFG *cfg = ctx.getCFG();
if (!cfg)
return nullptr;
- return new PostOrderCFGView(cfg);
+ return std::make_unique<PostOrderCFGView>(cfg);
}
const void *PostOrderCFGView::getTag() { static int x; return &x; }
diff --git a/clang/lib/Analysis/ProgramPoint.cpp b/clang/lib/Analysis/ProgramPoint.cpp
index 0783fbed53155..2a91749affd2a 100644
--- a/clang/lib/Analysis/ProgramPoint.cpp
+++ b/clang/lib/Analysis/ProgramPoint.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/ProgramPoint.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/JsonSupport.h"
using namespace clang;
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp
index 369879ad65f50..221d137dadb87 100644
--- a/clang/lib/Analysis/ReachableCode.cpp
+++ b/clang/lib/Analysis/ReachableCode.cpp
@@ -138,10 +138,10 @@ static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM) {
assert(Loc.isMacroID());
SourceLocation Last;
- while (Loc.isMacroID()) {
+ do {
Last = Loc;
Loc = SM.getImmediateMacroCallerLoc(Loc);
- }
+ } while (Loc.isMacroID());
return Last;
}
diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp
index 6f46917b2dfc6..9f45a8efe546f 100644
--- a/clang/lib/Analysis/RetainSummaryManager.cpp
+++ b/clang/lib/Analysis/RetainSummaryManager.cpp
@@ -140,12 +140,15 @@ RetainSummaryManager::getPersistentSummary(const RetainSummary &OldSumm) {
static bool isSubclass(const Decl *D,
StringRef ClassName) {
using namespace ast_matchers;
- DeclarationMatcher SubclassM = cxxRecordDecl(isSameOrDerivedFrom(ClassName));
+ DeclarationMatcher SubclassM =
+ cxxRecordDecl(isSameOrDerivedFrom(std::string(ClassName)));
return !(match(SubclassM, *D, D->getASTContext()).empty());
}
static bool isOSObjectSubclass(const Decl *D) {
- return D && isSubclass(D, "OSMetaClassBase");
+ // OSSymbols are particular OSObjects that are allocated globally
+ // and therefore aren't really refcounted, so we ignore them.
+ return D && isSubclass(D, "OSMetaClassBase") && !isSubclass(D, "OSSymbol");
}
static bool isOSObjectDynamicCast(StringRef S) {
@@ -662,6 +665,7 @@ RetainSummaryManager::getSummary(AnyCall C,
switch (C.getKind()) {
case AnyCall::Function:
case AnyCall::Constructor:
+ case AnyCall::InheritedConstructor:
case AnyCall::Allocator:
case AnyCall::Deallocator:
Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp
index 48f4106b6bae8..1208eaf93e25d 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -905,11 +905,7 @@ public:
ScopedLockableFactEntry(const CapabilityExpr &CE, SourceLocation Loc)
: FactEntry(CE, LK_Exclusive, Loc, false) {}
- void addExclusiveLock(const CapabilityExpr &M) {
- UnderlyingMutexes.emplace_back(M.sexpr(), UCK_Acquired);
- }
-
- void addSharedLock(const CapabilityExpr &M) {
+ void addLock(const CapabilityExpr &M) {
UnderlyingMutexes.emplace_back(M.sexpr(), UCK_Acquired);
}
@@ -999,7 +995,10 @@ private:
FSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
!Cp, LK_Exclusive, loc));
} else if (Handler) {
- Handler->handleUnmatchedUnlock(DiagKind, Cp.toString(), loc);
+ SourceLocation PrevLoc;
+ if (const FactEntry *Neg = FSet.findLock(FactMan, !Cp))
+ PrevLoc = Neg->loc();
+ Handler->handleUnmatchedUnlock(DiagKind, Cp.toString(), loc, PrevLoc);
}
}
};
@@ -1249,8 +1248,7 @@ static StringRef ClassifyDiagnostic(const ValueDecl *VD) {
}
template <typename AttrTy>
-static typename std::enable_if<!has_arg_iterator_range<AttrTy>::value,
- StringRef>::type
+static std::enable_if_t<!has_arg_iterator_range<AttrTy>::value, StringRef>
ClassifyDiagnostic(const AttrTy *A) {
if (const ValueDecl *VD = getValueDecl(A->getArg()))
return ClassifyDiagnostic(VD);
@@ -1258,8 +1256,7 @@ ClassifyDiagnostic(const AttrTy *A) {
}
template <typename AttrTy>
-static typename std::enable_if<has_arg_iterator_range<AttrTy>::value,
- StringRef>::type
+static std::enable_if_t<has_arg_iterator_range<AttrTy>::value, StringRef>
ClassifyDiagnostic(const AttrTy *A) {
for (const auto *Arg : A->args()) {
if (const ValueDecl *VD = getValueDecl(Arg))
@@ -1328,7 +1325,10 @@ void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, const CapabilityExpr &Cp,
const FactEntry *LDat = FSet.findLock(FactMan, Cp);
if (!LDat) {
- Handler.handleUnmatchedUnlock(DiagKind, Cp.toString(), UnlockLoc);
+ SourceLocation PrevLoc;
+ if (const FactEntry *Neg = FSet.findLock(FactMan, !Cp))
+ PrevLoc = Neg->loc();
+ Handler.handleUnmatchedUnlock(DiagKind, Cp.toString(), UnlockLoc, PrevLoc);
return;
}
@@ -1803,7 +1803,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
SourceLocation Loc = Exp->getExprLoc();
CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
- CapExprSet ScopedExclusiveReqs, ScopedSharedReqs;
+ CapExprSet ScopedReqsAndExcludes;
StringRef CapDiagKind = "mutex";
// Figure out if we're constructing an object of scoped lockable class
@@ -1894,19 +1894,20 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
POK_FunctionCall, ClassifyDiagnostic(A),
Exp->getExprLoc());
// use for adopting a lock
- if (isScopedVar) {
- Analyzer->getMutexIDs(A->isShared() ? ScopedSharedReqs
- : ScopedExclusiveReqs,
- A, Exp, D, VD);
- }
+ if (isScopedVar)
+ Analyzer->getMutexIDs(ScopedReqsAndExcludes, A, Exp, D, VD);
}
break;
}
case attr::LocksExcluded: {
const auto *A = cast<LocksExcludedAttr>(At);
- for (auto *Arg : A->args())
+ for (auto *Arg : A->args()) {
warnIfMutexHeld(D, Exp, Arg, ClassifyDiagnostic(A));
+ // use for deferring a lock
+ if (isScopedVar)
+ Analyzer->getMutexIDs(ScopedReqsAndExcludes, A, Exp, D, VD);
+ }
break;
}
@@ -1946,13 +1947,11 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
auto ScopedEntry = std::make_unique<ScopedLockableFactEntry>(Scp, MLoc);
for (const auto &M : ExclusiveLocksToAdd)
- ScopedEntry->addExclusiveLock(M);
- for (const auto &M : ScopedExclusiveReqs)
- ScopedEntry->addExclusiveLock(M);
+ ScopedEntry->addLock(M);
for (const auto &M : SharedLocksToAdd)
- ScopedEntry->addSharedLock(M);
- for (const auto &M : ScopedSharedReqs)
- ScopedEntry->addSharedLock(M);
+ ScopedEntry->addLock(M);
+ for (const auto &M : ScopedReqsAndExcludes)
+ ScopedEntry->addLock(M);
for (const auto &M : ExclusiveLocksToRemove)
ScopedEntry->addExclusiveUnlock(M);
for (const auto &M : SharedLocksToRemove)
@@ -2141,12 +2140,14 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) {
// handle constructors that involve temporaries
if (auto *EWC = dyn_cast<ExprWithCleanups>(E))
- E = EWC->getSubExpr();
- if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
- if (ICE->getCastKind() == CK_NoOp)
- E = ICE->getSubExpr();
+ E = EWC->getSubExpr()->IgnoreParens();
+ if (auto *CE = dyn_cast<CastExpr>(E))
+ if (CE->getCastKind() == CK_NoOp ||
+ CE->getCastKind() == CK_ConstructorConversion ||
+ CE->getCastKind() == CK_UserDefinedConversion)
+ E = CE->getSubExpr()->IgnoreParens();
if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
- E = BTE->getSubExpr();
+ E = BTE->getSubExpr()->IgnoreParens();
if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
const auto *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor());
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index 8a233d4a44f10..67cd39728c350 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -24,6 +24,7 @@
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
@@ -213,68 +214,6 @@ ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
}
//------------------------------------------------------------------------====//
-// Worklist: worklist for dataflow analysis.
-//====------------------------------------------------------------------------//
-
-namespace {
-
-class DataflowWorklist {
- PostOrderCFGView::iterator PO_I, PO_E;
- SmallVector<const CFGBlock *, 20> worklist;
- llvm::BitVector enqueuedBlocks;
-
-public:
- DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
- : PO_I(view.begin()), PO_E(view.end()),
- enqueuedBlocks(cfg.getNumBlockIDs(), true) {
- // Treat the first block as already analyzed.
- if (PO_I != PO_E) {
- assert(*PO_I == &cfg.getEntry());
- enqueuedBlocks[(*PO_I)->getBlockID()] = false;
- ++PO_I;
- }
- }
-
- void enqueueSuccessors(const CFGBlock *block);
- const CFGBlock *dequeue();
-};
-
-} // namespace
-
-void DataflowWorklist::enqueueSuccessors(const CFGBlock *block) {
- for (CFGBlock::const_succ_iterator I = block->succ_begin(),
- E = block->succ_end(); I != E; ++I) {
- const CFGBlock *Successor = *I;
- if (!Successor || enqueuedBlocks[Successor->getBlockID()])
- continue;
- worklist.push_back(Successor);
- enqueuedBlocks[Successor->getBlockID()] = true;
- }
-}
-
-const CFGBlock *DataflowWorklist::dequeue() {
- const CFGBlock *B = nullptr;
-
- // First dequeue from the worklist. This can represent
- // updates along backedges that we want propagated as quickly as possible.
- if (!worklist.empty())
- B = worklist.pop_back_val();
-
- // Next dequeue from the initial reverse post order. This is the
- // theoretical ideal in the presence of no back edges.
- else if (PO_I != PO_E) {
- B = *PO_I;
- ++PO_I;
- }
- else
- return nullptr;
-
- assert(enqueuedBlocks[B->getBlockID()] == true);
- enqueuedBlocks[B->getBlockID()] = false;
- return B;
-}
-
-//------------------------------------------------------------------------====//
// Classification of DeclRefExprs as use or initialization.
//====------------------------------------------------------------------------//
@@ -329,6 +268,7 @@ public:
Init,
Use,
SelfInit,
+ ConstRefUse,
Ignore
};
@@ -465,6 +405,15 @@ static bool isPointerToConst(const QualType &QT) {
return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified();
}
+static bool hasTrivialBody(CallExpr *CE) {
+ if (FunctionDecl *FD = CE->getDirectCallee()) {
+ if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
+ return FTD->getTemplatedDecl()->hasTrivialBody();
+ return FD->hasTrivialBody();
+ }
+ return false;
+}
+
void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
// Classify arguments to std::move as used.
if (CE->isCallToStdMove()) {
@@ -473,15 +422,17 @@ void ClassifyRefs::VisitCallExpr(CallExpr *CE) {
classify(CE->getArg(0), Use);
return;
}
-
- // If a value is passed by const pointer or by const reference to a function,
+ bool isTrivialBody = hasTrivialBody(CE);
+ // If a value is passed by const pointer to a function,
// we should not assume that it is initialized by the call, and we
// conservatively do not assume that it is used.
+ // If a value is passed by const reference to a function,
+ // it should already be initialized.
for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
if ((*I)->isGLValue()) {
if ((*I)->getType().isConstQualified())
- classify((*I), Ignore);
+ classify((*I), isTrivialBody ? Ignore : ConstRefUse);
} else if (isPointerToConst((*I)->getType())) {
const Expr *Ex = stripCasts(DC->getParentASTContext(), *I);
const auto *UO = dyn_cast<UnaryOperator>(Ex);
@@ -530,12 +481,14 @@ public:
handler(handler) {}
void reportUse(const Expr *ex, const VarDecl *vd);
+ void reportConstRefUse(const Expr *ex, const VarDecl *vd);
void VisitBinaryOperator(BinaryOperator *bo);
void VisitBlockExpr(BlockExpr *be);
void VisitCallExpr(CallExpr *ce);
void VisitDeclRefExpr(DeclRefExpr *dr);
void VisitDeclStmt(DeclStmt *ds);
+ void VisitGCCAsmStmt(GCCAsmStmt *as);
void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS);
void VisitObjCMessageExpr(ObjCMessageExpr *ME);
void VisitOMPExecutableDirective(OMPExecutableDirective *ED);
@@ -636,6 +589,28 @@ public:
continue;
}
+ if (AtPredExit == MayUninitialized) {
+ // If the predecessor's terminator is an "asm goto" that initializes
+ // the variable, then it won't be counted as "initialized" on the
+ // non-fallthrough paths.
+ CFGTerminator term = Pred->getTerminator();
+ if (const auto *as = dyn_cast_or_null<GCCAsmStmt>(term.getStmt())) {
+ const CFGBlock *fallthrough = *Pred->succ_begin();
+ if (as->isAsmGoto() &&
+ llvm::any_of(as->outputs(), [&](const Expr *output) {
+ return vd == findVar(output).getDecl() &&
+ llvm::any_of(as->labels(),
+ [&](const AddrLabelExpr *label) {
+ return label->getLabel()->getStmt() == B->Label &&
+ B != fallthrough;
+ });
+ })) {
+ Use.setUninitAfterDecl();
+ continue;
+ }
+ }
+ }
+
unsigned &SV = SuccsVisited[Pred->getBlockID()];
if (!SV) {
// When visiting the first successor of a block, mark all NULL
@@ -705,6 +680,12 @@ void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) {
handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
}
+void TransferFunctions::reportConstRefUse(const Expr *ex, const VarDecl *vd) {
+ Value v = vals[vd];
+ if (isAlwaysUninit(v))
+ handler.handleConstRefUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
+}
+
void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
// This represents an initialization of the 'element' value.
if (const auto *DS = dyn_cast<DeclStmt>(FS->getElement())) {
@@ -772,7 +753,10 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
vals[cast<VarDecl>(dr->getDecl())] = Initialized;
break;
case ClassifyRefs::SelfInit:
- handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
+ handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
+ break;
+ case ClassifyRefs::ConstRefUse:
+ reportConstRefUse(dr, cast<VarDecl>(dr->getDecl()));
break;
}
}
@@ -821,6 +805,20 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
}
}
+void TransferFunctions::VisitGCCAsmStmt(GCCAsmStmt *as) {
+ // An "asm goto" statement is a terminator that may initialize some variables.
+ if (!as->isAsmGoto())
+ return;
+
+ for (const Expr *o : as->outputs())
+ if (const VarDecl *VD = findVar(o).getDecl())
+ if (vals[VD] != Initialized)
+ // If the variable isn't initialized by the time we get here, then we
+ // mark it as potentially uninitialized for those cases where it's used
+ // on an indirect path, where it's not guaranteed to be defined.
+ vals[VD] = MayUninitialized;
+}
+
void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
// If the Objective-C message expression is an implicit no-return that
// is not modeled in the CFG, set the tracked dataflow values to Unknown.
@@ -858,6 +856,10 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
if (Optional<CFGStmt> cs = I.getAs<CFGStmt>())
tf.Visit(const_cast<Stmt *>(cs->getStmt()));
}
+ CFGTerminator terminator = block->getTerminator();
+ if (auto *as = dyn_cast_or_null<GCCAsmStmt>(terminator.getStmt()))
+ if (as->isAsmGoto())
+ tf.Visit(as);
return vals.updateValueVectorWithScratch(block);
}
@@ -887,6 +889,12 @@ struct PruneBlocksHandler : public UninitVariablesHandler {
hadAnyUse = true;
}
+ void handleConstRefUseOfUninitVariable(const VarDecl *vd,
+ const UninitUse &use) override {
+ hadUse[currentBlock] = true;
+ hadAnyUse = true;
+ }
+
/// Called when the uninitialized variable analysis detects the
/// idiom 'int x = x'. All other uses of 'x' within the initializer
/// are handled by handleUseOfUninitVariable.
@@ -924,7 +932,7 @@ void clang::runUninitializedVariablesAnalysis(
}
// Proceed with the workist.
- DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>());
+ ForwardDataflowWorklist worklist(cfg, ac);
llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
worklist.enqueueSuccessors(&cfg.getEntry());
llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
diff --git a/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp b/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp
index 77de3630ae7ec..32fba9c93752c 100644
--- a/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp
+++ b/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp
@@ -21,7 +21,7 @@ void registerMyChecker(CheckerManager &Mgr) {
<< '\n';
}
-bool shouldRegisterMyChecker(const LangOptions &LO) { return true; }
+bool shouldRegisterMyChecker(const CheckerManager &mgr) { return true; }
} // end anonymous namespace