-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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: Use SpanMarker
to improve coverage spans for if !
expressions
#118198
Conversation
(rustbot has picked a reviewer for you, use r? to override) |
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
d1f2f5c
to
913183e
Compare
It occurs to me that another approach would have been to make the That would avoid the need to inject a span marker in this case, though I still think (And the downside would be that coverage builds wouldn't get to omit the temporary boolean value.) |
Looking again at the thread for #111752, I realise that some of those match arms are now load-bearing for language semantics. I think that mostly applies to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you mentioned that you plan to eventually move capturing this span information to HIR, so I think injecting these coverage statements here is just temporary?
I actually think of these span markers as mostly separate from the ones that I intend to introduce for capturing branch spans. This PR was the result of a few different ideas coming together in my head:
So I think these particular marker statements will hang around even after we also have proper branch detection in MIR building. These span markers are mainly about giving more accurate hints to the existing span-extraction code in the instrumentor, whereas the branch markers will be separate from that span-extraction stuff. |
One distinction to note is that these span markers get injected into the basic block that represents the condition, whereas branch markers will get injected into the blocks representing the then/else arms. |
49100ec
to
5f0d15f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r=me with 2 nits.
@@ -90,6 +90,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |||
let local_scope = this.local_scope(); | |||
let (success_block, failure_block) = | |||
this.in_if_then_scope(local_scope, expr_span, |this| { | |||
// Help out coverage instrumentation by injecting a dummy statement with | |||
// the original condition's span (including `!`). This fixes #115468. | |||
if this.tcx.sess.instrument_coverage() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this test happen inside push_coverage_span_marker
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
push_coverage_span_marker
is a method on CFG
, which doesn't have its own copy of tcx
or sess
.
So the only way to perform the test would be to also pass tcx/sess as an additional argument, which seems backwards to me. Better to perform the test in the outer code that already has access to the necessary information.
Having the test outside also makes it easier to see from outside that this code has no effect on the CFG in non-coverage builds.
let temp_place = Place::from(self.local_decls.push(local_decl)); | ||
self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice 🎉
389d682
to
9b0d342
Compare
… MIR There are cases where coverage instrumentation wants to show a span for some syntax element, but there is no MIR node that naturally carries that span, so the instrumentor can't see it. MIR building can now use this new kind of coverage statement to deliberately include those spans in MIR, attached to a dummy statement that has no other effect.
This replaces the previous workaround, which was to inject a dummy `Assign` statement.
When MIR is built for an if-not expression, the `!` part of the condition doesn't correspond to any MIR statement, so coverage instrumentation normally can't see it. We can fix that by deliberately injecting a dummy statement whose sole purpose is to associate that span with its enclosing block.
@bors r+ rollup |
coverage: Use `SpanMarker` to improve coverage spans for `if !` expressions Coverage instrumentation works by extracting source code spans from MIR. However, some kinds of syntax are effectively erased during MIR building, so their spans don't necessarily exist anywhere in MIR, making them invisible to the coverage instrumentor (unless we resort to various heuristics and hacks to recover them). This PR introduces `CoverageKind::SpanMarker`, which is a new variant of `StatementKind::Coverage`. Its sole purpose is to represent spans that would otherwise not appear in MIR, so that the coverage instrumentor can extract them. When coverage is enabled, the MIR builder can insert these dummy statements as needed, to improve the accuracy of spans used by coverage mappings. Fixes rust-lang#115468. --- `@rustbot` label +A-code-coverage
coverage: Use `SpanMarker` to improve coverage spans for `if !` expressions Coverage instrumentation works by extracting source code spans from MIR. However, some kinds of syntax are effectively erased during MIR building, so their spans don't necessarily exist anywhere in MIR, making them invisible to the coverage instrumentor (unless we resort to various heuristics and hacks to recover them). This PR introduces `CoverageKind::SpanMarker`, which is a new variant of `StatementKind::Coverage`. Its sole purpose is to represent spans that would otherwise not appear in MIR, so that the coverage instrumentor can extract them. When coverage is enabled, the MIR builder can insert these dummy statements as needed, to improve the accuracy of spans used by coverage mappings. Fixes rust-lang#115468. --- ``@rustbot`` label +A-code-coverage
…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
…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
Rollup merge of rust-lang#118198 - Zalathar:if-not, r=cjgillot coverage: Use `SpanMarker` to improve coverage spans for `if !` expressions Coverage instrumentation works by extracting source code spans from MIR. However, some kinds of syntax are effectively erased during MIR building, so their spans don't necessarily exist anywhere in MIR, making them invisible to the coverage instrumentor (unless we resort to various heuristics and hacks to recover them). This PR introduces `CoverageKind::SpanMarker`, which is a new variant of `StatementKind::Coverage`. Its sole purpose is to represent spans that would otherwise not appear in MIR, so that the coverage instrumentor can extract them. When coverage is enabled, the MIR builder can insert these dummy statements as needed, to improve the accuracy of spans used by coverage mappings. Fixes rust-lang#115468. --- ```@rustbot``` label +A-code-coverage
This turns out to have contributed to the emergence of #118850. |
coverage: Regression test for `assert!(!false)` This verifies that rust-lang#118904 has already been fixed by rust-lang#118198. --- `@rustbot` label +A-code-coverage
coverage: Regression test for `assert!(!false)` This verifies that rust-lang#118904 has already been fixed by rust-lang#118198. --- `@rustbot` label +A-code-coverage
Coverage instrumentation works by extracting source code spans from MIR. However, some kinds of syntax are effectively erased during MIR building, so their spans don't necessarily exist anywhere in MIR, making them invisible to the coverage instrumentor (unless we resort to various heuristics and hacks to recover them).
This PR introduces
CoverageKind::SpanMarker
, which is a new variant ofStatementKind::Coverage
. Its sole purpose is to represent spans that would otherwise not appear in MIR, so that the coverage instrumentor can extract them.When coverage is enabled, the MIR builder can insert these dummy statements as needed, to improve the accuracy of spans used by coverage mappings.
Fixes #115468.
@rustbot label +A-code-coverage