llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.51k stars 11.79k forks source link

clang-tidy bugprone-infinite-loop triggers for obviously finite loops in templates #51423

Closed horenmar closed 2 years ago

horenmar commented 3 years ago
Bugzilla Link 52081
Version unspecified
OS All
CC @fabianwolff

Extended Description

clang-tidy's bugprone-infinite-loop triggers for loops that are easily provable to be finite, in cases like this:

template int a() { return 1; }

template void foo() { const int error = a(); do {} while ( false && error == 0); }

int main() { foo(); }

The loop is obviously finite (false && error == 0 is always false, thus the loop will only ever run once), but clang-tidy does not see this and issues bugprone-infinite-loop instead (https://godbolt.org/z/vh69oMbsx).

Interestingly, relatively small changes to the body of foo can change whether the diagnostic is issued or not, as the code below is (correctly) not diagnosed as infinite:

int a() { return 1; }

template void foo() { const int error = a(); do {} while (false && error == 0); }

int main() { foo(); }

(see https://godbolt.org/z/rzheEfEWh)


Further context

The original reproducer comes from Catch2, where the REQUIRE macro expands into a similar loop, specifically

do { // code that tests the expression } while ((void)0, (false) && static_cast<const bool&>( !!(__VA_ARGS__) ) )

the construction is a bit weird (there are underlying reasons), but ultimately the condition always resolves to false. However, when used in combination with TEMPLATE_TEST_CASE, which is a macro used for writing type-parametrized tests, it trigers false-positive diagnostic of bugprone-infinite-loop.

From looking around, this bug was already reported and solved once for the simple case, where the loop is not inside a macro, in llvm/llvm-project#44161 , but that caused a regression, reported in llvm/llvm-project#44239 , and fixed in https://reviews.llvm.org/rG8c4cf23dee1ac3f259c4795b275cc9bb1234aa29 which I suspect causes the error here.

FabianWolff commented 2 years ago

clang-tidy's bugprone-infinite-loop triggers for loops that are easily provable to be finite, in cases like this: [...]

bugprone-infinite-loop checks whether the condition is "known false", and, if not, assumes that it is "potentially true" and thus might be an infinite loop. Furthermore, the current logic bails out if the condition depends on template parameters, i.e. loops whose condition (transitively) depends on a template parameter are never "known false", which explains why your first example triggers the warning while the second example does not.

Obviously, fully solving this problem would require some kind of satisfiability solver (to see whether any choice of dependent variables might make the condition true), but I'm working on a patch that should cover the most common cases, including the examples you have given.

horenmar commented 3 years ago

assigned to @fabianwolff