From 40f0172c6aed0b2fb055c19108d226f8fb410f8c Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Fri, 3 May 2024 14:32:01 +0200 Subject: [PATCH 01/14] Add -Zfixed-x18 Signed-off-by: Alice Ryhl --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 5 +++ compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ .../src/compiler-flags/fixed-x18.md | 32 +++++++++++++++++++ tests/codegen/fixed-x18.rs | 22 +++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/fixed-x18.md create mode 100644 tests/codegen/fixed-x18.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 5552b38102511..dbce7f43e62c6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -615,6 +615,11 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), + fixed_x18: bool = (false, parse_bool, [TRACKED], + "make the x18 register reserved on AArch64 (default: no)"), flatten_format_args: bool = (true, parse_bool, [TRACKED], "flatten nested format_args!() and literals into a simplified format_args!() call \ (default: yes)"), diff --git a/src/doc/unstable-book/src/compiler-flags/fixed-x18.md b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md new file mode 100644 index 0000000000000..8c8bff5fa296d --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md @@ -0,0 +1,32 @@ +# `fixed-x18` + +This option prevents the compiler from using the x18 register. It is only +supported on aarch64. + +From the [ABI spec][arm-abi]: + +> X18 is the platform register and is reserved for the use of platform ABIs. +> This is an additional temporary register on platforms that don't assign a +> special meaning to it. + +This flag only has an effect when the x18 register would otherwise be considered +a temporary register. When the flag is applied, x18 is always a reserved +register. + +This flag is intended for use with the shadow call stack sanitizer. Generally, +when that sanitizer is enabled, the x18 register is used to store a pointer to +the shadow stack. Enabling this flag prevents the compiler from overwriting the +shadow stack pointer with temporary data, which is necessary for the sanitizer +to work correctly. + +Currently, the `-Zsanitizer=shadow-call-stack` flag is only supported on +platforms that always treat x18 as a reserved register, and the `-Zfixed-x18` +flag is not required to use the sanitizer on such platforms. However, the +sanitizer may be supported on targets where this is not the case in the future. + +It is undefined behavior for `-Zsanitizer=shadow-call-stack` code to call into +code where x18 is a temporary register. On the other hand, when you are *not* +using the shadow call stack sanitizer, compilation units compiled with and +without the `-Zfixed-x18` flag are compatible with each other. + +[arm-abi]: https://developer.arm.com/documentation/den0024/a/The-ABI-for-ARM-64-bit-Architecture/Register-use-in-the-AArch64-Procedure-Call-Standard/Parameters-in-general-purpose-registers diff --git a/tests/codegen/fixed-x18.rs b/tests/codegen/fixed-x18.rs new file mode 100644 index 0000000000000..4997a39a7263d --- /dev/null +++ b/tests/codegen/fixed-x18.rs @@ -0,0 +1,22 @@ +// Test that the `reserve-x18` target feature is (not) emitted when +// the `-Zfixed-x18` flag is (not) set. + +//@ revisions: unset set +//@ needs-llvm-components: aarch64 +//@ compile-flags: --target aarch64-unknown-none +//@ [set] compile-flags: -Zfixed-x18 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // unset-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } + // set: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } +} From 518becf5ea30807f98b89002a70e5640e6e8bbf4 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 14 May 2024 21:09:42 +0200 Subject: [PATCH 02/14] Fail on non-aarch64 targets --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index dbce7f43e62c6..b3359b816025b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -617,6 +617,11 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec Date: Wed, 15 May 2024 10:01:55 +0200 Subject: [PATCH 03/14] Use an error struct instead of a panic --- compiler/rustc_codegen_llvm/messages.ftl | 2 ++ compiler/rustc_codegen_llvm/src/errors.rs | 6 +++++ compiler/rustc_codegen_llvm/src/llvm_util.rs | 9 ++++---- tests/ui/abi/fixed_x18.aarch64.stderr | 2 ++ tests/ui/abi/fixed_x18.arm.stderr | 2 ++ tests/ui/abi/fixed_x18.i686.stderr | 2 ++ tests/ui/abi/fixed_x18.riscv32.stderr | 2 ++ tests/ui/abi/fixed_x18.riscv64.stderr | 2 ++ tests/ui/abi/fixed_x18.rs | 23 ++++++++++++++++++++ tests/ui/abi/fixed_x18.x64.stderr | 2 ++ 10 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 tests/ui/abi/fixed_x18.aarch64.stderr create mode 100644 tests/ui/abi/fixed_x18.arm.stderr create mode 100644 tests/ui/abi/fixed_x18.i686.stderr create mode 100644 tests/ui/abi/fixed_x18.riscv32.stderr create mode 100644 tests/ui/abi/fixed_x18.riscv64.stderr create mode 100644 tests/ui/abi/fixed_x18.rs create mode 100644 tests/ui/abi/fixed_x18.x64.stderr diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index d14fe0299e64c..1c126e797621b 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -18,6 +18,8 @@ codegen_llvm_error_creating_import_library = codegen_llvm_error_writing_def_file = Error writing .DEF file: {$error} +codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture + codegen_llvm_from_llvm_diag = {$message} codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index e15eda7c66c14..9d83dc811633b 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -254,3 +254,9 @@ pub struct MismatchedDataLayout<'a> { pub(crate) struct InvalidTargetFeaturePrefix<'a> { pub feature: &'a str, } + +#[derive(Diagnostic)] +#[diag(codegen_llvm_fixed_x18_invalid_arch)] +pub(crate) struct FixedX18InvalidArch<'a> { + pub arch: &'a str, +} diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index b3359b816025b..53b9b530e9bd6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -1,6 +1,6 @@ use crate::back::write::create_informational_target_machine; use crate::errors::{ - InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable, + FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature, }; use crate::llvm; @@ -618,11 +618,10 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec Date: Wed, 15 May 2024 12:35:39 +0200 Subject: [PATCH 04/14] Remove fixed_x18.aarch64.stderr --- tests/ui/abi/fixed_x18.aarch64.stderr | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 tests/ui/abi/fixed_x18.aarch64.stderr diff --git a/tests/ui/abi/fixed_x18.aarch64.stderr b/tests/ui/abi/fixed_x18.aarch64.stderr deleted file mode 100644 index 6dc367f9edce6..0000000000000 --- a/tests/ui/abi/fixed_x18.aarch64.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Zfixed-x18` flag is not supported on the `x86_64` architecture - From 7677ff2879dda850c4e0622116be7751a77a2810 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 15 May 2024 13:09:02 +0200 Subject: [PATCH 05/14] Remove aarch64 from revisions list --- tests/ui/abi/fixed_x18.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/abi/fixed_x18.rs b/tests/ui/abi/fixed_x18.rs index e62b9c24d223b..6d00cb2709da2 100644 --- a/tests/ui/abi/fixed_x18.rs +++ b/tests/ui/abi/fixed_x18.rs @@ -1,7 +1,7 @@ // This tests that -Zfixed-x18 causes a compilation failure on targets other than aarch64. // Behavior on aarch64 is tested by tests/codegen/fixed-x18.rs. // -//@ revisions: x64 i686 aarch64 arm riscv32 riscv64 +//@ revisions: x64 i686 arm riscv32 riscv64 // //@ compile-flags: -Zfixed-x18 //@ [x64] needs-llvm-components: x86 From 448d63e9469c293c3855867d29cbff210691db92 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 29 May 2024 14:06:53 +1000 Subject: [PATCH 06/14] Tweak various coverage test files for slightly nicer formatting For coverage tests, splitting code across multiple lines often makes the resulting coverage report easier to interpret, so we force rustfmt to retain line breaks by adding dummy line comments with `//`. --- tests/coverage/auxiliary/used_crate.rs | 10 +++---- tests/coverage/auxiliary/used_inline_crate.rs | 10 +++---- tests/coverage/coroutine.coverage | 4 +-- tests/coverage/coroutine.rs | 4 +-- tests/coverage/inline-dead.coverage | 2 +- tests/coverage/inline-dead.rs | 2 +- tests/coverage/inner_items.coverage | 2 +- tests/coverage/inner_items.rs | 2 +- tests/coverage/partial_eq.coverage | 2 +- tests/coverage/partial_eq.rs | 2 +- tests/coverage/try_error_result.cov-map | 12 ++++----- tests/coverage/try_error_result.coverage | 4 +-- tests/coverage/try_error_result.rs | 4 +-- tests/coverage/uses_crate.coverage | 26 +++++++++---------- tests/coverage/uses_inline_crate.coverage | 26 +++++++++---------- 15 files changed, 54 insertions(+), 58 deletions(-) diff --git a/tests/coverage/auxiliary/used_crate.rs b/tests/coverage/auxiliary/used_crate.rs index 72d479c74a68d..c0556a5bb4cd4 100644 --- a/tests/coverage/auxiliary/used_crate.rs +++ b/tests/coverage/auxiliary/used_crate.rs @@ -17,23 +17,23 @@ pub fn used_function() { } pub fn used_only_from_bin_crate_generic_function(arg: T) { - println!("used_only_from_bin_crate_generic_function with {:?}", arg); + println!("used_only_from_bin_crate_generic_function with {arg:?}"); } // Expect for above function: `Unexecuted instantiation` (see below) pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); } pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); } pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); } pub fn unused_generic_function(arg: T) { - println!("unused_generic_function with {:?}", arg); + println!("unused_generic_function with {arg:?}"); } pub fn unused_function() { diff --git a/tests/coverage/auxiliary/used_inline_crate.rs b/tests/coverage/auxiliary/used_inline_crate.rs index d5fe7478aa414..165d5c1e30969 100644 --- a/tests/coverage/auxiliary/used_inline_crate.rs +++ b/tests/coverage/auxiliary/used_inline_crate.rs @@ -31,28 +31,28 @@ pub fn used_inline_function() { #[inline(always)] pub fn used_only_from_bin_crate_generic_function(arg: T) { - println!("used_only_from_bin_crate_generic_function with {:?}", arg); + println!("used_only_from_bin_crate_generic_function with {arg:?}"); } // Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) #[inline(always)] pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); } #[inline(always)] pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); } #[inline(always)] pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); } #[inline(always)] pub fn unused_generic_function(arg: T) { - println!("unused_generic_function with {:?}", arg); + println!("unused_generic_function with {arg:?}"); } #[inline(always)] diff --git a/tests/coverage/coroutine.coverage b/tests/coverage/coroutine.coverage index 68b52d1983160..afe13b48ff6d5 100644 --- a/tests/coverage/coroutine.coverage +++ b/tests/coverage/coroutine.coverage @@ -10,9 +10,9 @@ LL| |// to handle this condition, and still report dead block coverage. LL| 1|fn get_u32(val: bool) -> Result { LL| 1| if val { - LL| 1| Ok(1) + LL| 1| Ok(1) // LL| | } else { - LL| 0| Err(String::from("some error")) + LL| 0| Err(String::from("some error")) // LL| | } LL| 1|} LL| | diff --git a/tests/coverage/coroutine.rs b/tests/coverage/coroutine.rs index 7f72e0d8bd424..84d1b3304c57c 100644 --- a/tests/coverage/coroutine.rs +++ b/tests/coverage/coroutine.rs @@ -10,9 +10,9 @@ use std::pin::Pin; // to handle this condition, and still report dead block coverage. fn get_u32(val: bool) -> Result { if val { - Ok(1) + Ok(1) // } else { - Err(String::from("some error")) + Err(String::from("some error")) // } } diff --git a/tests/coverage/inline-dead.coverage b/tests/coverage/inline-dead.coverage index a2d24fd2f6a68..c12668ce89a2c 100644 --- a/tests/coverage/inline-dead.coverage +++ b/tests/coverage/inline-dead.coverage @@ -14,7 +14,7 @@ LL| |#[inline] LL| 1|fn live() -> u32 { LL| 1| if B { - LL| 0| dead() + LL| 0| dead() // LL| | } else { LL| 1| 0 LL| | } diff --git a/tests/coverage/inline-dead.rs b/tests/coverage/inline-dead.rs index 327e68c60bb73..4eb397a43fc17 100644 --- a/tests/coverage/inline-dead.rs +++ b/tests/coverage/inline-dead.rs @@ -13,7 +13,7 @@ fn main() { #[inline] fn live() -> u32 { if B { - dead() + dead() // } else { 0 } diff --git a/tests/coverage/inner_items.coverage b/tests/coverage/inner_items.coverage index 65493bcd9db45..152f3da1a2217 100644 --- a/tests/coverage/inner_items.coverage +++ b/tests/coverage/inner_items.coverage @@ -52,7 +52,7 @@ ^0 LL| | LL| 1| let mut val = InStruct { - LL| 1| in_struct_field: 101, + LL| 1| in_struct_field: 101, // LL| 1| }; LL| 1| LL| 1| val.default_trait_func(); diff --git a/tests/coverage/inner_items.rs b/tests/coverage/inner_items.rs index bcb62b3031cd9..4d513e612f06d 100644 --- a/tests/coverage/inner_items.rs +++ b/tests/coverage/inner_items.rs @@ -50,7 +50,7 @@ fn main() { } let mut val = InStruct { - in_struct_field: 101, + in_struct_field: 101, // }; val.default_trait_func(); diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/partial_eq.coverage index 9de1c933570cb..c6f9d5bf6a6aa 100644 --- a/tests/coverage/partial_eq.coverage +++ b/tests/coverage/partial_eq.coverage @@ -26,7 +26,7 @@ LL| 1| "{:?} < {:?} = {}", LL| 1| version_3_2_1, LL| 1| version_3_3_0, - LL| 1| version_3_2_1 < version_3_3_0 + LL| 1| version_3_2_1 < version_3_3_0, // LL| 1| ); LL| 1|} LL| | diff --git a/tests/coverage/partial_eq.rs b/tests/coverage/partial_eq.rs index 825e266f111f5..0e96dc2b6853f 100644 --- a/tests/coverage/partial_eq.rs +++ b/tests/coverage/partial_eq.rs @@ -26,7 +26,7 @@ fn main() { "{:?} < {:?} = {}", version_3_2_1, version_3_3_0, - version_3_2_1 < version_3_3_0 + version_3_2_1 < version_3_3_0, // ); } diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index 49e6c7ceefca4..9c18827d8e68b 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -25,26 +25,26 @@ Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) Function name: try_error_result::call -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) +- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 20) - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Function name: try_error_result::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 73, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 115, 1) to (start + 2, 12) +- Code(Counter(0)) at (prev + 113, 1) to (start + 2, 12) - Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11) = (c0 - c1) @@ -81,7 +81,7 @@ Number of file 0 mappings: 11 = (((c4 + Zero) + Zero) + c3) Function name: try_error_result::test2 -Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3e, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02] +Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 36 @@ -122,7 +122,7 @@ Number of expressions: 36 - expression 34 operands: lhs = Expression(35, Add), rhs = Zero - expression 35 operands: lhs = Counter(6), rhs = Zero Number of file 0 mappings: 40 -- Code(Counter(0)) at (prev + 62, 1) to (start + 3, 23) +- Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23) - Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14) = (c0 + (Zero + c2)) - Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 4, 26) diff --git a/tests/coverage/try_error_result.coverage b/tests/coverage/try_error_result.coverage index 6fbe8b8db13fc..7100248f7df85 100644 --- a/tests/coverage/try_error_result.coverage +++ b/tests/coverage/try_error_result.coverage @@ -1,4 +1,5 @@ LL| |#![allow(unused_assignments)] + LL| |#![cfg_attr(rustfmt, rustfmt::skip)] LL| |//@ failure-status: 1 LL| | LL| 6|fn call(return_error: bool) -> Result<(), ()> { @@ -9,7 +10,6 @@ LL| | } LL| 6|} LL| | - LL| |#[rustfmt::skip] LL| 1|fn test1() -> Result<(), ()> { LL| 1| let mut LL| 1| countdown = 10 @@ -59,7 +59,6 @@ LL| 17| } LL| |} LL| | - LL| |#[rustfmt::skip] LL| 1|fn test2() -> Result<(), ()> { LL| 1| let thing1 = Thing1{}; LL| 1| let mut @@ -117,7 +116,6 @@ LL| 0| Ok(()) LL| 1|} LL| | - LL| |#[rustfmt::skip] LL| 1|fn main() -> Result<(), ()> { LL| 1| test1().expect_err("test1 should fail"); LL| 1| test2() diff --git a/tests/coverage/try_error_result.rs b/tests/coverage/try_error_result.rs index f36283c34c8bd..1fd176c353d92 100644 --- a/tests/coverage/try_error_result.rs +++ b/tests/coverage/try_error_result.rs @@ -1,4 +1,5 @@ #![allow(unused_assignments)] +#![cfg_attr(rustfmt, rustfmt::skip)] //@ failure-status: 1 fn call(return_error: bool) -> Result<(), ()> { @@ -9,7 +10,6 @@ fn call(return_error: bool) -> Result<(), ()> { } } -#[rustfmt::skip] fn test1() -> Result<(), ()> { let mut countdown = 10 @@ -58,7 +58,6 @@ impl Thing2 { } } -#[rustfmt::skip] fn test2() -> Result<(), ()> { let thing1 = Thing1{}; let mut @@ -111,7 +110,6 @@ fn test2() -> Result<(), ()> { Ok(()) } -#[rustfmt::skip] fn main() -> Result<(), ()> { test1().expect_err("test1 should fail"); test2() diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/uses_crate.coverage index a6a570a085021..d001eeffd8636 100644 --- a/tests/coverage/uses_crate.coverage +++ b/tests/coverage/uses_crate.coverage @@ -19,69 +19,69 @@ $DIR/auxiliary/used_crate.rs: LL| 1|} LL| | LL| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { - LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + LL| 2| println!("used_only_from_bin_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> ------------------ | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_crate::used_only_from_bin_crate_generic_function::<&str>: | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| |// Expect for above function: `Unexecuted instantiation` (see below) LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_crate::used_only_from_this_lib_crate_generic_function::>: | LL| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| | LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_crate::used_from_bin_crate_and_lib_crate_generic_function::>: | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| | LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| | LL| 0|pub fn unused_generic_function(arg: T) { - LL| 0| println!("unused_generic_function with {:?}", arg); + LL| 0| println!("unused_generic_function with {arg:?}"); LL| 0|} LL| | LL| 0|pub fn unused_function() { diff --git a/tests/coverage/uses_inline_crate.coverage b/tests/coverage/uses_inline_crate.coverage index 0c9735990c7ef..832a5a6a62b44 100644 --- a/tests/coverage/uses_inline_crate.coverage +++ b/tests/coverage/uses_inline_crate.coverage @@ -34,74 +34,74 @@ $DIR/auxiliary/used_inline_crate.rs: LL| | LL| |#[inline(always)] LL| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { - LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + LL| 2| println!("used_only_from_bin_crate_generic_function with {arg:?}"); LL| 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>: | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) LL| | LL| |#[inline(always)] LL| 4|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - LL| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + LL| 4| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); LL| 4|} ------------------ | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: | LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); | LL| 2|} ------------------ | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: | LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); | LL| 2|} ------------------ LL| | LL| |#[inline(always)] LL| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - LL| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); LL| 3|} ------------------ | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 2|} ------------------ | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::>: | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| | LL| |#[inline(always)] LL| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - LL| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); LL| 3|} ------------------ | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 2|} ------------------ LL| | LL| |#[inline(always)] LL| 0|pub fn unused_generic_function(arg: T) { - LL| 0| println!("unused_generic_function with {:?}", arg); + LL| 0| println!("unused_generic_function with {arg:?}"); LL| 0|} LL| | LL| |#[inline(always)] From 9dc6e082791fe0f3116c34a922de75947883644c Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 29 May 2024 14:27:57 +1000 Subject: [PATCH 07/14] Manually run `x fmt` on all source files in `tests/coverage/` Currently we can't automatically enforce formatting on tests (see #125637), but we can at least keep things relatively tidy by occasionally running the formatter manually. This was done by temporarily commenting out the `"/tests/"` exclusion in `rustfmt.toml`, and then running `x fmt tests/coverage` and `x test coverage --bless`. --- tests/coverage/coroutine.cov-map | 8 ++++---- tests/coverage/coroutine.coverage | 3 ++- tests/coverage/coroutine.rs | 3 ++- tests/coverage/let_else_loop.cov-map | 6 +++--- tests/coverage/let_else_loop.coverage | 6 +----- tests/coverage/let_else_loop.rs | 6 +----- tests/coverage/partial_eq.cov-map | 8 ++++---- tests/coverage/partial_eq.coverage | 6 +----- tests/coverage/partial_eq.rs | 6 +----- tests/coverage/yield.cov-map | 14 +++++++------- tests/coverage/yield.coverage | 6 ++++-- tests/coverage/yield.rs | 6 ++++-- 12 files changed, 34 insertions(+), 44 deletions(-) diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index 6ead788b82f9c..6ff5ed74a96db 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -12,7 +12,7 @@ Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Function name: coroutine::main -Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -26,7 +26,7 @@ Number of expressions: 8 - expression 7 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22) -- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) +- Code(Counter(0)) at (prev + 8, 11) to (start + 0, 46) - Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45) - Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 53) = ((c1 + c2) + c3) @@ -41,11 +41,11 @@ Number of file 0 mappings: 9 = ((c4 - c5) - c6) Function name: coroutine::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 29, 01, 1f, 05, 02, 10, 01, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 21, 41) to (start + 1, 31) +- Code(Counter(0)) at (prev + 22, 8) to (start + 1, 31) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) diff --git a/tests/coverage/coroutine.coverage b/tests/coverage/coroutine.coverage index afe13b48ff6d5..611470c577388 100644 --- a/tests/coverage/coroutine.coverage +++ b/tests/coverage/coroutine.coverage @@ -18,7 +18,8 @@ LL| | LL| 1|fn main() { LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| let mut coroutine = #[coroutine] || { + LL| 1| let mut coroutine = #[coroutine] + LL| 1| || { LL| 1| yield get_u32(is_true); LL| 1| return "foo"; LL| 1| }; diff --git a/tests/coverage/coroutine.rs b/tests/coverage/coroutine.rs index 84d1b3304c57c..bd149764b3737 100644 --- a/tests/coverage/coroutine.rs +++ b/tests/coverage/coroutine.rs @@ -18,7 +18,8 @@ fn get_u32(val: bool) -> Result { fn main() { let is_true = std::env::args().len() == 1; - let mut coroutine = #[coroutine] || { + let mut coroutine = #[coroutine] + || { yield get_u32(is_true); return "foo"; }; diff --git a/tests/coverage/let_else_loop.cov-map b/tests/coverage/let_else_loop.cov-map index b0cee30052200..13d0d08adb119 100644 --- a/tests/coverage/let_else_loop.cov-map +++ b/tests/coverage/let_else_loop.cov-map @@ -1,12 +1,12 @@ Function name: let_else_loop::_if (unused) -Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 02, 09, 00, 10, 00, 02, 09, 00, 10] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 01, 0f, 00, 16, 00, 00, 20, 00, 27] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 3 - Code(Zero) at (prev + 22, 1) to (start + 1, 12) -- Code(Zero) at (prev + 2, 9) to (start + 0, 16) -- Code(Zero) at (prev + 2, 9) to (start + 0, 16) +- Code(Zero) at (prev + 1, 15) to (start + 0, 22) +- Code(Zero) at (prev + 0, 32) to (start + 0, 39) Function name: let_else_loop::_loop_either_way (unused) Raw bytes (19): 0x[01, 01, 00, 03, 00, 0f, 01, 01, 14, 00, 01, 1c, 00, 23, 00, 01, 05, 00, 0c] diff --git a/tests/coverage/let_else_loop.coverage b/tests/coverage/let_else_loop.coverage index d193c8ca1b514..bd13f6e56501c 100644 --- a/tests/coverage/let_else_loop.coverage +++ b/tests/coverage/let_else_loop.coverage @@ -21,11 +21,7 @@ LL| |// Variant using regular `if` instead of let-else. LL| |// This doesn't trigger the original ICE, but might help detect regressions. LL| 0|fn _if(cond: bool) { - LL| 0| if cond { - LL| 0| loop {} - LL| | } else { - LL| 0| loop {} - LL| | } + LL| 0| if cond { loop {} } else { loop {} } LL| |} LL| | LL| |#[coverage(off)] diff --git a/tests/coverage/let_else_loop.rs b/tests/coverage/let_else_loop.rs index 12e0aeabcab95..8217c0d072a67 100644 --- a/tests/coverage/let_else_loop.rs +++ b/tests/coverage/let_else_loop.rs @@ -20,11 +20,7 @@ fn _loop_either_way(cond: bool) { // Variant using regular `if` instead of let-else. // This doesn't trigger the original ICE, but might help detect regressions. fn _if(cond: bool) { - if cond { - loop {} - } else { - loop {} - } + if cond { loop {} } else { loop {} } } #[coverage(off)] diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map index 80670fbfa5a75..6c39ac0e378b8 100644 --- a/tests/coverage/partial_eq.cov-map +++ b/tests/coverage/partial_eq.cov-map @@ -1,16 +1,16 @@ Function name: ::new -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 06, 06] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 02, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 5) to (start + 6, 6) +- Code(Counter(0)) at (prev + 12, 5) to (start + 2, 6) Function name: partial_eq::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 0a, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 0a, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 21, 1) to (start + 10, 2) +- Code(Counter(0)) at (prev + 17, 1) to (start + 10, 2) diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/partial_eq.coverage index c6f9d5bf6a6aa..dc5b82b3c5f1a 100644 --- a/tests/coverage/partial_eq.coverage +++ b/tests/coverage/partial_eq.coverage @@ -10,11 +10,7 @@ LL| | LL| |impl Version { LL| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self { - LL| 2| Self { - LL| 2| major, - LL| 2| minor, - LL| 2| patch, - LL| 2| } + LL| 2| Self { major, minor, patch } LL| 2| } LL| |} LL| | diff --git a/tests/coverage/partial_eq.rs b/tests/coverage/partial_eq.rs index 0e96dc2b6853f..081502d4a9d64 100644 --- a/tests/coverage/partial_eq.rs +++ b/tests/coverage/partial_eq.rs @@ -10,11 +10,7 @@ pub struct Version { impl Version { pub fn new(major: usize, minor: usize, patch: usize) -> Self { - Self { - major, - minor, - patch, - } + Self { major, minor, patch } } } diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index 0347aaaa36765..a273c688e248a 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -1,5 +1,5 @@ Function name: yield::main -Raw bytes (106): 0x[01, 01, 0b, 05, 00, 0d, 11, 22, 15, 0d, 11, 11, 15, 22, 15, 0d, 11, 22, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 06, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 22, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 13, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 07, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02] +Raw bytes (106): 0x[01, 01, 0b, 05, 00, 0d, 11, 22, 15, 0d, 11, 11, 15, 22, 15, 0d, 11, 22, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 22, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 13, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 08, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 11 @@ -16,7 +16,7 @@ Number of expressions: 11 - expression 10 operands: lhs = Counter(9), rhs = Counter(10) Number of file 0 mappings: 16 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22) -- Code(Counter(0)) at (prev + 6, 11) to (start + 0, 46) +- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) - Code(Counter(3)) at (prev + 1, 39) to (start + 0, 41) - Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 52) = (c1 + Zero) @@ -29,7 +29,7 @@ Number of file 0 mappings: 16 = (c4 + c5) - Code(Expression(7, Sub)) at (prev + 3, 9) to (start + 0, 22) = ((c3 - c4) - c5) -- Code(Expression(7, Sub)) at (prev + 7, 11) to (start + 0, 46) +- Code(Expression(7, Sub)) at (prev + 8, 11) to (start + 0, 46) = ((c3 - c4) - c5) - Code(Counter(8)) at (prev + 1, 39) to (start + 0, 41) - Code(Expression(9, Add)) at (prev + 1, 14) to (start + 0, 52) @@ -41,21 +41,21 @@ Number of file 0 mappings: 16 - Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2) Function name: yield::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 29, 01, 10, 05, 02, 10, 01, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 09, 08, 01, 10, 05, 02, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 8, 41) to (start + 1, 16) +- Code(Counter(0)) at (prev + 9, 8) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) Function name: yield::main::{closure#1} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 29, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 08, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 22, 41) to (start + 1, 16) +- Code(Counter(0)) at (prev + 24, 8) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) - Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) diff --git a/tests/coverage/yield.coverage b/tests/coverage/yield.coverage index e2fc9196d2444..2c133cbec5495 100644 --- a/tests/coverage/yield.coverage +++ b/tests/coverage/yield.coverage @@ -5,7 +5,8 @@ LL| |use std::pin::Pin; LL| | LL| 1|fn main() { - LL| 1| let mut coroutine = #[coroutine] || { + LL| 1| let mut coroutine = #[coroutine] + LL| 1| || { LL| 1| yield 1; LL| 1| return "foo"; LL| 1| }; @@ -19,7 +20,8 @@ LL| 0| _ => panic!("unexpected value from resume"), LL| | } LL| | - LL| 1| let mut coroutine = #[coroutine] || { + LL| 1| let mut coroutine = #[coroutine] + LL| 1| || { LL| 1| yield 1; LL| 1| yield 2; LL| 0| yield 3; diff --git a/tests/coverage/yield.rs b/tests/coverage/yield.rs index 64ea27066047e..e02e3d3561243 100644 --- a/tests/coverage/yield.rs +++ b/tests/coverage/yield.rs @@ -5,7 +5,8 @@ use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = #[coroutine] || { + let mut coroutine = #[coroutine] + || { yield 1; return "foo"; }; @@ -19,7 +20,8 @@ fn main() { _ => panic!("unexpected value from resume"), } - let mut coroutine = #[coroutine] || { + let mut coroutine = #[coroutine] + || { yield 1; yield 2; yield 3; From bcfefe1c7e8de6c7b3ee79d402bb107303934e63 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 May 2024 08:28:44 +0000 Subject: [PATCH 08/14] Reintroduce name resolution check for trying to access locals from an inline const --- compiler/rustc_resolve/src/late.rs | 5 +++++ tests/ui/inline-const/referencing_local_variables.rs | 6 ++++++ .../inline-const/referencing_local_variables.stderr | 11 +++++++++++ 3 files changed, 22 insertions(+) create mode 100644 tests/ui/inline-const/referencing_local_variables.rs create mode 100644 tests/ui/inline-const/referencing_local_variables.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 08326d1ef57ec..98dc507d86327 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4502,6 +4502,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.visit_expr(elem); self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes)); } + ExprKind::ConstBlock(ref expr) => { + self.resolve_anon_const_manual(false, AnonConstKind::InlineConst, |this| { + this.visit_expr(expr) + }); + } ExprKind::Index(ref elem, ref idx, _) => { self.resolve_expr(elem, Some(expr)); self.visit_expr(idx); diff --git a/tests/ui/inline-const/referencing_local_variables.rs b/tests/ui/inline-const/referencing_local_variables.rs new file mode 100644 index 0000000000000..f9f0fef07f08b --- /dev/null +++ b/tests/ui/inline-const/referencing_local_variables.rs @@ -0,0 +1,6 @@ +const fn test_me(a: usize) -> usize { + const { a } + //~^ ERROR: attempt to use a non-constant value in a constant +} + +fn main() {} diff --git a/tests/ui/inline-const/referencing_local_variables.stderr b/tests/ui/inline-const/referencing_local_variables.stderr new file mode 100644 index 0000000000000..4a0a54066024e --- /dev/null +++ b/tests/ui/inline-const/referencing_local_variables.stderr @@ -0,0 +1,11 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/referencing_local_variables.rs:2:13 + | +LL | const fn test_me(a: usize) -> usize { + | - this would need to be a `const` +LL | const { a } + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0435`. From eafe80f5d9c0b0703d548fe9916dac62ba89791c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2024 11:21:17 +0200 Subject: [PATCH 09/14] tier 3 target policy: clarify the point about producing assembly --- src/doc/rustc/src/target-tier-policy.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md index 48b58f6f06adb..e9cf2a0d1ae5b 100644 --- a/src/doc/rustc/src/target-tier-policy.md +++ b/src/doc/rustc/src/target-tier-policy.md @@ -247,7 +247,8 @@ approved by the appropriate team for that shared code before acceptance. target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target. - Tier 3 targets must be able to produce assembly using at least one of - rustc's supported backends from any host target. + rustc's supported backends from any host target. (Having support in a fork + of the backend is not sufficient, it must be upstream.) If a tier 3 target stops meeting these requirements, or the target maintainers no longer have interest or time, or the target shows no signs of activity and From 7845c6e09ca2b9fec6494bbfd5ca3e8af257314b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 29 May 2024 16:16:45 +1000 Subject: [PATCH 10/14] coverage: Avoid overflow when the MC/DC condition limit is exceeded If we perform this subtraction and then add 1, the subtraction can sometimes overflow to -1 before the addition can bring its value back to 0. That behaviour seems to be benign, but it nevertheless causes test failures in compiler configurations that check for overflow. We can avoid the overflow by instead subtracting (N - 1), which is algebraically equivalent, and more closely matches what the code is actually trying to do. --- compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 9cfb25e663d11..728b63d5b21b1 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -217,12 +217,13 @@ impl MCDCInfoBuilder { } _ => { // Do not generate mcdc mappings and statements for decisions with too many conditions. - let rebase_idx = self.branch_spans.len() - decision.conditions_num + 1; + // Therefore, first erase the condition info of the (N-1) previous branch spans. + let rebase_idx = self.branch_spans.len() - (decision.conditions_num - 1); for branch in &mut self.branch_spans[rebase_idx..] { branch.condition_info = None; } - // ConditionInfo of this branch shall also be reset. + // Then, erase this last branch span's info too, for a total of N. condition_info = None; tcx.dcx().emit_warn(MCDCExceedsConditionNumLimit { From 34a1828feab6bc634e629849ad73db7042e5c8a5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 1 May 2024 10:44:31 +1000 Subject: [PATCH 11/14] coverage: Add tests for the MC/DC condition limit --- tests/coverage/mcdc/condition-limit.cov-map | 162 ++++++++++++++++++ tests/coverage/mcdc/condition-limit.coverage | 76 ++++++++ tests/coverage/mcdc/condition-limit.rs | 32 ++++ .../mcdc-condition-limit.bad.stderr | 8 + .../mcdc-condition-limit.rs | 32 ++++ 5 files changed, 310 insertions(+) create mode 100644 tests/coverage/mcdc/condition-limit.cov-map create mode 100644 tests/coverage/mcdc/condition-limit.coverage create mode 100644 tests/coverage/mcdc/condition-limit.rs create mode 100644 tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr create mode 100644 tests/ui/instrument-coverage/mcdc-condition-limit.rs diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map new file mode 100644 index 0000000000000..b4447a33691ad --- /dev/null +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -0,0 +1,162 @@ +Function name: condition_limit::bad +Raw bytes (204): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 11, 01, 14, 01, 03, 09, 20, 05, 02, 03, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 7a, 1d, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 20, 76, 19, 00, 12, 00, 13, 76, 00, 17, 00, 18, 20, 72, 15, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 20, 6e, 11, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 20, 6a, 0d, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 20, 21, 09, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 44 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(7) +- expression 2 operands: lhs = Counter(1), rhs = Counter(7) +- expression 3 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 4 operands: lhs = Counter(1), rhs = Counter(7) +- expression 5 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 6 operands: lhs = Counter(1), rhs = Counter(7) +- expression 7 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 8 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 9 operands: lhs = Counter(1), rhs = Counter(7) +- expression 10 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 11 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 12 operands: lhs = Counter(1), rhs = Counter(7) +- expression 13 operands: lhs = Expression(28, Sub), rhs = Counter(4) +- expression 14 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 15 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 16 operands: lhs = Counter(1), rhs = Counter(7) +- expression 17 operands: lhs = Expression(28, Sub), rhs = Counter(4) +- expression 18 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 19 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 20 operands: lhs = Counter(1), rhs = Counter(7) +- expression 21 operands: lhs = Expression(27, Sub), rhs = Counter(3) +- expression 22 operands: lhs = Expression(28, Sub), rhs = Counter(4) +- expression 23 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 24 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 25 operands: lhs = Counter(1), rhs = Counter(7) +- expression 26 operands: lhs = Expression(27, Sub), rhs = Counter(3) +- expression 27 operands: lhs = Expression(28, Sub), rhs = Counter(4) +- expression 28 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 30 operands: lhs = Counter(1), rhs = Counter(7) +- expression 31 operands: lhs = Expression(39, Add), rhs = Expression(0, Sub) +- expression 32 operands: lhs = Expression(40, Add), rhs = Counter(7) +- expression 33 operands: lhs = Expression(41, Add), rhs = Counter(6) +- expression 34 operands: lhs = Expression(42, Add), rhs = Counter(5) +- expression 35 operands: lhs = Expression(43, Add), rhs = Counter(4) +- expression 36 operands: lhs = Counter(2), rhs = Counter(3) +- expression 37 operands: lhs = Counter(8), rhs = Expression(38, Add) +- expression 38 operands: lhs = Expression(39, Add), rhs = Expression(0, Sub) +- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(7) +- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(6) +- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(5) +- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4) +- expression 43 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 20, 1) to (start + 3, 9) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 3, 8) to (start + 0, 9) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Expression(30, Sub), false: Counter(7) } at (prev + 0, 13) to (start + 0, 14) + true = (c1 - c7) + false = c7 +- Code(Expression(30, Sub)) at (prev + 0, 18) to (start + 0, 19) + = (c1 - c7) +- Branch { true: Expression(29, Sub), false: Counter(6) } at (prev + 0, 18) to (start + 0, 19) + true = ((c1 - c7) - c6) + false = c6 +- Code(Expression(29, Sub)) at (prev + 0, 23) to (start + 0, 24) + = ((c1 - c7) - c6) +- Branch { true: Expression(28, Sub), false: Counter(5) } at (prev + 0, 23) to (start + 0, 24) + true = (((c1 - c7) - c6) - c5) + false = c5 +- Code(Expression(28, Sub)) at (prev + 0, 28) to (start + 0, 29) + = (((c1 - c7) - c6) - c5) +- Branch { true: Expression(27, Sub), false: Counter(4) } at (prev + 0, 28) to (start + 0, 29) + true = ((((c1 - c7) - c6) - c5) - c4) + false = c4 +- Code(Expression(27, Sub)) at (prev + 0, 33) to (start + 0, 34) + = ((((c1 - c7) - c6) - c5) - c4) +- Branch { true: Expression(26, Sub), false: Counter(3) } at (prev + 0, 33) to (start + 0, 34) + true = (((((c1 - c7) - c6) - c5) - c4) - c3) + false = c3 +- Code(Expression(26, Sub)) at (prev + 0, 38) to (start + 0, 39) + = (((((c1 - c7) - c6) - c5) - c4) - c3) +- Branch { true: Counter(8), false: Counter(2) } at (prev + 0, 38) to (start + 0, 39) + true = c8 + false = c2 +- Code(Counter(8)) at (prev + 0, 40) to (start + 2, 6) +- Code(Expression(38, Add)) at (prev + 2, 6) to (start + 0, 7) + = ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1)) +- Code(Expression(37, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c8 + ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1))) + +Function name: condition_limit::good +Raw bytes (180): 0x[01, 01, 20, 01, 05, 05, 19, 05, 19, 52, 15, 05, 19, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 1d, 6f, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 10, 01, 0c, 01, 03, 09, 28, 00, 06, 03, 08, 00, 22, 30, 05, 02, 01, 06, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 52, 19, 06, 05, 00, 00, 0d, 00, 0e, 52, 00, 12, 00, 13, 30, 4e, 15, 05, 04, 00, 00, 12, 00, 13, 4e, 00, 17, 00, 18, 30, 4a, 11, 04, 03, 00, 00, 17, 00, 18, 4a, 00, 1c, 00, 1d, 30, 46, 0d, 03, 02, 00, 00, 1c, 00, 1d, 46, 00, 21, 00, 22, 30, 1d, 09, 02, 00, 00, 00, 21, 00, 22, 1d, 00, 23, 02, 06, 6f, 02, 06, 00, 07, 6b, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 32 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(6) +- expression 2 operands: lhs = Counter(1), rhs = Counter(6) +- expression 3 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 4 operands: lhs = Counter(1), rhs = Counter(6) +- expression 5 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 6 operands: lhs = Counter(1), rhs = Counter(6) +- expression 7 operands: lhs = Expression(19, Sub), rhs = Counter(4) +- expression 8 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 9 operands: lhs = Counter(1), rhs = Counter(6) +- expression 10 operands: lhs = Expression(19, Sub), rhs = Counter(4) +- expression 11 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 12 operands: lhs = Counter(1), rhs = Counter(6) +- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(3) +- expression 14 operands: lhs = Expression(19, Sub), rhs = Counter(4) +- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 16 operands: lhs = Counter(1), rhs = Counter(6) +- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(3) +- expression 18 operands: lhs = Expression(19, Sub), rhs = Counter(4) +- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 20 operands: lhs = Counter(1), rhs = Counter(6) +- expression 21 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub) +- expression 22 operands: lhs = Expression(29, Add), rhs = Counter(6) +- expression 23 operands: lhs = Expression(30, Add), rhs = Counter(5) +- expression 24 operands: lhs = Expression(31, Add), rhs = Counter(4) +- expression 25 operands: lhs = Counter(2), rhs = Counter(3) +- expression 26 operands: lhs = Counter(7), rhs = Expression(27, Add) +- expression 27 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub) +- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(6) +- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(5) +- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(4) +- expression 31 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 12, 1) to (start + 3, 9) +- MCDCDecision { bitmap_idx: 0, conditions_num: 6 } at (prev + 3, 8) to (start + 0, 34) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 6, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Expression(20, Sub), false: Counter(6), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) + true = (c1 - c6) + false = c6 +- Code(Expression(20, Sub)) at (prev + 0, 18) to (start + 0, 19) + = (c1 - c6) +- MCDCBranch { true: Expression(19, Sub), false: Counter(5), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) + true = ((c1 - c6) - c5) + false = c5 +- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 24) + = ((c1 - c6) - c5) +- MCDCBranch { true: Expression(18, Sub), false: Counter(4), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) + true = (((c1 - c6) - c5) - c4) + false = c4 +- Code(Expression(18, Sub)) at (prev + 0, 28) to (start + 0, 29) + = (((c1 - c6) - c5) - c4) +- MCDCBranch { true: Expression(17, Sub), false: Counter(3), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) + true = ((((c1 - c6) - c5) - c4) - c3) + false = c3 +- Code(Expression(17, Sub)) at (prev + 0, 33) to (start + 0, 34) + = ((((c1 - c6) - c5) - c4) - c3) +- MCDCBranch { true: Counter(7), false: Counter(2), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) + true = c7 + false = c2 +- Code(Counter(7)) at (prev + 0, 35) to (start + 2, 6) +- Code(Expression(27, Add)) at (prev + 2, 6) to (start + 0, 7) + = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) +- Code(Expression(26, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c7 + (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1))) + diff --git a/tests/coverage/mcdc/condition-limit.coverage b/tests/coverage/mcdc/condition-limit.coverage new file mode 100644 index 0000000000000..4eb87432fab48 --- /dev/null +++ b/tests/coverage/mcdc/condition-limit.coverage @@ -0,0 +1,76 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ min-llvm-version: 18 + LL| |//@ compile-flags: -Zcoverage-options=mcdc + LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc + LL| | + LL| |// Check that MC/DC instrumentation can gracefully handle conditions that + LL| |// exceed LLVM's limit of 6 conditions per decision. + LL| |// + LL| |// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) + LL| | + LL| 1|fn good() { + LL| 1| // With only 6 conditions, perform full MC/DC instrumentation. + LL| 1| let [a, b, c, d, e, f] = <[bool; 6]>::default(); + LL| 1| if a && b && c && d && e && f { + ^0 ^0 ^0 ^0 ^0 + ------------------ + | Branch (LL:8): [True: 0, False: 1] + | Branch (LL:13): [True: 0, False: 0] + | Branch (LL:18): [True: 0, False: 0] + | Branch (LL:23): [True: 0, False: 0] + | Branch (LL:28): [True: 0, False: 0] + | Branch (LL:33): [True: 0, False: 0] + ------------------ + |---> MC/DC Decision Region (LL:8) to (LL:34) + | + | Number of Conditions: 6 + | Condition C1 --> (LL:8) + | Condition C2 --> (LL:13) + | Condition C3 --> (LL:18) + | Condition C4 --> (LL:23) + | Condition C5 --> (LL:28) + | Condition C6 --> (LL:33) + | + | Executed MC/DC Test Vectors: + | + | C1, C2, C3, C4, C5, C6 Result + | 1 { F, -, -, -, -, - = F } + | + | C1-Pair: not covered + | C2-Pair: not covered + | C3-Pair: not covered + | C4-Pair: not covered + | C5-Pair: not covered + | C6-Pair: not covered + | MC/DC Coverage for Decision: 0.00% + | + ------------------ + LL| 0| core::hint::black_box("hello"); + LL| 1| } + LL| 1|} + LL| | + LL| 1|fn bad() { + LL| 1| // With 7 conditions, fall back to branch instrumentation only. + LL| 1| let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); + LL| 1| if a && b && c && d && e && f && g { + ^0 ^0 ^0 ^0 ^0 ^0 + ------------------ + | Branch (LL:8): [True: 0, False: 1] + | Branch (LL:13): [True: 0, False: 0] + | Branch (LL:18): [True: 0, False: 0] + | Branch (LL:23): [True: 0, False: 0] + | Branch (LL:28): [True: 0, False: 0] + | Branch (LL:33): [True: 0, False: 0] + | Branch (LL:38): [True: 0, False: 0] + ------------------ + LL| 0| core::hint::black_box("hello"); + LL| 1| } + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | good(); + LL| | bad(); + LL| |} + diff --git a/tests/coverage/mcdc/condition-limit.rs b/tests/coverage/mcdc/condition-limit.rs new file mode 100644 index 0000000000000..571c600ebd096 --- /dev/null +++ b/tests/coverage/mcdc/condition-limit.rs @@ -0,0 +1,32 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ min-llvm-version: 18 +//@ compile-flags: -Zcoverage-options=mcdc +//@ llvm-cov-flags: --show-branches=count --show-mcdc + +// Check that MC/DC instrumentation can gracefully handle conditions that +// exceed LLVM's limit of 6 conditions per decision. +// +// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) + +fn good() { + // With only 6 conditions, perform full MC/DC instrumentation. + let [a, b, c, d, e, f] = <[bool; 6]>::default(); + if a && b && c && d && e && f { + core::hint::black_box("hello"); + } +} + +fn bad() { + // With 7 conditions, fall back to branch instrumentation only. + let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); + if a && b && c && d && e && f && g { + core::hint::black_box("hello"); + } +} + +#[coverage(off)] +fn main() { + good(); + bad(); +} diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr new file mode 100644 index 0000000000000..4d8d7e1560d08 --- /dev/null +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr @@ -0,0 +1,8 @@ +warning: Conditions number of the decision (7) exceeds limit (6). MCDC analysis will not count this expression. + --> $DIR/mcdc-condition-limit.rs:29:8 + | +LL | if a && b && c && d && e && f && g { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.rs b/tests/ui/instrument-coverage/mcdc-condition-limit.rs new file mode 100644 index 0000000000000..64c5f8e9b7798 --- /dev/null +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.rs @@ -0,0 +1,32 @@ +//@ edition: 2021 +//@ min-llvm-version: 18 +//@ revisions: good bad +//@ check-pass +//@ compile-flags: -Cinstrument-coverage -Zcoverage-options=mcdc -Zno-profiler-runtime + +// Check that we emit some kind of diagnostic when MC/DC instrumentation sees +// code that exceeds the limit of 6 conditions per decision, and falls back +// to only instrumenting that code for branch coverage. +// +// See also `tests/coverage/mcdc/condition-limit.rs`, which tests the actual +// effect on instrumentation. +// +// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) + +#[cfg(good)] +fn main() { + // 6 conditions is OK, so no diagnostic. + let [a, b, c, d, e, f] = <[bool; 6]>::default(); + if a && b && c && d && e && f { + core::hint::black_box("hello"); + } +} + +#[cfg(bad)] +fn main() { + // 7 conditions is too many, so issue a diagnostic. + let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); + if a && b && c && d && e && f && g { //[bad]~ WARNING Conditions number of the decision + core::hint::black_box("hello"); + } +} From bb865cb83f835a746db13bc6d186f22464f80fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 29 May 2024 10:37:21 +0000 Subject: [PATCH 12/14] remove unneeded extern crate in rmake test --- tests/run-make/rust-lld-by-default/rmake.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/run-make/rust-lld-by-default/rmake.rs b/tests/run-make/rust-lld-by-default/rmake.rs index 876968727f3ca..6a8dae1043e37 100644 --- a/tests/run-make/rust-lld-by-default/rmake.rs +++ b/tests/run-make/rust-lld-by-default/rmake.rs @@ -4,8 +4,6 @@ //@ needs-rust-lld //@ only-x86_64-unknown-linux-gnu -extern crate run_make_support; - use run_make_support::regex::Regex; use run_make_support::rustc; use std::process::Output; From 268b9a74e38595c5ee71d7bb9152ee1a3bbf9242 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 29 May 2024 21:12:47 +1000 Subject: [PATCH 13/14] Extract coverage-specific code out of `compiletest::runtest` This moves a few hundred lines of coverage-specific code out of the main module, making navigation a bit easier. --- src/tools/compiletest/src/runtest.rs | 363 +---------------- src/tools/compiletest/src/runtest/coverage.rs | 367 ++++++++++++++++++ src/tools/compiletest/src/runtest/tests.rs | 68 ---- 3 files changed, 372 insertions(+), 426 deletions(-) create mode 100644 src/tools/compiletest/src/runtest/coverage.rs diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e8ceff847224f..910a829fbea1e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -9,7 +9,7 @@ use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; use crate::common::{CoverageMap, CoverageRun, Pretty, RunPassValgrind}; -use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP, UI_RUN_STDERR, UI_RUN_STDOUT}; +use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT}; use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; @@ -41,6 +41,7 @@ use tracing::*; use crate::extract_gdb_version; use crate::is_android_gdb_target; +mod coverage; mod debugger; use debugger::DebuggerCommands; @@ -53,6 +54,7 @@ macro_rules! static_regex { RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) }}; } +use static_regex; const FAKE_SRC_BASE: &str = "fake-test-src-base"; @@ -267,8 +269,8 @@ impl<'test> TestCx<'test> { MirOpt => self.run_mir_opt_test(), Assembly => self.run_assembly_test(), JsDocTest => self.run_js_doc_test(), - CoverageMap => self.run_coverage_map_test(), - CoverageRun => self.run_coverage_run_test(), + CoverageMap => self.run_coverage_map_test(), // see self::coverage + CoverageRun => self.run_coverage_run_test(), // see self::coverage Crashes => self.run_crash_test(), } } @@ -504,224 +506,6 @@ impl<'test> TestCx<'test> { } } - fn run_coverage_map_test(&self) { - let Some(coverage_dump_path) = &self.config.coverage_dump_path else { - self.fatal("missing --coverage-dump"); - }; - - let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir(); - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - drop(proc_res); - - let mut dump_command = Command::new(coverage_dump_path); - dump_command.arg(llvm_ir_path); - let proc_res = self.run_command_to_procres(&mut dump_command); - if !proc_res.status.success() { - self.fatal_proc_rec("coverage-dump failed!", &proc_res); - } - - let kind = UI_COVERAGE_MAP; - - let expected_coverage_dump = self.load_expected_output(kind); - let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]); - - let coverage_dump_errors = - self.compare_output(kind, &actual_coverage_dump, &expected_coverage_dump); - - if coverage_dump_errors > 0 { - self.fatal_proc_rec( - &format!("{coverage_dump_errors} errors occurred comparing coverage output."), - &proc_res, - ); - } - } - - fn run_coverage_run_test(&self) { - let should_run = self.run_if_enabled(); - let proc_res = self.compile_test(should_run, Emit::None); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - drop(proc_res); - - if let WillExecute::Disabled = should_run { - return; - } - - let profraw_path = self.output_base_dir().join("default.profraw"); - let profdata_path = self.output_base_dir().join("default.profdata"); - - // Delete any existing profraw/profdata files to rule out unintended - // interference between repeated test runs. - if profraw_path.exists() { - std::fs::remove_file(&profraw_path).unwrap(); - } - if profdata_path.exists() { - std::fs::remove_file(&profdata_path).unwrap(); - } - - let proc_res = self.exec_compiled_test_general( - &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())], - false, - ); - if self.props.failure_status.is_some() { - self.check_correct_failure_status(&proc_res); - } else if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - drop(proc_res); - - let mut profraw_paths = vec![profraw_path]; - let mut bin_paths = vec![self.make_exe_name()]; - - if self.config.suite == "coverage-run-rustdoc" { - self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths); - } - - // Run `llvm-profdata merge` to index the raw coverage output. - let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| { - cmd.args(["merge", "--sparse", "--output"]); - cmd.arg(&profdata_path); - cmd.args(&profraw_paths); - }); - if !proc_res.status.success() { - self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res); - } - drop(proc_res); - - // Run `llvm-cov show` to produce a coverage report in text format. - let proc_res = self.run_llvm_tool("llvm-cov", |cmd| { - cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]); - - cmd.arg("--Xdemangler"); - cmd.arg(self.config.rust_demangler_path.as_ref().unwrap()); - - cmd.arg("--instr-profile"); - cmd.arg(&profdata_path); - - for bin in &bin_paths { - cmd.arg("--object"); - cmd.arg(bin); - } - - cmd.args(&self.props.llvm_cov_flags); - }); - if !proc_res.status.success() { - self.fatal_proc_rec("llvm-cov show failed!", &proc_res); - } - - let kind = UI_COVERAGE; - - let expected_coverage = self.load_expected_output(kind); - let normalized_actual_coverage = - self.normalize_coverage_output(&proc_res.stdout).unwrap_or_else(|err| { - self.fatal_proc_rec(&err, &proc_res); - }); - - let coverage_errors = - self.compare_output(kind, &normalized_actual_coverage, &expected_coverage); - - if coverage_errors > 0 { - self.fatal_proc_rec( - &format!("{} errors occurred comparing coverage output.", coverage_errors), - &proc_res, - ); - } - } - - /// Run any doctests embedded in this test file, and add any resulting - /// `.profraw` files and doctest executables to the given vectors. - fn run_doctests_for_coverage( - &self, - profraw_paths: &mut Vec, - bin_paths: &mut Vec, - ) { - // Put .profraw files and doctest executables in dedicated directories, - // to make it easier to glob them all later. - let profraws_dir = self.output_base_dir().join("doc_profraws"); - let bins_dir = self.output_base_dir().join("doc_bins"); - - // Remove existing directories to prevent cross-run interference. - if profraws_dir.try_exists().unwrap() { - std::fs::remove_dir_all(&profraws_dir).unwrap(); - } - if bins_dir.try_exists().unwrap() { - std::fs::remove_dir_all(&bins_dir).unwrap(); - } - - let mut rustdoc_cmd = - Command::new(self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed")); - - // In general there will be multiple doctest binaries running, so we - // tell the profiler runtime to write their coverage data into separate - // profraw files. - rustdoc_cmd.env("LLVM_PROFILE_FILE", profraws_dir.join("%p-%m.profraw")); - - rustdoc_cmd.args(["--test", "-Cinstrument-coverage"]); - - // Without this, the doctests complain about not being able to find - // their enclosing file's crate for some reason. - rustdoc_cmd.args(["--crate-name", "workaround_for_79771"]); - - // Persist the doctest binaries so that `llvm-cov show` can read their - // embedded coverage mappings later. - rustdoc_cmd.arg("-Zunstable-options"); - rustdoc_cmd.arg("--persist-doctests"); - rustdoc_cmd.arg(&bins_dir); - - rustdoc_cmd.arg("-L"); - rustdoc_cmd.arg(self.aux_output_dir_name()); - - rustdoc_cmd.arg(&self.testpaths.file); - - let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None); - if !proc_res.status.success() { - self.fatal_proc_rec("rustdoc --test failed!", &proc_res) - } - - fn glob_iter(path: impl AsRef) -> impl Iterator { - let path_str = path.as_ref().to_str().unwrap(); - let iter = glob(path_str).unwrap(); - iter.map(Result::unwrap) - } - - // Find all profraw files in the profraw directory. - for p in glob_iter(profraws_dir.join("*.profraw")) { - profraw_paths.push(p); - } - // Find all executables in the `--persist-doctests` directory, while - // avoiding other file types (e.g. `.pdb` on Windows). This doesn't - // need to be perfect, as long as it can handle the files actually - // produced by `rustdoc --test`. - for p in glob_iter(bins_dir.join("**/*")) { - let is_bin = p.is_file() - && match p.extension() { - None => true, - Some(ext) => ext == OsStr::new("exe"), - }; - if is_bin { - bin_paths.push(p); - } - } - } - - fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes { - let tool_path = self - .config - .llvm_bin_dir - .as_ref() - .expect("this test expects the LLVM bin dir to be available") - .join(name); - - let mut cmd = Command::new(tool_path); - configure_cmd_fn(&mut cmd); - - self.run_command_to_procres(&mut cmd) - } - fn run_command_to_procres(&self, cmd: &mut Command) -> ProcRes { let output = cmd.output().unwrap_or_else(|e| panic!("failed to exec `{cmd:?}`: {e:?}")); @@ -737,143 +521,6 @@ impl<'test> TestCx<'test> { proc_res } - fn normalize_coverage_output(&self, coverage: &str) -> Result { - let normalized = self.normalize_output(coverage, &[]); - let normalized = Self::anonymize_coverage_line_numbers(&normalized); - - let mut lines = normalized.lines().collect::>(); - - Self::sort_coverage_file_sections(&mut lines)?; - Self::sort_coverage_subviews(&mut lines)?; - - let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::(); - Ok(joined_lines) - } - - /// Replace line numbers in coverage reports with the placeholder `LL`, - /// so that the tests are less sensitive to lines being added/removed. - fn anonymize_coverage_line_numbers(coverage: &str) -> String { - // The coverage reporter prints line numbers at the start of a line. - // They are truncated or left-padded to occupy exactly 5 columns. - // (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.) - // A pipe character `|` appears immediately after the final digit. - // - // Line numbers that appear inside expansion/instantiation subviews - // have an additional prefix of ` |` for each nesting level. - // - // Branch views also include the relevant line number, so we want to - // redact those too. (These line numbers don't have padding.) - // - // Note: The pattern `(?m:^)` matches the start of a line. - - // ` 1|` => ` LL|` - // ` 10|` => ` LL|` - // ` 100|` => ` LL|` - // ` | 1000|` => ` | LL|` - // ` | | 1000|` => ` | | LL|` - let coverage = static_regex!(r"(?m:^)(?(?: \|)*) *[0-9]+\|") - .replace_all(&coverage, "${prefix} LL|"); - - // ` | Branch (1:` => ` | Branch (LL:` - // ` | | Branch (10:` => ` | | Branch (LL:` - let coverage = static_regex!(r"(?m:^)(?(?: \|)+ Branch \()[0-9]+:") - .replace_all(&coverage, "${prefix}LL:"); - - // ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:` - let coverage = - static_regex!(r"(?m:^)(?(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?[0-9]+\) to \()[0-9]+:") - .replace_all(&coverage, "${prefix}LL:${middle}LL:"); - - // ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:` - let coverage = - static_regex!(r"(?m:^)(?(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:") - .replace_all(&coverage, "${prefix}LL:"); - - coverage.into_owned() - } - - /// Coverage reports can describe multiple source files, separated by - /// blank lines. The order of these files is unpredictable (since it - /// depends on implementation details), so we need to sort the file - /// sections into a consistent order before comparing against a snapshot. - fn sort_coverage_file_sections(coverage_lines: &mut Vec<&str>) -> Result<(), String> { - // Group the lines into file sections, separated by blank lines. - let mut sections = coverage_lines.split(|line| line.is_empty()).collect::>(); - - // The last section should be empty, representing an extra trailing blank line. - if !sections.last().is_some_and(|last| last.is_empty()) { - return Err("coverage report should end with an extra blank line".to_owned()); - } - - // Sort the file sections (not including the final empty "section"). - let except_last = sections.len() - 1; - (&mut sections[..except_last]).sort(); - - // Join the file sections back into a flat list of lines, with - // sections separated by blank lines. - let joined = sections.join(&[""] as &[_]); - assert_eq!(joined.len(), coverage_lines.len()); - *coverage_lines = joined; - - Ok(()) - } - - fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> { - let mut output_lines = Vec::new(); - - // We accumulate a list of zero or more "subviews", where each - // subview is a list of one or more lines. - let mut subviews: Vec> = Vec::new(); - - fn flush<'a>(subviews: &mut Vec>, output_lines: &mut Vec<&'a str>) { - if subviews.is_empty() { - return; - } - - // Take and clear the list of accumulated subviews. - let mut subviews = std::mem::take(subviews); - - // The last "subview" should be just a boundary line on its own, - // so exclude it when sorting the other subviews. - let except_last = subviews.len() - 1; - (&mut subviews[..except_last]).sort(); - - for view in subviews { - for line in view { - output_lines.push(line); - } - } - } - - for (line, line_num) in coverage_lines.iter().zip(1..) { - if line.starts_with(" ------------------") { - // This is a subview boundary line, so start a new subview. - subviews.push(vec![line]); - } else if line.starts_with(" |") { - // Add this line to the current subview. - subviews - .last_mut() - .ok_or(format!( - "unexpected subview line outside of a subview on line {line_num}" - ))? - .push(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(&mut subviews, &mut output_lines); - output_lines.push(line); - } - } - - flush(&mut subviews, &mut output_lines); - assert!(subviews.is_empty()); - - assert_eq!(output_lines.len(), coverage_lines.len()); - *coverage_lines = output_lines; - - Ok(()) - } - fn run_pretty_test(&self) { if self.props.pp_exact.is_some() { logv(self.config, "testing for exact pretty-printing".to_owned()); diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs new file mode 100644 index 0000000000000..dad3fb3013333 --- /dev/null +++ b/src/tools/compiletest/src/runtest/coverage.rs @@ -0,0 +1,367 @@ +//! Code specific to the coverage test suites. + +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use glob::glob; + +use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP}; +use crate::runtest::{static_regex, Emit, ProcRes, TestCx, WillExecute}; + +impl<'test> TestCx<'test> { + pub(crate) fn run_coverage_map_test(&self) { + let Some(coverage_dump_path) = &self.config.coverage_dump_path else { + self.fatal("missing --coverage-dump"); + }; + + let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir(); + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + drop(proc_res); + + let mut dump_command = Command::new(coverage_dump_path); + dump_command.arg(llvm_ir_path); + let proc_res = self.run_command_to_procres(&mut dump_command); + if !proc_res.status.success() { + self.fatal_proc_rec("coverage-dump failed!", &proc_res); + } + + let kind = UI_COVERAGE_MAP; + + let expected_coverage_dump = self.load_expected_output(kind); + let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]); + + let coverage_dump_errors = + self.compare_output(kind, &actual_coverage_dump, &expected_coverage_dump); + + if coverage_dump_errors > 0 { + self.fatal_proc_rec( + &format!("{coverage_dump_errors} errors occurred comparing coverage output."), + &proc_res, + ); + } + } + + pub(crate) fn run_coverage_run_test(&self) { + let should_run = self.run_if_enabled(); + let proc_res = self.compile_test(should_run, Emit::None); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + drop(proc_res); + + if let WillExecute::Disabled = should_run { + return; + } + + let profraw_path = self.output_base_dir().join("default.profraw"); + let profdata_path = self.output_base_dir().join("default.profdata"); + + // Delete any existing profraw/profdata files to rule out unintended + // interference between repeated test runs. + if profraw_path.exists() { + std::fs::remove_file(&profraw_path).unwrap(); + } + if profdata_path.exists() { + std::fs::remove_file(&profdata_path).unwrap(); + } + + let proc_res = self.exec_compiled_test_general( + &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())], + false, + ); + if self.props.failure_status.is_some() { + self.check_correct_failure_status(&proc_res); + } else if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + drop(proc_res); + + let mut profraw_paths = vec![profraw_path]; + let mut bin_paths = vec![self.make_exe_name()]; + + if self.config.suite == "coverage-run-rustdoc" { + self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths); + } + + // Run `llvm-profdata merge` to index the raw coverage output. + let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| { + cmd.args(["merge", "--sparse", "--output"]); + cmd.arg(&profdata_path); + cmd.args(&profraw_paths); + }); + if !proc_res.status.success() { + self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res); + } + drop(proc_res); + + // Run `llvm-cov show` to produce a coverage report in text format. + let proc_res = self.run_llvm_tool("llvm-cov", |cmd| { + cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]); + + cmd.arg("--Xdemangler"); + cmd.arg(self.config.rust_demangler_path.as_ref().unwrap()); + + cmd.arg("--instr-profile"); + cmd.arg(&profdata_path); + + for bin in &bin_paths { + cmd.arg("--object"); + cmd.arg(bin); + } + + cmd.args(&self.props.llvm_cov_flags); + }); + if !proc_res.status.success() { + self.fatal_proc_rec("llvm-cov show failed!", &proc_res); + } + + let kind = UI_COVERAGE; + + let expected_coverage = self.load_expected_output(kind); + let normalized_actual_coverage = + self.normalize_coverage_output(&proc_res.stdout).unwrap_or_else(|err| { + self.fatal_proc_rec(&err, &proc_res); + }); + + let coverage_errors = + self.compare_output(kind, &normalized_actual_coverage, &expected_coverage); + + if coverage_errors > 0 { + self.fatal_proc_rec( + &format!("{} errors occurred comparing coverage output.", coverage_errors), + &proc_res, + ); + } + } + + /// Run any doctests embedded in this test file, and add any resulting + /// `.profraw` files and doctest executables to the given vectors. + fn run_doctests_for_coverage( + &self, + profraw_paths: &mut Vec, + bin_paths: &mut Vec, + ) { + // Put .profraw files and doctest executables in dedicated directories, + // to make it easier to glob them all later. + let profraws_dir = self.output_base_dir().join("doc_profraws"); + let bins_dir = self.output_base_dir().join("doc_bins"); + + // Remove existing directories to prevent cross-run interference. + if profraws_dir.try_exists().unwrap() { + std::fs::remove_dir_all(&profraws_dir).unwrap(); + } + if bins_dir.try_exists().unwrap() { + std::fs::remove_dir_all(&bins_dir).unwrap(); + } + + let mut rustdoc_cmd = + Command::new(self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed")); + + // In general there will be multiple doctest binaries running, so we + // tell the profiler runtime to write their coverage data into separate + // profraw files. + rustdoc_cmd.env("LLVM_PROFILE_FILE", profraws_dir.join("%p-%m.profraw")); + + rustdoc_cmd.args(["--test", "-Cinstrument-coverage"]); + + // Without this, the doctests complain about not being able to find + // their enclosing file's crate for some reason. + rustdoc_cmd.args(["--crate-name", "workaround_for_79771"]); + + // Persist the doctest binaries so that `llvm-cov show` can read their + // embedded coverage mappings later. + rustdoc_cmd.arg("-Zunstable-options"); + rustdoc_cmd.arg("--persist-doctests"); + rustdoc_cmd.arg(&bins_dir); + + rustdoc_cmd.arg("-L"); + rustdoc_cmd.arg(self.aux_output_dir_name()); + + rustdoc_cmd.arg(&self.testpaths.file); + + let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc --test failed!", &proc_res) + } + + fn glob_iter(path: impl AsRef) -> impl Iterator { + let path_str = path.as_ref().to_str().unwrap(); + let iter = glob(path_str).unwrap(); + iter.map(Result::unwrap) + } + + // Find all profraw files in the profraw directory. + for p in glob_iter(profraws_dir.join("*.profraw")) { + profraw_paths.push(p); + } + // Find all executables in the `--persist-doctests` directory, while + // avoiding other file types (e.g. `.pdb` on Windows). This doesn't + // need to be perfect, as long as it can handle the files actually + // produced by `rustdoc --test`. + for p in glob_iter(bins_dir.join("**/*")) { + let is_bin = p.is_file() + && match p.extension() { + None => true, + Some(ext) => ext == OsStr::new("exe"), + }; + if is_bin { + bin_paths.push(p); + } + } + } + + fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes { + let tool_path = self + .config + .llvm_bin_dir + .as_ref() + .expect("this test expects the LLVM bin dir to be available") + .join(name); + + let mut cmd = Command::new(tool_path); + configure_cmd_fn(&mut cmd); + + self.run_command_to_procres(&mut cmd) + } + + fn normalize_coverage_output(&self, coverage: &str) -> Result { + let normalized = self.normalize_output(coverage, &[]); + let normalized = Self::anonymize_coverage_line_numbers(&normalized); + + let mut lines = normalized.lines().collect::>(); + + Self::sort_coverage_file_sections(&mut lines)?; + Self::sort_coverage_subviews(&mut lines)?; + + let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::(); + Ok(joined_lines) + } + + /// Replace line numbers in coverage reports with the placeholder `LL`, + /// so that the tests are less sensitive to lines being added/removed. + fn anonymize_coverage_line_numbers(coverage: &str) -> String { + // The coverage reporter prints line numbers at the start of a line. + // They are truncated or left-padded to occupy exactly 5 columns. + // (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.) + // A pipe character `|` appears immediately after the final digit. + // + // Line numbers that appear inside expansion/instantiation subviews + // have an additional prefix of ` |` for each nesting level. + // + // Branch views also include the relevant line number, so we want to + // redact those too. (These line numbers don't have padding.) + // + // Note: The pattern `(?m:^)` matches the start of a line. + + // ` 1|` => ` LL|` + // ` 10|` => ` LL|` + // ` 100|` => ` LL|` + // ` | 1000|` => ` | LL|` + // ` | | 1000|` => ` | | LL|` + let coverage = static_regex!(r"(?m:^)(?(?: \|)*) *[0-9]+\|") + .replace_all(&coverage, "${prefix} LL|"); + + // ` | Branch (1:` => ` | Branch (LL:` + // ` | | Branch (10:` => ` | | Branch (LL:` + let coverage = static_regex!(r"(?m:^)(?(?: \|)+ Branch \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:"); + + // ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:` + let coverage = + static_regex!(r"(?m:^)(?(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?[0-9]+\) to \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:${middle}LL:"); + + // ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:` + let coverage = + static_regex!(r"(?m:^)(?(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:"); + + coverage.into_owned() + } + + /// Coverage reports can describe multiple source files, separated by + /// blank lines. The order of these files is unpredictable (since it + /// depends on implementation details), so we need to sort the file + /// sections into a consistent order before comparing against a snapshot. + fn sort_coverage_file_sections(coverage_lines: &mut Vec<&str>) -> Result<(), String> { + // Group the lines into file sections, separated by blank lines. + let mut sections = coverage_lines.split(|line| line.is_empty()).collect::>(); + + // The last section should be empty, representing an extra trailing blank line. + if !sections.last().is_some_and(|last| last.is_empty()) { + return Err("coverage report should end with an extra blank line".to_owned()); + } + + // Sort the file sections (not including the final empty "section"). + let except_last = sections.len() - 1; + (&mut sections[..except_last]).sort(); + + // Join the file sections back into a flat list of lines, with + // sections separated by blank lines. + let joined = sections.join(&[""] as &[_]); + assert_eq!(joined.len(), coverage_lines.len()); + *coverage_lines = joined; + + Ok(()) + } + + fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> { + let mut output_lines = Vec::new(); + + // We accumulate a list of zero or more "subviews", where each + // subview is a list of one or more lines. + let mut subviews: Vec> = Vec::new(); + + fn flush<'a>(subviews: &mut Vec>, output_lines: &mut Vec<&'a str>) { + if subviews.is_empty() { + return; + } + + // Take and clear the list of accumulated subviews. + let mut subviews = std::mem::take(subviews); + + // The last "subview" should be just a boundary line on its own, + // so exclude it when sorting the other subviews. + let except_last = subviews.len() - 1; + (&mut subviews[..except_last]).sort(); + + for view in subviews { + for line in view { + output_lines.push(line); + } + } + } + + for (line, line_num) in coverage_lines.iter().zip(1..) { + if line.starts_with(" ------------------") { + // This is a subview boundary line, so start a new subview. + subviews.push(vec![line]); + } else if line.starts_with(" |") { + // Add this line to the current subview. + subviews + .last_mut() + .ok_or(format!( + "unexpected subview line outside of a subview on line {line_num}" + ))? + .push(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(&mut subviews, &mut output_lines); + output_lines.push(line); + } + } + + flush(&mut subviews, &mut output_lines); + assert!(subviews.is_empty()); + + assert_eq!(output_lines.len(), coverage_lines.len()); + *coverage_lines = output_lines; + + Ok(()) + } +} diff --git a/src/tools/compiletest/src/runtest/tests.rs b/src/tools/compiletest/src/runtest/tests.rs index 817b56109a504..fb3dd326a4c80 100644 --- a/src/tools/compiletest/src/runtest/tests.rs +++ b/src/tools/compiletest/src/runtest/tests.rs @@ -48,71 +48,3 @@ fn normalize_platform_differences() { r#"println!("test\ntest")"#, ); } - -/// Test for anonymizing line numbers in coverage reports, especially for -/// MC/DC regions. -/// -/// FIXME(#123409): This test can be removed when we have examples of MC/DC -/// coverage in the actual coverage test suite. -#[test] -fn anonymize_coverage_line_numbers() { - let anon = |coverage| TestCx::anonymize_coverage_line_numbers(coverage); - - let input = r#" - 7| 2|fn mcdc_check_neither(a: bool, b: bool) { - 8| 2| if a && b { - ^0 - ------------------ - |---> MC/DC Decision Region (8:8) to (8:14) - | - | Number of Conditions: 2 - | Condition C1 --> (8:8) - | Condition C2 --> (8:13) - | - | Executed MC/DC Test Vectors: - | - | C1, C2 Result - | 1 { F, - = F } - | - | C1-Pair: not covered - | C2-Pair: not covered - | MC/DC Coverage for Decision: 0.00% - | - ------------------ - 9| 0| say("a and b"); - 10| 2| } else { - 11| 2| say("not both"); - 12| 2| } - 13| 2|} -"#; - - let expected = r#" - LL| 2|fn mcdc_check_neither(a: bool, b: bool) { - LL| 2| if a && b { - ^0 - ------------------ - |---> MC/DC Decision Region (LL:8) to (LL:14) - | - | Number of Conditions: 2 - | Condition C1 --> (LL:8) - | Condition C2 --> (LL:13) - | - | Executed MC/DC Test Vectors: - | - | C1, C2 Result - | 1 { F, - = F } - | - | C1-Pair: not covered - | C2-Pair: not covered - | MC/DC Coverage for Decision: 0.00% - | - ------------------ - LL| 0| say("a and b"); - LL| 2| } else { - LL| 2| say("not both"); - LL| 2| } - LL| 2|} -"#; - - assert_eq!(anon(input), expected); -} From 4aafecb1693c30625c3f8d75f428edf3dad22755 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 29 May 2024 16:58:46 +0200 Subject: [PATCH 14/14] Simplify check for unsupported architectures --- tests/ui/abi/fixed_x18.arm.stderr | 2 -- tests/ui/abi/fixed_x18.i686.stderr | 2 -- tests/ui/abi/fixed_x18.riscv32.stderr | 2 -- tests/ui/abi/fixed_x18.riscv64.stderr | 2 -- tests/ui/abi/fixed_x18.rs | 2 ++ tests/ui/abi/fixed_x18.x64.stderr | 2 -- 6 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 tests/ui/abi/fixed_x18.arm.stderr delete mode 100644 tests/ui/abi/fixed_x18.i686.stderr delete mode 100644 tests/ui/abi/fixed_x18.riscv32.stderr delete mode 100644 tests/ui/abi/fixed_x18.riscv64.stderr delete mode 100644 tests/ui/abi/fixed_x18.x64.stderr diff --git a/tests/ui/abi/fixed_x18.arm.stderr b/tests/ui/abi/fixed_x18.arm.stderr deleted file mode 100644 index 68728dd9307a8..0000000000000 --- a/tests/ui/abi/fixed_x18.arm.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Zfixed-x18` flag is not supported on the `arm` architecture - diff --git a/tests/ui/abi/fixed_x18.i686.stderr b/tests/ui/abi/fixed_x18.i686.stderr deleted file mode 100644 index 458c0679f8439..0000000000000 --- a/tests/ui/abi/fixed_x18.i686.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Zfixed-x18` flag is not supported on the `x86` architecture - diff --git a/tests/ui/abi/fixed_x18.riscv32.stderr b/tests/ui/abi/fixed_x18.riscv32.stderr deleted file mode 100644 index e872fb4455b72..0000000000000 --- a/tests/ui/abi/fixed_x18.riscv32.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Zfixed-x18` flag is not supported on the `riscv32` architecture - diff --git a/tests/ui/abi/fixed_x18.riscv64.stderr b/tests/ui/abi/fixed_x18.riscv64.stderr deleted file mode 100644 index 7127e5d7056f7..0000000000000 --- a/tests/ui/abi/fixed_x18.riscv64.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Zfixed-x18` flag is not supported on the `riscv64` architecture - diff --git a/tests/ui/abi/fixed_x18.rs b/tests/ui/abi/fixed_x18.rs index 6d00cb2709da2..f1ff3e1d53418 100644 --- a/tests/ui/abi/fixed_x18.rs +++ b/tests/ui/abi/fixed_x18.rs @@ -2,6 +2,8 @@ // Behavior on aarch64 is tested by tests/codegen/fixed-x18.rs. // //@ revisions: x64 i686 arm riscv32 riscv64 +//@ error-pattern: the `-Zfixed-x18` flag is not supported +//@ dont-check-compiler-stderr // //@ compile-flags: -Zfixed-x18 //@ [x64] needs-llvm-components: x86 diff --git a/tests/ui/abi/fixed_x18.x64.stderr b/tests/ui/abi/fixed_x18.x64.stderr deleted file mode 100644 index 6dc367f9edce6..0000000000000 --- a/tests/ui/abi/fixed_x18.x64.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the `-Zfixed-x18` flag is not supported on the `x86_64` architecture -