diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
| commit | 344a3780b2e33f6ca763666c380202b18aab72a3 (patch) | |
| tree | f0b203ee6eb71d7fdd792373e3c81eb18d6934dd /clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp | |
| parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) | |
vendor/llvm-project/llvmorg-13-init-16847-g88e66fa60ae5vendor/llvm-project/llvmorg-12.0.1-rc2-0-ge7dac564cd0evendor/llvm-project/llvmorg-12.0.1-0-gfed41342a82f
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp | 77 |
1 files changed, 58 insertions, 19 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp index dc268e562237..e5f4e9ea30c9 100644 --- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -79,14 +79,17 @@ ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) { return State; } -static internal::Matcher<Stmt> simpleCondition(StringRef BindName) { - return binaryOperator(anyOf(hasOperatorName("<"), hasOperatorName(">"), - hasOperatorName("<="), hasOperatorName(">="), - hasOperatorName("!=")), - hasEitherOperand(ignoringParenImpCasts(declRefExpr( - to(varDecl(hasType(isInteger())).bind(BindName))))), - hasEitherOperand(ignoringParenImpCasts( - integerLiteral().bind("boundNum")))) +static internal::Matcher<Stmt> simpleCondition(StringRef BindName, + StringRef RefName) { + return binaryOperator( + anyOf(hasOperatorName("<"), hasOperatorName(">"), + hasOperatorName("<="), hasOperatorName(">="), + hasOperatorName("!=")), + hasEitherOperand(ignoringParenImpCasts( + declRefExpr(to(varDecl(hasType(isInteger())).bind(BindName))) + .bind(RefName))), + hasEitherOperand( + ignoringParenImpCasts(integerLiteral().bind("boundNum")))) .bind("conditionOperator"); } @@ -138,7 +141,7 @@ static internal::Matcher<Stmt> hasSuspiciousStmt(StringRef NodeName) { static internal::Matcher<Stmt> forLoopMatcher() { return forStmt( - hasCondition(simpleCondition("initVarName")), + hasCondition(simpleCondition("initVarName", "initVarRef")), // Initialization should match the form: 'int i = 6' or 'i = 42'. hasLoopInit( anyOf(declStmt(hasSingleDecl( @@ -156,17 +159,52 @@ static internal::Matcher<Stmt> forLoopMatcher() { hasUnaryOperand(declRefExpr( to(varDecl(allOf(equalsBoundNode("initVarName"), hasType(isInteger())))))))), - unless(hasBody(hasSuspiciousStmt("initVarName")))).bind("forLoop"); + unless(hasBody(hasSuspiciousStmt("initVarName")))) + .bind("forLoop"); } -static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) { - // Global variables assumed as escaped variables. +static bool isCapturedByReference(ExplodedNode *N, const DeclRefExpr *DR) { + + // Get the lambda CXXRecordDecl + assert(DR->refersToEnclosingVariableOrCapture()); + const LocationContext *LocCtxt = N->getLocationContext(); + const Decl *D = LocCtxt->getDecl(); + const auto *MD = cast<CXXMethodDecl>(D); + assert(MD && MD->getParent()->isLambda() && + "Captured variable should only be seen while evaluating a lambda"); + const CXXRecordDecl *LambdaCXXRec = MD->getParent(); + + // Lookup the fields of the lambda + llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields; + FieldDecl *LambdaThisCaptureField; + LambdaCXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField); + + // Check if the counter is captured by reference + const VarDecl *VD = cast<VarDecl>(DR->getDecl()->getCanonicalDecl()); + assert(VD); + const FieldDecl *FD = LambdaCaptureFields[VD]; + assert(FD && "Captured variable without a corresponding field"); + return FD->getType()->isReferenceType(); +} + +// A loop counter is considered escaped if: +// case 1: It is a global variable. +// case 2: It is a reference parameter or a reference capture. +// case 3: It is assigned to a non-const reference variable or parameter. +// case 4: Has its address taken. +static bool isPossiblyEscaped(ExplodedNode *N, const DeclRefExpr *DR) { + const VarDecl *VD = cast<VarDecl>(DR->getDecl()->getCanonicalDecl()); + assert(VD); + // Case 1: if (VD->hasGlobalStorage()) return true; - const bool isParm = isa<ParmVarDecl>(VD); - // Reference parameters are assumed as escaped variables. - if (isParm && VD->getType()->isReferenceType()) + const bool IsRefParamOrCapture = + isa<ParmVarDecl>(VD) || DR->refersToEnclosingVariableOrCapture(); + // Case 2: + if ((DR->refersToEnclosingVariableOrCapture() && + isCapturedByReference(N, DR)) || + (IsRefParamOrCapture && VD->getType()->isReferenceType())) return true; while (!N->pred_empty()) { @@ -189,6 +227,7 @@ static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) { // on VD and reference initialized by VD. ASTContext &ASTCtx = N->getLocationContext()->getAnalysisDeclContext()->getASTContext(); + // Case 3 and 4: auto Match = match(stmt(anyOf(callByRef(equalsNode(VD)), getAddrTo(equalsNode(VD)), assignedToRef(equalsNode(VD)))), @@ -199,8 +238,8 @@ static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) { N = N->getFirstPred(); } - // Parameter declaration will not be found. - if (isParm) + // Reference parameter and reference capture will not be found. + if (IsRefParamOrCapture) return false; llvm_unreachable("Reached root without finding the declaration of VD"); @@ -218,7 +257,7 @@ bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx, if (Matches.empty()) return false; - auto CounterVar = Matches[0].getNodeAs<VarDecl>("initVarName"); + const auto *CounterVarRef = Matches[0].getNodeAs<DeclRefExpr>("initVarRef"); llvm::APInt BoundNum = Matches[0].getNodeAs<IntegerLiteral>("boundNum")->getValue(); llvm::APInt InitNum = @@ -235,7 +274,7 @@ bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx, maxStep = (BoundNum - InitNum).abs().getZExtValue(); // Check if the counter of the loop is not escaped before. - return !isPossiblyEscaped(CounterVar->getCanonicalDecl(), Pred); + return !isPossiblyEscaped(Pred, CounterVarRef); } bool madeNewBranch(ExplodedNode *N, const Stmt *LoopStmt) { |
