https://github.com/yashaggarwal85d updated https://github.com/llvm/llvm-project/pull/236084
>From 81b3b4e3089077c0eef7d5792964294a89825361 Mon Sep 17 00:00:00 2001 From: Yash Aggarwal <[email protected]> Date: Tue, 27 Oct 2026 11:20:17 +0000 Subject: [PATCH 1/2] [clang-tidy] Fix loop-convert for iterators with non-trivial destructors --- .../clang-tidy/modernize/LoopConvertCheck.cpp | 3 +- clang-tools-extra/docs/ReleaseNotes.md | 5 +++ .../loop-convert-nontrivial-iterator-dtor.cpp | 43 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-nontrivial-iterator-dtor.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp index 75bf2a73259000..d5b252b66522c3 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp @@ -197,8 +197,7 @@ static StatementMatcher makeIteratorLoopMatcher(bool IsReverse) { const StatementMatcher IteratorBoundMatcher = expr(anyOf(ignoringParenImpCasts( declRefExpr(to(varDecl(equalsBoundNode(EndVarName))))), - ignoringParenImpCasts(expr(EndCallMatcher).bind(EndCallName)), - materializeTemporaryExpr(ignoringParenImpCasts( + ignoringParenImpCasts(ignoringImplicit( expr(EndCallMatcher).bind(EndCallName))))); const StatementMatcher IteratorComparisonMatcher = expr(ignoringParenImpCasts( diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md index 310b084c04eb04..45c5f30d05be7f 100644 --- a/clang-tools-extra/docs/ReleaseNotes.md +++ b/clang-tools-extra/docs/ReleaseNotes.md @@ -283,6 +283,11 @@ infrastructure are described first, followed by tool-specific sections. nested expressions involving different macros or a mix of macro and non-macro operands. +- Improved {doc}`modernize-loop-convert + <clang-tidy/checks/modernize/loop-convert>` check to also convert iterator + loops that call `end()` in the condition when the iterator type has a + non-trivial destructor. + - Fixed a crash in {doc}`modernize-raw-string-literal <clang-tidy/checks/modernize/raw-string-literal>` on synthetic string literals created for raw user-defined literal operators, such as `12_w`. diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-nontrivial-iterator-dtor.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-nontrivial-iterator-dtor.cpp new file mode 100644 index 00000000000000..c19f21a59183c0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-nontrivial-iterator-dtor.cpp @@ -0,0 +1,43 @@ +// RUN: %check_clang_tidy %s modernize-loop-convert %t + +struct Container { + struct iterator { + ~iterator() {} + int &operator*() const; + iterator &operator++(); + bool operator!=(const iterator &) const; + }; + iterator begin(); + iterator end(); +}; + +void f(Container &C) { + for (Container::iterator It = C.begin(); It != C.end(); ++It) + (void)*It; + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (int & It : C) + // CHECK-FIXES-NEXT: (void)It; + + for (Container::iterator It = C.begin(); It != (C.end()); ++It) + (void)*It; + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (int & It : C) + // CHECK-FIXES-NEXT: (void)It; + + for (Container::iterator It = C.begin(); C.end() != It; ++It) + (void)*It; + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (int & It : C) + // CHECK-FIXES-NEXT: (void)It; + + for (Container::iterator It = C.begin(), E = C.end(); It != E; ++It) + (void)*It; + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (int & It : C) + // CHECK-FIXES-NEXT: (void)It; +} + +void negative(Container &C, Container &D) { + for (Container::iterator It = C.begin(); It != D.end(); ++It) + (void)*It; +} >From 7f067bd26789fd38ffb9507eae23a5cb6b099ace Mon Sep 17 00:00:00 2001 From: Yash Aggarwal <[email protected]> Date: Mon, 2 Nov 2026 04:14:42 +0000 Subject: [PATCH 2/2] Move the non-trivial iterator destructor tests into loop-convert-extra.cpp --- .../Inputs/loop-convert/structures.h | 12 ++++++ .../checkers/modernize/loop-convert-extra.cpp | 33 ++++++++++++++ .../loop-convert-nontrivial-iterator-dtor.cpp | 43 ------------------- 3 files changed, 45 insertions(+), 43 deletions(-) delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-nontrivial-iterator-dtor.cpp diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/loop-convert/structures.h b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/loop-convert/structures.h index 64ea452c0062f9..011a3b3e6e43f0 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/loop-convert/structures.h +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/loop-convert/structures.h @@ -252,6 +252,18 @@ struct RValueDerefContainer { iterator end() const; }; +template <typename T> +struct NonTrivialDtorContainer { + struct iterator { + ~iterator(); + bool operator!=(const iterator &other) const; + T &operator*(); + iterator &operator++(); + }; + iterator begin(); + iterator end(); +}; + namespace Macros { struct MacroStruct { diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-extra.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-extra.cpp index 161427ca9ecb44..758dc7fc8f9750 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-extra.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-extra.cpp @@ -1073,6 +1073,39 @@ void f() { } // namespace InitLists +namespace NonTrivialIteratorDtor { + +void f(NonTrivialDtorContainer<int> &C, NonTrivialDtorContainer<int> &D) { + for (NonTrivialDtorContainer<int>::iterator It = C.begin(); It != C.end(); ++It) + (void)*It; + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (int & It : C) + // CHECK-FIXES-NEXT: (void)It; + + for (NonTrivialDtorContainer<int>::iterator It = C.begin(); It != (C.end()); ++It) + (void)*It; + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (int & It : C) + // CHECK-FIXES-NEXT: (void)It; + + for (NonTrivialDtorContainer<int>::iterator It = C.begin(); C.end() != It; ++It) + (void)*It; + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (int & It : C) + // CHECK-FIXES-NEXT: (void)It; + + for (NonTrivialDtorContainer<int>::iterator It = C.begin(), E = C.end(); It != E; ++It) + (void)*It; + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead + // CHECK-FIXES: for (int & It : C) + // CHECK-FIXES-NEXT: (void)It; + + for (NonTrivialDtorContainer<int>::iterator It = C.begin(); It != D.end(); ++It) + (void)*It; +} + +} // namespace NonTrivialIteratorDtor + void bug28341() { char v[5]; for(int i = 0; i < 5; ++i) { diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-nontrivial-iterator-dtor.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-nontrivial-iterator-dtor.cpp deleted file mode 100644 index c19f21a59183c0..00000000000000 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-nontrivial-iterator-dtor.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %check_clang_tidy %s modernize-loop-convert %t - -struct Container { - struct iterator { - ~iterator() {} - int &operator*() const; - iterator &operator++(); - bool operator!=(const iterator &) const; - }; - iterator begin(); - iterator end(); -}; - -void f(Container &C) { - for (Container::iterator It = C.begin(); It != C.end(); ++It) - (void)*It; - // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead - // CHECK-FIXES: for (int & It : C) - // CHECK-FIXES-NEXT: (void)It; - - for (Container::iterator It = C.begin(); It != (C.end()); ++It) - (void)*It; - // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead - // CHECK-FIXES: for (int & It : C) - // CHECK-FIXES-NEXT: (void)It; - - for (Container::iterator It = C.begin(); C.end() != It; ++It) - (void)*It; - // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead - // CHECK-FIXES: for (int & It : C) - // CHECK-FIXES-NEXT: (void)It; - - for (Container::iterator It = C.begin(), E = C.end(); It != E; ++It) - (void)*It; - // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead - // CHECK-FIXES: for (int & It : C) - // CHECK-FIXES-NEXT: (void)It; -} - -void negative(Container &C, Container &D) { - for (Container::iterator It = C.begin(); It != D.end(); ++It) - (void)*It; -} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
