mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Rollup merge of #111179 - Zalathar:sort-groups, r=Mark-Simulacrum
Fix instrument-coverage tests by using Python to sort instantiation groups #110942 was intended to fix a set of `-Cinstrument-coverage` tests, but it ended up silently *breaking* those tests on Linux, for annoying reasons detailed at #111171. Dealing with `diff --ignore-matching-lines` across multiple platforms has been such a hassle that I've instead written a simple Python script that can detect instantiation groups in the output of `llvm-cov show`, and sort them in a predictable order so that they can be used as snapshots for an ordinary invocation of `diff`. This approach should be much less error-prone, because it can't accidentally ignore the wrong lines, and any unforeseen problems will tend to result in a Python exception or a failing diff.
This commit is contained in:
commit
ea332b5937
@ -138,6 +138,7 @@ endif
|
|||||||
) \
|
) \
|
||||||
2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \
|
2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \
|
||||||
| "$(PYTHON)" $(BASEDIR)/normalize_paths.py \
|
| "$(PYTHON)" $(BASEDIR)/normalize_paths.py \
|
||||||
|
| "$(PYTHON)" $(BASEDIR)/sort_subviews.py \
|
||||||
> "$(TMPDIR)"/actual_show_coverage.$@.txt || \
|
> "$(TMPDIR)"/actual_show_coverage.$@.txt || \
|
||||||
( status=$$? ; \
|
( status=$$? ; \
|
||||||
>&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \
|
>&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \
|
||||||
@ -158,23 +159,15 @@ ifdef RUSTC_BLESS_TEST
|
|||||||
else
|
else
|
||||||
# Compare the show coverage output (`--bless` refreshes `typical` files).
|
# Compare the show coverage output (`--bless` refreshes `typical` files).
|
||||||
#
|
#
|
||||||
# FIXME(richkadel): None of the Rust test source samples have the
|
# `llvm-cov show` normally prints instantiation groups in an unpredictable
|
||||||
# `// ignore-llvm-cov-show-diffs` anymore. This directive exists to work around a limitation
|
# order, but we have used `sort_subviews.py` to sort them, so we can still
|
||||||
# with `llvm-cov show`. When reporting coverage for multiple instantiations of a generic function,
|
# check the output directly with `diff`.
|
||||||
# with different type substitutions, `llvm-cov show` prints these in a non-deterministic order,
|
|
||||||
# breaking the `diff` comparison.
|
|
||||||
#
|
#
|
||||||
# A partial workaround is implemented below, with `diff --ignore-matching-lines=RE`
|
# Some of the test cases are currently not working (since #110393) and have
|
||||||
# to ignore each line prefixing each generic instantiation coverage code region.
|
# been marked with `// ignore-llvm-cov-show-diffs` so that they don't fail
|
||||||
#
|
# the build.
|
||||||
# This workaround only works if the coverage counts are identical across all reported
|
|
||||||
# instantiations. If there is no way to ensure this, you may need to apply the
|
|
||||||
# `// ignore-llvm-cov-show-diffs` directive, and check for differences using the
|
|
||||||
# `.json` files to validate that results have not changed. (Until then, the JSON
|
|
||||||
# files are redundant, so there is no need to generate `expected_*.json` files or
|
|
||||||
# compare actual JSON results.)
|
|
||||||
|
|
||||||
$(DIFF) --ignore-matching-lines='^ \| .*::<.*>.*:$$' --ignore-matching-lines='^ \| <.*>::.*:$$' \
|
$(DIFF) \
|
||||||
expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \
|
expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \
|
||||||
( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \
|
( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \
|
||||||
>&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \
|
>&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \
|
||||||
|
@ -41,9 +41,9 @@
|
|||||||
41| 1| // executed asynchronously.
|
41| 1| // executed asynchronously.
|
||||||
42| 1| match x {
|
42| 1| match x {
|
||||||
43| 1| y if c(x).await == y + 1 => { d().await; }
|
43| 1| y if c(x).await == y + 1 => { d().await; }
|
||||||
^0 ^0 ^0 ^0
|
^0 ^0 ^0 ^0
|
||||||
44| 1| y if f().await == y + 1 => (),
|
44| 1| y if f().await == y + 1 => (),
|
||||||
^0 ^0 ^0
|
^0 ^0 ^0
|
||||||
45| 1| _ => (),
|
45| 1| _ => (),
|
||||||
46| | }
|
46| | }
|
||||||
47| 1|}
|
47| 1|}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
1| |// compile-flags: --edition=2021
|
||||||
|
2| |
|
||||||
|
3| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a
|
||||||
|
4| |// predictable order, while preserving their heterogeneous contents.
|
||||||
|
5| |
|
||||||
|
6| 1|fn main() {
|
||||||
|
7| 1| let cond = std::env::args().len() > 1;
|
||||||
|
8| 1| generic_fn::<()>(cond);
|
||||||
|
9| 1| generic_fn::<&'static str>(!cond);
|
||||||
|
10| 1| if false {
|
||||||
|
11| 0| generic_fn::<char>(cond);
|
||||||
|
12| 1| }
|
||||||
|
13| 1| generic_fn::<i32>(cond);
|
||||||
|
14| 1| other_fn();
|
||||||
|
15| 1|}
|
||||||
|
16| |
|
||||||
|
17| 3|fn generic_fn<T>(cond: bool) {
|
||||||
|
18| 3| if cond {
|
||||||
|
19| 1| println!("{}", std::any::type_name::<T>());
|
||||||
|
20| 2| }
|
||||||
|
21| 3|}
|
||||||
|
------------------
|
||||||
|
| Unexecuted instantiation: sort_groups::generic_fn::<char>
|
||||||
|
------------------
|
||||||
|
| sort_groups::generic_fn::<&str>:
|
||||||
|
| 17| 1|fn generic_fn<T>(cond: bool) {
|
||||||
|
| 18| 1| if cond {
|
||||||
|
| 19| 1| println!("{}", std::any::type_name::<T>());
|
||||||
|
| 20| 1| }
|
||||||
|
| ^0
|
||||||
|
| 21| 1|}
|
||||||
|
------------------
|
||||||
|
| sort_groups::generic_fn::<()>:
|
||||||
|
| 17| 1|fn generic_fn<T>(cond: bool) {
|
||||||
|
| 18| 1| if cond {
|
||||||
|
| 19| 0| println!("{}", std::any::type_name::<T>());
|
||||||
|
| 20| 1| }
|
||||||
|
| 21| 1|}
|
||||||
|
------------------
|
||||||
|
| sort_groups::generic_fn::<i32>:
|
||||||
|
| 17| 1|fn generic_fn<T>(cond: bool) {
|
||||||
|
| 18| 1| if cond {
|
||||||
|
| 19| 0| println!("{}", std::any::type_name::<T>());
|
||||||
|
| 20| 1| }
|
||||||
|
| 21| 1|}
|
||||||
|
------------------
|
||||||
|
22| |
|
||||||
|
23| 1|fn other_fn() {}
|
||||||
|
|
@ -19,29 +19,29 @@
|
|||||||
18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||||
19| 2|}
|
19| 2|}
|
||||||
------------------
|
------------------
|
||||||
| used_crate::used_only_from_bin_crate_generic_function::<&str>:
|
| Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_>
|
||||||
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
|
||||||
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
|
||||||
| 19| 1|}
|
|
||||||
------------------
|
------------------
|
||||||
| used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
|
| used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
|
||||||
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||||
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||||
| 19| 1|}
|
| 19| 1|}
|
||||||
------------------
|
------------------
|
||||||
| Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_>
|
| used_crate::used_only_from_bin_crate_generic_function::<&str>:
|
||||||
|
| 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||||
|
| 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||||
|
| 19| 1|}
|
||||||
------------------
|
------------------
|
||||||
20| |// Expect for above function: `Unexecuted instantiation` (see below)
|
20| |// Expect for above function: `Unexecuted instantiation` (see below)
|
||||||
21| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
21| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||||
22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||||
23| 2|}
|
23| 2|}
|
||||||
------------------
|
------------------
|
||||||
| used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
| used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
|
||||||
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||||
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||||
| 23| 1|}
|
| 23| 1|}
|
||||||
------------------
|
------------------
|
||||||
| used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
|
| used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
||||||
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||||
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||||
| 23| 1|}
|
| 23| 1|}
|
||||||
@ -51,12 +51,12 @@
|
|||||||
26| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
26| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||||
27| 2|}
|
27| 2|}
|
||||||
------------------
|
------------------
|
||||||
| used_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
| used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
||||||
| 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
| 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||||
| 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
| 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||||
| 27| 1|}
|
| 27| 1|}
|
||||||
------------------
|
------------------
|
||||||
| used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
| used_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
||||||
| 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
| 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||||
| 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
| 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||||
| 27| 1|}
|
| 27| 1|}
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||||
41| 2|}
|
41| 2|}
|
||||||
------------------
|
------------------
|
||||||
|
| Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_>
|
||||||
|
------------------
|
||||||
| used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
|
| used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
|
||||||
| 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
| 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||||
| 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
| 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||||
@ -51,8 +53,6 @@
|
|||||||
| 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
| 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||||
| 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
| 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||||
| 41| 1|}
|
| 41| 1|}
|
||||||
------------------
|
|
||||||
| Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_>
|
|
||||||
------------------
|
------------------
|
||||||
42| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`)
|
42| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`)
|
||||||
43| |
|
43| |
|
||||||
@ -77,15 +77,15 @@
|
|||||||
51| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
51| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||||
52| 3|}
|
52| 3|}
|
||||||
------------------
|
------------------
|
||||||
| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
|
||||||
| 50| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
|
||||||
| 51| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
|
||||||
| 52| 1|}
|
|
||||||
------------------
|
|
||||||
| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
||||||
| 50| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
| 50| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||||
| 51| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
| 51| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||||
| 52| 2|}
|
| 52| 2|}
|
||||||
|
------------------
|
||||||
|
| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
||||||
|
| 50| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||||
|
| 51| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||||
|
| 52| 1|}
|
||||||
------------------
|
------------------
|
||||||
53| |
|
53| |
|
||||||
54| |#[inline(always)]
|
54| |#[inline(always)]
|
||||||
|
50
tests/run-make/coverage-reports/sort_subviews.py
Normal file
50
tests/run-make/coverage-reports/sort_subviews.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# `llvm-cov show` prints grouped subviews (e.g. for generic functions) in an
|
||||||
|
# unstable order, which is inconvenient when checking output snapshots with
|
||||||
|
# `diff`. To work around that, this script detects consecutive subviews in its
|
||||||
|
# piped input, and sorts them while preserving their contents.
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
subviews = []
|
||||||
|
|
||||||
|
def flush_subviews():
|
||||||
|
if not subviews:
|
||||||
|
return
|
||||||
|
|
||||||
|
# The last "subview" should be just a boundary line on its own, so
|
||||||
|
# temporarily remove it before sorting the accumulated subviews.
|
||||||
|
terminator = subviews.pop()
|
||||||
|
subviews.sort()
|
||||||
|
subviews.append(terminator)
|
||||||
|
|
||||||
|
for view in subviews:
|
||||||
|
for line in view:
|
||||||
|
print(line, end="")
|
||||||
|
|
||||||
|
subviews.clear()
|
||||||
|
|
||||||
|
for line in sys.stdin:
|
||||||
|
if line.startswith(" ------------------"):
|
||||||
|
# This is a subview boundary line, so start a new subview.
|
||||||
|
subviews.append([line])
|
||||||
|
elif line.startswith(" |"):
|
||||||
|
# Add this line to the current subview.
|
||||||
|
subviews[-1].append(line)
|
||||||
|
else:
|
||||||
|
# This line is not part of a subview, so sort and print any
|
||||||
|
# accumulated subviews, and then print the line as-is.
|
||||||
|
flush_subviews()
|
||||||
|
print(line, end="")
|
||||||
|
|
||||||
|
flush_subviews()
|
||||||
|
assert not subviews
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
23
tests/run-make/coverage/sort_groups.rs
Normal file
23
tests/run-make/coverage/sort_groups.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// compile-flags: --edition=2021
|
||||||
|
|
||||||
|
// Demonstrate that `sort_subviews.py` can sort instantiation groups into a
|
||||||
|
// predictable order, while preserving their heterogeneous contents.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cond = std::env::args().len() > 1;
|
||||||
|
generic_fn::<()>(cond);
|
||||||
|
generic_fn::<&'static str>(!cond);
|
||||||
|
if false {
|
||||||
|
generic_fn::<char>(cond);
|
||||||
|
}
|
||||||
|
generic_fn::<i32>(cond);
|
||||||
|
other_fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generic_fn<T>(cond: bool) {
|
||||||
|
if cond {
|
||||||
|
println!("{}", std::any::type_name::<T>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn other_fn() {}
|
Loading…
Reference in New Issue
Block a user