Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coverage: Simplify the heuristic for ignoring async fn return spans #118666

Merged
merged 3 commits into from
Dec 9, 2023

Conversation

Zalathar
Copy link
Contributor

@Zalathar Zalathar commented Dec 6, 2023

The code for extracting coverage spans from MIR has a special heuristic for dealing with async fn, so that the function's closing brace does not have a confusing double count.

The code implementing that heuristic is currently mixed in with the code for flushing remaining spans after the main refinement loop, making the refinement code harder to understand.

We can solve that by hoisting the heuristic to an earlier stage, after the spans have been extracted and sorted but before they have been processed by the refinement loop.

The coverage tests verify that the heuristic is still effective, so coverage mappings/reports for async fn have not changed.


This PR also has the side-effect of fixing the None some_prev panic that started appearing after #118525.

The old code assumed that prev would always be present after the refinement loop. That was only true if the list of collected spans was non-empty, but prior to #118525 that didn't seem to come up in practice. After that change, the list of collected spans could be empty in some specific circumstances, leading to panics.

The new code uses an if let to inspect prev, which correctly does nothing if there is no span present.

@rustbot
Copy link
Collaborator

rustbot commented Dec 6, 2023

r? @b-naber

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 6, 2023
@rustbot
Copy link
Collaborator

rustbot commented Dec 6, 2023

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

@rustbot rustbot added the A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) label Dec 6, 2023
@Zalathar Zalathar force-pushed the body-closure branch 4 times, most recently from a27e878 to 5d00fe9 Compare December 8, 2023 04:57
@Zalathar
Copy link
Contributor Author

Zalathar commented Dec 8, 2023

I was able to find a simple repro for the None some_prev ICE, so I've included a regression test for it.

I manually verified that it passes before #118525, then fails, and now passes again.

@cjgillot
Copy link
Contributor

cjgillot commented Dec 8, 2023

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Dec 8, 2023

📌 Commit e01338a has been approved by cjgillot

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 8, 2023
@Zalathar
Copy link
Contributor Author

Zalathar commented Dec 9, 2023

It's out of scope for this PR, but another thing that might be worth trying is to have the heuristic try to accurately detect whether the current function really is async fn or not.

We can probably get that information by looking backwards at HIR, or by inspecting span contexts.

workingjubilee added a commit to workingjubilee/rustc that referenced this pull request Dec 9, 2023
coverage: Simplify the heuristic for ignoring `async fn` return spans

The code for extracting coverage spans from MIR has a special heuristic for dealing with `async fn`, so that the function's closing brace does not have a confusing double count.

The code implementing that heuristic is currently mixed in with the code for flushing remaining spans after the main refinement loop, making the refinement code harder to understand.

We can solve that by hoisting the heuristic to an earlier stage, after the spans have been extracted and sorted but before they have been processed by the refinement loop.

The coverage tests verify that the heuristic is still effective, so coverage mappings/reports for `async fn` have not changed.

---

This PR also has the side-effect of fixing the `None some_prev` panic that started appearing after rust-lang#118525.

The old code assumed that `prev` would always be present after the refinement loop. That was only true if the list of collected spans was non-empty, but prior to rust-lang#118525 that didn't seem to come up in practice. After that change, the list of collected spans could be empty in some specific circumstances, leading to panics.

The new code uses an `if let` to inspect `prev`, which correctly does nothing if there is no span present.
workingjubilee added a commit to workingjubilee/rustc that referenced this pull request Dec 9, 2023
coverage: Simplify the heuristic for ignoring `async fn` return spans

The code for extracting coverage spans from MIR has a special heuristic for dealing with `async fn`, so that the function's closing brace does not have a confusing double count.

The code implementing that heuristic is currently mixed in with the code for flushing remaining spans after the main refinement loop, making the refinement code harder to understand.

We can solve that by hoisting the heuristic to an earlier stage, after the spans have been extracted and sorted but before they have been processed by the refinement loop.

The coverage tests verify that the heuristic is still effective, so coverage mappings/reports for `async fn` have not changed.

---

This PR also has the side-effect of fixing the `None some_prev` panic that started appearing after rust-lang#118525.

The old code assumed that `prev` would always be present after the refinement loop. That was only true if the list of collected spans was non-empty, but prior to rust-lang#118525 that didn't seem to come up in practice. After that change, the list of collected spans could be empty in some specific circumstances, leading to panics.

The new code uses an `if let` to inspect `prev`, which correctly does nothing if there is no span present.
bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 9, 2023
…kingjubilee

Rollup of 8 pull requests

Successful merges:

 - rust-lang#118198 (coverage: Use `SpanMarker` to improve coverage spans for `if !` expressions)
 - rust-lang#118512 (Add tests related to normalization in implied bounds)
 - rust-lang#118610 (update target feature following LLVM API change)
 - rust-lang#118666 (coverage: Simplify the heuristic for ignoring `async fn` return spans)
 - rust-lang#118737 (Extend tidy alphabetical checking to `tests/`.)
 - rust-lang#118756 (use bold magenta instead of bold white for highlighting)
 - rust-lang#118762 (Some more minor `async gen`-related nits)
 - rust-lang#118764 (Make async generators fused by default)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 9, 2023
…kingjubilee

Rollup of 7 pull requests

Successful merges:

 - rust-lang#118198 (coverage: Use `SpanMarker` to improve coverage spans for `if !` expressions)
 - rust-lang#118512 (Add tests related to normalization in implied bounds)
 - rust-lang#118610 (update target feature following LLVM API change)
 - rust-lang#118666 (coverage: Simplify the heuristic for ignoring `async fn` return spans)
 - rust-lang#118737 (Extend tidy alphabetical checking to `tests/`.)
 - rust-lang#118762 (Some more minor `async gen`-related nits)
 - rust-lang#118764 (Make async generators fused by default)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit feb8793 into rust-lang:master Dec 9, 2023
11 checks passed
@rustbot rustbot added this to the 1.76.0 milestone Dec 9, 2023
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Dec 9, 2023
Rollup merge of rust-lang#118666 - Zalathar:body-closure, r=cjgillot

coverage: Simplify the heuristic for ignoring `async fn` return spans

The code for extracting coverage spans from MIR has a special heuristic for dealing with `async fn`, so that the function's closing brace does not have a confusing double count.

The code implementing that heuristic is currently mixed in with the code for flushing remaining spans after the main refinement loop, making the refinement code harder to understand.

We can solve that by hoisting the heuristic to an earlier stage, after the spans have been extracted and sorted but before they have been processed by the refinement loop.

The coverage tests verify that the heuristic is still effective, so coverage mappings/reports for `async fn` have not changed.

---

This PR also has the side-effect of fixing the `None some_prev` panic that started appearing after rust-lang#118525.

The old code assumed that `prev` would always be present after the refinement loop. That was only true if the list of collected spans was non-empty, but prior to rust-lang#118525 that didn't seem to come up in practice. After that change, the list of collected spans could be empty in some specific circumstances, leading to panics.

The new code uses an `if let` to inspect `prev`, which correctly does nothing if there is no span present.
@Zalathar Zalathar deleted the body-closure branch December 9, 2023 12:43
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Dec 18, 2023
coverage: Skip instrumenting a function if no spans were extracted from MIR

The immediate symptoms of rust-lang#118643 were fixed by rust-lang#118666, but some users reported that their builds now encounter another coverage-related ICE:

```
error: internal compiler error: compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs:98:17: A used function should have had coverage mapping data but did not: (...)
```

I was able to reproduce at least one cause of this error: if no relevant spans could be extracted from a function, but the function contains `CoverageKind::SpanMarker` statements, then codegen still thinks the function is instrumented and complains about the fact that it has no coverage spans.

This PR prevents that from happening in two ways:
- If we didn't extract any relevant spans from MIR, skip instrumenting the entire function and don't create a `FunctionCoverateInfo` for it.
- If coverage codegen sees a `CoverageKind::SpanMarker` statement, skip it early and avoid creating `func_coverage`.

---

Fixes rust-lang#118850.
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Dec 18, 2023
Rollup merge of rust-lang#118852 - Zalathar:no-spans, r=cjgillot

coverage: Skip instrumenting a function if no spans were extracted from MIR

The immediate symptoms of rust-lang#118643 were fixed by rust-lang#118666, but some users reported that their builds now encounter another coverage-related ICE:

```
error: internal compiler error: compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs:98:17: A used function should have had coverage mapping data but did not: (...)
```

I was able to reproduce at least one cause of this error: if no relevant spans could be extracted from a function, but the function contains `CoverageKind::SpanMarker` statements, then codegen still thinks the function is instrumented and complains about the fact that it has no coverage spans.

This PR prevents that from happening in two ways:
- If we didn't extract any relevant spans from MIR, skip instrumenting the entire function and don't create a `FunctionCoverateInfo` for it.
- If coverage codegen sees a `CoverageKind::SpanMarker` statement, skip it early and avoid creating `func_coverage`.

---

Fixes rust-lang#118850.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants