diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis')
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; |