<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/140893>140893</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[coverage] nested macro with unused branch leads to incorrect coverage
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
justincady
</td>
</tr>
</table>
<pre>
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=default.profdata
```
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.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzMV1-P4jYQ_zTmZUSUOEDggQcWbk8rtXfS9VSpT8ixJ8RX40S2A7vfvpokwGaB6-21lRohkdjz5-fxzM9j4b3eWcQlmz6w6WYkmlBWbvmt8UFbKdTLKK_Uy3JdKQRZHdCJHYLDunJB2x1oD9rKyjmUAUSAUCJIYQx4HRCOJVoQsBfSVSArG4S2HoSFxjYeFeROWFlG8OFZ7GuDLF2xuP3N4v4Xrxh_ZPyxsxHJdiDVVppGIbB07YPSVVSy9EOnqm0AtCI3qIClG4hZ-tAb5anCQluEX__YPm0Ynz8zvoDsxuwvnz8yPi_2gfE1RFFEcq8eNl2zeAXAsofzO4AugPF575s0aPrqucgD1E7bUFw8MZ4ynsJ2-_tqu_ry8bftlvEFSx9ea7Fsc230pgeWbS4h2QttGZ_Tq3A7Sd5kKRwwvhJud-g2vwfdap-jwDhnfKo6fFPf_ys2Xdt2qnV2imhne9GPnhFxLi6ypyfpFkcYO6SvN_1tDqSQN9qosYx82SVF4x3jjzkt61EaYXcwHh_QeV1ZYBmB7Cd3DmuC0An1IgTnnpmidlWhDY619cGNd2jRiYAwLk4FMN6Luqb0Pw1EEsbV-YvFq4jMXT7fODLmsB-TFyWCgD26HcLY18J5BIWFaEyIaNqJI9l9PUQadwzK6gC-rI7w2jn0q-jXxNLNLWvD0H8tr2qdqrdovLY78wJ74f70bamzWdwnyiyGxpO8tjTa5tssBuGhFi5oYcxLZxPVnTKftLgH2zzYMkgWURJlfQoltMd9emXr73ACSfA2IbJT-qUD3TuMQbOToZNucHoejDvP91iFRGa3LGRvsX-feS7FPz8rdsu_yTB3CWcx1H4nXyXxYN3d208wWJJc2flhTkv4VQA2vdX0RqCTyUD8p3gQkukbn-9jRoBkNjRwjyuT7EaAB-wJ_Vn49Gn9-cuXD-uvveJ8qJicY35bfJgHN8n3qWjLG7tzmU75plYioIJQgThUWkFLBj0BPG2o1o86lJexjhQINVmqXZUb3IPSXtQ1Cufb5DugpTwkiZMDQ5VQCg-ibw_a1fxTxng_XbzJpX-NNK5K_j2k8SN0cbP2bzHHXWZ4bzPzH1PDZf5nyv9_VPmn55I4j5AAS1fwuro_Vceu-GzQ7rTLp8PVnw_Rt5yR3OaMK4oYyF16sB-jBfCNr6nVDyV1_h7oSxdaEi90bT4-18K21ZejFI1HeAIpLPgm90GHJiBUoURHHYUPrpGhjV9Xj0QfRWNlIH26R_RzHYcYIRGqYkA6wirYIfUn3R3EoW9M8FEHeGV8RRaeYJuj0XjAbWtKKxQGcizFQVcOSnRtbEMpAtDthUjI94T2902OL6vGKMjx0uE8wBFhq7TaAj6jpFW3xlt2I8z0xXjm4UjDjW_aDqkkcrQ-gq8lWgIu6tpVtdMioHk5kekAkCaG3qMNog1ah_yCiHo1VNDYHlo0UstULdKFGOEyySbZPE3jbDYql7M8VuksTmdyMVNqMpkXmEkU-aQo5nORTEZ6yWM-jac8SdIkSWaRkFmu-LTg88l8kogpm8S4F9pE1I5GlduNtPcNLpNJPF-kIyNyNL69aHJu8QjtLKXpdDNyy7aHzZudZ5PYaB_8xUzQwbQ31HNLPd2ARU_nRZd1tFXDWyUYFMpTXl4uqCf1UePMsgyh9nSytGW306Fs8khW-76dftWmf0MZGH9s4XrGH_v1HJb8rwAAAP__9nEdrA">