diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /clang/lib/Analysis | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'clang/lib/Analysis')
-rw-r--r-- | clang/lib/Analysis/AnalysisDeclContext.cpp | 117 | ||||
-rw-r--r-- | clang/lib/Analysis/BodyFarm.cpp | 44 | ||||
-rw-r--r-- | clang/lib/Analysis/CFG.cpp | 40 | ||||
-rw-r--r-- | clang/lib/Analysis/CallGraph.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Analysis/CloneDetection.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Analysis/ExprMutationAnalyzer.cpp | 43 | ||||
-rw-r--r-- | clang/lib/Analysis/LiveVariables.cpp | 62 | ||||
-rw-r--r-- | clang/lib/Analysis/PathDiagnostic.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Analysis/PostOrderCFGView.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Analysis/ProgramPoint.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Analysis/ReachableCode.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Analysis/RetainSummaryManager.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Analysis/ThreadSafety.cpp | 59 | ||||
-rw-r--r-- | clang/lib/Analysis/UninitializedValues.cpp | 142 | ||||
-rw-r--r-- | clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp | 2 |
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 |