https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120319
Bug ID: 120319 Summary: Unexpected number of branch outcomes and line coverage for C++ programs Product: gcc Version: 16.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: gcov-profile Assignee: unassigned at gcc dot gnu.org Reporter: wentaoz5 at illinois dot edu Target Milestone: --- Hit the issue when measuring https://sources.debian.org/src/lzma/9.22-2.2/CPP/7zip/Bundles/LzmaCon/lzmp.cpp/#L790 The symptom is two-fold: (1) additional number of branch outcomes (2) line coverage gets multiplied by a factor. The specific triggering conditions are shown below with examples but one thing in common is C++ -- the same programs but written in C behave more intuitively. How to reproduce: $ gcc --version gcc (GCC) 16.0.0 20250511 (experimental) Copyright (C) 2025 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ cat > test_cpp.cc << 'EOF' int foo(int x) { return 1; } int a, b; int main() { if ( a && foo(b) ) return 1; if (a) return 2; if (foo(b)) return 3; return 0; } EOF $ g++ --coverage test_cpp.cc -o test_cpp $ ./test_cpp $ gcov -b -c test_cpp $ cat test_cpp.cc.gcov -: 0:Source:test_cpp.cc -: 0:Graph:test_cpp.gcno -: 0:Data:test_cpp.gcda -: 0:Runs:1 function _Z3fooi called 1 returned 100% blocks executed 100% 1: 1:int foo(int x) { return 1; } -: 2: -: 3:int a, b; -: 4: function main called 1 returned 100% blocks executed 57% 1: 5:int main() { -: 6: 1: 7: if ( 1: 8: a 1*: 9: && branch 0 taken 0 (fallthrough) branch 1 taken 1 branch 2 never executed (fallthrough) branch 3 never executed branch 4 taken 0 (fallthrough) branch 5 taken 1 #####: 10: foo(b) call 0 never executed -: 11: ) #####: 12: return 1; -: 13: 1: 14: if (a) branch 0 taken 0 (fallthrough) branch 1 taken 1 #####: 15: return 2; -: 16: 1: 17: if (foo(b)) call 0 returned 1 branch 1 taken 1 (fallthrough) branch 2 taken 0 1: 18: return 3; -: 19: #####: 20: return 0; -: 21:} The first predicate in the form of "X && Y" is reported to have 6 outcomes. In contrast, the second or the third predicate where sub-expression is there alone is reported to have 2 outcomes. Renaming the same program to "something.c" and using gcc gives more intuitive results, namely "X && Y" is reported to have 4 outcomes. $ cat > test_cpp2.cc << 'EOF' int a, b; int foo (int x) { return 1; } int main(void) { if (a && foo(b)) return 1; return 0; } EOF $ g++ --coverage test_cpp2.cc -o test_cpp2 $ ./test_cpp2 $ gcov -b -c test_cpp2 $ cat test_cpp2.cc.gcov -: 0:Source:test_cpp2.cc -: 0:Graph:test_cpp2.gcno -: 0:Data:test_cpp2.gcda -: 0:Runs:1 -: 1:int a, b; -: 2: function _Z3fooi called 0 returned 0% blocks executed 0% #####: 3:int foo (int x) { return 1; } -: 4: function main called 1 returned 100% blocks executed 56% 1: 5:int main(void) { 2: 6: if (a 1*: 7: && foo(b)) branch 0 taken 0 (fallthrough) branch 1 taken 1 call 2 never executed branch 3 never executed (fallthrough) branch 4 never executed branch 5 taken 0 (fallthrough) branch 6 taken 1 #####: 8: return 1; 1: 9: return 0; -: 10:} Line 6 is reported to be executed twice. Again, renaming the file to "something.c" eliminates the behavior. On a side note, sticking to C++ but letting variable "a" be a local variable also eliminates the behavior.