-
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 tests for remaining TerminatorKinds and async, improve Assert #79109
Conversation
r? @oli-obk (rust_highfive has picked a reviewer for you, use r? to override) |
r? @tmandry |
fyi: @wesleywiser |
! ... I forgot to bless at least one of the new tests. I'm building the blessed results now and will push an update. Then I also plan to pull this PR down to my Mac and to my Windows VM so I can make sure (as best as I can) that these tests work on all 3 platforms (including Linux, my main dev environment). |
Oh, and I just realized I should rebase with the latest changes (including the 2 PRs that just landed for coverage). They may not affect this PR, but I need to be sure. |
d6936f5
to
ba60b3e
Compare
new tests are blessed and pass on Linux... I'll be testing Mac and Windows next. |
FYI, something seems broken in the rustc build. After rebasing today, and then pulling down this PR to MacOS and Windows local environments, neither of those will build the I "think" it might still work on Linux, but I'm a little afraid to try a clean build at this point 😨 |
Issue #79124 affects local builds of this PR |
Tests are working on Mac. Windows test is taking forever... ;-) |
ba60b3e
to
48ab271
Compare
Windows tests pass as well. @tmandry - subject to any review feedback changes requested, this PR should be good to merge. Thanks! |
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.
Switching to focusing on test behavior now.
I think the most important tweak would be to focus on how braces behave, and try to make them as consistent as possible across syntactic forms.
16| 11| while countdown > 0 { | ||
17| 10| if countdown < 5 { | ||
18| 4| might_abort(false); | ||
19| 6| } |
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.
As a data point, I was confused by the count on this line, since I was expecting to match either of the above two lines.
I'm sure this pre-exists this PR but I hadn't noticed it until now.
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.
This is actually correct.
The condition countdown < 5
executed 10 times (10 loop iterations).
It evaluated to true
4 times, and executed the might_abort()
call.
It skipped the body of the might_abort()
call 6 times (hidden else
).
I wanted to capture the coverage of the non-true condition. Say the condition was countdown < 50
, which is always true
. In that case, we wouldn't have a test for what happens if might_abort()
is not called.
So counting the "hidden else" is important.
I can clarify this, but I should probably clarify it in a different test that's more focused on if
blocks inside loops, and keep this test focused on testing the Abort
terminator.
One side-note... The Span for the "hidden else" starts as a 0-length span right after the right brace, if I'm not mistaken. But code region counts versus line counts are confusing for 0-length regions, so I always expend them by 1 character, preferably to the right (in the typical case, after the brace) UNLESS it's at the end of the line, in which case I have to expand it to the left (which is the right brace).
You can't see it because there are no more code regions on that line, and the code block ends at the semicolon after the might_abort()
call.
If there was no semicolon (say, if might_abort() returned a value), then there would be multiple code regions on that line, and you would see the one character highlighted. I'm not sure that would help clarify things anymore than in it's existing state though.
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.
Yeah, I was able to infer what it was doing, I just found it confusing at first. Your explanation was helpful to understand why doing this is a good idea, thanks.
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.
I went ahead and expanded this example, and added comments and notes to help explain the counter for the implicit else
.
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.
Great news here! I changed how the Span is set for implicit else
when lowering from AST, and it works! No more special case for Goto
. Lots of related issues resolved.
11| | y if f().await == y => (), | ||
12| | _ => (), | ||
13| | } | ||
14| 1|} |
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.
If I had a magic wand, I think the ideal would be for the function signature to count calls..? Or possibly the opening and (optionally) closing brace. I'm not sure which would be more intuitive.
Technically when you call an async fn you aren't running any of its code, so counting the braces might still be incorrect, but as long as the user can understand and reason about what happened I'm not especially concerned about that.
I think closing brace only is not very intuitive.
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.
I think I'd like to count the opening brace or signature, as you suggest. I'll look into that.
There's a second issue here:
Why do the generator bodies show no counts? (Not even 0.)
I need to understand that and see if it can be fixed.
If I counted the bodies, then we SHOULD see something like:
5| 1|async fn f() -> u8 { 1 }
^0
As it is, though, there's no way to tell that this async function was actually NOT executed.
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.
Interesting. I wonder if the counters are getting optimized out somehow.
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.
Partial correction. The body of f()
actually was executed (because the test blocks on i()
, and i()
await
s f()
.
But g()
is a similar example of the point I was trying to make.
From the debug logs, I can see the generator/closure MIR for the body of g()
is never passed to Rust's codegen phase.
(FYI, -Clink-dead-code does not make a difference either; I think that flag is only used by the target linker.)
I think I may have looked into this (and if so, it was a hard problem) but it would be nice to find any MIR's skipped at codegen, and still inject something in the coverage map for the function body to, hopefully, produce line counts of 0 for the body.
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.
@tmandry @wesleywiser - I'm a little unsure how to proceed here.
I'll try my best to summarize my understanding and what I think I want to do but don't know how:
-
Given a
Crate
,rustc_mir::monomorphize::collector
finds the "root"DefId
s (via theRootCollector
, a HIRItemLikeVisitor
), and traverses them to generate a set ofMonoItem
s. This is where the async closures (Generator
s) are getting dropped if they are not going to be called. (From debug logs,i::{closure#0}()
andf::{closure#0}()
are both logged, because they are going to be called, but the other async functions' closures are not mentioned at all. There is no "path" from the roots (onlymain()
in this case) to those closures. -
It seems to me I can make another
ItemLikeVisitor
, find all of thehir::ItemKindFn
s, get theirDefId
s, and look them up in the set ofMonoItem
s. If aDefId
is not found among theMonoItem
s, then it will not be codegen'ed, and therefore won't have coverage. -
At that point, I want to add at least one
Zero
counter with span (code region) for the span of the closure/generator, for each missingDefId
, to therustc_codegen_ssa::coverageinfo::map::FunctionCoverage
(the collection of counters and coderegions built up during the codegen phase, and eventually written out as the "Coverage Map". I would do this withFunctionCoverage::add_counter(self, counter, region)
.
Here's where I get confused...
The FunctionCoverage
is stored in a hash map in CrateCoverageContext
, and that object is constructed as a field in CodegenCx
, but CodegenCx
appears to be constructed for a specific CodegenUnit
IIUC, codegen of a given crate can be partitioned across multiple CodegenUnit
s, and each CodegenUnit
will have only a subset of the crate's MonoItem
s; so if that's true:
-
Given a
DefId
in someCrate
, even if theDefId
is not be found among theMonoItem
s of oneCodegenUnit
, theDefId
might still be found among theMonoItem
s of one of the otherCodegenUnit
s for thatCrate
. If so, that prevents me being able to check for missingDefIds
when I'm starting to codegen the Coverage Map, because the Coverage Map finalization happens within theCodegenCx
of only oneCodegenUnit
. -
But if I search for a
DefId
among allMonoItem
s of allCodegenUnit
s, and don't find it, how do I know whichCodegenCx
to use, to add the missing Counter and code region for that function?
What's even more baffling to me is, it looks to me like a CoverageMap is codegenned for each CodegenCx
, and assuming there are more than one, then the code appears to be set up to generate multiple coverage maps. I don't really get how that would work (or why it appears to work now), but I assume it does work since evidence suggests as much.
So I guess I just don't understand something, and hopefully the solution (to adding counters and code regions for functions/closures that are missing from the MonoItems is easier than it appears.
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.
The discussion continued at https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/counters.20for.20uncalled.20functions
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.
I couldn't simply inject code regions for functions not codegenned, as discussed in the PR for my attempted changes in draft PR #79392, but I was able to make other changes to improve this.
I'm now adding a coverage code region for the function signature, up to (but not including) the opening brace. The existing code for combining spans helps simplify (I think in a good way) how the function signature span can continue into the function body, if no other spans interfere. I think the results look good.
I also addressed showing 0
coverage for closures and async
function bodies by injecting what the Coverage Mapping Format calls a "gap region". There are additional notes on this, and some non-intuitive results (but not wrong) occasionally. Given the trade-offs, this is better for ensuring missing coverage is identified.
And, as I showed in #79109 (comment), -C link-dead-code
does make a difference for some unused functions. (Just pointing that out, since I discussed it here as well.)
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.
I made a different change, backing out my original approach to closures, and I'm now adding coverage for any unused MIR. This addresses missing coverage for async functions, closures, and unused regular functions.
25| 1|async fn i(x: u8) { | ||
26| 1| match x { | ||
27| 1| y if f().await == y + 1 => (), | ||
^0 ^0 |
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.
Does the y
being uncovered also happen in non-async code? I think I remember you mentioning something like this. It's not wrong if you consider that it's the binding of y
. It is a bit unintuitive, though.
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.
Yes, this is the same for async and non-async.
Yes it was discussed because it is less intuitive. At one point, I tried to include the y
in the pattern code region, but the logic to allow that (which may seem more intuitive, but is counter to what the MIR says) caused problems handling other cases.
I decided it was better to honor the MIR in all cases and show what's really happening.
This is not just one of those situations where we can be accurate but non-intuitive, or intuitive but inaccurate; the other problem is, it would require special case handling in the coverage code (which is something we both prefer to avoid). 😄
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.
Yeah, special casing is not great. We can always change the way MIR building emits source info at some point.
59| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { | ||
60| 1| break val; | ||
61| | } | ||
62| 0| } |
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.
This would cause tooling to complain about missing coverage of this line, but the break does happen.
Would it be possible to make all loop exits count the closing loop brace?
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.
@tmandry - I'm confused by your interpretation on this one.
To me, this is intuitive. The bottom of the loop is never reached.
This is a coverage gap because the program does not test an iteration of the loop when it does not break.
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.
Oh, now I see. That makes sense.
40| | // Demonstrate the difference with `TerminatorKind::Assert` as of 2020-11-15. Assert is no | ||
41| | // longer treated as a `BasicCoverageBlock` terminator, which changed the coverage region, | ||
42| | // for the executed `then` block above, to include the closing brace on line 30. That | ||
43| | // changed the line count, but the coverage code region (for the `else if` condition) is | ||
44| | // still valid. | ||
45| | // | ||
46| | // Note that `if` (then) and `else` blocks include the closing brace in their coverage | ||
47| | // code regions when the last line in the block ends in a semicolon, because the Rust | ||
48| | // compiler inserts a `StatementKind::Assign` to assign `const ()` to a `Place`, for the | ||
49| | // empty value for the executed block. When the last line does not end in a semicolon | ||
50| | // (that is, when the block actually results in a value), the additional `Assign` is not | ||
51| | // generated, and the brace is not included. | ||
52| 1| let mut countdown = 0; |
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.
Yeah, this is pretty unintuitive. "Closing brace is counted when the scope is exited, or skipped by if/loop condition," seems like the most logical behavior to me.
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.
"Closing brace is counted when the scope is exited, or skipped by if/loop condition,"
@tmandry are you quoting something here, or just suggesting a way you'd like it described?
On the one hand, counting the closing brace when exiting the scope is how we currently count the closing brace of a function, so this would be more consistent with that.
An argument could be made that I shouldn't count the closing brace of a function, though, if the function was exited by an early return
.
The truth is, in some cases, the reason things work the way they do for functions and for loops is because it was the best I could do given the MIR, and seemed "reasonable" (even if there were alternatives like these).
Personally, I like the idea of changing how function end braces are counted, rather than changing how loop end braces are counted. I think it's more intuitive to count the end brace only if the code did not exit the scope earlier (by break, continue, or return).
Either way, it's inconsistent now.
Should we continue debating this here? Or log it as an unresolved new "Issue" and invite the community for comment?
If the latter, maybe I shouldn't change either one, for now, since it could be a waste of time if we decide to go a different way.
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.
Yeah I think there are a few competing principles..
- Consistency
- Intuitiveness
- Preserving all information
and I'm not exactly sure how to resolve them. My quote was one idea I had.
This might be good to hash out in an issue somewhere.
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.
I think a lot of things like this are resolved with my most recent improvements.
45| |// 6. By best practice, programs should not panic. By design, the coverage implementation will not | ||
46| |// incur additional cost (in program size and execution time) to improve coverage results for | ||
47| |// an event that is not supposted to happen. |
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.
I don't think this is always true. Of course there are uses like when invariants are violated (bugs), and #[should_panic]
tests which you mention below. In addition, salsa supports unwinding as a cancellation mechanism for queries.
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.
Point taken. It's still my opinion that the best practice is not to use panic!
as a programming model. (Even salsa appears to support both panic
and Result::Err
for cancelling, if I'm not mistaken. I'm curious why not just go with the Result::Err method, unless it's for legacy reasons.)
But since this may be more my opinion, I'll rephrase.
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.
I think they support unwinding because otherwise cancellation becomes "infectious" and something you have to handle throughout your code, even though it isn't a classic error handling case. I think rust-analyzer uses it.
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.
I'm updating the comment.
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.
fixed
src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.yield.txt
Outdated
Show resolved
Hide resolved
@@ -0,0 +1,34 @@ | |||
1| |#![allow(unused_assignments)] |
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.
I'm not seeing how these -deadcode test files are any different, or add value. I guess that's one piece of the cleanup to be done.
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.
The -Clink-dead-code
defaults to on
on Linux and Mac, and off
on Windows. If the results are different, the tests would fail on Windows if I only had one variation.
I wasn't sure if I'd get different coverage results depending on the flag. Now that I have several examples, I'll diff
them to see. It's a little risky to assume the flag makes no difference, even if true for the current tests.
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.
@tmandry - FYI, currently, two tests have slightly different coverage results.
$ diff -r coverage-reports-base coverage-reports-deadcode -x '*counters*' -x '*.json' -x 'prett*' -x 'Make*'
15c15
< 15| |async fn e() -> u8 { 1 }
---
> 15| 0|async fn e() -> u8 { 1 }
19c19
< 19| |async fn foo() -> [bool; 10] { [false; 10] }
---
> 19| 0|async fn foo() -> [bool; 10] { [false; 10] }
diff --color -r -x '*counters*' -x '*.json' -x 'prett*' -x 'Make*' '--color=never' coverage-reports-base/expected_show_coverage.partial_eq.txt coverage-reports-deadcode/expected_show_coverage.partial_eq.txt
5a6,15
> ------------------
> | Unexecuted instantiation: <partial_eq::Version as core::cmp::PartialOrd>::gt
> ------------------
> | Unexecuted instantiation: <partial_eq::Version as core::cmp::PartialOrd>::le
> ------------------
> | Unexecuted instantiation: <partial_eq::Version as core::cmp::PartialOrd>::ge
> ------------------
> | <partial_eq::Version as core::cmp::PartialOrd>::lt:
> | 4| 1|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
> ------------------
8a19,28
> ------------------
> | Unexecuted instantiation: <partial_eq::Version as core::cmp::PartialOrd>::gt::{closure#0}
> ------------------
> | Unexecuted instantiation: <partial_eq::Version as core::cmp::PartialOrd>::ge::{closure#0}
> ------------------
> | <partial_eq::Version as core::cmp::PartialOrd>::lt::{closure#0}:
> | 7| 1| minor: usize,
> ------------------
> | Unexecuted instantiation: <partial_eq::Version as core::cmp::PartialOrd>::le::{closure#0}
> ------------------
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.
deadcode is no longer applicable to coverage! I'm able to instrument the deadcode functions without using the -Clink-dead-code
option. Special tests are now gone.
@tmandry I think there may be at least one or two improvements I can make, but while I do agree with you that some of the results are hard to interpret, there are cases that are both hard to interpret and still correct. (Maybe I can't make them any easier to interpret without making the coverage results inaccurate or incomplete.) In those cases, I don't think we should sacrifice coverage accuracy/completeness just to make the results "appear" more intuitive (and I think you'd agree), but I also don't know if there's much I can do to make them more clear. Maybe add comments at points in the examples where we see confusing results? |
17| 0| might_panic(true); | ||
18| 10| } else if countdown < 5 { | ||
19| 3| might_panic(false); | ||
20| 15| } |
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.
I just noticed this incorrect line count, 15
, here and at the same point in the panic_unwind.rs
test.
This is wrong of course.
I suspect I have overlapping coverage regions with different counters, and they are adding up. (Best guess for now.) I'll look into it.
I think it may be related to how I implement the "hidden else", discussed in my previous reply to @tmandry in abort.rs
. I may need to rethink what to do if the span is at the end of a line, and possible expand to the first character in the next line, if not at the end of the body.
(FYI, the expansion to the left is actually what I want for the end of the body. This is how I count function Return
s. So I don't want to break that.)
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.
I fixed this when I fixed the Goto
implicit else span, and remove the special case handling of Goto
(which didn't work that well in some cases... like this one).
@bors delegate+ |
✌️ @richkadel can now approve this pull request |
☔ The latest upstream changes (presumably #79441) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
48ab271
to
311b635
Compare
Some significant coverage count improvements while also simplifying the code a bit, removing some special case handling. |
311b635
to
6ee4a41
Compare
I learned some things while reviewing these changes, and managed to simplify things even further, removing the benefits of enforcing I did run into a couple of weird anomalies, which I had to account for in the The other is, a couple of tests create coverage results from built-in Rust macros, that now show up in I'm assuming that the new procedure in |
@tmandry - Although you gave me permission to approve this already, I do think the changes here are substantial enough to warrant another look. Good news is, I removed more than I added (in the normal code base) AND removed half of the tests (due to removing the need for Can you take another look? |
⌛ Testing commit 2c99600a8679615f601aa010825012e9b46fe59b with merge cfd64d0875173833732b8c0b2c9ca92bc0d0b1bb... |
Tested and validate results for panic unwind, panic abort, assert!() macro, TerminatorKind::Assert (for example, numeric overflow), and async/await. Implemented a previous documented idea to change Assert handling to be the same as FalseUnwind and Goto, so it doesn't get its own BasicCoverageBlock anymore. This changed a couple of coverage regions, but I validated those changes are not any worse than the prior results, and probably help assure some consistency (even if some people might disagree with how the code region is consistently computed). Fixed issue with async/await. AggregateKind::Generator needs to be handled like AggregateKind::Closure; coverage span for the outer async function should not "cover" the async body, which is actually executed in a separate "closure" MIR.
In preparation for removing the -deadcode variants
Fixes multiple issue with counters, with simplification Includes a change to the implicit else span in ast_lowering, so coverage of the implicit else no longer spans the `then` block. Adds coverage for unused closures and async function bodies. Fixes: rust-lang#78542 Adding unreachable regions for known MIR missing from coverage map Cleaned up PR commits, and removed link-dead-code requirement and tests Coverage no longer depends on Issue rust-lang#76038 (`-C link-dead-code` is no longer needed or enforced, so MSVC can use the same tests as Linux and MacOS now) Restrict adding unreachable regions to covered files Improved the code that adds coverage for uncalled functions (with MIR but not-codegenned) to avoid generating coverage in files not already included in the files with covered functions. Resolved last known issue requiring --emit llvm-ir workaround Fixed bugs in how unreachable code spans were added.
Added one more test (two files) showing coverage of generics and unused functions across crates. Created and referenced new Issues, as requested. Added comments. Added a note about the possible effects of compiler options on LLVM coverage maps.
The original test produced a single crate with two mods, which was not the goal of the test.
💔 Test failed - checks-actions |
2c99600
to
dc4bd90
Compare
@bors retry |
@bors r=tmandry |
📌 Commit dc4bd90 has been approved by |
target/debug/deps/lib-30768f9c53506dc5 \ | ||
target/debug/deps/json5format-fececd4653271682 |
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.
my experience in ZcashFoundation/zebra#1293 indicates that this will not produce the proper coverage report. I didn't quite get to the bottom of exactly what was happening but when I tried specifying the bins as a list of space separated arguments it would lose some of the coverage reports, and ordering mattered. My guess is it was ignoring everything after the first, or overwriting them somehow. In order to fix it I had to prefix every bin with -object
.
ZcashFoundation/zebra@f4b1cd2 This is the PR where I did it, the fix being adding the printf
when we output the file names.
It might also be a good idea to suggest how to extract the list of binaries that were ran by cargo-test
, or link to examples that do so.
cargo test --no-run --message-format=json \
| jq -r "select(.profile.test == true) | .filenames[]" \
| grep -v dSYM -
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.
Cool! Thanks for the recommendation. I've been struggling to get this PR to land so I may apply these suggestions in a follow-up PR.
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.
I've addressed this in #79818.
Thanks again!
☀️ Test successful - checks-actions |
Tested and validate results for panic unwind, panic abort, assert!()
macro, TerminatorKind::Assert (for example, numeric overflow), and
async/await.
Implemented a previous documented idea to change Assert handling to be
the same as FalseUnwind and Goto, so it doesn't get its own
BasicCoverageBlock anymore. This changed a couple of coverage regions,
but I validated those changes are not any worse than the prior results,
and probably help assure some consistency (even if some people might
disagree with how the code region is consistently computed).
Fixed issue with async/await. AggregateKind::Generator needs to be
handled like AggregateKind::Closure; coverage span for the outer async
function should not "cover" the async body, which is actually executed
in a separate "closure" MIR.