Issue |
140893
|
Summary |
[coverage] nested macro with unused branch leads to incorrect coverage
|
Labels |
new issue
|
Assignees |
|
Reporter |
justincady
|
Code coverage reporting is incorrect at the call site when a macro contains an unused branch. Example:
```
// macro.c
#include <stdio.h>
int enabled = 0;
#define MY_ID(x) 7
#define MY_LOG(fmt, ...) \
{ \
if (enabled) { \
printf(fmt, ## __VA_ARGS__); \
} \
}
int main(int argc, char *argv[]) {
MY_LOG("%d, %s, %d\n",
MY_ID(argc),
"a",
1);
}
```
```
# build-c.sh
/usr/bin/clang --version | /bin/grep "clang version"
/usr/bin/clang -fprofile-instr-generate -fcoverage-mapping coverage.c -o coverage
./coverage
/usr/bin/llvm-profdata merge -sparse default.profraw -o default.profdata
/usr/bin/llvm-cov show ./coverage -instr-profile=""
```
The coverage report confusingly marks the `MY_LOG` usage in `main` as partially covered:
```
$ ./build-c.sh
clang version 19.1.7
1| |#include <stdio.h>
2| |
3| |int enabled = 0;
4| |
5| 0|#define MY_ID(x) 7
6| |
7| |#define MY_LOG(fmt, ...) \
8| 1| { \
9| 1| if (enabled) { \
10| 0| printf(fmt, ## __VA_ARGS__); \
11| 0| } \
12| 1| }
13| |
14| 1|int main(int argc, char *argv[]) {
15| 1| MY_LOG("%d, %s, %d\n",
16| 1| MY_ID(argc),
17| 0| "a", // INCORRECT
18| 0| 1); // INCORRECT
19| 1|}
```
If the example is updated to avoid using `MY_ID` withing `MY_LOG`, the problem disappears (even if the updated line has a branch):
```
$ ./build-c.sh
clang version 19.1.7
1| |#include <stdio.h>
2| |
3| |int enabled = 0;
4| |
5| |#define MY_ID(x) 7
6| |
7| |#define MY_LOG(fmt, ...) \
8| 1| { \
9| 1| if (enabled) { \
10| 0| printf(fmt, ## __VA_ARGS__); \
11| 0| } \
12| 1| }
13| |
14| 1|int main(int argc, char *argv[]) {
15| 1| MY_LOG("%d, %s, %d\n",
16| 1| enabled ? 1 : 2, // Now the entire MY_LOG usage is covered
17| 1| "a",
18| 1| 1);
19| 1|}
```
I suspect this is specific to macro expansion because I can substitute other constructs, including function calls, in the place of `MY_ID` and get correct results.
Also, I _believe_ the ideal behavior here is that all lines within `MY_LOG` usage in `main` should be covered; we _did_ execute that line and that's what usually happens. Then, appropriately, the `MY_LOG` implementation lines should be marked uncovered.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs