https://github.com/aviralg created https://github.com/llvm/llvm-project/pull/147410
Tuple structured bindings can introduce new variable declarations under `BindingDecl` nodes which are currently ignored by the infinite loop checker. This PR implements support for extracting variables from these nodes. Subsequent logic for checking if these variables have changed has been reused. >From 782095442544692d3f0e32ed5da4ee1d772c1f9a Mon Sep 17 00:00:00 2001 From: Aviral Goel <agoe...@apple.com> Date: Mon, 7 Jul 2025 14:38:00 -0700 Subject: [PATCH] [clang-tidy] bugprone-infinite-loop: Add support for tuple structured bindings Tuple structured bindings can introduce new variable declarations under `BindingDecl` nodes which are currently ignored by the infinite loop checker. This PR implements support for extracting variables from these nodes. Subsequent logic for checking if these variables have changed has been reused. --- .../clang-tidy/bugprone/InfiniteLoopCheck.cpp | 35 +++++++++++++------ .../checkers/bugprone/infinite-loop.cpp | 15 ++++++++ 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp index 07116a7ff15f5..2ae0dbc3f53ba 100644 --- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp @@ -65,24 +65,37 @@ static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var, return ExprMutationAnalyzer(*LoopStmt, *Context).isMutated(Var); } +static bool isVarDeclPossiblyChanged(const Decl *Func, const Stmt *LoopStmt, + const VarDecl *Var, ASTContext *Context) { + if (!Var->isLocalVarDeclOrParm()) + return true; + + if (Var->getType().isVolatileQualified()) + return true; + + if (!Var->getType().getTypePtr()->isIntegerType()) + return true; + + return hasPtrOrReferenceInFunc(Func, Var) || + isChanged(LoopStmt, Var, Context); +} + /// Return whether `Cond` is a variable that is possibly changed in `LoopStmt`. static bool isVarThatIsPossiblyChanged(const Decl *Func, const Stmt *LoopStmt, const Stmt *Cond, ASTContext *Context) { if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) { - if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) { - if (!Var->isLocalVarDeclOrParm()) - return true; - - if (Var->getType().isVolatileQualified()) - return true; + const ValueDecl *VD = DRE->getDecl(); - if (!Var->getType().getTypePtr()->isIntegerType()) - return true; + if (const auto *Var = dyn_cast<VarDecl>(VD)) { + return isVarDeclPossiblyChanged(Func, LoopStmt, Var, Context); + } - return hasPtrOrReferenceInFunc(Func, Var) || - isChanged(LoopStmt, Var, Context); - // FIXME: Track references. + if (const auto *BD = dyn_cast<BindingDecl>(VD)) { + return isVarDeclPossiblyChanged(Func, LoopStmt, BD->getHoldingVar(), + Context); } + + // FIXME: Track references. } else if (isa<MemberExpr, CallExpr, ObjCIvarRefExpr, ObjCPropertyRefExpr, ObjCMessageExpr>(Cond)) { // FIXME: Handle MemberExpr. diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/infinite-loop.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/infinite-loop.cpp index bc14ece3f332c..e5d3a7da0d763 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/infinite-loop.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/infinite-loop.cpp @@ -592,6 +592,21 @@ void test_structured_bindings_bad() { } } +std::tuple<uint8_t *, size_t> get_chunk() { + static uint8_t buf[10]; + return { &buf[0], 2 }; +} + +void test_structured_bindings_tuple() { + auto [ p, size ] = get_chunk(); + size_t maxLen = 8; + + while (size < maxLen) { + // No warning. The loop is finite because 'size' is being incremented in each iteration and compared against 'maxLen' for termination + p[size++] = ' '; + } +} + void test_volatile_cast() { // This is a no-op cast. Clang ignores the qualifier, we should too. for (int i = 0; (volatile int)i < 10;) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits