Repository: rust
Issue: Coverage instrumentation loses information in macro-generated code
Labels: T-compiler,C-bug,E-needs-mcve,A-proc-macros,A-code-coverage

I tried this code (using [`thiserror`](https://github.com/dtolnay/thiserror/) v1.0.58):

```rust
use thiserror::Error;

#[derive(Error, Debug)]
pub enum E {
    #[error("{}", if *.0 { "a" } else { "b" })]
    X(bool)
}

#[cfg(test)]
mod tests {
    use super::E;

    #[test]
    fn test() {
        assert_eq!(E::X(true).to_string(), "a");
    }
}
```

I expected to see this happen: When running the test with `cargo llvm-cov --text`, the `else` arm should be marked as uncovered while the `then` arm should be shown as covered.

Instead, this happened: The code in the `#[error]` attribute does not have any coverage data. When run with `cargo llvm-cov --text`, this is the result:
```console
$ cargo llvm-cov --text
[...]
    1|       |use thiserror::Error;
    2|       |
    3|      1|#[derive(Error, Debug)]
    4|       |pub enum E {
    5|       |    #[error("{}", if *.0 { "a" } else { "b" })]
    6|       |    X(bool)
    7|       |}
    8|       |
    9|       |#[cfg(test)]
   10|       |mod tests {
   11|       |    use super::E;
   12|       |
   13|       |    #[test]
   14|      1|    fn test() {
   15|      1|        assert_eq!(E::X(true).to_string(), "a");
   16|      1|    }
   17|       |}
```

Note that the proc-macro generated code is shown as covering line 3.

If the code is wrapped in a function (either a normal function or a lambda), the coverage information is correct:

```rust
use thiserror::Error;

#[derive(Error, Debug)]
pub enum E {
    #[error("{}", (|| if *.0 { "a" } else { "b" })())]
    X(bool)
}

#[cfg(test)]
mod tests {
    use super::E;

    #[test]
    fn test() {
        assert_eq!(E::X(true).to_string(), "a");
    }
}
```
will lead to
```console
cargo llvm-cov --text
[...]
    1|       |use thiserror::Error;
    2|       |
    3|      1|#[derive(Error, Debug)]
    4|       |pub enum E {
    5|      1|    #[error("{}", (|| if *.0 { "a" } else { "b" })())]
                                                          ^0
    6|       |    X(bool)
    7|       |}
    8|       |
    9|       |#[cfg(test)]
   10|       |mod tests {
   11|       |    use super::E;
   12|       |
   13|       |    #[test]
   14|      1|    fn test() {
   15|      1|        assert_eq!(E::X(true).to_string(), "a");
   16|      1|    }
   17|       |}
```

Note that now `"b"` is shown as uncovered.

I initially encountered this while writing a proc-macro similar to `thiserror` that generates error messages based on `enum` definitions. To work around this issue, I wrapped the code that I wanted to have coverage information in IIFEs *inside* the proc-macro.

### Meta

`rustc --version --verbose`:
```console
$ rustc --version --verbose
rustc 1.79.0-nightly (9d79cd5f7 2024-04-05)
binary: rustc
commit-hash: 9d79cd5f79e75bd0d2083260271307ce9acd9081
commit-date: 2024-04-05
host: x86_64-unknown-linux-gnu
release: 1.79.0-nightly
LLVM version: 18.1.2
$ cargo llvm-cov --version
cargo-llvm-cov 0.6.9
$ grep 'name = "thiserror"' Cargo.lock -A1
name = "thiserror"
version = "1.0.58"
```