altera-id-dependent-backward-branch mass false positive: all variables assigned/initialized with a variable are considered id-dependent #52790
Description
Inspired by this StackOverflow question.
Steps to reproduce
- Consider the following code and save it to
a.cpp:
void foo(int x, int y) {
x = y;
while (x < y) {
}
}- Run
clang-tidy-13 --checks=altera-id-dependent-backward-branch a.cpp
I'm running on Ubuntu 20.04.3 LTS:
Ubuntu LLVM version 13.0.1
Optimized build.
Default target: x86_64-pc-linux-gnu
Host CPU: haswell
Expected outcome
There are no warnings, except maybe "this loop is never executed".
Real outcome
Error while trying to load a compilation database:
Could not auto-detect compilation database for file "a.cpp"
No compilation database found in /home/yeputons or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Error while opening JSON database: No such file or directory
Running without flags.
1 warning generated.
/home/yeputons/a.cpp:3:12: warning: backward branch (while loop) is ID-dependent due to variable reference to 'x' and may cause performance degradation [altera-id-dependent-backward-branch]
while (x < y) {
Comments
This look completely unrelated to the altera-id-dependent-backward-branch check's docs: there is no get_local_id or anything like this in sight.
If I remove the x = y assignment, the warning goes away.
There is also no note on why exactly x is considered id-dependent, while there should be one. Maybe I need some extra flags or it's a separate issue?
Probable cause
I'm not familiar with LLVM's source code, but it seems to me that the bug is in saveIdDepVarFromReference at the very least: it saves all potentially id-dependent variables in IdDepVarsMap regardless of whether the right-hand side of the assignment/initialization is id-dependent itself. Looks like some early returns are missing. Similar bug probably happens in saveIdDepFieldFromReference as well.
More high-level picture is as follows:
- The warning is issued here iff
IdDepVaris found in theIdDepVarsMapmap. - Variable
xis marked as id-dependent by one ofIdDependentBackwardBranchCheck::saveIdDep*methods from here (they're the only place modifyingIdDepVarsMap). - They are called from this bunch of
ifs. In particular, if there is aPotentialVar(pot_tid_varmatch) andRefExpr(assign_ref_varmatch),saveIdDepVarFromReferenceis called. pot_tid_varmatches either a variable initialized from a variable or a field (because the latter may be id-dependent) or a similar assignment. In both cases, eitherassign_ref_varorassign_ref_fieldis matches as well viaRefVarOrFielddepending on whether the initializer is a variable or a field.- Hence,
saveIdDepVarFromReferenceis called on thex = yassignment as well withassign_ref_var = yandpot_tid_var = x. - While
saveIdDepVarFromReferencechecks that the right hand side is inIdDepFieldsMap, it does not do anything to with knowledge and assumes thatPotentialVaris always id-dependent.
Suggested fix
- Early return from
saveIdDepVarFromReferenceifRefVar/RefField(there should be only one, an assertion would be nice to have) is not found inIdDepVarsMap. - Rename both
saveIdDepVarFromReferenceandsaveIdDepFieldFromReferenceto something likepotentiallySaveIdDepVarFromReferenceto highlight that it performs some checks itself. It's easy to assume that the variable is already established to be id-dependent while reviewingsaveIdDepVarFromReference. - Rename
PotentialVarandpot_tid_varto something likePossiblyIdDependentVar/possibly_iddep_varto highlight that it's not necessary id-dependent even more.PotentialVaris more open to interpretation and the erroneoussaveIdDepVarFromReference(RefExpr, MemExpr, PotentialVar);line does not immediately stand out as "save only a possible id dependent variable as really id-dependent". However, I'm not sure if that would really help, as the line is already inside some if-statement which looks somewhat reasonable.
Activity