rust/tests/run-coverage/closure.coverage
Zalathar 4690f97099 coverage: Fix an unstable-sort inconsistency in coverage spans
This code was calling `sort_unstable_by`, but failed to impose a total order on
the initial spans. That resulted in unpredictable handling of closure spans,
producing inconsistencies in the coverage maps and in user-visible coverage
reports.

This patch fixes the problem by always sorting closure spans before
otherwise-identical non-closure spans, and also switches to a stable sort in
case the ordering is still not total.
2023-09-18 21:28:56 +10:00

228 lines
8.4 KiB
Plaintext

LL| |#![allow(unused_assignments, unused_variables)]
LL| |// compile-flags: -C opt-level=2
LL| |
LL| |// This test used to be sensitive to certain coverage-specific hacks in
LL| |// `rustc_middle/mir/mono.rs`, but those hacks were later cleaned up by
LL| |// <https://github.com/rust-lang/rust/pull/83666>.
LL| |
LL| 1|fn main() {
LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
LL| 1| // dependent conditions.
LL| 1| let is_true = std::env::args().len() == 1;
LL| 1| let is_false = !is_true;
LL| 1|
LL| 1| let mut some_string = Some(String::from("the string content"));
LL| 1| println!(
LL| 1| "The string or alt: {}"
LL| 1| ,
LL| 1| some_string
LL| 1| .
LL| 1| unwrap_or_else
LL| 1| (
LL| 1| ||
LL| 0| {
LL| 0| let mut countdown = 0;
LL| 0| if is_false {
LL| 0| countdown = 10;
LL| 0| }
LL| 0| "alt string 1".to_owned()
LL| 1| }
LL| 1| )
LL| 1| );
LL| 1|
LL| 1| some_string = Some(String::from("the string content"));
LL| 1| let
LL| 1| a
LL| | =
LL| | ||
LL| 0| {
LL| 0| let mut countdown = 0;
LL| 0| if is_false {
LL| 0| countdown = 10;
LL| 0| }
LL| 0| "alt string 2".to_owned()
LL| 0| };
LL| 1| println!(
LL| 1| "The string or alt: {}"
LL| 1| ,
LL| 1| some_string
LL| 1| .
LL| 1| unwrap_or_else
LL| 1| (
LL| 1| a
LL| 1| )
LL| 1| );
LL| 1|
LL| 1| some_string = None;
LL| 1| println!(
LL| 1| "The string or alt: {}"
LL| 1| ,
LL| 1| some_string
LL| 1| .
LL| 1| unwrap_or_else
LL| 1| (
LL| 1| ||
LL| 1| {
LL| 1| let mut countdown = 0;
LL| 1| if is_false {
LL| 0| countdown = 10;
LL| 1| }
LL| 1| "alt string 3".to_owned()
LL| 1| }
LL| 1| )
LL| 1| );
LL| 1|
LL| 1| some_string = None;
LL| 1| let
LL| 1| a
LL| | =
LL| | ||
LL| 1| {
LL| 1| let mut countdown = 0;
LL| 1| if is_false {
LL| 0| countdown = 10;
LL| 1| }
LL| 1| "alt string 4".to_owned()
LL| 1| };
LL| 1| println!(
LL| 1| "The string or alt: {}"
LL| 1| ,
LL| 1| some_string
LL| 1| .
LL| 1| unwrap_or_else
LL| 1| (
LL| 1| a
LL| 1| )
LL| 1| );
LL| 1|
LL| 1| let
LL| 1| quote_closure
LL| | =
LL| | |val|
LL| 5| {
LL| 5| let mut countdown = 0;
LL| 5| if is_false {
LL| 0| countdown = 10;
LL| 5| }
LL| 5| format!("'{}'", val)
LL| 5| };
LL| 1| println!(
LL| 1| "Repeated, quoted string: {:?}"
LL| 1| ,
LL| 1| std::iter::repeat("repeat me")
LL| 1| .take(5)
LL| 1| .map
LL| 1| (
LL| 1| quote_closure
LL| 1| )
LL| 1| .collect::<Vec<_>>()
LL| 1| );
LL| 1|
LL| 1| let
LL| 1| _unused_closure
LL| | =
LL| | |
LL| | mut countdown
LL| | |
LL| 0| {
LL| 0| if is_false {
LL| 0| countdown = 10;
LL| 0| }
LL| 0| "closure should be unused".to_owned()
LL| 0| };
LL| |
LL| 1| let mut countdown = 10;
LL| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1;
^0
LL| |
LL| |
LL| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called");
LL| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called");
^0
LL| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called");
^0
LL| |
LL| |
LL| |
LL| |
LL| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") };
^0
LL| |
LL| 1| let _shortish_unused_closure = | _unused_arg: u8 | {
LL| 0| println!("not called")
LL| 0| };
LL| |
LL| 1| let _as_short_unused_closure = |
LL| | _unused_arg: u8
LL| 0| | { println!("not called") };
LL| |
LL| 1| let _almost_as_short_unused_closure = |
LL| | _unused_arg: u8
LL| 0| | { println!("not called") }
LL| | ;
LL| |
LL| |
LL| |
LL| |
LL| |
LL| 1| let _short_unused_closure_line_break_no_block = | _unused_arg: u8 |
LL| 0|println!("not called")
LL| | ;
LL| |
LL| 1| let _short_unused_closure_line_break_no_block2 =
LL| | | _unused_arg: u8 |
LL| 0| println!(
LL| 0| "not called"
LL| 0| )
LL| | ;
LL| |
LL| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch =
LL| | | _unused_arg: u8 |
LL| 0| println!(
LL| 0| "not called: {}",
LL| 0| if is_true { "check" } else { "me" }
LL| 0| )
LL| | ;
LL| |
LL| 1| let short_used_not_covered_closure_line_break_block_embedded_branch =
LL| | | _unused_arg: u8 |
LL| 0| {
LL| 0| println!(
LL| 0| "not called: {}",
LL| 0| if is_true { "check" } else { "me" }
LL| | )
LL| 0| }
LL| | ;
LL| |
LL| 1| let short_used_covered_closure_line_break_no_block_embedded_branch =
LL| | | _unused_arg: u8 |
LL| 1| println!(
LL| 1| "not called: {}",
LL| 1| if is_true { "check" } else { "me" }
^0
LL| 1| )
LL| | ;
LL| |
LL| 1| let short_used_covered_closure_line_break_block_embedded_branch =
LL| | | _unused_arg: u8 |
LL| 1| {
LL| 1| println!(
LL| 1| "not called: {}",
LL| 1| if is_true { "check" } else { "me" }
^0
LL| | )
LL| 1| }
LL| | ;
LL| |
LL| 1| if is_false {
LL| 0| short_used_not_covered_closure_macro(0);
LL| 0| short_used_not_covered_closure_line_break_no_block_embedded_branch(0);
LL| 0| short_used_not_covered_closure_line_break_block_embedded_branch(0);
LL| 1| }
LL| 1| short_used_covered_closure_macro(0);
LL| 1| short_used_covered_closure_line_break_no_block_embedded_branch(0);
LL| 1| short_used_covered_closure_line_break_block_embedded_branch(0);
LL| 1|}