Index: clang-tools-extra/clang-tidy/utils/Aliasing.cpp =================================================================== --- clang-tools-extra/clang-tidy/utils/Aliasing.cpp +++ clang-tools-extra/clang-tidy/utils/Aliasing.cpp @@ -55,6 +55,13 @@ return llvm::any_of(Call->arguments(), [Var](const Expr *ArgE) { return isAccessForVar(ArgE, Var); }); + } else if (const auto *ILE = dyn_cast(S)) { + return llvm::any_of(ILE->inits(), [Var](const Expr *ChildE) { + // If the child expression is a reference to Var, this means that it's + // used as an initializer of a reference-typed field. Otherwise + // it would have been surrounded with an implicit lvalue-to-rvalue cast. + return isAccessForVar(ChildE, Var); + }); } return false; Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp @@ -576,3 +576,29 @@ // No warning. The loop is finite because 'y' is a reference to 'x'. } } + +struct AggregateWithReference { + int &y; +}; + +void test_structured_bindings_good() { + int x = 0; + AggregateWithReference ref { x }; + auto &[y] = ref; + for (; x < 10; ++y) { + // No warning. The loop is finite because 'y' is a reference to 'x'. + } +} + +struct AggregateWithValue { + int y; +}; + +void test_structured_bindings_bad() { + int x = 0; + AggregateWithValue val { x }; + auto &[y] = val; + for (; x < 10; ++y) { + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (x) are updated in the loop body [bugprone-infinite-loop] + } +}