From d199a63b1160f3eaab372aa969ab91248ee24315 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 25 Oct 2024 10:55:38 +0200 Subject: [PATCH 01/79] ABI compatibility: remove section on target features --- library/core/src/primitive_docs.rs | 32 ++++++------------------------ 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 95fa6c9c9507c..f28b65c6f2586 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1743,20 +1743,18 @@ mod prim_ref {} /// alignment, they might be passed in different registers and hence not be ABI-compatible. /// /// ABI compatibility as a concern only arises in code that alters the type of function pointers, -/// code that imports functions via `extern` blocks, and in code that combines `#[target_feature]` -/// with `extern fn`. Altering the type of function pointers is wildly unsafe (as in, a lot more -/// unsafe than even [`transmute_copy`][mem::transmute_copy]), and should only occur in the most -/// exceptional circumstances. Most Rust code just imports functions via `use`. `#[target_feature]` -/// is also used rarely. So, most likely you do not have to worry about ABI compatibility. +/// and code that imports functions via `extern` blocks. Altering the type of function pointers is +/// wildly unsafe (as in, a lot more unsafe than even [`transmute_copy`][mem::transmute_copy]), and +/// should only occur in the most exceptional circumstances. Most Rust code just imports functions +/// via `use`. So, most likely you do not have to worry about ABI compatibility. /// /// But assuming such circumstances, what are the rules? For this section, we are only considering /// the ABI of direct Rust-to-Rust calls, not linking in general -- once functions are imported via /// `extern` blocks, there are more things to consider that we do not go into here. /// /// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string, -/// must take the same number of arguments, the individual argument types and the return types must -/// be ABI-compatible, and the target feature requirements must be met (see the subsection below for -/// the last point). The ABI string is declared via `extern "ABI" fn(...) -> ...`; note that +/// must take the same number of arguments, and the individual argument types and the return types +/// must be ABI-compatible. The ABI string is declared via `extern "ABI" fn(...) -> ...`; note that /// `fn name(...) -> ...` implicitly uses the `"Rust"` ABI string and `extern fn name(...) -> ...` /// implicitly uses the `"C"` ABI string. /// @@ -1826,24 +1824,6 @@ mod prim_ref {} /// Behavior since transmuting `None::>` to `NonZero` violates the non-zero /// requirement. /// -/// #### Requirements concerning target features -/// -/// Under some conditions, the signature used by the caller and the callee can be ABI-incompatible -/// even if the exact same ABI string and types are being used. As an example, the -/// `std::arch::x86_64::__m256` type has a different `extern "C"` ABI when the `avx` feature is -/// enabled vs when it is not enabled. -/// -/// Therefore, to ensure ABI compatibility when code using different target features is combined -/// (such as via `#[target_feature]`), we further require that one of the following conditions is -/// met: -/// -/// - The function uses the `"Rust"` ABI string (which is the default without `extern`). -/// - Caller and callee are using the exact same set of target features. For the callee we consider -/// the features enabled (via `#[target_feature]` and `-C target-feature`/`-C target-cpu`) at the -/// declaration site; for the caller we consider the features enabled at the call site. -/// - Neither any argument nor the return value involves a SIMD type (`#[repr(simd)]`) that is not -/// behind a pointer indirection (i.e., `*mut __m256` is fine, but `(i32, __m256)` is not). -/// /// ### Trait implementations /// /// In this documentation the shorthand `fn(T₁, T₂, …, Tₙ)` is used to represent non-variadic From 9622a79378d90a65b6cfc51074c227928387081d Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Tue, 22 Oct 2024 19:54:20 +0200 Subject: [PATCH 02/79] Implement LLVM x86 vpclmulqdq intrinsics --- src/tools/miri/src/shims/x86/mod.rs | 94 +++++---- .../shims/x86/intrinsics-x86-vpclmulqdq.rs | 189 ++++++++++++++++++ 2 files changed, 245 insertions(+), 38 deletions(-) create mode 100644 src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 9339d301aeecd..e2b02873aefee 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -95,11 +95,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - "pclmulqdq" => { + "pclmulqdq" | "pclmulqdq.256" | "pclmulqdq.512" => { + let mut len = 2; // in units of 64bits + this.expect_target_feature_for_intrinsic(link_name, "pclmulqdq")?; + if unprefixed_name.ends_with(".256") { + this.expect_target_feature_for_intrinsic(link_name, "vpclmulqdq")?; + len = 4; + } else if unprefixed_name.ends_with(".512") { + this.expect_target_feature_for_intrinsic(link_name, "vpclmulqdq")?; + this.expect_target_feature_for_intrinsic(link_name, "avx512f")?; + len = 8; + } + let [left, right, imm] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - pclmulqdq(this, left, right, imm, dest)?; + pclmulqdq(this, left, right, imm, dest, len)?; } name if name.starts_with("bmi.") => { @@ -1134,9 +1145,12 @@ fn pmulhrsw<'tcx>( /// Perform a carry-less multiplication of two 64-bit integers, selected from `left` and `right` according to `imm8`, /// and store the results in `dst`. /// -/// `left` and `right` are both vectors of type 2 x i64. Only bits 0 and 4 of `imm8` matter; +/// `left` and `right` are both vectors of type `len` x i64. Only bits 0 and 4 of `imm8` matter; /// they select the element of `left` and `right`, respectively. /// +/// `len` is the SIMD vector length (in counts of `i64` values). It is expected to be one of +/// `2`, `4`, or `8`. +/// /// fn pclmulqdq<'tcx>( this: &mut MiriInterpCx<'tcx>, @@ -1144,51 +1158,55 @@ fn pclmulqdq<'tcx>( right: &OpTy<'tcx>, imm8: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, + len: u64, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, right.layout); assert_eq!(left.layout.size, dest.layout.size); + assert!([2u64, 4, 8].contains(&len)); - // Transmute to `[u64; 2]` + // Transmute the input into arrays of `[u64; len]`. + // Transmute the output into an array of `[u128, len / 2]`. - let array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?; - let left = left.transmute(array_layout, this)?; - let right = right.transmute(array_layout, this)?; - let dest = dest.transmute(array_layout, this)?; + let src_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, len))?; + let dest_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u128, len / 2))?; + + let left = left.transmute(src_layout, this)?; + let right = right.transmute(src_layout, this)?; + let dest = dest.transmute(dest_layout, this)?; let imm8 = this.read_scalar(imm8)?.to_u8()?; - // select the 64-bit integer from left that the user specified (low or high) - let index = if (imm8 & 0x01) == 0 { 0 } else { 1 }; - let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u64()?; - - // select the 64-bit integer from right that the user specified (low or high) - let index = if (imm8 & 0x10) == 0 { 0 } else { 1 }; - let right = this.read_scalar(&this.project_index(&right, index)?)?.to_u64()?; - - // Perform carry-less multiplication - // - // This operation is like long multiplication, but ignores all carries. - // That idea corresponds to the xor operator, which is used in the implementation. - // - // Wikipedia has an example https://en.wikipedia.org/wiki/Carry-less_product#Example - let mut result: u128 = 0; - - for i in 0..64 { - // if the i-th bit in right is set - if (right & (1 << i)) != 0 { - // xor result with `left` shifted to the left by i positions - result ^= u128::from(left) << i; + for i in 0..(len / 2) { + let lo = i.strict_mul(2); + let hi = i.strict_mul(2).strict_add(1); + + // select the 64-bit integer from left that the user specified (low or high) + let index = if (imm8 & 0x01) == 0 { lo } else { hi }; + let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u64()?; + + // select the 64-bit integer from right that the user specified (low or high) + let index = if (imm8 & 0x10) == 0 { lo } else { hi }; + let right = this.read_scalar(&this.project_index(&right, index)?)?.to_u64()?; + + // Perform carry-less multiplication. + // + // This operation is like long multiplication, but ignores all carries. + // That idea corresponds to the xor operator, which is used in the implementation. + // + // Wikipedia has an example https://en.wikipedia.org/wiki/Carry-less_product#Example + let mut result: u128 = 0; + + for i in 0..64 { + // if the i-th bit in right is set + if (right & (1 << i)) != 0 { + // xor result with `left` shifted to the left by i positions + result ^= u128::from(left) << i; + } } - } - - let result_low = (result & 0xFFFF_FFFF_FFFF_FFFF) as u64; - let result_high = (result >> 64) as u64; - - let dest_low = this.project_index(&dest, 0)?; - this.write_scalar(Scalar::from_u64(result_low), &dest_low)?; - let dest_high = this.project_index(&dest, 1)?; - this.write_scalar(Scalar::from_u64(result_high), &dest_high)?; + let dest = this.project_index(&dest, i)?; + this.write_scalar(Scalar::from_u128(result), &dest)?; + } interp_ok(()) } diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs new file mode 100644 index 0000000000000..084462260bfcd --- /dev/null +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs @@ -0,0 +1,189 @@ +// We're testing x86 target specific features +//@only-target: x86_64 i686 +//@compile-flags: -C target-feature=+vpclmulqdq,+avx512f + +// The constants in the tests below are just bit patterns. They should not +// be interpreted as integers; signedness does not make sense for them, but +// __mXXXi happens to be defined in terms of signed integers. +#![allow(overflowing_literals)] +#![feature(avx512_target_feature)] +#![feature(stdarch_x86_avx512)] + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; +use std::mem::transmute; + +fn main() { + // Mostly copied from library/stdarch/crates/core_arch/src/x86/vpclmulqdq.rs + + assert!(is_x86_feature_detected!("pclmulqdq")); + assert!(is_x86_feature_detected!("vpclmulqdq")); + assert!(is_x86_feature_detected!("avx512f")); + + unsafe { + test_mm256_clmulepi64_epi128(); + test_mm512_clmulepi64_epi128(); + } +} + +macro_rules! verify_kat_pclmul { + ($broadcast:ident, $clmul:ident, $assert:ident) => { + // Constants taken from https://software.intel.com/sites/default/files/managed/72/cc/clmul-wp-rev-2.02-2014-04-20.pdf + let a = _mm_set_epi64x(0x7b5b546573745665, 0x63746f725d53475d); + let a = $broadcast(a); + let b = _mm_set_epi64x(0x4869285368617929, 0x5b477565726f6e5d); + let b = $broadcast(b); + let r00 = _mm_set_epi64x(0x1d4d84c85c3440c0, 0x929633d5d36f0451); + let r00 = $broadcast(r00); + let r01 = _mm_set_epi64x(0x1bd17c8d556ab5a1, 0x7fa540ac2a281315); + let r01 = $broadcast(r01); + let r10 = _mm_set_epi64x(0x1a2bf6db3a30862f, 0xbabf262df4b7d5c9); + let r10 = $broadcast(r10); + let r11 = _mm_set_epi64x(0x1d1e1f2c592e7c45, 0xd66ee03e410fd4ed); + let r11 = $broadcast(r11); + + $assert($clmul::<0x00>(a, b), r00); + $assert($clmul::<0x10>(a, b), r01); + $assert($clmul::<0x01>(a, b), r10); + $assert($clmul::<0x11>(a, b), r11); + + let a0 = _mm_set_epi64x(0x0000000000000000, 0x8000000000000000); + let a0 = $broadcast(a0); + let r = _mm_set_epi64x(0x4000000000000000, 0x0000000000000000); + let r = $broadcast(r); + $assert($clmul::<0x00>(a0, a0), r); + } +} + +// this function tests one of the possible 4 instances +// with different inputs across lanes for the 512-bit version +#[target_feature(enable = "vpclmulqdq,avx512f")] +unsafe fn verify_512_helper( + linear: unsafe fn(__m128i, __m128i) -> __m128i, + vectorized: unsafe fn(__m512i, __m512i) -> __m512i, +) { + let a = _mm512_set_epi64( + 0xDCB4DB3657BF0B7D, + 0x18DB0601068EDD9F, + 0xB76B908233200DC5, + 0xE478235FA8E22D5E, + 0xAB05CFFA2621154C, + 0x1171B47A186174C9, + 0x8C6B6C0E7595CEC9, + 0xBE3E7D4934E961BD, + ); + let b = _mm512_set_epi64( + 0x672F6F105A94CEA7, + 0x8298B8FFCA5F829C, + 0xA3927047B3FB61D8, + 0x978093862CDE7187, + 0xB1927AB22F31D0EC, + 0xA9A5DA619BE4D7AF, + 0xCA2590F56884FDC6, + 0x19BE9F660038BDB5, + ); + + let a_decomp = transmute::<_, [__m128i; 4]>(a); + let b_decomp = transmute::<_, [__m128i; 4]>(b); + + let r = vectorized(a, b); + + let e_decomp = [ + linear(a_decomp[0], b_decomp[0]), + linear(a_decomp[1], b_decomp[1]), + linear(a_decomp[2], b_decomp[2]), + linear(a_decomp[3], b_decomp[3]), + ]; + let e = transmute::<_, __m512i>(e_decomp); + + assert_eq_m512i(r, e) +} + +// this function tests one of the possible 4 instances +// with different inputs across lanes for the 256-bit version +#[target_feature(enable = "vpclmulqdq")] +unsafe fn verify_256_helper( + linear: unsafe fn(__m128i, __m128i) -> __m128i, + vectorized: unsafe fn(__m256i, __m256i) -> __m256i, +) { + let a = _mm256_set_epi64x( + 0xDCB4DB3657BF0B7D, + 0x18DB0601068EDD9F, + 0xB76B908233200DC5, + 0xE478235FA8E22D5E, + ); + let b = _mm256_set_epi64x( + 0x672F6F105A94CEA7, + 0x8298B8FFCA5F829C, + 0xA3927047B3FB61D8, + 0x978093862CDE7187, + ); + + let a_decomp = transmute::<_, [__m128i; 2]>(a); + let b_decomp = transmute::<_, [__m128i; 2]>(b); + + let r = vectorized(a, b); + + let e_decomp = [linear(a_decomp[0], b_decomp[0]), linear(a_decomp[1], b_decomp[1])]; + let e = transmute::<_, __m256i>(e_decomp); + + assert_eq_m256i(r, e) +} + +#[target_feature(enable = "vpclmulqdq,avx512f")] +unsafe fn test_mm512_clmulepi64_epi128() { + verify_kat_pclmul!(_mm512_broadcast_i32x4, _mm512_clmulepi64_epi128, assert_eq_m512i); + + verify_512_helper( + |a, b| _mm_clmulepi64_si128::<0x00>(a, b), + |a, b| _mm512_clmulepi64_epi128::<0x00>(a, b), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128::<0x01>(a, b), + |a, b| _mm512_clmulepi64_epi128::<0x01>(a, b), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128::<0x10>(a, b), + |a, b| _mm512_clmulepi64_epi128::<0x10>(a, b), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128::<0x11>(a, b), + |a, b| _mm512_clmulepi64_epi128::<0x11>(a, b), + ); +} + +#[target_feature(enable = "vpclmulqdq")] +unsafe fn test_mm256_clmulepi64_epi128() { + verify_kat_pclmul!(_mm256_broadcastsi128_si256, _mm256_clmulepi64_epi128, assert_eq_m256i); + + verify_256_helper( + |a, b| _mm_clmulepi64_si128::<0x00>(a, b), + |a, b| _mm256_clmulepi64_epi128::<0x00>(a, b), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128::<0x01>(a, b), + |a, b| _mm256_clmulepi64_epi128::<0x01>(a, b), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128::<0x10>(a, b), + |a, b| _mm256_clmulepi64_epi128::<0x10>(a, b), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128::<0x11>(a, b), + |a, b| _mm256_clmulepi64_epi128::<0x11>(a, b), + ); +} + +#[track_caller] +#[target_feature(enable = "avx512f")] +unsafe fn assert_eq_m512i(a: __m512i, b: __m512i) { + assert_eq!(transmute::<_, [u64; 8]>(a), transmute::<_, [u64; 8]>(b)) +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) { + assert_eq!(transmute::<_, [u64; 4]>(a), transmute::<_, [u64; 4]>(b)) +} From 05530b6e109f01b23b6515b3940d008791bbeee0 Mon Sep 17 00:00:00 2001 From: Tobias Decking Date: Sat, 26 Oct 2024 13:58:59 +0200 Subject: [PATCH 03/79] Adjust the vpclmulqdq test case --- .../tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs index 084462260bfcd..68964728e4ea4 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs @@ -1,6 +1,8 @@ // We're testing x86 target specific features +//@revisions: avx512 avx //@only-target: x86_64 i686 -//@compile-flags: -C target-feature=+vpclmulqdq,+avx512f +//@[avx512]compile-flags: -C target-feature=+vpclmulqdq,+avx512f +//@[avx]compile-flags: -C target-feature=+vpclmulqdq,+avx2 // The constants in the tests below are just bit patterns. They should not // be interpreted as integers; signedness does not make sense for them, but @@ -20,11 +22,13 @@ fn main() { assert!(is_x86_feature_detected!("pclmulqdq")); assert!(is_x86_feature_detected!("vpclmulqdq")); - assert!(is_x86_feature_detected!("avx512f")); unsafe { test_mm256_clmulepi64_epi128(); - test_mm512_clmulepi64_epi128(); + + if is_x86_feature_detected!("avx512f") { + test_mm512_clmulepi64_epi128(); + } } } From cdc40a40e8b2f9e563b88568778bac7e22ec5599 Mon Sep 17 00:00:00 2001 From: Konstantin Andrikopoulos Date: Wed, 9 Oct 2024 02:02:42 +0200 Subject: [PATCH 04/79] Add option for generating coverage reports Add a `--coverage` option in the `test` subcommand of the miri script. This option, when set, will generate a coverage report after running the tests. `cargo-binutils` is needed as a dependency to generate the reports. --- src/tools/miri/.github/workflows/ci.yml | 13 +++- src/tools/miri/miri-script/Cargo.lock | 43 +++++++++- src/tools/miri/miri-script/Cargo.toml | 1 + src/tools/miri/miri-script/src/commands.rs | 21 ++++- src/tools/miri/miri-script/src/coverage.rs | 91 ++++++++++++++++++++++ src/tools/miri/miri-script/src/main.rs | 8 +- src/tools/miri/miri-script/src/util.rs | 7 +- 7 files changed, 173 insertions(+), 11 deletions(-) create mode 100644 src/tools/miri/miri-script/src/coverage.rs diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 2e49131982297..209fd622202e2 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -58,11 +58,20 @@ jobs: - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" ./miri doc --document-private-items + coverage: + name: coverage report + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/workflows/setup + - name: coverage + run: ./miri test --coverage + # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! # And they should be added below in `cron-fail-notify` as well. conclusion: - needs: [build, style] + needs: [build, style, coverage] # We need to ensure this job does *not* get skipped if its dependencies fail, # because a skipped job is considered a success by GitHub. So we have to # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run @@ -86,7 +95,7 @@ jobs: contents: write # ... and create a PR. pull-requests: write - needs: [build, style] + needs: [build, style, coverage] if: ${{ github.event_name == 'schedule' && failure() }} steps: # Send a Zulip notification diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index 146e613c24b36..8dad30df6d1e6 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -63,6 +63,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + [[package]] name = "getrandom" version = "0.2.12" @@ -100,9 +106,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libredox" @@ -138,11 +144,18 @@ dependencies = [ "rustc_version", "serde_json", "shell-words", + "tempfile", "walkdir", "which", "xshell", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + [[package]] name = "option-ext" version = "0.2.0" @@ -195,9 +208,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags", "errno", @@ -276,6 +289,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "thiserror" version = "1.0.57" @@ -357,6 +383,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index 23b9a62515920..5b31d5a6ff97b 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -24,3 +24,4 @@ rustc_version = "0.4" dunce = "1.0.4" directories = "5" serde_json = "1" +tempfile = "3.13.0" diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 36175c8dd2bd2..21029d0b5b3db 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -172,7 +172,8 @@ impl Command { Command::Install { flags } => Self::install(flags), Command::Build { flags } => Self::build(flags), Command::Check { flags } => Self::check(flags), - Command::Test { bless, flags, target } => Self::test(bless, flags, target), + Command::Test { bless, flags, target, coverage } => + Self::test(bless, flags, target, coverage), Command::Run { dep, verbose, many_seeds, target, edition, flags } => Self::run(dep, verbose, many_seeds, target, edition, flags), Command::Doc { flags } => Self::doc(flags), @@ -458,9 +459,20 @@ impl Command { Ok(()) } - fn test(bless: bool, mut flags: Vec, target: Option) -> Result<()> { + fn test( + bless: bool, + mut flags: Vec, + target: Option, + coverage: bool, + ) -> Result<()> { let mut e = MiriEnv::new()?; + let coverage = coverage.then_some(crate::coverage::CoverageReport::new()?); + + if let Some(report) = &coverage { + report.add_env_vars(&mut e)?; + } + // Prepare a sysroot. (Also builds cargo-miri, which we need.) e.build_miri_sysroot(/* quiet */ false, target.as_deref())?; @@ -479,6 +491,11 @@ impl Command { // Then test, and let caller control flags. // Only in root project as `cargo-miri` has no tests. e.test(".", &flags)?; + + if let Some(coverage) = &coverage { + coverage.show_coverage_report(&e)?; + } + Ok(()) } diff --git a/src/tools/miri/miri-script/src/coverage.rs b/src/tools/miri/miri-script/src/coverage.rs new file mode 100644 index 0000000000000..8cafcea0d16f3 --- /dev/null +++ b/src/tools/miri/miri-script/src/coverage.rs @@ -0,0 +1,91 @@ +use std::path::PathBuf; + +use anyhow::{Context, Result}; +use path_macro::path; +use tempfile::TempDir; +use xshell::cmd; + +use crate::util::MiriEnv; + +/// CoverageReport can generate code coverage reports for miri. +pub struct CoverageReport { + /// path is a temporary directory where intermediate coverage artifacts will be stored. + /// (The final output will be stored in a permanent location.) + path: TempDir, +} + +impl CoverageReport { + /// Creates a new CoverageReport. + /// + /// # Errors + /// + /// An error will be returned if a temporary directory could not be created. + pub fn new() -> Result { + Ok(Self { path: TempDir::new()? }) + } + + /// add_env_vars will add the required environment variables to MiriEnv `e`. + pub fn add_env_vars(&self, e: &mut MiriEnv) -> Result<()> { + let mut rustflags = e.sh.var("RUSTFLAGS")?; + rustflags.push_str(" -C instrument-coverage"); + e.sh.set_var("RUSTFLAGS", rustflags); + + // Copy-pasting from: https://doc.rust-lang.org/rustc/instrument-coverage.html#instrumentation-based-code-coverage + // The format symbols below have the following meaning: + // - %p - The process ID. + // - %Nm - the instrumented binary’s signature: + // The runtime creates a pool of N raw profiles, used for on-line + // profile merging. The runtime takes care of selecting a raw profile + // from the pool, locking it, and updating it before the program + // exits. N must be between 1 and 9, and defaults to 1 if omitted + // (with simply %m). + // + // Additionally the default for LLVM_PROFILE_FILE is default_%m_%p.profraw. + // So we just use the same template, replacing "default" with "miri". + let file_template = self.path.path().join("miri_%m_%p.profraw"); + e.sh.set_var("LLVM_PROFILE_FILE", file_template); + Ok(()) + } + + /// show_coverage_report will print coverage information using the artifact + /// files in `self.path`. + pub fn show_coverage_report(&self, e: &MiriEnv) -> Result<()> { + let profraw_files = self.profraw_files()?; + + let profdata_bin = path!(e.libdir / ".." / "bin" / "llvm-profdata"); + + let merged_file = path!(e.miri_dir / "target" / "coverage.profdata"); + + // Merge the profraw files + cmd!(e.sh, "{profdata_bin} merge -sparse {profraw_files...} -o {merged_file}") + .quiet() + .run()?; + + // Create the coverage report. + let cov_bin = path!(e.libdir / ".." / "bin" / "llvm-cov"); + let miri_bin = + e.build_get_binary(".").context("failed to get filename of miri executable")?; + cmd!( + e.sh, + "{cov_bin} report --instr-profile={merged_file} --object {miri_bin} --sources src/" + ) + .run()?; + + println!("Profile data saved in {}", merged_file.display()); + Ok(()) + } + + /// profraw_files returns the profraw files in `self.path`. + /// + /// # Errors + /// + /// An error will be returned if `self.path` can't be read. + fn profraw_files(&self) -> Result> { + Ok(std::fs::read_dir(&self.path)? + .filter_map(|r| r.ok()) + .filter(|e| e.file_type().is_ok_and(|t| t.is_file())) + .map(|e| e.path()) + .filter(|p| p.extension().is_some_and(|e| e == "profraw")) + .collect()) + } +} diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index 0620f3aaf0993..a329f62790338 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -2,6 +2,7 @@ mod args; mod commands; +mod coverage; mod util; use std::ops::Range; @@ -34,6 +35,8 @@ pub enum Command { /// The cross-interpretation target. /// If none then the host is the target. target: Option, + /// Produce coverage report if set. + coverage: bool, /// Flags that are passed through to the test harness. flags: Vec, }, @@ -158,9 +161,12 @@ fn main() -> Result<()> { let mut target = None; let mut bless = false; let mut flags = Vec::new(); + let mut coverage = false; loop { if args.get_long_flag("bless")? { bless = true; + } else if args.get_long_flag("coverage")? { + coverage = true; } else if let Some(val) = args.get_long_opt("target")? { target = Some(val); } else if let Some(flag) = args.get_other() { @@ -169,7 +175,7 @@ fn main() -> Result<()> { break; } } - Command::Test { bless, flags, target } + Command::Test { bless, flags, target, coverage } } Some("run") => { let mut dep = false; diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs index f5a6a8188a0dc..e6e85747d4d5f 100644 --- a/src/tools/miri/miri-script/src/util.rs +++ b/src/tools/miri/miri-script/src/util.rs @@ -41,6 +41,8 @@ pub struct MiriEnv { pub sysroot: PathBuf, /// The shell we use. pub sh: Shell, + /// The library dir in the sysroot. + pub libdir: PathBuf, } impl MiriEnv { @@ -96,7 +98,8 @@ impl MiriEnv { // so that Windows can find the DLLs. if cfg!(windows) { let old_path = sh.var("PATH")?; - let new_path = env::join_paths(iter::once(libdir).chain(env::split_paths(&old_path)))?; + let new_path = + env::join_paths(iter::once(libdir.clone()).chain(env::split_paths(&old_path)))?; sh.set_var("PATH", new_path); } @@ -111,7 +114,7 @@ impl MiriEnv { std::process::exit(1); } - Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags }) + Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags, libdir }) } pub fn cargo_cmd(&self, crate_dir: impl AsRef, cmd: &str) -> Cmd<'_> { From c8ce9e68d4cdae32b8a0859e4e381356452d2dc2 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Fri, 25 Oct 2024 18:34:00 +0300 Subject: [PATCH 05/79] Android: Added syscall support --- src/tools/miri/ci/ci.sh | 2 +- .../src/shims/unix/android/foreign_items.rs | 4 ++ .../src/shims/unix/linux/foreign_items.rs | 51 +-------------- src/tools/miri/src/shims/unix/linux/mod.rs | 1 + .../miri/src/shims/unix/linux/syscall.rs | 63 +++++++++++++++++++ .../tests/pass-dep/concurrency/linux-futex.rs | 1 + .../miri/tests/pass-dep/libc/libc-random.rs | 41 ++++++------ 7 files changed, 93 insertions(+), 70 deletions(-) create mode 100644 src/tools/miri/src/shims/unix/linux/syscall.rs diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 4e7cbc50ca03b..0356d7ecf1015 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -154,7 +154,7 @@ case $HOST_TARGET in TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap threadname pthread + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync threadname pthread TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index b6f04951fc7e7..2e10e82d936f3 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -2,6 +2,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::shims::unix::android::thread::prctl; +use crate::shims::unix::linux::syscall::syscall; use crate::*; pub fn is_dyn_sym(_name: &str) -> bool { @@ -26,6 +27,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } + // Dynamically invoked syscalls + "syscall" => syscall(this, link_name, abi, args, dest)?, + // Threading "prctl" => prctl(this, link_name, abi, args, dest)?, diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 6616a9845c09b..a126d5b4fabd7 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -4,8 +4,7 @@ use rustc_target::spec::abi::Abi; use self::shims::unix::linux::epoll::EvalContextExt as _; use self::shims::unix::linux::eventfd::EvalContextExt as _; use self::shims::unix::linux::mem::EvalContextExt as _; -use self::shims::unix::linux::sync::futex; -use crate::helpers::check_min_arg_count; +use self::shims::unix::linux::syscall::syscall; use crate::machine::{SIGRTMAX, SIGRTMIN}; use crate::shims::unix::*; use crate::*; @@ -117,53 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Dynamically invoked syscalls "syscall" => { - // We do not use `check_shim` here because `syscall` is variadic. The argument - // count is checked bellow. - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; - // The syscall variadic function is legal to call with more arguments than needed, - // extra arguments are simply ignored. The important check is that when we use an - // argument, we have to also check all arguments *before* it to ensure that they - // have the right type. - - let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?; - let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?; - let sys_eventfd2 = this.eval_libc("SYS_eventfd2").to_target_usize(this)?; - - let [op] = check_min_arg_count("syscall", args)?; - match this.read_target_usize(op)? { - // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way (e.g. HashMap). - num if num == sys_getrandom => { - // Used by getrandom 0.1 - // The first argument is the syscall id, so skip over it. - let [_, ptr, len, flags] = - check_min_arg_count("syscall(SYS_getrandom, ...)", args)?; - - let ptr = this.read_pointer(ptr)?; - let len = this.read_target_usize(len)?; - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG. - // See for a discussion of argument sizes. - let _flags = this.read_scalar(flags)?.to_i32()?; - - this.gen_random(ptr, len)?; - this.write_scalar(Scalar::from_target_usize(len, this), dest)?; - } - // `futex` is used by some synchronization primitives. - num if num == sys_futex => { - futex(this, args, dest)?; - } - num if num == sys_eventfd2 => { - let [_, initval, flags] = - check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?; - - let result = this.eventfd(initval, flags)?; - this.write_int(result.to_i32()?, dest)?; - } - num => { - throw_unsup_format!("syscall: unsupported syscall number {num}"); - } - } + syscall(this, link_name, abi, args, dest)?; } // Miscellaneous diff --git a/src/tools/miri/src/shims/unix/linux/mod.rs b/src/tools/miri/src/shims/unix/linux/mod.rs index 84b604eb9b82e..159e5aca03105 100644 --- a/src/tools/miri/src/shims/unix/linux/mod.rs +++ b/src/tools/miri/src/shims/unix/linux/mod.rs @@ -3,3 +3,4 @@ pub mod eventfd; pub mod foreign_items; pub mod mem; pub mod sync; +pub mod syscall; diff --git a/src/tools/miri/src/shims/unix/linux/syscall.rs b/src/tools/miri/src/shims/unix/linux/syscall.rs new file mode 100644 index 0000000000000..72e02447d8049 --- /dev/null +++ b/src/tools/miri/src/shims/unix/linux/syscall.rs @@ -0,0 +1,63 @@ +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use self::shims::unix::linux::eventfd::EvalContextExt as _; +use crate::helpers::check_min_arg_count; +use crate::shims::unix::linux::sync::futex; +use crate::*; + +pub fn syscall<'tcx>( + this: &mut MiriInterpCx<'tcx>, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx> { + // We do not use `check_shim` here because `syscall` is variadic. The argument + // count is checked bellow. + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + // The syscall variadic function is legal to call with more arguments than needed, + // extra arguments are simply ignored. The important check is that when we use an + // argument, we have to also check all arguments *before* it to ensure that they + // have the right type. + + let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?; + let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?; + let sys_eventfd2 = this.eval_libc("SYS_eventfd2").to_target_usize(this)?; + + let [op] = check_min_arg_count("syscall", args)?; + match this.read_target_usize(op)? { + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` + // is called if a `HashMap` is created the regular way (e.g. HashMap). + num if num == sys_getrandom => { + // Used by getrandom 0.1 + // The first argument is the syscall id, so skip over it. + let [_, ptr, len, flags] = check_min_arg_count("syscall(SYS_getrandom, ...)", args)?; + + let ptr = this.read_pointer(ptr)?; + let len = this.read_target_usize(len)?; + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG. + // See for a discussion of argument sizes. + let _flags = this.read_scalar(flags)?.to_i32()?; + + this.gen_random(ptr, len)?; + this.write_scalar(Scalar::from_target_usize(len, this), dest)?; + } + // `futex` is used by some synchronization primitives. + num if num == sys_futex => { + futex(this, args, dest)?; + } + num if num == sys_eventfd2 => { + let [_, initval, flags] = check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?; + + let result = this.eventfd(initval, flags)?; + this.write_int(result.to_i32()?, dest)?; + } + num => { + throw_unsup_format!("syscall: unsupported syscall number {num}"); + } + }; + + interp_ok(()) +} diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs index 20e642a0a2952..2a36c10f7d4d7 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs @@ -1,4 +1,5 @@ //@only-target: linux +//@only-target: android //@compile-flags: -Zmiri-disable-isolation // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint diff --git a/src/tools/miri/tests/pass-dep/libc/libc-random.rs b/src/tools/miri/tests/pass-dep/libc/libc-random.rs index 8f4398cbd8fe1..7c4010f6c0ac6 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-random.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-random.rs @@ -28,26 +28,27 @@ fn test_getrandom() { let mut buf = [0u8; 5]; unsafe { - #[cfg(target_os = "linux")] - assert_eq!( - libc::syscall( - libc::SYS_getrandom, - ptr::null_mut::(), - 0 as libc::size_t, - 0 as libc::c_uint, - ), - 0, - ); - #[cfg(target_os = "linux")] - assert_eq!( - libc::syscall( - libc::SYS_getrandom, - buf.as_mut_ptr() as *mut libc::c_void, - 5 as libc::size_t, - 0 as libc::c_uint, - ), - 5, - ); + #[cfg(any(target_os = "linux", target_os = "android"))] + { + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + ptr::null_mut::(), + 0 as libc::size_t, + 0 as libc::c_uint, + ), + 0, + ); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint, + ), + 5, + ); + } assert_eq!( libc::getrandom(ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint), From 6365ea10f4176e8fd90b8e32a6b749a7878e2a38 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Oct 2024 21:48:56 +0100 Subject: [PATCH 06/79] contributing guide: mention expectations around force pushes and squashing --- src/tools/miri/CONTRIBUTING.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index d0bcf68eacb19..e97f4bf86d834 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -13,6 +13,25 @@ for a list of Miri maintainers. [Rust Zulip]: https://rust-lang.zulipchat.com +### Pull review process + +When you get a review, please take care of the requested changes in new commits. Do not amend +existing commits. Generally avoid force-pushing. The only time you should force push is when there +is a conflict with the master branch (in that case you should rebase across master, not merge), and +all the way at the end of the review process when the reviewer tells you that the PR is done and you +should squash the commits. For the latter case, use `git rebase --keep-base ...` to squash without +changing the base commit your PR branches off of. Use your own judgment and the reviewer's guidance +to decide whether the PR should be squashed into a single commit or multiple logically separate +commits. (All this is to work around the fact that Github is quite bad at dealing with force pushes +and does not support `git range-diff`. Maybe one day Github will be good at git and then life can +become easier.) + +Most PRs bounce back and forth between the reviewer and the author several times, so it is good to +keep track of who is expected to take the next step. We are using the `S-waiting-for-review` and +`S-waiting-for-author` labels for that. If a reviewer asked you to do some changes and you think +they are all taken care of, post a comment saying `@rustbot ready` to mark a PR as ready for the +next round of review. + ### Larger-scale contributions If you are thinking about making a larger-scale contribution -- in particular anything that needs @@ -45,14 +64,6 @@ process for such contributions: This process is largely informal, and its primary goal is to more clearly communicate expectations. Please get in touch with us if you have any questions! -### Managing the review state - -Most PRs bounce back and forth between the reviewer and the author several times, so it is good to -keep track of who is expected to take the next step. We are using the `S-waiting-for-review` and -`S-waiting-for-author` labels for that. If a reviewer asked you to do some changes and you think -they are all taken care of, post a comment saying `@rustbot ready` to mark a PR as ready for the -next round of review. - ## Preparing the build environment Miri heavily relies on internal and unstable rustc interfaces to execute MIR, From 1990f1560801ca3f9e6a3286e58204aa329ee037 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 30 Oct 2024 01:10:33 +0000 Subject: [PATCH 07/79] Reject raw lifetime followed by \' as well --- compiler/rustc_lexer/src/lib.rs | 12 +++++++++++- .../ui/lifetimes/raw/immediately-followed-by-lt.rs | 14 ++++++++++++++ .../raw/immediately-followed-by-lt.stderr | 13 +++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lifetimes/raw/immediately-followed-by-lt.rs create mode 100644 tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index b0ab50dd77388..f9f2a14dbd275 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -715,7 +715,17 @@ impl Cursor<'_> { self.bump(); self.bump(); self.eat_while(is_id_continue); - return RawLifetime; + match self.first() { + '\'' => { + // Check if after skipping literal contents we've met a closing + // single quote (which means that user attempted to create a + // string with single quotes). + self.bump(); + let kind = Char { terminated: true }; + return Literal { kind, suffix_start: self.pos_within_token() }; + } + _ => return RawLifetime, + } } // Either a lifetime or a character literal with diff --git a/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs b/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs new file mode 100644 index 0000000000000..fe2b6de7bb3e2 --- /dev/null +++ b/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 + +// Make sure we reject the case where a raw lifetime is immediately followed by another +// lifetime. This reserves a modest amount of space for changing lexing to, for example, +// delay rejection of overlong char literals like `'r#long'id`. + +macro_rules! w { + ($($tt:tt)*) => {} +} + +w!('r#long'id); +//~^ ERROR character literal may only contain one codepoint + +fn main() {} diff --git a/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr b/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr new file mode 100644 index 0000000000000..1caeec84b22c9 --- /dev/null +++ b/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr @@ -0,0 +1,13 @@ +error: character literal may only contain one codepoint + --> $DIR/immediately-followed-by-lt.rs:11:4 + | +LL | w!('r#long'id); + | ^^^^^^^^ + | +help: if you meant to write a string literal, use double quotes + | +LL | w!("r#long"id); + | ~ ~ + +error: aborting due to 1 previous error + From ff6e703bf14ed6f071aa01fd2231340c08d1312d Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 30 Oct 2024 05:05:05 +0000 Subject: [PATCH 08/79] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 133edd3191d5b..0e3537b185fc2 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -814df6e50eaf89b90793e7d9618bb60f1f18377a +16422dbd8958179379214e8f43fdb73a06b2eada From 9785c7cf94f5e30742f886764f2d25b6a4da66e8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 30 Oct 2024 14:45:17 +0000 Subject: [PATCH 09/79] Enforce that raw lifetime identifiers must be valid raw identifiers --- compiler/rustc_parse/messages.ftl | 2 ++ compiler/rustc_parse/src/errors.rs | 8 +++++ compiler/rustc_parse/src/lexer/mod.rs | 14 +++++--- .../ui/lifetimes/raw/raw-lt-invalid-raw-id.rs | 20 ++++++++++++ .../raw/raw-lt-invalid-raw-id.stderr | 32 +++++++++++++++++++ 5 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs create mode 100644 tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1af7fb9b86a7c..ef259703f0cf5 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -77,6 +77,8 @@ parse_box_syntax_removed_suggestion = use `Box::new()` instead parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier +parse_cannot_be_raw_lifetime = `{$ident}` cannot be a raw lifetime + parse_catch_after_try = keyword `catch` cannot follow a `try` block .help = try using `match` on the result of the `try` block instead diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index fdd500e90f807..7ec4ad6dc359f 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2018,6 +2018,14 @@ pub(crate) struct CannotBeRawIdent { pub ident: Symbol, } +#[derive(Diagnostic)] +#[diag(parse_cannot_be_raw_lifetime)] +pub(crate) struct CannotBeRawLifetime { + #[primary_span] + pub span: Span, + pub ident: Symbol, +} + #[derive(Diagnostic)] #[diag(parse_keyword_lifetime)] pub(crate) struct KeywordLifetime { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d627ef3d2cbe3..226de65445c8a 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -294,15 +294,21 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let prefix_span = self.mk_sp(start, ident_start); if prefix_span.at_least_rust_2021() { - let lifetime_name_without_tick = self.str_from(ident_start); + let span = self.mk_sp(start, self.pos); + + let lifetime_name_without_tick = Symbol::intern(&self.str_from(ident_start)); + if !lifetime_name_without_tick.can_be_raw() { + self.dcx().emit_err(errors::CannotBeRawLifetime { span, ident: lifetime_name_without_tick }); + } + // Put the `'` back onto the lifetime name. - let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.len() + 1); + let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.as_str().len() + 1); lifetime_name.push('\''); - lifetime_name += lifetime_name_without_tick; + lifetime_name += lifetime_name_without_tick.as_str(); let sym = Symbol::intern(&lifetime_name); // Make sure we mark this as a raw identifier. - self.psess.raw_identifier_spans.push(self.mk_sp(start, self.pos)); + self.psess.raw_identifier_spans.push(span); token::Lifetime(sym, IdentIsRaw::Yes) } else { diff --git a/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs new file mode 100644 index 0000000000000..882fad925f371 --- /dev/null +++ b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs @@ -0,0 +1,20 @@ +//@ edition: 2021 + +// Reject raw lifetimes with identifier parts that wouldn't be valid raw identifiers. + +macro_rules! w { + ($tt:tt) => {}; +} + +w!('r#_); +//~^ ERROR `_` cannot be a raw lifetime +w!('r#self); +//~^ ERROR `self` cannot be a raw lifetime +w!('r#super); +//~^ ERROR `super` cannot be a raw lifetime +w!('r#Self); +//~^ ERROR `Self` cannot be a raw lifetime +w!('r#crate); +//~^ ERROR `crate` cannot be a raw lifetime + +fn main() {} diff --git a/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr new file mode 100644 index 0000000000000..4cbb89b7a558b --- /dev/null +++ b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr @@ -0,0 +1,32 @@ +error: `_` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:9:4 + | +LL | w!('r#_); + | ^^^^ + +error: `self` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:11:4 + | +LL | w!('r#self); + | ^^^^^^^ + +error: `super` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:13:4 + | +LL | w!('r#super); + | ^^^^^^^^ + +error: `Self` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:15:4 + | +LL | w!('r#Self); + | ^^^^^^^ + +error: `crate` cannot be a raw lifetime + --> $DIR/raw-lt-invalid-raw-id.rs:17:4 + | +LL | w!('r#crate); + | ^^^^^^^^ + +error: aborting due to 5 previous errors + From 488d5b0d8e3dd25321615ae702689348574cc77f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 24 Sep 2024 11:01:51 -0700 Subject: [PATCH 10/79] rustdoc-search: add type param names to index --- src/librustdoc/html/render/mod.rs | 1 + src/librustdoc/html/render/search_index.rs | 45 ++++++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8446235fb1881..a17c7626148ab 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -204,6 +204,7 @@ pub(crate) struct IndexItemFunctionType { inputs: Vec, output: Vec, where_clause: Vec>, + param_names: Vec, } impl IndexItemFunctionType { diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index d1939adc1a501..ee2fc1f44b345 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -646,9 +646,25 @@ pub(crate) fn build_index<'tcx>( full_paths.push((*index, path)); } + let param_names: Vec<(usize, String)> = { + let mut prev = Vec::new(); + let mut result = Vec::new(); + for (index, item) in self.items.iter().enumerate() { + if let Some(ty) = &item.search_type + && let my = + ty.param_names.iter().map(|sym| sym.as_str()).collect::>() + && my != prev + { + result.push((index, my.join(","))); + prev = my; + } + } + result + }; + let has_aliases = !self.aliases.is_empty(); let mut crate_data = - serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?; + serializer.serialize_struct("CrateData", if has_aliases { 13 } else { 12 })?; crate_data.serialize_field("t", &types)?; crate_data.serialize_field("n", &names)?; crate_data.serialize_field("q", &full_paths)?; @@ -660,6 +676,7 @@ pub(crate) fn build_index<'tcx>( crate_data.serialize_field("b", &self.associated_item_disambiguators)?; crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?; crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?; + crate_data.serialize_field("P", ¶m_names)?; if has_aliases { crate_data.serialize_field("a", &self.aliases)?; } @@ -758,7 +775,7 @@ pub(crate) fn get_function_type_for_search<'tcx>( None } }); - let (mut inputs, mut output, where_clause) = match item.kind { + let (mut inputs, mut output, param_names, where_clause) = match item.kind { clean::ForeignFunctionItem(ref f, _) | clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) @@ -771,7 +788,7 @@ pub(crate) fn get_function_type_for_search<'tcx>( inputs.retain(|a| a.id.is_some() || a.generics.is_some()); output.retain(|a| a.id.is_some() || a.generics.is_some()); - Some(IndexItemFunctionType { inputs, output, where_clause }) + Some(IndexItemFunctionType { inputs, output, where_clause, param_names }) } fn get_index_type( @@ -1285,7 +1302,7 @@ fn get_fn_inputs_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>, cache: &Cache, -) -> (Vec, Vec, Vec>) { +) -> (Vec, Vec, Vec, Vec>) { let decl = &func.decl; let mut rgen: FxIndexMap)> = Default::default(); @@ -1331,7 +1348,21 @@ fn get_fn_inputs_and_outputs<'tcx>( let mut ret_types = Vec::new(); simplify_fn_type(self_, generics, &decl.output, tcx, 0, &mut ret_types, &mut rgen, true, cache); - let mut simplified_params = rgen.into_values().collect::>(); - simplified_params.sort_by_key(|(idx, _)| -idx); - (arg_types, ret_types, simplified_params.into_iter().map(|(_idx, traits)| traits).collect()) + let mut simplified_params = rgen.into_iter().collect::>(); + simplified_params.sort_by_key(|(_, (idx, _))| -idx); + ( + arg_types, + ret_types, + simplified_params + .iter() + .map(|(name, (_idx, _traits))| match name { + SimplifiedParam::Symbol(name) => *name, + SimplifiedParam::Anonymous(_) => kw::Empty, + SimplifiedParam::AssociatedType(def_id, name) => { + Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name)) + } + }) + .collect(), + simplified_params.into_iter().map(|(_name, (_idx, traits))| traits).collect(), + ) } From 2cc1c0c39a481be5a4498dbee4f89a479dabd9c9 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 24 Sep 2024 11:04:04 -0700 Subject: [PATCH 11/79] rustdoc-search: simplify the checkTypes fast path This reduces code size while still matching the common case for plain, concrete types. --- src/librustdoc/html/static/js/search.js | 37 ++++++++----------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index eed64d024c046..995c2e041941c 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2727,33 +2727,18 @@ class DocSearch { if (unboxingDepth >= UNBOXING_LIMIT) { return false; } - if (row.bindings.size === 0 && elem.bindings.size === 0) { - if (elem.id < 0 && mgens === null) { - return row.id < 0 || checkIfInList( - row.generics, - elem, - whereClause, - mgens, - unboxingDepth + 1, - ); - } - if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 && - typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 && - // special case - elem.id !== this.typeNameIdOfArrayOrSlice - && elem.id !== this.typeNameIdOfTupleOrUnit - && elem.id !== this.typeNameIdOfHof - ) { - return row.id === elem.id || checkIfInList( - row.generics, - elem, - whereClause, - mgens, - unboxingDepth, - ); - } + if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 && + row.generics.length === 0 && elem.generics.length === 0 && + row.bindings.size === 0 && elem.bindings.size === 0 && + // special case + elem.id !== this.typeNameIdOfArrayOrSlice && + elem.id !== this.typeNameIdOfHof && + elem.id !== this.typeNameIdOfTupleOrUnit + ) { + return row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty); + } else { + return unifyFunctionTypes([row], [elem], whereClause, mgens, null, unboxingDepth); } - return unifyFunctionTypes([row], [elem], whereClause, mgens, null, unboxingDepth); }; /** From 5c7e7dfe10acde559ad78a700dfefbfaf0ed8772 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 24 Sep 2024 12:33:09 -0700 Subject: [PATCH 12/79] rustdoc-search: pass original names through AST --- src/librustdoc/html/static/js/search.js | 46 +++--- src/tools/rustdoc-js/tester.js | 1 - tests/rustdoc-gui/search-corrections.goml | 12 +- tests/rustdoc-js-std/parser-bindings.js | 52 +++--- tests/rustdoc-js-std/parser-errors.js | 159 +++++++------------ tests/rustdoc-js-std/parser-filter.js | 27 ++-- tests/rustdoc-js-std/parser-generics.js | 18 +-- tests/rustdoc-js-std/parser-hof.js | 86 ++++------ tests/rustdoc-js-std/parser-ident.js | 37 ++--- tests/rustdoc-js-std/parser-literal.js | 7 +- tests/rustdoc-js-std/parser-paths.js | 31 ++-- tests/rustdoc-js-std/parser-quote.js | 21 +-- tests/rustdoc-js-std/parser-reference.js | 55 +++---- tests/rustdoc-js-std/parser-returned.js | 33 ++-- tests/rustdoc-js-std/parser-separators.js | 24 +-- tests/rustdoc-js-std/parser-slice-array.js | 56 +++---- tests/rustdoc-js-std/parser-tuple.js | 65 +++----- tests/rustdoc-js-std/parser-weird-queries.js | 18 +-- tests/rustdoc-js/non-english-identifier.js | 34 ++-- 19 files changed, 295 insertions(+), 487 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 995c2e041941c..a4471f1d885a4 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -276,7 +276,7 @@ function getFilteredNextElem(query, parserState, elems, isInGenerics) { // The type filter doesn't count as an element since it's a modifier. const typeFilterElem = elems.pop(); checkExtraTypeFilterCharacters(start, parserState); - parserState.typeFilter = typeFilterElem.name; + parserState.typeFilter = typeFilterElem.normalizedPathLast; parserState.pos += 1; parserState.totalElems -= 1; query.literalSearch = false; @@ -686,7 +686,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) { } else if (quadcolon !== null) { throw ["Unexpected ", quadcolon[0]]; } - const pathSegments = path.split(/(?:::\s*)|(?:\s+(?:::\s*)?)/); + const pathSegments = path.split(/(?:::\s*)|(?:\s+(?:::\s*)?)/).map(x => x.toLowerCase()); // In case we only have something like `

`, there is no name. if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) { @@ -726,7 +726,10 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) { if (gen.name !== null) { gen.bindingName.generics.unshift(gen); } - bindings.set(gen.bindingName.name, gen.bindingName.generics); + bindings.set( + gen.bindingName.name.toLowerCase().replace(/_/g, ""), + gen.bindingName.generics, + ); return false; } return true; @@ -1786,8 +1789,7 @@ class DocSearch { */ function newParsedQuery(userQuery) { return { - original: userQuery, - userQuery: userQuery.toLowerCase(), + userQuery, elems: [], returned: [], // Total number of "top" elements (does not include generics). @@ -1909,7 +1911,7 @@ class DocSearch { genericsElems: 0, typeFilter: null, isInBinding: null, - userQuery: userQuery.toLowerCase(), + userQuery, }; let query = newParsedQuery(userQuery); @@ -2097,7 +2099,7 @@ class DocSearch { */ const sortResults = async(results, isType, preferredCrate) => { const userQuery = parsedQuery.userQuery; - const casedUserQuery = parsedQuery.original; + const normalizedUserQuery = parsedQuery.userQuery.toLowerCase(); const result_list = []; for (const result of results.values()) { result.item = this.searchIndex[result.id]; @@ -2109,15 +2111,15 @@ class DocSearch { let a, b; // sort by exact case-sensitive match - a = (aaa.item.name !== casedUserQuery); - b = (bbb.item.name !== casedUserQuery); + a = (aaa.item.name !== userQuery); + b = (bbb.item.name !== userQuery); if (a !== b) { return a - b; } // sort by exact match with regard to the last word (mismatch goes later) - a = (aaa.word !== userQuery); - b = (bbb.word !== userQuery); + a = (aaa.word !== normalizedUserQuery); + b = (bbb.word !== normalizedUserQuery); if (a !== b) { return a - b; } @@ -3163,21 +3165,25 @@ class DocSearch { if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1 && elem.generics.length === 0 && elem.bindings.size === 0) || elem.typeFilter === TY_GENERIC) { - if (genericSymbols.has(elem.name)) { - elem.id = genericSymbols.get(elem.name); + if (genericSymbols.has(elem.normalizedPathLast)) { + elem.id = genericSymbols.get(elem.normalizedPathLast); } else { elem.id = -(genericSymbols.size + 1); - genericSymbols.set(elem.name, elem.id); + genericSymbols.set(elem.normalizedPathLast, elem.id); } - if (elem.typeFilter === -1 && elem.name.length >= 3) { + if (elem.typeFilter === -1 && elem.normalizedPathLast.length >= 3) { // Silly heuristic to catch if the user probably meant // to not write a generic parameter. We don't use it, // just bring it up. - const maxPartDistance = Math.floor(elem.name.length / 3); + const maxPartDistance = Math.floor(elem.normalizedPathLast.length / 3); let matchDist = maxPartDistance + 1; let matchName = ""; for (const name of this.typeNameIdMap.keys()) { - const dist = editDistance(name, elem.name, maxPartDistance); + const dist = editDistance( + name, + elem.normalizedPathLast, + maxPartDistance, + ); if (dist <= matchDist && dist <= maxPartDistance) { if (dist === matchDist && matchName > name) { continue; @@ -3289,7 +3295,7 @@ class DocSearch { sorted_returned, sorted_others, parsedQuery); - await handleAliases(ret, parsedQuery.original.replace(/"/g, ""), + await handleAliases(ret, parsedQuery.userQuery.replace(/"/g, ""), filterCrates, currentCrate); await Promise.all([ret.others, ret.returned, ret.in_args].map(async list => { const descs = await Promise.all(list.map(result => { @@ -3709,11 +3715,11 @@ async function search(forced) { } // Update document title to maintain a meaningful browser history - searchState.title = "\"" + query.original + "\" Search - Rust"; + searchState.title = "\"" + query.userQuery + "\" Search - Rust"; // Because searching is incremental by character, only the most // recent search query is added to the browser history. - updateSearchHistory(buildUrl(query.original, filterCrates)); + updateSearchHistory(buildUrl(query.userQuery, filterCrates)); await showResults( await docSearch.execQuery(query, filterCrates, window.currentCrate), diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index e162ba033cc55..63cda4111e6ad 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -84,7 +84,6 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position) if (fullPath.length === 0) { fieldsToCheck = [ "foundElems", - "original", "returned", "userQuery", "error", diff --git a/tests/rustdoc-gui/search-corrections.goml b/tests/rustdoc-gui/search-corrections.goml index b81b1f382a957..f80675730c41a 100644 --- a/tests/rustdoc-gui/search-corrections.goml +++ b/tests/rustdoc-gui/search-corrections.goml @@ -24,7 +24,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Type \"notablestructwithlongnamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." + "Type \"NotableStructWithLongNamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." ) // Corrections do get shown on the "In Return Type" tab. @@ -35,7 +35,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Type \"notablestructwithlongnamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." + "Type \"NotableStructWithLongNamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." ) // Now, explicit return values @@ -52,7 +52,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Type \"notablestructwithlongnamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." + "Type \"NotableStructWithLongNamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." ) // Now, generic correction @@ -69,7 +69,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Type \"notablestructwithlongnamr\" not found and used as generic parameter. Consider searching for \"notablestructwithlongname\" instead." + "Type \"NotableStructWithLongNamr\" not found and used as generic parameter. Consider searching for \"notablestructwithlongname\" instead." ) // Now, generic correction plus error @@ -86,7 +86,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Type \"notablestructwithlongnamr\" not found and used as generic parameter. Consider searching for \"notablestructwithlongname\" instead." + "Type \"NotableStructWithLongNamr\" not found and used as generic parameter. Consider searching for \"notablestructwithlongname\" instead." ) go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" @@ -102,5 +102,5 @@ assert-css: (".error", { }) assert-text: ( ".error", - "Query parser error: \"Generic type parameter notablestructwithlongnamr does not accept generic parameters\"." + "Query parser error: \"Generic type parameter NotableStructWithLongNamr does not accept generic parameters\"." ) diff --git a/tests/rustdoc-js-std/parser-bindings.js b/tests/rustdoc-js-std/parser-bindings.js index c4909c6242d75..bd379f139ffa2 100644 --- a/tests/rustdoc-js-std/parser-bindings.js +++ b/tests/rustdoc-js-std/parser-bindings.js @@ -3,20 +3,22 @@ const PARSED = [ query: 'A', elems: [ { - name: "a", + name: "A", fullPath: ["a"], pathWithoutLast: [], pathLast: "a", + normalizedPathLast: "a", generics: [], bindings: [ [ 'b', [ { - name: "c", + name: "C", fullPath: ["c"], pathWithoutLast: [], pathLast: "c", + normalizedPathLast: "c", generics: [], typeFilter: -1, }, @@ -27,16 +29,15 @@ const PARSED = [ }, ], foundElems: 1, - original: 'A', + userQuery: 'A', returned: [], - userQuery: 'a', error: null, }, { query: 'A', elems: [ { - name: "a", + name: "A", fullPath: ["a"], pathWithoutLast: [], pathLast: "a", @@ -45,7 +46,7 @@ const PARSED = [ [ 'b', [{ - name: "c", + name: "C", fullPath: ["c"], pathWithoutLast: [], pathLast: "c", @@ -58,16 +59,15 @@ const PARSED = [ }, ], foundElems: 1, - original: 'A', + userQuery: 'A', returned: [], - userQuery: 'a', error: null, }, { query: 'A', elems: [ { - name: "a", + name: "A", fullPath: ["a"], pathWithoutLast: [], pathLast: "a", @@ -89,16 +89,15 @@ const PARSED = [ }, ], foundElems: 1, - original: 'A', + userQuery: 'A', returned: [], - userQuery: 'a', error: null, }, { query: 'A', elems: [ { - name: "a", + name: "A", fullPath: ["a"], pathWithoutLast: [], pathLast: "a", @@ -120,16 +119,15 @@ const PARSED = [ }, ], foundElems: 1, - original: 'A', + userQuery: 'A', returned: [], - userQuery: 'a', error: null, }, { query: 'A', elems: [ { - name: "a", + name: "A", fullPath: ["a"], pathWithoutLast: [], pathLast: "a", @@ -160,52 +158,47 @@ const PARSED = [ }, ], foundElems: 1, - original: 'A', + userQuery: 'A', returned: [], - userQuery: 'a', error: null, }, { query: 'A', elems: [], foundElems: 0, - original: 'A', + userQuery: 'A', returned: [], - userQuery: 'a', error: "Cannot write `=` twice in a binding", }, { query: 'A', elems: [], foundElems: 0, - original: 'A', + userQuery: 'A', returned: [], - userQuery: 'a', error: "Unexpected `>` after `=`", }, { query: 'B=C', elems: [], foundElems: 0, - original: 'B=C', + userQuery: 'B=C', returned: [], - userQuery: 'b=c', error: "Type parameter `=` must be within generics list", }, { query: '[B=C]', elems: [], foundElems: 0, - original: '[B=C]', + userQuery: '[B=C]', returned: [], - userQuery: '[b=c]', error: "Type parameter `=` cannot be within slice `[]`", }, { query: 'A=C>', elems: [ { - name: "a", + name: "A", fullPath: ["a"], pathWithoutLast: [], pathLast: "a", @@ -215,7 +208,7 @@ const PARSED = [ 'b', [ { - name: "c", + name: "C", fullPath: ["c"], pathWithoutLast: [], pathLast: "c", @@ -223,7 +216,7 @@ const PARSED = [ typeFilter: -1, }, { - name: "x", + name: "X", fullPath: ["x"], pathWithoutLast: [], pathLast: "x", @@ -237,9 +230,8 @@ const PARSED = [ }, ], foundElems: 1, - original: 'A=C>', + userQuery: 'A=C>', returned: [], - userQuery: 'a=c>', error: null, }, ]; diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index 5ce35bf511d75..068298e72360a 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -3,450 +3,400 @@ const PARSED = [ query: '

', elems: [], foundElems: 0, - original: "

", + userQuery: "

", returned: [], - userQuery: "

", error: "Found generics without a path", }, { query: '->

', elems: [], foundElems: 0, - original: "->

", + userQuery: "->

", returned: [], - userQuery: "->

", error: "Found generics without a path", }, { query: '-> *', elems: [], foundElems: 0, - original: "-> *", - returned: [], userQuery: "-> *", + returned: [], error: "Unexpected `*` after ` ` (not a valid identifier)", }, { query: 'a<"P">', elems: [], foundElems: 0, - original: "a<\"P\">", + userQuery: "a<\"P\">", returned: [], - userQuery: "a<\"p\">", error: "Unexpected `\"` in generics", }, { query: '"P" "P"', elems: [], foundElems: 0, - original: "\"P\" \"P\"", + userQuery: "\"P\" \"P\"", returned: [], - userQuery: "\"p\" \"p\"", error: "Cannot have more than one element if you use quotes", }, { query: '"P","P"', elems: [], foundElems: 0, - original: "\"P\",\"P\"", + userQuery: "\"P\",\"P\"", returned: [], - userQuery: "\"p\",\"p\"", error: "Cannot have more than one literal search element", }, { query: "P,\"P\"", elems: [], foundElems: 0, - original: "P,\"P\"", + userQuery: "P,\"P\"", returned: [], - userQuery: "p,\"p\"", error: "Cannot use literal search when there is more than one element", }, { query: '"p" p', elems: [], foundElems: 0, - original: "\"p\" p", - returned: [], userQuery: "\"p\" p", + returned: [], error: "Cannot have more than one element if you use quotes", }, { query: '"p",p', elems: [], foundElems: 0, - original: "\"p\",p", - returned: [], userQuery: "\"p\",p", + returned: [], error: "Cannot have more than one element if you use quotes", }, { query: '"const": p', elems: [], foundElems: 0, - original: "\"const\": p", - returned: [], userQuery: "\"const\": p", + returned: [], error: "Cannot use quotes on type filter", }, { query: "a<:a>", elems: [], foundElems: 0, - original: "a<:a>", - returned: [], userQuery: "a<:a>", + returned: [], error: "Expected type filter before `:`", }, { query: "a<::a>", elems: [], foundElems: 0, - original: "a<::a>", - returned: [], userQuery: "a<::a>", + returned: [], error: "Unexpected `::`: paths cannot start with `::`", }, { query: "(p -> p", elems: [], foundElems: 0, - original: "(p -> p", - returned: [], userQuery: "(p -> p", + returned: [], error: "Unclosed `(`", }, { query: "::a::b", elems: [], foundElems: 0, - original: "::a::b", - returned: [], userQuery: "::a::b", + returned: [], error: "Paths cannot start with `::`", }, { query: " ::a::b", elems: [], foundElems: 0, - original: "::a::b", - returned: [], userQuery: "::a::b", + returned: [], error: "Paths cannot start with `::`", }, { query: "a::::b", elems: [], foundElems: 0, - original: "a::::b", - returned: [], userQuery: "a::::b", + returned: [], error: "Unexpected `::::`", }, { query: "a:: ::b", elems: [], foundElems: 0, - original: "a:: ::b", - returned: [], userQuery: "a:: ::b", + returned: [], error: "Unexpected `:: ::`", }, { query: "a::\t::b", elems: [], foundElems: 0, - original: "a:: ::b", - returned: [], userQuery: "a:: ::b", + returned: [], error: "Unexpected `:: ::`", }, { query: "a::b::", elems: [], foundElems: 0, - original: "a::b::", - returned: [], userQuery: "a::b::", + returned: [], error: "Paths cannot end with `::`", }, { query: ":a", elems: [], foundElems: 0, - original: ":a", - returned: [], userQuery: ":a", + returned: [], error: "Expected type filter before `:`", }, { query: "a,b:", elems: [], foundElems: 0, - original: "a,b:", - returned: [], userQuery: "a,b:", + returned: [], error: "Unexpected `:` (expected path after type filter `b:`)", }, { query: "a (b:", elems: [], foundElems: 0, - original: "a (b:", - returned: [], userQuery: "a (b:", + returned: [], error: "Unclosed `(`", }, { query: "_:", elems: [], foundElems: 0, - original: "_:", - returned: [], userQuery: "_:", + returned: [], error: "Unexpected `_` (not a valid identifier)", }, { query: "ab:", elems: [], foundElems: 0, - original: "ab:", - returned: [], userQuery: "ab:", + returned: [], error: "Unexpected `:` (expected path after type filter `ab:`)", }, { query: "a:b", elems: [], foundElems: 0, - original: "a:b", - returned: [], userQuery: "a:b", + returned: [], error: "Unknown type filter `a`", }, { query: "a-bb", elems: [], foundElems: 0, - original: "a-bb", - returned: [], userQuery: "a-bb", + returned: [], error: "Unexpected `-` (did you mean `->`?)", }, { query: "a>bb", elems: [], foundElems: 0, - original: "a>bb", - returned: [], userQuery: "a>bb", + returned: [], error: "Unexpected `>` (did you mean `->`?)", }, { query: "ab'", elems: [], foundElems: 0, - original: "ab'", - returned: [], userQuery: "ab'", + returned: [], error: "Unexpected `'` after `b` (not a valid identifier)", }, { query: '"p" ', elems: [], foundElems: 0, - original: '"p" ', - returned: [], userQuery: '"p" ', + returned: [], error: "Cannot have more than one element if you use quotes", }, { query: '"p",', elems: [], foundElems: 0, - original: '"p",', - returned: [], userQuery: '"p",', + returned: [], error: "Found generics without a path", }, { query: '"p" a', elems: [], foundElems: 0, - original: '"p" a', - returned: [], userQuery: '"p" a', + returned: [], error: "Cannot have more than one element if you use quotes", }, { query: '"p",a', elems: [], foundElems: 0, - original: '"p",a', - returned: [], userQuery: '"p",a', + returned: [], error: "Cannot have more than one element if you use quotes", }, { query: "a,<", elems: [], foundElems: 0, - original: 'a,<', - returned: [], userQuery: 'a,<', + returned: [], error: 'Found generics without a path', }, { query: "aaaaa<>b", elems: [], foundElems: 0, - original: 'aaaaa<>b', - returned: [], userQuery: 'aaaaa<>b', + returned: [], error: 'Expected `,`, `:` or `->` after `>`, found `b`', }, { query: "fn:aaaaa<>b", elems: [], foundElems: 0, - original: 'fn:aaaaa<>b', - returned: [], userQuery: 'fn:aaaaa<>b', + returned: [], error: 'Expected `,`, `:` or `->` after `>`, found `b`', }, { query: "->a<>b", elems: [], foundElems: 0, - original: '->a<>b', - returned: [], userQuery: '->a<>b', + returned: [], error: 'Expected `,` or `=` after `>`, found `b`', }, { query: "a<->", elems: [], foundElems: 0, - original: 'a<->', - returned: [], userQuery: 'a<->', + returned: [], error: 'Unclosed `<`', }, { query: "a:", elems: [], foundElems: 0, - original: "a:", - returned: [], userQuery: "a:", + returned: [], error: 'Unexpected `<` in type filter (before `:`)', }, { query: "a<>:", elems: [], foundElems: 0, - original: "a<>:", - returned: [], userQuery: "a<>:", + returned: [], error: 'Unexpected `<` in type filter (before `:`)', }, { query: "a,:", elems: [], foundElems: 0, - original: "a,:", - returned: [], userQuery: "a,:", + returned: [], error: 'Expected type filter before `:`', }, { query: "a!:", elems: [], foundElems: 0, - original: "a!:", - returned: [], userQuery: "a!:", + returned: [], error: 'Unexpected `!` in type filter (before `:`)', }, { query: " a<> :", elems: [], foundElems: 0, - original: "a<> :", - returned: [], userQuery: "a<> :", + returned: [], error: 'Expected `,`, `:` or `->` after `>`, found `:`', }, { query: "mod : :", elems: [], foundElems: 0, - original: "mod : :", - returned: [], userQuery: "mod : :", + returned: [], error: 'Unexpected `:` (expected path after type filter `mod:`)', }, { query: "mod: :", elems: [], foundElems: 0, - original: "mod: :", - returned: [], userQuery: "mod: :", + returned: [], error: 'Unexpected `:` (expected path after type filter `mod:`)', }, { query: "a!a", elems: [], foundElems: 0, - original: "a!a", - returned: [], userQuery: "a!a", + returned: [], error: 'Unexpected `!`: it can only be at the end of an ident', }, { query: "a!!", elems: [], foundElems: 0, - original: "a!!", - returned: [], userQuery: "a!!", + returned: [], error: 'Cannot have more than one `!` in an ident', }, { query: "mod:a!", elems: [], foundElems: 0, - original: "mod:a!", - returned: [], userQuery: "mod:a!", + returned: [], error: 'Invalid search type: macro `!` and `mod` both specified', }, { query: "mod:!", elems: [], foundElems: 0, - original: "mod:!", - returned: [], userQuery: "mod:!", + returned: [], error: 'Invalid search type: primitive never type `!` and `mod` both specified', }, { query: "a!::a", elems: [], foundElems: 0, - original: "a!::a", - returned: [], userQuery: "a!::a", + returned: [], error: 'Cannot have associated items in macros', }, { query: "a<", elems: [], foundElems: 0, - original: "a<", - returned: [], userQuery: "a<", + returned: [], error: "Unclosed `<`", }, { @@ -479,9 +429,8 @@ const PARSED = [ }, ], foundElems: 2, - original: "p , y", - returned: [], userQuery: "p , y", + returned: [], error: null, }, { @@ -514,9 +463,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "p", - returned: [], userQuery: "p", + returned: [], error: null, }, { @@ -548,9 +496,8 @@ const PARSED = [ }, ], foundElems: 3, - original: "p ,x , y", - returned: [], userQuery: "p ,x , y", + returned: [], error: null, }, ]; diff --git a/tests/rustdoc-js-std/parser-filter.js b/tests/rustdoc-js-std/parser-filter.js index a1dd0ea3b5a99..cda950461f7e0 100644 --- a/tests/rustdoc-js-std/parser-filter.js +++ b/tests/rustdoc-js-std/parser-filter.js @@ -10,9 +10,8 @@ const PARSED = [ typeFilter: 7, }], foundElems: 1, - original: "fn:foo", - returned: [], userQuery: "fn:foo", + returned: [], error: null, }, { @@ -26,18 +25,16 @@ const PARSED = [ typeFilter: 6, }], foundElems: 1, - original: "enum : foo", - returned: [], userQuery: "enum : foo", + returned: [], error: null, }, { query: 'macro:foo', elems: [], foundElems: 0, - original: "macro:foo", - returned: [], userQuery: "macro:foo", + returned: [], error: "Unexpected `<` in type filter (before `:`)", }, { @@ -51,9 +48,8 @@ const PARSED = [ typeFilter: 16, }], foundElems: 1, - original: "macro!", - returned: [], userQuery: "macro!", + returned: [], error: null, }, { @@ -67,9 +63,8 @@ const PARSED = [ typeFilter: 16, }], foundElems: 1, - original: "macro:mac!", - returned: [], userQuery: "macro:mac!", + returned: [], error: null, }, { @@ -83,16 +78,15 @@ const PARSED = [ typeFilter: 16, }], foundElems: 1, - original: "a::mac!", - returned: [], userQuery: "a::mac!", + returned: [], error: null, }, { query: '-> fn:foo', elems: [], foundElems: 1, - original: "-> fn:foo", + userQuery: "-> fn:foo", returned: [{ name: "foo", fullPath: ["foo"], @@ -101,14 +95,13 @@ const PARSED = [ generics: [], typeFilter: 7, }], - userQuery: "-> fn:foo", error: null, }, { query: '-> fn:foo', elems: [], foundElems: 1, - original: "-> fn:foo", + userQuery: "-> fn:foo", returned: [{ name: "foo", fullPath: ["foo"], @@ -126,14 +119,13 @@ const PARSED = [ ], typeFilter: 7, }], - userQuery: "-> fn:foo", error: null, }, { query: '-> fn:foo', elems: [], foundElems: 1, - original: "-> fn:foo", + userQuery: "-> fn:foo", returned: [{ name: "foo", fullPath: ["foo"], @@ -159,7 +151,6 @@ const PARSED = [ ], typeFilter: 7, }], - userQuery: "-> fn:foo", error: null, }, ]; diff --git a/tests/rustdoc-js-std/parser-generics.js b/tests/rustdoc-js-std/parser-generics.js index 726ee56c2c1ba..8b8d95bcb8883 100644 --- a/tests/rustdoc-js-std/parser-generics.js +++ b/tests/rustdoc-js-std/parser-generics.js @@ -3,9 +3,8 @@ const PARSED = [ query: 'A, E>', elems: [], foundElems: 0, - original: 'A, E>', + userQuery: 'A, E>', returned: [], - userQuery: 'a, e>', error: 'Unclosed `<`', }, { @@ -29,9 +28,8 @@ const PARSED = [ }, ], foundElems: 2, - original: "p<>,u8", - returned: [], userQuery: "p<>,u8", + returned: [], error: null, }, { @@ -55,9 +53,8 @@ const PARSED = [ }, ], foundElems: 1, - original: '"p"', - returned: [], userQuery: '"p"', + returned: [], error: null, }, { @@ -89,9 +86,8 @@ const PARSED = [ }, ], foundElems: 1, - original: 'p>', - returned: [], userQuery: 'p>', + returned: [], error: null, }, { @@ -130,9 +126,8 @@ const PARSED = [ }, ], foundElems: 1, - original: 'p, r>', - returned: [], userQuery: 'p, r>', + returned: [], error: null, }, { @@ -171,9 +166,8 @@ const PARSED = [ }, ], foundElems: 1, - original: 'p>', - returned: [], userQuery: 'p>', + returned: [], error: null, }, ]; diff --git a/tests/rustdoc-js-std/parser-hof.js b/tests/rustdoc-js-std/parser-hof.js index 0b99c45b7a922..ca76101541280 100644 --- a/tests/rustdoc-js-std/parser-hof.js +++ b/tests/rustdoc-js-std/parser-hof.js @@ -12,13 +12,13 @@ const PARSED = [ [ "output", [{ - name: "f", + name: "F", fullPath: ["f"], pathWithoutLast: [], pathLast: "f", generics: [ { - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -32,9 +32,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(-> F

)", + userQuery: "(-> F

)", returned: [], - userQuery: "(-> f

)", error: null, }, { @@ -49,7 +48,7 @@ const PARSED = [ [ "output", [{ - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -61,9 +60,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(-> P)", + userQuery: "(-> P)", returned: [], - userQuery: "(-> p)", error: null, }, { @@ -90,9 +88,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(->,a)", - returned: [], userQuery: "(->,a)", + returned: [], error: null, }, { @@ -103,13 +100,13 @@ const PARSED = [ pathWithoutLast: [], pathLast: "->", generics: [{ - name: "f", + name: "F", fullPath: ["f"], pathWithoutLast: [], pathLast: "f", generics: [ { - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -127,9 +124,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(F

->)", + userQuery: "(F

->)", returned: [], - userQuery: "(f

->)", error: null, }, { @@ -140,7 +136,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "->", generics: [{ - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -156,9 +152,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(P ->)", + userQuery: "(P ->)", returned: [], - userQuery: "(p ->)", error: null, }, { @@ -185,9 +180,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(,a->)", - returned: [], userQuery: "(,a->)", + returned: [], error: null, }, { @@ -221,9 +215,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(aaaaa->a)", - returned: [], userQuery: "(aaaaa->a)", + returned: [], error: null, }, { @@ -267,9 +260,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(aaaaa, b -> a)", - returned: [], userQuery: "(aaaaa, b -> a)", + returned: [], error: null, }, { @@ -313,9 +305,8 @@ const PARSED = [ typeFilter: 1, }], foundElems: 1, - original: "primitive:(aaaaa, b -> a)", - returned: [], userQuery: "primitive:(aaaaa, b -> a)", + returned: [], error: null, }, { @@ -369,16 +360,15 @@ const PARSED = [ } ], foundElems: 2, - original: "x, trait:(aaaaa, b -> a)", - returned: [], userQuery: "x, trait:(aaaaa, b -> a)", + returned: [], error: null, }, // Rust-style HOF { query: "Fn () -> F

", elems: [{ - name: "fn", + name: "Fn", fullPath: ["fn"], pathWithoutLast: [], pathLast: "fn", @@ -387,13 +377,13 @@ const PARSED = [ [ "output", [{ - name: "f", + name: "F", fullPath: ["f"], pathWithoutLast: [], pathLast: "f", generics: [ { - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -407,15 +397,14 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "Fn () -> F

", + userQuery: "Fn () -> F

", returned: [], - userQuery: "fn () -> f

", error: null, }, { query: "FnMut() -> P", elems: [{ - name: "fnmut", + name: "FnMut", fullPath: ["fnmut"], pathWithoutLast: [], pathLast: "fnmut", @@ -424,7 +413,7 @@ const PARSED = [ [ "output", [{ - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -436,15 +425,14 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "FnMut() -> P", + userQuery: "FnMut() -> P", returned: [], - userQuery: "fnmut() -> p", error: null, }, { query: "(FnMut() -> P)", elems: [{ - name: "fnmut", + name: "FnMut", fullPath: ["fnmut"], pathWithoutLast: [], pathLast: "fnmut", @@ -453,7 +441,7 @@ const PARSED = [ [ "output", [{ - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -465,26 +453,25 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "(FnMut() -> P)", + userQuery: "(FnMut() -> P)", returned: [], - userQuery: "(fnmut() -> p)", error: null, }, { query: "Fn(F

)", elems: [{ - name: "fn", + name: "Fn", fullPath: ["fn"], pathWithoutLast: [], pathLast: "fn", generics: [{ - name: "f", + name: "F", fullPath: ["f"], pathWithoutLast: [], pathLast: "f", generics: [ { - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -502,9 +489,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "Fn(F

)", + userQuery: "Fn(F

)", returned: [], - userQuery: "fn(f

)", error: null, }, { @@ -548,9 +534,8 @@ const PARSED = [ typeFilter: 1, }], foundElems: 1, - original: "primitive:fnonce(aaaaa, b) -> a", - returned: [], userQuery: "primitive:fnonce(aaaaa, b) -> a", + returned: [], error: null, }, { @@ -594,9 +579,8 @@ const PARSED = [ typeFilter: 1, }], foundElems: 1, - original: "primitive:fnonce(aaaaa, keyword:b) -> trait:a", - returned: [], userQuery: "primitive:fnonce(aaaaa, keyword:b) -> trait:a", + returned: [], error: null, }, { @@ -665,9 +649,8 @@ const PARSED = [ } ], foundElems: 2, - original: "x, trait:fn(aaaaa, b -> a)", - returned: [], userQuery: "x, trait:fn(aaaaa, b -> a)", + returned: [], error: null, }, { @@ -704,9 +687,8 @@ const PARSED = [ } ], foundElems: 2, - original: "a,b(c)", - returned: [], userQuery: "a,b(c)", + returned: [], error: null, }, ]; diff --git a/tests/rustdoc-js-std/parser-ident.js b/tests/rustdoc-js-std/parser-ident.js index cc79c58f1da3a..f65391b157188 100644 --- a/tests/rustdoc-js-std/parser-ident.js +++ b/tests/rustdoc-js-std/parser-ident.js @@ -2,7 +2,7 @@ const PARSED = [ { query: "R", elems: [{ - name: "r", + name: "R", fullPath: ["r"], pathWithoutLast: [], pathLast: "r", @@ -19,9 +19,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "R", + userQuery: "R", returned: [], - userQuery: "r", error: null, }, { @@ -35,9 +34,8 @@ const PARSED = [ typeFilter: 1, }], foundElems: 1, - original: "!", - returned: [], userQuery: "!", + returned: [], error: null, }, { @@ -51,27 +49,24 @@ const PARSED = [ typeFilter: 16, }], foundElems: 1, - original: "a!", - returned: [], userQuery: "a!", + returned: [], error: null, }, { query: "a!::b", elems: [], foundElems: 0, - original: "a!::b", - returned: [], userQuery: "a!::b", + returned: [], error: "Cannot have associated items in macros", }, { query: "!", elems: [], foundElems: 0, - original: "!", + userQuery: "!", returned: [], - userQuery: "!", error: "Never type `!` does not accept generic parameters", }, { @@ -85,36 +80,32 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "!::b", - returned: [], userQuery: "!::b", + returned: [], error: null, }, { query: "b::!", elems: [], foundElems: 0, - original: "b::!", - returned: [], userQuery: "b::!", + returned: [], error: "Never type `!` is not associated item", }, { query: "!::!", elems: [], foundElems: 0, - original: "!::!", - returned: [], userQuery: "!::!", + returned: [], error: "Never type `!` is not associated item", }, { query: "b::!::c", elems: [], foundElems: 0, - original: "b::!::c", - returned: [], userQuery: "b::!::c", + returned: [], error: "Never type `!` is not associated item", }, { @@ -126,7 +117,7 @@ const PARSED = [ pathLast: "b", generics: [ { - name: "t", + name: "T", fullPath: ["t"], pathWithoutLast: [], pathLast: "t", @@ -137,18 +128,16 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "!::b", + userQuery: "!::b", returned: [], - userQuery: "!::b", error: null, }, { query: "a!::b!", elems: [], foundElems: 0, - original: "a!::b!", - returned: [], userQuery: "a!::b!", + returned: [], error: "Cannot have associated items in macros", }, ]; diff --git a/tests/rustdoc-js-std/parser-literal.js b/tests/rustdoc-js-std/parser-literal.js index 87c06224dbf2d..63e07a246a13d 100644 --- a/tests/rustdoc-js-std/parser-literal.js +++ b/tests/rustdoc-js-std/parser-literal.js @@ -2,13 +2,13 @@ const PARSED = [ { query: 'R

', elems: [{ - name: "r", + name: "R", fullPath: ["r"], pathWithoutLast: [], pathLast: "r", generics: [ { - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -18,9 +18,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "R

", + userQuery: "R

", returned: [], - userQuery: "r

", error: null, } ]; diff --git a/tests/rustdoc-js-std/parser-paths.js b/tests/rustdoc-js-std/parser-paths.js index 774e5d028cc2c..bb34e22e518a4 100644 --- a/tests/rustdoc-js-std/parser-paths.js +++ b/tests/rustdoc-js-std/parser-paths.js @@ -2,7 +2,7 @@ const PARSED = [ { query: 'A::B', elems: [{ - name: "a::b", + name: "A::B", fullPath: ["a", "b"], pathWithoutLast: ["a"], pathLast: "b", @@ -10,9 +10,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "A::B", + userQuery: "A::B", returned: [], - userQuery: "a::b", error: null, }, { @@ -26,9 +25,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: 'a:: a', - returned: [], userQuery: 'a:: a', + returned: [], error: null, }, { @@ -42,9 +40,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: 'a ::a', - returned: [], userQuery: 'a ::a', + returned: [], error: null, }, { @@ -58,16 +55,15 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: 'a :: a', - returned: [], userQuery: 'a :: a', + returned: [], error: null, }, { query: 'A::B,C', elems: [ { - name: "a::b", + name: "A::B", fullPath: ["a", "b"], pathWithoutLast: ["a"], pathLast: "b", @@ -75,7 +71,7 @@ const PARSED = [ typeFilter: -1, }, { - name: "c", + name: "C", fullPath: ["c"], pathWithoutLast: [], pathLast: "c", @@ -84,16 +80,15 @@ const PARSED = [ }, ], foundElems: 2, - original: 'A::B,C', + userQuery: 'A::B,C', returned: [], - userQuery: 'a::b,c', error: null, }, { query: 'A::B,C', elems: [ { - name: "a::b", + name: "A::B", fullPath: ["a", "b"], pathWithoutLast: ["a"], pathLast: "b", @@ -109,7 +104,7 @@ const PARSED = [ typeFilter: -1, }, { - name: "c", + name: "C", fullPath: ["c"], pathWithoutLast: [], pathLast: "c", @@ -118,9 +113,8 @@ const PARSED = [ }, ], foundElems: 2, - original: 'A::B,C', + userQuery: 'A::B,C', returned: [], - userQuery: 'a::b,c', error: null, }, { @@ -134,9 +128,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "mod::a", - returned: [], userQuery: "mod::a", + returned: [], error: null, }, ]; diff --git a/tests/rustdoc-js-std/parser-quote.js b/tests/rustdoc-js-std/parser-quote.js index 731673cf4633c..b485047e385eb 100644 --- a/tests/rustdoc-js-std/parser-quote.js +++ b/tests/rustdoc-js-std/parser-quote.js @@ -3,7 +3,7 @@ const PARSED = [ query: '-> "p"', elems: [], foundElems: 1, - original: '-> "p"', + userQuery: '-> "p"', returned: [{ name: "p", fullPath: ["p"], @@ -12,7 +12,6 @@ const PARSED = [ generics: [], typeFilter: -1, }], - userQuery: '-> "p"', error: null, }, { @@ -26,54 +25,48 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: '"p",', - returned: [], userQuery: '"p",', + returned: [], error: null, }, { query: '"p" -> a', elems: [], foundElems: 0, - original: '"p" -> a', - returned: [], userQuery: '"p" -> a', + returned: [], error: "Cannot have more than one element if you use quotes", }, { query: '"a" -> "p"', elems: [], foundElems: 0, - original: '"a" -> "p"', - returned: [], userQuery: '"a" -> "p"', + returned: [], error: "Cannot have more than one literal search element", }, { query: '->"-"', elems: [], foundElems: 0, - original: '->"-"', - returned: [], userQuery: '->"-"', + returned: [], error: 'Unexpected `-` in a string element', }, { query: '"a', elems: [], foundElems: 0, - original: '"a', - returned: [], userQuery: '"a', + returned: [], error: 'Unclosed `"`', }, { query: '""', elems: [], foundElems: 0, - original: '""', - returned: [], userQuery: '""', + returned: [], error: 'Cannot have empty string element', }, ]; diff --git a/tests/rustdoc-js-std/parser-reference.js b/tests/rustdoc-js-std/parser-reference.js index 6b1250146bef8..0fa07ae989528 100644 --- a/tests/rustdoc-js-std/parser-reference.js +++ b/tests/rustdoc-js-std/parser-reference.js @@ -3,18 +3,16 @@ const PARSED = [ query: '&[', elems: [], foundElems: 0, - original: '&[', - returned: [], userQuery: '&[', + returned: [], error: 'Unclosed `[`', }, { query: '[&', elems: [], foundElems: 0, - original: '[&', - returned: [], userQuery: '[&', + returned: [], error: 'Unclosed `[`', }, { @@ -39,7 +37,7 @@ const PARSED = [ pathLast: "reference", generics: [ { - name: "d", + name: "D", fullPath: ["d"], pathWithoutLast: [], pathLast: "d", @@ -65,9 +63,8 @@ const PARSED = [ }, ], foundElems: 2, - original: '&&&D, []', + userQuery: '&&&D, []', returned: [], - userQuery: '&&&d, []', error: null, }, { @@ -98,7 +95,7 @@ const PARSED = [ pathLast: "[]", generics: [ { - name: "d", + name: "D", fullPath: ["d"], pathWithoutLast: [], pathLast: "d", @@ -119,9 +116,8 @@ const PARSED = [ }, ], foundElems: 1, - original: '&&&[D]', + userQuery: '&&&[D]', returned: [], - userQuery: '&&&[d]', error: null, }, { @@ -137,9 +133,8 @@ const PARSED = [ }, ], foundElems: 1, - original: '&', - returned: [], userQuery: '&', + returned: [], error: null, }, { @@ -164,9 +159,8 @@ const PARSED = [ }, ], foundElems: 1, - original: '&mut', - returned: [], userQuery: '&mut', + returned: [], error: null, }, { @@ -190,9 +184,8 @@ const PARSED = [ }, ], foundElems: 2, - original: "&,u8", - returned: [], userQuery: "&,u8", + returned: [], error: null, }, { @@ -225,9 +218,8 @@ const PARSED = [ }, ], foundElems: 2, - original: "&mut,u8", - returned: [], userQuery: "&mut,u8", + returned: [], error: null, }, { @@ -252,9 +244,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "&u8", - returned: [], userQuery: "&u8", + returned: [], error: null, }, { @@ -288,9 +279,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "&u8", - returned: [], userQuery: "&u8", + returned: [], error: null, }, { @@ -324,9 +314,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "u8<&u8>", - returned: [], userQuery: "u8<&u8>", + returned: [], error: null, }, { @@ -368,9 +357,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "u8<&u8, u8>", - returned: [], userQuery: "u8<&u8, u8>", + returned: [], error: null, }, { @@ -404,9 +392,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "u8<&u8>", - returned: [], userQuery: "u8<&u8>", + returned: [], error: null, }, { @@ -456,9 +443,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "u8<&mut u8, u8>", - returned: [], userQuery: "u8<&mut u8, u8>", + returned: [], error: null, }, { @@ -483,18 +469,16 @@ const PARSED = [ }, ], foundElems: 1, - original: "primitive:&u8", - returned: [], userQuery: "primitive:&u8", + returned: [], error: null, }, { query: 'macro:&u8', elems: [], foundElems: 0, - original: "macro:&u8", - returned: [], userQuery: "macro:&u8", + returned: [], error: "Invalid search type: primitive `&` and `macro` both specified", }, { @@ -519,9 +503,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "¯o:u8", - returned: [], userQuery: "¯o:u8", + returned: [], error: null, }, ]; diff --git a/tests/rustdoc-js-std/parser-returned.js b/tests/rustdoc-js-std/parser-returned.js index 8f68209bb966f..30ce26a892059 100644 --- a/tests/rustdoc-js-std/parser-returned.js +++ b/tests/rustdoc-js-std/parser-returned.js @@ -3,15 +3,15 @@ const PARSED = [ query: "-> F

", elems: [], foundElems: 1, - original: "-> F

", + userQuery: "-> F

", returned: [{ - name: "f", + name: "F", fullPath: ["f"], pathWithoutLast: [], pathLast: "f", generics: [ { - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", @@ -20,30 +20,28 @@ const PARSED = [ ], typeFilter: -1, }], - userQuery: "-> f

", error: null, }, { query: "-> P", elems: [], foundElems: 1, - original: "-> P", + userQuery: "-> P", returned: [{ - name: "p", + name: "P", fullPath: ["p"], pathWithoutLast: [], pathLast: "p", generics: [], typeFilter: -1, }], - userQuery: "-> p", error: null, }, { query: "->,a", elems: [], foundElems: 1, - original: "->,a", + userQuery: "->,a", returned: [{ name: "a", fullPath: ["a"], @@ -52,7 +50,6 @@ const PARSED = [ generics: [], typeFilter: -1, }], - userQuery: "->,a", error: null, }, { @@ -66,7 +63,7 @@ const PARSED = [ typeFilter: -1, }], foundElems: 2, - original: "aaaaa->a", + userQuery: "aaaaa->a", returned: [{ name: "a", fullPath: ["a"], @@ -75,14 +72,13 @@ const PARSED = [ generics: [], typeFilter: -1, }], - userQuery: "aaaaa->a", error: null, }, { query: "-> !", elems: [], foundElems: 1, - original: "-> !", + userQuery: "-> !", returned: [{ name: "never", fullPath: ["never"], @@ -91,7 +87,6 @@ const PARSED = [ generics: [], typeFilter: 1, }], - userQuery: "-> !", error: null, }, { @@ -105,9 +100,8 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "a->", - returned: [], userQuery: "a->", + returned: [], hasReturnArrow: true, error: null, }, @@ -122,9 +116,8 @@ const PARSED = [ typeFilter: 1, }], foundElems: 1, - original: "!->", - returned: [], userQuery: "!->", + returned: [], hasReturnArrow: true, error: null, }, @@ -139,9 +132,8 @@ const PARSED = [ typeFilter: 1, }], foundElems: 1, - original: "! ->", - returned: [], userQuery: "! ->", + returned: [], hasReturnArrow: true, error: null, }, @@ -156,9 +148,8 @@ const PARSED = [ typeFilter: 1, }], foundElems: 1, - original: "primitive:!->", - returned: [], userQuery: "primitive:!->", + returned: [], hasReturnArrow: true, error: null, }, diff --git a/tests/rustdoc-js-std/parser-separators.js b/tests/rustdoc-js-std/parser-separators.js index 7f95f61b006bb..cf271c80cdce2 100644 --- a/tests/rustdoc-js-std/parser-separators.js +++ b/tests/rustdoc-js-std/parser-separators.js @@ -14,9 +14,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "aaaaaa b", - returned: [], userQuery: "aaaaaa b", + returned: [], error: null, }, { @@ -40,9 +39,8 @@ const PARSED = [ }, ], foundElems: 2, - original: "aaaaaa, b", - returned: [], userQuery: "aaaaaa, b", + returned: [], error: null, }, { @@ -58,9 +56,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "a b", - returned: [], userQuery: "a b", + returned: [], error: null, }, { @@ -84,9 +81,8 @@ const PARSED = [ }, ], foundElems: 2, - original: "a,b", - returned: [], userQuery: "a,b", + returned: [], error: null, }, { @@ -102,9 +98,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "a b", - returned: [], userQuery: "a b", + returned: [], error: null, }, { @@ -128,9 +123,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "a", - returned: [], userQuery: "a", + returned: [], error: null, }, { @@ -161,9 +155,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "a", - returned: [], userQuery: "a", + returned: [], error: null, }, { @@ -187,9 +180,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "a", - returned: [], userQuery: "a", + returned: [], error: null, }, ]; diff --git a/tests/rustdoc-js-std/parser-slice-array.js b/tests/rustdoc-js-std/parser-slice-array.js index 1de52af94e6b0..6579794553599 100644 --- a/tests/rustdoc-js-std/parser-slice-array.js +++ b/tests/rustdoc-js-std/parser-slice-array.js @@ -3,9 +3,8 @@ const PARSED = [ query: '[[[D, []]]', elems: [], foundElems: 0, - original: '[[[D, []]]', + userQuery: '[[[D, []]]', returned: [], - userQuery: '[[[d, []]]', error: 'Unclosed `[`', }, { @@ -30,7 +29,7 @@ const PARSED = [ pathLast: "[]", generics: [ { - name: "d", + name: "D", fullPath: ["d"], pathWithoutLast: [], pathLast: "d", @@ -56,9 +55,8 @@ const PARSED = [ }, ], foundElems: 1, - original: '[[[D, []]]]', + userQuery: '[[[D, []]]]', returned: [], - userQuery: '[[[d, []]]]', error: null, }, { @@ -82,9 +80,8 @@ const PARSED = [ }, ], foundElems: 2, - original: "[],u8", - returned: [], userQuery: "[],u8", + returned: [], error: null, }, { @@ -109,9 +106,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "[u8]", - returned: [], userQuery: "[u8]", + returned: [], error: null, }, { @@ -144,9 +140,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "[u8,u8]", - returned: [], userQuery: "[u8,u8]", + returned: [], error: null, }, { @@ -180,9 +175,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "[u8]", - returned: [], userQuery: "[u8]", + returned: [], error: null, }, { @@ -198,90 +192,80 @@ const PARSED = [ }, ], foundElems: 1, - original: "[]", - returned: [], userQuery: "[]", + returned: [], error: null, }, { query: '[>', elems: [], foundElems: 0, - original: "[>", - returned: [], userQuery: "[>", + returned: [], error: "Unexpected `>` after `[`", }, { query: '[<', elems: [], foundElems: 0, - original: "[<", - returned: [], userQuery: "[<", + returned: [], error: "Found generics without a path", }, { query: '[a>', elems: [], foundElems: 0, - original: "[a>", - returned: [], userQuery: "[a>", + returned: [], error: "Unexpected `>` after `[`", }, { query: '[a<', elems: [], foundElems: 0, - original: "[a<", - returned: [], userQuery: "[a<", + returned: [], error: "Unclosed `<`", }, { query: '[a', elems: [], foundElems: 0, - original: "[a", - returned: [], userQuery: "[a", + returned: [], error: "Unclosed `[`", }, { query: '[', elems: [], foundElems: 0, - original: "[", - returned: [], userQuery: "[", + returned: [], error: "Unclosed `[`", }, { query: ']', elems: [], foundElems: 0, - original: "]", - returned: [], userQuery: "]", + returned: [], error: "Unexpected `]`", }, { query: '[a', elems: [], foundElems: 0, - original: "[a", - returned: [], userQuery: "[a", + returned: [], error: "Unclosed `[`", }, { query: 'a]', elems: [], foundElems: 0, - original: "a]", - returned: [], userQuery: "a]", + returned: [], error: "Unexpected `]` after `>`", }, { @@ -306,18 +290,16 @@ const PARSED = [ }, ], foundElems: 1, - original: "primitive:[u8]", - returned: [], userQuery: "primitive:[u8]", + returned: [], error: null, }, { query: 'macro:[u8]', elems: [], foundElems: 0, - original: "macro:[u8]", - returned: [], userQuery: "macro:[u8]", + returned: [], error: "Invalid search type: primitive `[]` and `macro` both specified", }, ]; diff --git a/tests/rustdoc-js-std/parser-tuple.js b/tests/rustdoc-js-std/parser-tuple.js index eb16289d3c055..6192506838708 100644 --- a/tests/rustdoc-js-std/parser-tuple.js +++ b/tests/rustdoc-js-std/parser-tuple.js @@ -3,9 +3,8 @@ const PARSED = [ query: '(((D, ()))', elems: [], foundElems: 0, - original: '(((D, ()))', + userQuery: '(((D, ()))', returned: [], - userQuery: '(((d, ()))', error: 'Unclosed `(`', }, { @@ -18,7 +17,7 @@ const PARSED = [ pathLast: "()", generics: [ { - name: "d", + name: "D", fullPath: ["d"], pathWithoutLast: [], pathLast: "d", @@ -38,9 +37,8 @@ const PARSED = [ } ], foundElems: 1, - original: '(((D, ())))', + userQuery: '(((D, ())))', returned: [], - userQuery: '(((d, ())))', error: null, }, { @@ -64,9 +62,8 @@ const PARSED = [ }, ], foundElems: 2, - original: "(),u8", - returned: [], userQuery: "(),u8", + returned: [], error: null, }, // Parens act as grouping operators when: @@ -88,9 +85,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "(u8)", - returned: [], userQuery: "(u8)", + returned: [], error: null, }, { @@ -115,9 +111,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "(u8,)", - returned: [], userQuery: "(u8,)", + returned: [], error: null, }, { @@ -142,9 +137,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "(,u8)", - returned: [], userQuery: "(,u8)", + returned: [], error: null, }, { @@ -169,9 +163,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "primitive:(u8)", - returned: [], userQuery: "primitive:(u8)", + returned: [], error: null, }, { @@ -187,9 +180,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "(primitive:u8)", - returned: [], userQuery: "(primitive:u8)", + returned: [], error: null, }, { @@ -222,9 +214,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "(u8,u8)", - returned: [], userQuery: "(u8,u8)", + returned: [], error: null, }, { @@ -249,9 +240,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "(u8)", - returned: [], userQuery: "(u8)", + returned: [], error: null, }, { @@ -267,99 +257,88 @@ const PARSED = [ }, ], foundElems: 1, - original: "()", - returned: [], userQuery: "()", + returned: [], error: null, }, { query: '(>', elems: [], foundElems: 0, - original: "(>", - returned: [], userQuery: "(>", + returned: [], error: "Unexpected `>` after `(`", }, { query: '(<', elems: [], foundElems: 0, - original: "(<", - returned: [], userQuery: "(<", + returned: [], error: "Found generics without a path", }, { query: '(a>', elems: [], foundElems: 0, - original: "(a>", - returned: [], userQuery: "(a>", + returned: [], error: "Unexpected `>` after `(`", }, { query: '(a<', elems: [], foundElems: 0, - original: "(a<", - returned: [], userQuery: "(a<", + returned: [], error: "Unclosed `<`", }, { query: '(a', elems: [], foundElems: 0, - original: "(a", - returned: [], userQuery: "(a", + returned: [], error: "Unclosed `(`", }, { query: '(', elems: [], foundElems: 0, - original: "(", - returned: [], userQuery: "(", + returned: [], error: "Unclosed `(`", }, { query: ')', elems: [], foundElems: 0, - original: ")", - returned: [], userQuery: ")", + returned: [], error: "Unexpected `)`", }, { query: '(a', elems: [], foundElems: 0, - original: "(a", - returned: [], userQuery: "(a", + returned: [], error: "Unclosed `(`", }, { query: 'a)', elems: [], foundElems: 0, - original: "a)", - returned: [], userQuery: "a)", + returned: [], error: "Unexpected `)` after `>`", }, { query: 'macro:(u8)', elems: [], foundElems: 0, - original: "macro:(u8)", - returned: [], userQuery: "macro:(u8)", + returned: [], error: "Invalid search type: primitive `()` and `macro` both specified", }, ]; diff --git a/tests/rustdoc-js-std/parser-weird-queries.js b/tests/rustdoc-js-std/parser-weird-queries.js index 499b82a346948..828b0a7d9f66a 100644 --- a/tests/rustdoc-js-std/parser-weird-queries.js +++ b/tests/rustdoc-js-std/parser-weird-queries.js @@ -15,9 +15,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "a b", - returned: [], userQuery: "a b", + returned: [], error: null, }, { @@ -32,9 +31,8 @@ const PARSED = [ }, ], foundElems: 1, - original: "a b", - returned: [], userQuery: "a b", + returned: [], error: null, }, { @@ -56,36 +54,32 @@ const PARSED = [ }, ], foundElems: 2, - original: "aaa,a", - returned: [], userQuery: "aaa,a", + returned: [], error: null, }, { query: ',,,,', elems: [], foundElems: 0, - original: ",,,,", - returned: [], userQuery: ",,,,", + returned: [], error: null, }, { query: 'mod :', elems: [], foundElems: 0, - original: 'mod :', - returned: [], userQuery: 'mod :', + returned: [], error: "Unexpected `:` (expected path after type filter `mod:`)", }, { query: 'mod\t:', elems: [], foundElems: 0, - original: 'mod :', - returned: [], userQuery: 'mod :', + returned: [], error: "Unexpected `:` (expected path after type filter `mod:`)", }, ]; diff --git a/tests/rustdoc-js/non-english-identifier.js b/tests/rustdoc-js/non-english-identifier.js index 1765a69152a8f..6a2c4cc637c96 100644 --- a/tests/rustdoc-js/non-english-identifier.js +++ b/tests/rustdoc-js/non-english-identifier.js @@ -11,30 +11,29 @@ const PARSED = [ }], returned: [], foundElems: 1, - original: "中文", userQuery: "中文", error: null, }, { query: '_0Mixed中英文', elems: [{ - name: "_0mixed中英文", + name: "_0Mixed中英文", fullPath: ["_0mixed中英文"], pathWithoutLast: [], pathLast: "_0mixed中英文", + normalizedPathLast: "0mixed中英文", generics: [], typeFilter: -1, }], foundElems: 1, - original: "_0Mixed中英文", + userQuery: "_0Mixed中英文", returned: [], - userQuery: "_0mixed中英文", error: null, }, { query: 'my_crate::中文API', elems: [{ - name: "my_crate::中文api", + name: "my_crate::中文API", fullPath: ["my_crate", "中文api"], pathWithoutLast: ["my_crate"], pathLast: "中文api", @@ -42,26 +41,25 @@ const PARSED = [ typeFilter: -1, }], foundElems: 1, - original: "my_crate::中文API", + userQuery: "my_crate::中文API", returned: [], - userQuery: "my_crate::中文api", error: null, }, { query: '类型A,类型B<约束C>->返回类型<关联类型=路径::约束D>', elems: [{ - name: "类型a", + name: "类型A", fullPath: ["类型a"], pathWithoutLast: [], pathLast: "类型a", generics: [], }, { - name: "类型b", + name: "类型B", fullPath: ["类型b"], pathWithoutLast: [], pathLast: "类型b", generics: [{ - name: "约束c", + name: "约束C", fullPath: ["约束c"], pathWithoutLast: [], pathLast: "约束c", @@ -71,15 +69,21 @@ const PARSED = [ foundElems: 3, totalElems: 5, literalSearch: true, - original: "类型A,类型B<约束C>->返回类型<关联类型=路径::约束D>", + userQuery: "类型A,类型B<约束C>->返回类型<关联类型=路径::约束D>", returned: [{ name: "返回类型", fullPath: ["返回类型"], pathWithoutLast: [], pathLast: "返回类型", generics: [], + bindings: [["关联类型", [{ + name: "路径::约束D", + fullPath: ["路径", "约束d"], + pathWithoutLast: ["路径"], + pathLast: "约束d", + generics: [], + }]]], }], - userQuery: "类型a,类型b<约束c>->返回类型<关联类型=路径::约束d>", error: null, }, { @@ -93,18 +97,16 @@ const PARSED = [ typeFilter: 16, }], foundElems: 1, - original: "my_crate 中文宏!", - returned: [], userQuery: "my_crate 中文宏!", + returned: [], error: null, }, { query: '非法符号——', elems: [], foundElems: 0, - original: "非法符号——", - returned: [], userQuery: "非法符号——", + returned: [], error: "Unexpected `—` after `号` (not a valid identifier)", } ] From 5973005d93c182fe38c79449ec87e968dc23de62 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 24 Sep 2024 12:36:05 -0700 Subject: [PATCH 13/79] rustdoc-search: use correct type annotations --- src/librustdoc/html/static/js/externs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js index 3d3e0a8f8381c..fe66c8536b715 100644 --- a/src/librustdoc/html/static/js/externs.js +++ b/src/librustdoc/html/static/js/externs.js @@ -9,12 +9,12 @@ function initSearch(searchIndex){} /** * @typedef {{ * name: string, - * id: integer|null, + * id: number|null, * fullPath: Array, * pathWithoutLast: Array, * pathLast: string, * generics: Array, - * bindings: Map>, + * bindings: Map>, * }} */ let QueryElement; From 20a4b4fea1e5f3005973ae1391b039722d207119 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 24 Sep 2024 14:31:44 -0700 Subject: [PATCH 14/79] rustdoc-search: show types signatures in results --- src/librustdoc/html/static/css/rustdoc.css | 21 +- src/librustdoc/html/static/js/externs.js | 3 + src/librustdoc/html/static/js/search.js | 688 ++++++++++++++++-- src/tools/rustdoc-js/tester.js | 54 +- .../rustdoc-gui/search-about-this-result.goml | 42 ++ .../rustdoc-js-std/option-type-signatures.js | 174 ++++- tests/rustdoc-js/assoc-type-unbound.js | 39 + tests/rustdoc-js/assoc-type-unbound.rs | 4 + tests/rustdoc-js/assoc-type.js | 48 +- tests/rustdoc-js/generics-trait.js | 48 +- 10 files changed, 995 insertions(+), 126 deletions(-) create mode 100644 tests/rustdoc-gui/search-about-this-result.goml create mode 100644 tests/rustdoc-js/assoc-type-unbound.js create mode 100644 tests/rustdoc-js/assoc-type-unbound.rs diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 1042d254749e3..66a8a19892886 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -264,6 +264,7 @@ a.anchor, .mobile-topbar h2 a, h1 a, .search-results a, +.search-results li, .stab, .result-name i { color: var(--main-color); @@ -379,7 +380,7 @@ details:not(.toggle) summary { margin-bottom: .6em; } -code, pre, .code-header { +code, pre, .code-header, .type-signature { font-family: "Source Code Pro", monospace; } .docblock code, .docblock-short code { @@ -1205,22 +1206,28 @@ so that we can apply CSS-filters to change the arrow color in themes */ .search-results.active { display: block; + margin: 0; + padding: 0; } .search-results > a { - display: flex; + display: grid; + grid-template-areas: + "search-result-name search-result-desc" + "search-result-type-signature search-result-type-signature"; + grid-template-columns: .6fr .4fr; /* A little margin ensures the browser's outlining of focused links has room to display. */ margin-left: 2px; margin-right: 2px; border-bottom: 1px solid var(--search-result-border-color); - gap: 1em; + column-gap: 1em; } .search-results > a > div.desc { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; - flex: 2; + grid-area: search-result-desc; } .search-results a:hover, @@ -1232,7 +1239,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ display: flex; align-items: center; justify-content: start; - flex: 3; + grid-area: search-result-name; } .search-results .result-name .alias { color: var(--search-results-alias-color); @@ -1253,6 +1260,10 @@ so that we can apply CSS-filters to change the arrow color in themes */ .search-results .result-name .path > * { display: inline; } +.search-results .type-signature { + grid-area: search-result-type-signature; + white-space: pre-wrap; +} .popover { position: absolute; diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js index fe66c8536b715..c4faca1c0c3bc 100644 --- a/src/librustdoc/html/static/js/externs.js +++ b/src/librustdoc/html/static/js/externs.js @@ -92,6 +92,9 @@ let Results; * parent: (Object|undefined), * path: string, * ty: number, + * type: FunctionSearchType?, + * displayType: Promise>>|null, + * displayTypeMappedNames: Promise]>>|null, * }} */ let ResultObject; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index a4471f1d885a4..0458b81d35257 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -15,7 +15,16 @@ if (!Array.prototype.toSpliced) { }; } -(function() { +function onEachBtwn(arr, func, funcBtwn) { + let skipped = true; + for (const value of arr) { + if (!skipped) { + funcBtwn(value); + } + skipped = func(value); + } +} + // ==================== Core search logic begin ==================== // This mapping table should match the discriminants of // `rustdoc::formats::item_type::ItemType` type in Rust. @@ -50,8 +59,10 @@ const itemTypes = [ ]; // used for special search precedence +const TY_PRIMITIVE = itemTypes.indexOf("primitive"); const TY_GENERIC = itemTypes.indexOf("generic"); const TY_IMPORT = itemTypes.indexOf("import"); +const TY_TRAIT = itemTypes.indexOf("trait"); const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../"; // Hard limit on how deep to recurse into generics when doing type-driven search. @@ -1117,6 +1128,13 @@ class DocSearch { * @type {Map} */ this.typeNameIdMap = new Map(); + /** + * Map from type ID to associated type name. Used for display, + * not for search. + * + * @type {Map} + */ + this.assocTypeIdNameMap = new Map(); this.ALIASES = new Map(); this.rootPath = rootPath; this.searchState = searchState; @@ -1161,6 +1179,14 @@ class DocSearch { * Special type name IDs for searching higher order functions (`->` syntax). */ this.typeNameIdOfHof = this.buildTypeMapIndex("->"); + /** + * Special type name IDs the output assoc type. + */ + this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true); + /** + * Special type name IDs for searching by reference. + */ + this.typeNameIdOfReference = this.buildTypeMapIndex("reference"); /** * Empty, immutable map used in item search types with no bindings. @@ -1237,9 +1263,9 @@ class DocSearch { * * @return {Array} */ - buildItemSearchTypeAll(types, lowercasePaths) { + buildItemSearchTypeAll(types, paths, lowercasePaths) { return types.length > 0 ? - types.map(type => this.buildItemSearchType(type, lowercasePaths)) : + types.map(type => this.buildItemSearchType(type, paths, lowercasePaths)) : this.EMPTY_GENERICS_ARRAY; } @@ -1248,7 +1274,7 @@ class DocSearch { * * @param {RawFunctionType} type */ - buildItemSearchType(type, lowercasePaths, isAssocType) { + buildItemSearchType(type, paths, lowercasePaths, isAssocType) { const PATH_INDEX_DATA = 0; const GENERICS_DATA = 1; const BINDINGS_DATA = 2; @@ -1261,6 +1287,7 @@ class DocSearch { pathIndex = type[PATH_INDEX_DATA]; generics = this.buildItemSearchTypeAll( type[GENERICS_DATA], + paths, lowercasePaths, ); if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) { @@ -1277,8 +1304,8 @@ class DocSearch { // // As a result, the key should never have generics on it. return [ - this.buildItemSearchType(assocType, lowercasePaths, true).id, - this.buildItemSearchTypeAll(constraints, lowercasePaths), + this.buildItemSearchType(assocType, paths, lowercasePaths, true).id, + this.buildItemSearchTypeAll(constraints, paths, lowercasePaths), ]; })); } else { @@ -1294,6 +1321,7 @@ class DocSearch { // the actual names of generic parameters aren't stored, since they aren't API result = { id: pathIndex, + name: "", ty: TY_GENERIC, path: null, exactPath: null, @@ -1304,6 +1332,7 @@ class DocSearch { // `0` is used as a sentinel because it's fewer bytes than `null` result = { id: null, + name: "", ty: null, path: null, exactPath: null, @@ -1312,8 +1341,13 @@ class DocSearch { }; } else { const item = lowercasePaths[pathIndex - 1]; + const id = this.buildTypeMapIndex(item.name, isAssocType); + if (isAssocType) { + this.assocTypeIdNameMap.set(id, paths[pathIndex - 1].name); + } result = { - id: this.buildTypeMapIndex(item.name, isAssocType), + id, + name: paths[pathIndex - 1].name, ty: item.ty, path: item.path, exactPath: item.exactPath, @@ -1355,7 +1389,7 @@ class DocSearch { } if (cr.ty === result.ty && cr.path === result.path && cr.bindings === result.bindings && cr.generics === result.generics - && cr.ty === result.ty + && cr.ty === result.ty && cr.name === result.name ) { return cr; } @@ -1466,11 +1500,12 @@ class DocSearch { * The raw function search type format is generated using serde in * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string * + * @param {Array<{name: string, ty: number}>} paths * @param {Array<{name: string, ty: number}>} lowercasePaths * * @return {null|FunctionSearchType} */ - const buildFunctionSearchTypeCallback = lowercasePaths => { + const buildFunctionSearchTypeCallback = (paths, lowercasePaths) => { return functionSearchType => { if (functionSearchType === 0) { return null; @@ -1480,11 +1515,16 @@ class DocSearch { let inputs, output; if (typeof functionSearchType[INPUTS_DATA] === "number") { inputs = [ - this.buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths), + this.buildItemSearchType( + functionSearchType[INPUTS_DATA], + paths, + lowercasePaths, + ), ]; } else { inputs = this.buildItemSearchTypeAll( functionSearchType[INPUTS_DATA], + paths, lowercasePaths, ); } @@ -1493,12 +1533,14 @@ class DocSearch { output = [ this.buildItemSearchType( functionSearchType[OUTPUT_DATA], + paths, lowercasePaths, ), ]; } else { output = this.buildItemSearchTypeAll( functionSearchType[OUTPUT_DATA], + paths, lowercasePaths, ); } @@ -1509,8 +1551,12 @@ class DocSearch { const l = functionSearchType.length; for (let i = 2; i < l; ++i) { where_clause.push(typeof functionSearchType[i] === "number" - ? [this.buildItemSearchType(functionSearchType[i], lowercasePaths)] - : this.buildItemSearchTypeAll(functionSearchType[i], lowercasePaths)); + ? [this.buildItemSearchType(functionSearchType[i], paths, lowercasePaths)] + : this.buildItemSearchTypeAll( + functionSearchType[i], + paths, + lowercasePaths, + )); } return { inputs, output, where_clause, @@ -1554,6 +1600,13 @@ class DocSearch { this.searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e)); let descIndex = 0; + /** + * List of generic function type parameter names. + * Used for display, not for searching. + * @type {[string]} + */ + let lastParamNames = []; + // This object should have exactly the same set of fields as the "row" // object defined below. Your JavaScript runtime will thank you. // https://mathiasbynens.be/notes/shapes-ics @@ -1568,6 +1621,7 @@ class DocSearch { desc: crateCorpus.doc, parent: undefined, type: null, + paramNames: lastParamNames, id, word: crate, normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""), @@ -1604,6 +1658,10 @@ class DocSearch { // an array of [(String) alias name // [Number] index to items] const aliases = crateCorpus.a; + // an array of [(Number) item index, + // (String) comma-separated list of function generic param names] + // an item whose index is not present will fall back to the previous present path + const itemParamNames = new Map(crateCorpus.P); // an array of [{name: String, ty: Number}] const lowercasePaths = []; @@ -1611,7 +1669,7 @@ class DocSearch { // a string representing the list of function types const itemFunctionDecoder = new VlqHexDecoder( crateCorpus.f, - buildFunctionSearchTypeCallback(lowercasePaths), + buildFunctionSearchTypeCallback(paths, lowercasePaths), ); // convert `rawPaths` entries into object form @@ -1662,6 +1720,9 @@ class DocSearch { const name = itemNames[i] === "" ? lastName : itemNames[i]; const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase(); const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath; + const paramNames = itemParamNames.has(i) ? + itemParamNames.get(i).split(",") : + lastParamNames; const type = itemFunctionDecoder.next(); if (type !== null) { if (type) { @@ -1694,6 +1755,7 @@ class DocSearch { itemPaths.get(itemReexports.get(i)) : path, parent: itemParentIdx > 0 ? paths[itemParentIdx - 1] : undefined, type, + paramNames, id, word, normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""), @@ -1704,6 +1766,7 @@ class DocSearch { id += 1; searchIndex.push(row); lastPath = row.path; + lastParamNames = row.paramNames; if (!this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) { descIndex += 1; } @@ -2048,18 +2111,21 @@ class DocSearch { * marked for removal. * * @param {[ResultObject]} results + * @param {"sig"|"elems"|"returned"|null} typeInfo + * @param {ParsedQuery} query * @returns {[ResultObject]} */ - const transformResults = results => { + const transformResults = (results, typeInfo) => { const duplicates = new Set(); const out = []; for (const result of results) { if (result.id !== -1) { - const obj = this.searchIndex[result.id]; - obj.dist = result.dist; - const res = buildHrefAndPath(obj); - obj.displayPath = pathSplitter(res[0]); + const res = buildHrefAndPath(this.searchIndex[result.id]); + const obj = Object.assign({ + dist: result.dist, + displayPath: pathSplitter(res[0]), + }, this.searchIndex[result.id]); // To be sure than it some items aren't considered as duplicate. obj.fullPath = res[2] + "|" + obj.ty; @@ -2078,6 +2144,11 @@ class DocSearch { duplicates.add(obj.fullPath); duplicates.add(res[2]); + if (typeInfo !== null) { + obj.displayTypeSignature = + this.formatDisplayTypeSignature(obj, typeInfo); + } + obj.href = res[1]; out.push(obj); if (out.length >= MAX_RESULTS) { @@ -2088,6 +2159,327 @@ class DocSearch { return out; }; + /** + * Add extra data to result objects, and filter items that have been + * marked for removal. + * + * The output is formatted as an array of hunks, where odd numbered + * hunks are highlighted and even numbered ones are not. + * + * @param {ResultObject} obj + * @param {"sig"|"elems"|"returned"|null} typeInfo + * @param {ParsedQuery} query + * @returns Promise< + * "type": Array, + * "mappedNames": Map, + * "whereClause": Map>, + * > + */ + this.formatDisplayTypeSignature = async(obj, typeInfo) => { + let fnInputs = null; + let fnOutput = null; + let mgens = null; + if (typeInfo !== "elems" && typeInfo !== "returned") { + fnInputs = unifyFunctionTypes( + obj.type.inputs, + parsedQuery.elems, + obj.type.where_clause, + null, + mgensScratch => { + fnOutput = unifyFunctionTypes( + obj.type.output, + parsedQuery.returned, + obj.type.where_clause, + mgensScratch, + mgensOut => { + mgens = mgensOut; + return true; + }, + 0, + ); + return !!fnOutput; + }, + 0, + ); + } else { + const arr = typeInfo === "elems" ? obj.type.inputs : obj.type.output; + const highlighted = unifyFunctionTypes( + arr, + parsedQuery.elems, + obj.type.where_clause, + null, + mgensOut => { + mgens = mgensOut; + return true; + }, + 0, + ); + if (typeInfo === "elems") { + fnInputs = highlighted; + } else { + fnOutput = highlighted; + } + } + if (!fnInputs) { + fnInputs = obj.type.inputs; + } + if (!fnOutput) { + fnOutput = obj.type.output; + } + const mappedNames = new Map(); + const whereClause = new Map(); + + const fnParamNames = obj.paramNames; + const queryParamNames = []; + /** + * Recursively writes a map of IDs to query generic names, + * which are later used to map query generic names to function generic names. + * For example, when the user writes `X -> Option` and the function + * is actually written as `T -> Option`, this function stores the + * mapping `(-1, "X")`, and the writeFn function looks up the entry + * for -1 to form the final, user-visible mapping of "X is T". + * + * @param {QueryElement} queryElem + */ + const remapQuery = queryElem => { + if (queryElem.id < 0) { + queryParamNames[-1 - queryElem.id] = queryElem.name; + } + if (queryElem.generics.length > 0) { + queryElem.generics.forEach(remapQuery); + } + if (queryElem.bindings.size > 0) { + [...queryElem.bindings.values()].flat().forEach(remapQuery); + } + }; + + parsedQuery.elems.forEach(remapQuery); + parsedQuery.returned.forEach(remapQuery); + + /** + * Write text to a highlighting array. + * Index 0 is not highlighted, index 1 is highlighted, + * index 2 is not highlighted, etc. + * + * @param {{name: string, highlighted: bool|undefined}} fnType - input + * @param {[string]} result + */ + const pushText = (fnType, result) => { + // If !!(result.length % 2) == false, then pushing a new slot starts an even + // numbered slot. Even numbered slots are not highlighted. + // + // `highlighted` will not be defined if an entire subtree is not highlighted, + // so `!!` is used to coerce it to boolean. `result.length % 2` is used to + // check if the number is even, but it evaluates to a number, so it also + // needs coerced to a boolean. + if (!!(result.length % 2) === !!fnType.highlighted) { + result.push(""); + } else if (result.length === 0 && !!fnType.highlighted) { + result.push(""); + result.push(""); + } + + result[result.length - 1] += fnType.name; + }; + + /** + * Write a higher order function type: either a function pointer + * or a trait bound on Fn, FnMut, or FnOnce. + * + * @param {FunctionType} fnType - input + * @param {[string]} result + */ + const writeHof = (fnType, result) => { + const hofOutput = fnType.bindings.get(this.typeNameIdOfOutput) || []; + const hofInputs = fnType.generics; + pushText(fnType, result); + pushText({name: " (", highlighted: false}, result); + let needsComma = false; + for (const fnType of hofInputs) { + if (needsComma) { + pushText({ name: ", ", highlighted: false }, result); + } + needsComma = true; + writeFn(fnType, result); + } + pushText({ + name: hofOutput.length === 0 ? ")" : ") -> ", + highlighted: false, + }, result); + if (hofOutput.length > 1) { + pushText({name: "(", highlighted: false}, result); + } + needsComma = false; + for (const fnType of hofOutput) { + if (needsComma) { + pushText({ name: ", ", highlighted: false }, result); + } + needsComma = true; + writeFn(fnType, result); + } + if (hofOutput.length > 1) { + pushText({name: ")", highlighted: false}, result); + } + }; + + /** + * Write a primitive type with special syntax, like `!` or `[T]`. + * Returns `false` if the supplied type isn't special. + * + * @param {FunctionType} fnType + * @param {[string]} result + */ + const writeSpecialPrimitive = (fnType, result) => { + if (fnType.id === this.typeNameIdOfArray || fnType.id === this.typeNameIdOfSlice || + fnType.id === this.typeNameIdOfTuple || fnType.id === this.typeNameIdOfUnit) { + const [ob, sb] = + fnType.id === this.typeNameIdOfArray || + fnType.id === this.typeNameIdOfSlice ? + ["[", "]"] : + ["(", ")"]; + pushText({ name: ob, highlighted: fnType.highlighted }, result); + onEachBtwn( + fnType.generics, + nested => writeFn(nested, result), + () => pushText({ name: ", ", highlighted: false }, result), + ); + pushText({ name: sb, highlighted: fnType.highlighted }, result); + return true; + } else if (fnType.id === this.typeNameIdOfReference) { + pushText({ name: "&", highlighted: fnType.highlighted }, result); + let prevHighlighted = false; + onEachBtwn( + fnType.generics, + value => { + prevHighlighted = value.highlighted; + writeFn(value, result); + }, + value => pushText({ + name: " ", + highlighted: prevHighlighted && value.highlighted, + }, result), + ); + return true; + } else if (fnType.id === this.typeNameIdOfFn) { + writeHof(fnType, result); + return true; + } + return false; + }; + /** + * Write a type. This function checks for special types, + * like slices, with their own formatting. It also handles + * updating the where clause and generic type param map. + * + * @param {FunctionType} fnType + * @param {[string]} result + */ + const writeFn = (fnType, result) => { + if (fnType.id < 0) { + const queryId = mgens && mgens.has(fnType.id) ? mgens.get(fnType.id) : null; + if (fnParamNames[-1 - fnType.id] === "") { + for (const nested of fnType.generics) { + writeFn(nested, result); + } + return; + } else if (queryId < 0) { + mappedNames.set( + fnParamNames[-1 - fnType.id], + queryParamNames[-1 - queryId], + ); + } + pushText({ + name: fnParamNames[-1 - fnType.id], + highlighted: !!fnType.highlighted, + }, result); + const where = []; + onEachBtwn( + fnType.generics, + nested => writeFn(nested, where), + () => pushText({ name: " + ", highlighted: false }, where), + ); + if (where.length > 0) { + whereClause.set(fnParamNames[-1 - fnType.id], where); + } + } else { + if (fnType.ty === TY_PRIMITIVE) { + if (writeSpecialPrimitive(fnType, result)) { + return; + } + } else if (fnType.ty === TY_TRAIT && ( + fnType.id === this.typeNameIdOfFn || + fnType.id === this.typeNameIdOfFnMut || + fnType.id === this.typeNameIdOfFnOnce)) { + writeHof(fnType, result); + return; + } + pushText(fnType, result); + let hasBindings = false; + if (fnType.bindings.size > 0) { + onEachBtwn( + fnType.bindings, + ([key, values]) => { + const name = this.assocTypeIdNameMap.get(key); + if (values.length === 1 && values[0].id < 0 && + `${fnType.name}::${name}` === fnParamNames[-1 - values[0].id]) { + // the internal `Item=Iterator::Item` type variable should be + // shown in the where clause and name mapping output, but is + // redundant in this spot + for (const value of values) { + writeFn(value, []); + } + return true; + } + if (!hasBindings) { + hasBindings = true; + pushText({ name: "<", highlighted: false }, result); + } + pushText({ name, highlighted: false }, result); + pushText({ + name: values.length > 1 ? "=(" : "=", + highlighted: false, + }, result); + onEachBtwn( + values, + value => writeFn(value, result), + () => pushText({ name: " + ", highlighted: false }, result), + ); + if (values.length > 1) { + pushText({ name: ")", highlighted: false }, result); + } + }, + () => pushText({ name: ", ", highlighted: false }, result), + ); + } + if (fnType.generics.length > 0) { + pushText({ name: hasBindings ? ", " : "<", highlighted: false }, result); + } + onEachBtwn( + fnType.generics, + value => writeFn(value, result), + () => pushText({ name: ", ", highlighted: false }, result), + ); + if (hasBindings || fnType.generics.length > 0) { + pushText({ name: ">", highlighted: false }, result); + } + } + }; + const type = []; + onEachBtwn( + fnInputs, + fnType => writeFn(fnType, type), + () => pushText({ name: ", ", highlighted: false }, type), + ); + pushText({ name: " -> ", highlighted: false }, type); + onEachBtwn( + fnOutput, + fnType => writeFn(fnType, type), + () => pushText({ name: ", ", highlighted: false }, type), + ); + + return {type, mappedNames, whereClause}; + }; + /** * This function takes a result map, and sorts it by various criteria, including edit * distance, substring match, and the crate it comes from. @@ -2097,7 +2489,7 @@ class DocSearch { * @param {string} preferredCrate * @returns {Promise<[ResultObject]>} */ - const sortResults = async(results, isType, preferredCrate) => { + const sortResults = async(results, typeInfo, preferredCrate) => { const userQuery = parsedQuery.userQuery; const normalizedUserQuery = parsedQuery.userQuery.toLowerCase(); const result_list = []; @@ -2207,17 +2599,17 @@ class DocSearch { return 0; }); - return transformResults(result_list); + return transformResults(result_list, typeInfo); }; /** * This function checks if a list of search query `queryElems` can all be found in the * search index (`fnTypes`). * - * This function returns `true` on a match, or `false` if none. If `solutionCb` is + * This function returns highlighted results on a match, or `null`. If `solutionCb` is * supplied, it will call that function with mgens, and that callback can accept or - * reject the result bu returning `true` or `false`. If the callback returns false, - * then this function will try with a different solution, or bail with false if it + * reject the result by returning `true` or `false`. If the callback returns false, + * then this function will try with a different solution, or bail with null if it * runs out of candidates. * * @param {Array} fnTypesIn - The objects to check. @@ -2230,7 +2622,7 @@ class DocSearch { * - Limit checks that Ty matches Vec, * but not Vec>>>> * - * @return {boolean} - Returns true if a match, false otherwise. + * @return {[FunctionType]|null} - Returns highlighed results if a match, null otherwise. */ function unifyFunctionTypes( fnTypesIn, @@ -2241,17 +2633,17 @@ class DocSearch { unboxingDepth, ) { if (unboxingDepth >= UNBOXING_LIMIT) { - return false; + return null; } /** * @type Map|null */ const mgens = mgensIn === null ? null : new Map(mgensIn); if (queryElems.length === 0) { - return !solutionCb || solutionCb(mgens); + return (!solutionCb || solutionCb(mgens)) ? fnTypesIn : null; } if (!fnTypesIn || fnTypesIn.length === 0) { - return false; + return null; } const ql = queryElems.length; const fl = fnTypesIn.length; @@ -2260,7 +2652,7 @@ class DocSearch { if (ql === 1 && queryElems[0].generics.length === 0 && queryElems[0].bindings.size === 0) { const queryElem = queryElems[0]; - for (const fnType of fnTypesIn) { + for (const [i, fnType] of fnTypesIn.entries()) { if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) { continue; } @@ -2272,14 +2664,33 @@ class DocSearch { const mgensScratch = new Map(mgens); mgensScratch.set(fnType.id, queryElem.id); if (!solutionCb || solutionCb(mgensScratch)) { - return true; + const highlighted = [...fnTypesIn]; + highlighted[i] = Object.assign({ + highlighted: true, + }, fnType, { + generics: whereClause[-1 - fnType.id], + }); + return highlighted; } } else if (!solutionCb || solutionCb(mgens ? new Map(mgens) : null)) { // unifyFunctionTypeIsMatchCandidate already checks that ids match - return true; + const highlighted = [...fnTypesIn]; + highlighted[i] = Object.assign({ + highlighted: true, + }, fnType, { + generics: unifyFunctionTypes( + fnType.generics, + queryElem.generics, + whereClause, + mgens ? new Map(mgens) : null, + solutionCb, + unboxingDepth, + ) || fnType.generics, + }); + return highlighted; } } - for (const fnType of fnTypesIn) { + for (const [i, fnType] of fnTypesIn.entries()) { if (!unifyFunctionTypeIsUnboxCandidate( fnType, queryElem, @@ -2296,25 +2707,42 @@ class DocSearch { } const mgensScratch = new Map(mgens); mgensScratch.set(fnType.id, 0); - if (unifyFunctionTypes( + const highlightedGenerics = unifyFunctionTypes( whereClause[(-fnType.id) - 1], queryElems, whereClause, mgensScratch, solutionCb, unboxingDepth + 1, - )) { - return true; + ); + if (highlightedGenerics) { + const highlighted = [...fnTypesIn]; + highlighted[i] = Object.assign({ + highlighted: true, + }, fnType, { + generics: highlightedGenerics, + }); + return highlighted; + } + } else { + const highlightedGenerics = unifyFunctionTypes( + [...Array.from(fnType.bindings.values()).flat(), ...fnType.generics], + queryElems, + whereClause, + mgens ? new Map(mgens) : null, + solutionCb, + unboxingDepth + 1, + ); + if (highlightedGenerics) { + const highlighted = [...fnTypesIn]; + highlighted[i] = Object.assign({}, fnType, { + generics: highlightedGenerics, + bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => { + return [k, highlightedGenerics.splice(0, v.length)]; + })), + }); + return highlighted; } - } else if (unifyFunctionTypes( - [...fnType.generics, ...Array.from(fnType.bindings.values()).flat()], - queryElems, - whereClause, - mgens ? new Map(mgens) : null, - solutionCb, - unboxingDepth + 1, - )) { - return true; } } return false; @@ -2371,6 +2799,8 @@ class DocSearch { if (!queryElemsTmp) { queryElemsTmp = queryElems.slice(0, qlast); } + let unifiedGenerics = []; + let unifiedGenericsMgens = null; const passesUnification = unifyFunctionTypes( fnTypes, queryElemsTmp, @@ -2393,7 +2823,7 @@ class DocSearch { } const simplifiedGenerics = solution.simplifiedGenerics; for (const simplifiedMgens of solution.mgens) { - const passesUnification = unifyFunctionTypes( + unifiedGenerics = unifyFunctionTypes( simplifiedGenerics, queryElem.generics, whereClause, @@ -2401,7 +2831,8 @@ class DocSearch { solutionCb, unboxingDepth, ); - if (passesUnification) { + if (unifiedGenerics) { + unifiedGenericsMgens = simplifiedMgens; return true; } } @@ -2410,7 +2841,23 @@ class DocSearch { unboxingDepth, ); if (passesUnification) { - return true; + passesUnification.length = fl; + passesUnification[flast] = passesUnification[i]; + passesUnification[i] = Object.assign({}, fnType, { + highlighted: true, + generics: unifiedGenerics, + bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => { + return [k, queryElem.bindings.has(k) ? unifyFunctionTypes( + v, + queryElem.bindings.get(k), + whereClause, + unifiedGenericsMgens, + solutionCb, + unboxingDepth, + ) : unifiedGenerics.splice(0, v.length)]; + })), + }); + return passesUnification; } // backtrack fnTypes[flast] = fnTypes[i]; @@ -2445,7 +2892,7 @@ class DocSearch { Array.from(fnType.bindings.values()).flat() : []; const passesUnification = unifyFunctionTypes( - fnTypes.toSpliced(i, 1, ...generics, ...bindings), + fnTypes.toSpliced(i, 1, ...bindings, ...generics), queryElems, whereClause, mgensScratch, @@ -2453,10 +2900,24 @@ class DocSearch { unboxingDepth + 1, ); if (passesUnification) { - return true; + const highlightedGenerics = passesUnification.slice( + i, + i + generics.length + bindings.length, + ); + const highlightedFnType = Object.assign({}, fnType, { + generics: highlightedGenerics, + bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => { + return [k, highlightedGenerics.splice(0, v.length)]; + })), + }); + return passesUnification.toSpliced( + i, + generics.length + bindings.length, + highlightedFnType, + ); } } - return false; + return null; } /** * Check if this function is a match candidate. @@ -2627,7 +3088,7 @@ class DocSearch { } }); if (simplifiedGenerics.length > 0) { - simplifiedGenerics = [...simplifiedGenerics, ...binds]; + simplifiedGenerics = [...binds, ...simplifiedGenerics]; } else { simplifiedGenerics = binds; } @@ -3285,10 +3746,11 @@ class DocSearch { innerRunQuery(); } + const isType = parsedQuery.foundElems !== 1 || parsedQuery.hasReturnArrow; const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([ - sortResults(results_in_args, true, currentCrate), - sortResults(results_returned, true, currentCrate), - sortResults(results_others, false, currentCrate), + sortResults(results_in_args, "elems", currentCrate), + sortResults(results_returned, "returned", currentCrate), + sortResults(results_others, (isType ? "query" : null), currentCrate), ]); const ret = createQueryResults( sorted_in_args, @@ -3315,6 +3777,7 @@ class DocSearch { } } + // ==================== Core search logic end ==================== let rawSearchIndex; @@ -3446,15 +3909,18 @@ function focusSearchResult() { * @param {Array} array - The search results for this tab * @param {ParsedQuery} query * @param {boolean} display - True if this is the active tab + * @param {"sig"|"elems"|"returned"|null} typeInfo */ async function addTab(array, query, display) { const extraClass = display ? " active" : ""; - const output = document.createElement("div"); + const output = document.createElement( + array.length === 0 && query.error === null ? "div" : "ul", + ); if (array.length > 0) { output.className = "search-results " + extraClass; - for (const item of array) { + const lis = Promise.all(array.map(async item => { const name = item.name; const type = itemTypes[item.ty]; const longType = longItemTypes[item.ty]; @@ -3464,7 +3930,7 @@ async function addTab(array, query, display) { link.className = "result-" + type; link.href = item.href; - const resultName = document.createElement("div"); + const resultName = document.createElement("span"); resultName.className = "result-name"; resultName.insertAdjacentHTML( @@ -3487,10 +3953,73 @@ ${item.displayPath}${name}\ const description = document.createElement("div"); description.className = "desc"; description.insertAdjacentHTML("beforeend", item.desc); + if (item.displayTypeSignature) { + const {type, mappedNames, whereClause} = await item.displayTypeSignature; + const displayType = document.createElement("div"); + type.forEach((value, index) => { + if (index % 2 !== 0) { + const highlight = document.createElement("strong"); + highlight.appendChild(document.createTextNode(value)); + displayType.appendChild(highlight); + } else { + displayType.appendChild(document.createTextNode(value)); + } + }); + if (mappedNames.size > 0 || whereClause.size > 0) { + let addWhereLineFn = () => { + const line = document.createElement("div"); + line.className = "where"; + line.appendChild(document.createTextNode("where")); + displayType.appendChild(line); + addWhereLineFn = () => {}; + }; + for (const [name, qname] of mappedNames) { + // don't care unless the generic name is different + if (name === qname) { + continue; + } + addWhereLineFn(); + const line = document.createElement("div"); + line.className = "where"; + line.appendChild(document.createTextNode(` ${qname} matches `)); + const lineStrong = document.createElement("strong"); + lineStrong.appendChild(document.createTextNode(name)); + line.appendChild(lineStrong); + displayType.appendChild(line); + } + for (const [name, innerType] of whereClause) { + // don't care unless there's at least one highlighted entry + if (innerType.length <= 1) { + continue; + } + addWhereLineFn(); + const line = document.createElement("div"); + line.className = "where"; + line.appendChild(document.createTextNode(` ${name}: `)); + innerType.forEach((value, index) => { + if (index % 2 !== 0) { + const highlight = document.createElement("strong"); + highlight.appendChild(document.createTextNode(value)); + line.appendChild(highlight); + } else { + line.appendChild(document.createTextNode(value)); + } + }); + displayType.appendChild(line); + } + } + displayType.className = "type-signature"; + link.appendChild(displayType); + } link.appendChild(description); - output.appendChild(link); - } + return link; + })); + lis.then(lis => { + for (const li of lis) { + output.appendChild(li); + } + }); } else if (query.error === null) { output.className = "search-failed" + extraClass; output.innerHTML = "No results :(
" + @@ -3507,7 +4036,7 @@ ${item.displayPath}${name}\ "href=\"https://docs.rs\">Docs.rs
for documentation of crates released on" + " crates.io."; } - return [output, array.length]; + return output; } function makeTabHeader(tabNb, text, nbElems) { @@ -3564,24 +4093,18 @@ async function showResults(results, go_to_first, filterCrates) { currentResults = results.query.userQuery; - const [ret_others, ret_in_args, ret_returned] = await Promise.all([ - addTab(results.others, results.query, true), - addTab(results.in_args, results.query, false), - addTab(results.returned, results.query, false), - ]); - // Navigate to the relevant tab if the current tab is empty, like in case users search // for "-> String". If they had selected another tab previously, they have to click on // it again. let currentTab = searchState.currentTab; - if ((currentTab === 0 && ret_others[1] === 0) || - (currentTab === 1 && ret_in_args[1] === 0) || - (currentTab === 2 && ret_returned[1] === 0)) { - if (ret_others[1] !== 0) { + if ((currentTab === 0 && results.others.length === 0) || + (currentTab === 1 && results.in_args.length === 0) || + (currentTab === 2 && results.returned.length === 0)) { + if (results.others.length !== 0) { currentTab = 0; - } else if (ret_in_args[1] !== 0) { + } else if (results.in_args.length) { currentTab = 1; - } else if (ret_returned[1] !== 0) { + } else if (results.returned.length) { currentTab = 2; } } @@ -3610,14 +4133,14 @@ async function showResults(results, go_to_first, filterCrates) { }); output += `

Query parser error: "${error.join("")}".

`; output += "
" + - makeTabHeader(0, "In Names", ret_others[1]) + + makeTabHeader(0, "In Names", results.others.length) + "
"; currentTab = 0; } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) { output += "
" + - makeTabHeader(0, "In Names", ret_others[1]) + - makeTabHeader(1, "In Parameters", ret_in_args[1]) + - makeTabHeader(2, "In Return Types", ret_returned[1]) + + makeTabHeader(0, "In Names", results.others.length) + + makeTabHeader(1, "In Parameters", results.in_args.length) + + makeTabHeader(2, "In Return Types", results.returned.length) + "
"; } else { const signatureTabTitle = @@ -3625,7 +4148,7 @@ async function showResults(results, go_to_first, filterCrates) { results.query.returned.length === 0 ? "In Function Parameters" : "In Function Signatures"; output += "
" + - makeTabHeader(0, signatureTabTitle, ret_others[1]) + + makeTabHeader(0, signatureTabTitle, results.others.length) + "
"; currentTab = 0; } @@ -3647,11 +4170,17 @@ async function showResults(results, go_to_first, filterCrates) { `Consider searching for "${targ}" instead.`; } + const [ret_others, ret_in_args, ret_returned] = await Promise.all([ + addTab(results.others, results.query, currentTab === 0), + addTab(results.in_args, results.query, currentTab === 1), + addTab(results.returned, results.query, currentTab === 2), + ]); + const resultsElem = document.createElement("div"); resultsElem.id = "results"; - resultsElem.appendChild(ret_others[0]); - resultsElem.appendChild(ret_in_args[0]); - resultsElem.appendChild(ret_returned[0]); + resultsElem.appendChild(ret_others); + resultsElem.appendChild(ret_in_args); + resultsElem.appendChild(ret_returned); search.innerHTML = output; if (searchState.rustdocToolbar) { @@ -3933,4 +4462,3 @@ if (typeof window !== "undefined") { // exports. initSearch(new Map()); } -})(); diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 63cda4111e6ad..7aa5e102e6d2a 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -2,6 +2,14 @@ const fs = require("fs"); const path = require("path"); + +function arrayToCode(array) { + return array.map((value, index) => { + value = value.split(" ").join(" "); + return (index % 2 === 1) ? ("`" + value + "`") : value; + }).join(""); +} + function loadContent(content) { const Module = module.constructor; const m = new Module(); @@ -180,15 +188,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) { if (!result_v.forEach) { throw result_v; } - result_v.forEach((value, index) => { - value = value.split(" ").join(" "); - if (index % 2 === 1) { - result_v[index] = "`" + value + "`"; - } else { - result_v[index] = value; - } - }); - result_v = result_v.join(""); + result_v = arrayToCode(result_v); } const obj_path = fullPath + (fullPath.length > 0 ? "." : "") + key; valueCheck(obj_path, expected[key], result_v, error_text, queryName); @@ -436,9 +436,41 @@ function loadSearchJS(doc_folder, resource_suffix) { searchModule.initSearch(searchIndex.searchIndex); const docSearch = searchModule.docSearch; return { - doSearch: function(queryStr, filterCrate, currentCrate) { - return docSearch.execQuery(searchModule.parseQuery(queryStr), + doSearch: async function(queryStr, filterCrate, currentCrate) { + const result = await docSearch.execQuery(searchModule.parseQuery(queryStr), filterCrate, currentCrate); + for (const tab in result) { + if (!Object.prototype.hasOwnProperty.call(result, tab)) { + continue; + } + if (!(result[tab] instanceof Array)) { + continue; + } + for (const entry of result[tab]) { + for (const key in entry) { + if (!Object.prototype.hasOwnProperty.call(entry, key)) { + continue; + } + if (key === "displayTypeSignature") { + const {type, mappedNames, whereClause} = + await entry.displayTypeSignature; + entry.displayType = arrayToCode(type); + entry.displayMappedNames = [...mappedNames.entries()] + .map(([name, qname]) => { + return `${name} = ${qname}`; + }).join(", "); + entry.displayWhereClause = [...whereClause.entries()] + .flatMap(([name, value]) => { + if (value.length === 0) { + return []; + } + return [`${name}: ${arrayToCode(value)}`]; + }).join(", "); + } + } + } + } + return result; }, getCorrections: function(queryStr, filterCrate, currentCrate) { const parsedQuery = searchModule.parseQuery(queryStr); diff --git a/tests/rustdoc-gui/search-about-this-result.goml b/tests/rustdoc-gui/search-about-this-result.goml new file mode 100644 index 0000000000000..62780d01ed7e8 --- /dev/null +++ b/tests/rustdoc-gui/search-about-this-result.goml @@ -0,0 +1,42 @@ +// Check the "About this Result" popover. +// Try a complex result. +go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=scroll_traits::Iterator,(T->bool)->(Extend,Extend)" + +// These two commands are used to be sure the search will be run. +focus: ".search-input" +press-key: "Enter" + +wait-for: "#search-tabs" +assert-count: ("#search-tabs button", 1) +assert-count: (".search-results > a", 1) + +assert: "//div[@class='type-signature']/strong[text()='Iterator']" +assert: "//div[@class='type-signature']/strong[text()='(']" +assert: "//div[@class='type-signature']/strong[text()=')']" + +assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='FnMut']" +assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='Iterator::Item']" +assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='bool']" +assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='Extend']" + +assert-text: ("div.type-signature div.where:nth-child(4)", "where") +assert-text: ("div.type-signature div.where:nth-child(5)", " T matches Iterator::Item") +assert-text: ("div.type-signature div.where:nth-child(6)", " F: FnMut (&Iterator::Item) -> bool") +assert-text: ("div.type-signature div.where:nth-child(7)", " B: Default + Extend") + +// Try a simple result that *won't* give an info box. +go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=F->lib2::WhereWhitespace" + +// These two commands are used to be sure the search will be run. +focus: ".search-input" +press-key: "Enter" + +wait-for: "#search-tabs" +assert-text: ("//div[@class='type-signature']", "F -> WhereWhitespace") +assert-count: ("#search-tabs button", 1) +assert-count: (".search-results > a", 1) +assert-count: ("//div[@class='type-signature']/div[@class='where']", 0) + +assert: "//div[@class='type-signature']/strong[text()='F']" +assert: "//div[@class='type-signature']/strong[text()='WhereWhitespace']" +assert: "//div[@class='type-signature']/strong[text()='T']" diff --git a/tests/rustdoc-js-std/option-type-signatures.js b/tests/rustdoc-js-std/option-type-signatures.js index e154fa707ab3d..1690d5dc8b5bb 100644 --- a/tests/rustdoc-js-std/option-type-signatures.js +++ b/tests/rustdoc-js-std/option-type-signatures.js @@ -6,79 +6,217 @@ const EXPECTED = [ { 'query': 'option, fnonce -> option', 'others': [ - { 'path': 'std::option::Option', 'name': 'map' }, + { + 'path': 'std::option::Option', + 'name': 'map', + 'displayType': '`Option`, F -> `Option`', + 'displayWhereClause': "F: `FnOnce` (T) -> U", + }, + ], + }, + { + 'query': 'option, fnonce -> option', + 'others': [ + { + 'path': 'std::option::Option', + 'name': 'map', + 'displayType': '`Option`<`T`>, F -> `Option`', + 'displayWhereClause': "F: `FnOnce` (T) -> U", + }, ], }, { 'query': 'option -> default', 'others': [ - { 'path': 'std::option::Option', 'name': 'unwrap_or_default' }, - { 'path': 'std::option::Option', 'name': 'get_or_insert_default' }, + { + 'path': 'std::option::Option', + 'name': 'unwrap_or_default', + 'displayType': '`Option` -> `T`', + 'displayWhereClause': "T: `Default`", + }, + { + 'path': 'std::option::Option', + 'name': 'get_or_insert_default', + 'displayType': '&mut `Option` -> &mut `T`', + 'displayWhereClause': "T: `Default`", + }, ], }, { 'query': 'option -> []', 'others': [ - { 'path': 'std::option::Option', 'name': 'as_slice' }, - { 'path': 'std::option::Option', 'name': 'as_mut_slice' }, + { + 'path': 'std::option::Option', + 'name': 'as_slice', + 'displayType': '&`Option` -> &`[`T`]`', + }, + { + 'path': 'std::option::Option', + 'name': 'as_mut_slice', + 'displayType': '&mut `Option` -> &mut `[`T`]`', + }, ], }, { 'query': 'option, option -> option', 'others': [ - { 'path': 'std::option::Option', 'name': 'or' }, - { 'path': 'std::option::Option', 'name': 'xor' }, + { + 'path': 'std::option::Option', + 'name': 'or', + 'displayType': '`Option`<`T`>, `Option`<`T`> -> `Option`<`T`>', + }, + { + 'path': 'std::option::Option', + 'name': 'xor', + 'displayType': '`Option`<`T`>, `Option`<`T`> -> `Option`<`T`>', + }, ], }, { 'query': 'option, option -> option', 'others': [ - { 'path': 'std::option::Option', 'name': 'and' }, - { 'path': 'std::option::Option', 'name': 'zip' }, + { + 'path': 'std::option::Option', + 'name': 'and', + 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<`U`>', + }, + { + 'path': 'std::option::Option', + 'name': 'zip', + 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(T, `U`)>', + }, ], }, { 'query': 'option, option -> option', 'others': [ - { 'path': 'std::option::Option', 'name': 'and' }, - { 'path': 'std::option::Option', 'name': 'zip' }, + { + 'path': 'std::option::Option', + 'name': 'and', + 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<`U`>', + }, + { + 'path': 'std::option::Option', + 'name': 'zip', + 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(`T`, U)>', + }, ], }, { 'query': 'option, option -> option', 'others': [ - { 'path': 'std::option::Option', 'name': 'zip' }, + { + 'path': 'std::option::Option', + 'name': 'zip', + 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(`T`, `U`)>', + }, ], }, { 'query': 'option, e -> result', 'others': [ - { 'path': 'std::option::Option', 'name': 'ok_or' }, - { 'path': 'std::result::Result', 'name': 'transpose' }, + { + 'path': 'std::option::Option', + 'name': 'ok_or', + 'displayType': '`Option`<`T`>, `E` -> `Result`<`T`, `E`>', + }, + { + 'path': 'std::result::Result', + 'name': 'transpose', + 'displayType': 'Result<`Option`<`T`>, `E`> -> Option<`Result`<`T`, `E`>>', + }, ], }, { 'query': 'result, e> -> option>', 'others': [ - { 'path': 'std::result::Result', 'name': 'transpose' }, + { + 'path': 'std::result::Result', + 'name': 'transpose', + 'displayType': '`Result`<`Option`<`T`>, `E`> -> `Option`<`Result`<`T`, `E`>>', + }, ], }, { 'query': 'option, option -> bool', 'others': [ - { 'path': 'std::option::Option', 'name': 'eq' }, + { + 'path': 'std::option::Option', + 'name': 'eq', + 'displayType': '&`Option`<`T`>, &`Option`<`T`> -> `bool`', + }, ], }, { 'query': 'option> -> option', 'others': [ - { 'path': 'std::option::Option', 'name': 'flatten' }, + { + 'path': 'std::option::Option', + 'name': 'flatten', + 'displayType': '`Option`<`Option`<`T`>> -> `Option`<`T`>', + }, ], }, { 'query': 'option', 'returned': [ - { 'path': 'std::result::Result', 'name': 'ok' }, + { + 'path': 'std::result::Result', + 'name': 'ok', + 'displayType': 'Result -> `Option`<`T`>', + }, + ], + }, + { + 'query': 'option, (fnonce () -> u) -> option', + 'others': [ + { + 'path': 'std::option::Option', + 'name': 'map', + 'displayType': '`Option`<`T`>, F -> `Option`', + 'displayMappedNames': `T = t, U = u`, + 'displayWhereClause': "F: `FnOnce` (T) -> `U`", + }, + { + 'path': 'std::option::Option', + 'name': 'and_then', + 'displayType': '`Option`<`T`>, F -> `Option`', + 'displayMappedNames': `T = t, U = u`, + 'displayWhereClause': "F: `FnOnce` (T) -> Option<`U`>", + }, + { + 'path': 'std::option::Option', + 'name': 'zip_with', + 'displayType': 'Option, `Option`<`U`>, F -> `Option`', + 'displayMappedNames': `U = t, R = u`, + 'displayWhereClause': "F: `FnOnce` (T, U) -> `R`", + }, + { + 'path': 'std::task::Poll', + 'name': 'map_ok', + 'displayType': 'Poll<`Option`>>, F -> Poll<`Option`>>', + 'displayMappedNames': `T = t, U = u`, + 'displayWhereClause': "F: `FnOnce` (T) -> `U`", + }, + { + 'path': 'std::task::Poll', + 'name': 'map_err', + 'displayType': 'Poll<`Option`>>, F -> Poll<`Option`>>', + 'displayMappedNames': `T = t, U = u`, + 'displayWhereClause': "F: `FnOnce` (E) -> `U`", + }, + ], + }, + { + 'query': 'option, (fnonce () -> option) -> option', + 'others': [ + { + 'path': 'std::option::Option', + 'name': 'and_then', + 'displayType': '`Option`<`T`>, F -> `Option`', + 'displayMappedNames': `T = t, U = u`, + 'displayWhereClause': "F: `FnOnce` (T) -> `Option`<`U`>", + }, ], }, ]; diff --git a/tests/rustdoc-js/assoc-type-unbound.js b/tests/rustdoc-js/assoc-type-unbound.js new file mode 100644 index 0000000000000..611b8bd1501c7 --- /dev/null +++ b/tests/rustdoc-js/assoc-type-unbound.js @@ -0,0 +1,39 @@ +// exact-check + +const EXPECTED = [ + // Trait-associated types (that is, associated types with no constraints) + // are treated like type parameters, so that you can "pattern match" + // them. We should avoid redundant output (no `Item=MyIter::Item` stuff) + // and should give reasonable results + { + 'query': 'MyIter -> Option', + 'correction': null, + 'others': [ + { + 'path': 'assoc_type_unbound::MyIter', + 'name': 'next', + 'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>', + 'displayMappedNames': 'MyIter::Item = T', + 'displayWhereClause': '', + }, + ], + }, + { + 'query': 'MyIter -> Option', + 'correction': null, + 'others': [ + { + 'path': 'assoc_type_unbound::MyIter', + 'name': 'next', + 'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>', + 'displayMappedNames': 'MyIter::Item = T', + 'displayWhereClause': '', + }, + ], + }, + { + 'query': 'MyIter -> Option', + 'correction': null, + 'others': [], + }, +]; diff --git a/tests/rustdoc-js/assoc-type-unbound.rs b/tests/rustdoc-js/assoc-type-unbound.rs new file mode 100644 index 0000000000000..713b77b500723 --- /dev/null +++ b/tests/rustdoc-js/assoc-type-unbound.rs @@ -0,0 +1,4 @@ +pub trait MyIter { + type Item; + fn next(&mut self) -> Option; +} diff --git a/tests/rustdoc-js/assoc-type.js b/tests/rustdoc-js/assoc-type.js index eec4e7a8258fb..0edf10e794ed7 100644 --- a/tests/rustdoc-js/assoc-type.js +++ b/tests/rustdoc-js/assoc-type.js @@ -7,16 +7,40 @@ const EXPECTED = [ 'query': 'iterator -> u32', 'correction': null, 'others': [ - { 'path': 'assoc_type::my', 'name': 'other_fn' }, - { 'path': 'assoc_type', 'name': 'my_fn' }, + { + 'path': 'assoc_type::my', + 'name': 'other_fn', + 'displayType': 'X -> `u32`', + 'displayMappedNames': '', + 'displayWhereClause': 'X: `Iterator`<`Something`>', + }, + { + 'path': 'assoc_type', + 'name': 'my_fn', + 'displayType': 'X -> `u32`', + 'displayMappedNames': '', + 'displayWhereClause': 'X: `Iterator`', + }, ], }, { 'query': 'iterator', 'correction': null, 'in_args': [ - { 'path': 'assoc_type::my', 'name': 'other_fn' }, - { 'path': 'assoc_type', 'name': 'my_fn' }, + { + 'path': 'assoc_type::my', + 'name': 'other_fn', + 'displayType': 'X -> u32', + 'displayMappedNames': '', + 'displayWhereClause': 'X: `Iterator`<`Something`>', + }, + { + 'path': 'assoc_type', + 'name': 'my_fn', + 'displayType': 'X -> u32', + 'displayMappedNames': '', + 'displayWhereClause': 'X: `Iterator`', + }, ], }, { @@ -26,8 +50,20 @@ const EXPECTED = [ { 'path': 'assoc_type', 'name': 'Something' }, ], 'in_args': [ - { 'path': 'assoc_type::my', 'name': 'other_fn' }, - { 'path': 'assoc_type', 'name': 'my_fn' }, + { + 'path': 'assoc_type::my', + 'name': 'other_fn', + 'displayType': '`X` -> u32', + 'displayMappedNames': '', + 'displayWhereClause': 'X: Iterator<`Something`>', + }, + { + 'path': 'assoc_type', + 'name': 'my_fn', + 'displayType': '`X` -> u32', + 'displayMappedNames': '', + 'displayWhereClause': 'X: Iterator', + }, ], }, // if I write an explicit binding, only it shows up diff --git a/tests/rustdoc-js/generics-trait.js b/tests/rustdoc-js/generics-trait.js index a71393b5e0502..8da9c67050e62 100644 --- a/tests/rustdoc-js/generics-trait.js +++ b/tests/rustdoc-js/generics-trait.js @@ -5,10 +5,22 @@ const EXPECTED = [ 'query': 'Result', 'correction': null, 'in_args': [ - { 'path': 'generics_trait', 'name': 'beta' }, + { + 'path': 'generics_trait', + 'name': 'beta', + 'displayType': '`Result`<`T`, ()> -> ()', + 'displayMappedNames': '', + 'displayWhereClause': 'T: `SomeTrait`', + }, ], 'returned': [ - { 'path': 'generics_trait', 'name': 'bet' }, + { + 'path': 'generics_trait', + 'name': 'bet', + 'displayType': ' -> `Result`<`T`, ()>', + 'displayMappedNames': '', + 'displayWhereClause': 'T: `SomeTrait`', + }, ], }, { @@ -25,20 +37,44 @@ const EXPECTED = [ 'query': 'OtherThingxxxxxxxx', 'correction': null, 'in_args': [ - { 'path': 'generics_trait', 'name': 'alpha' }, + { + 'path': 'generics_trait', + 'name': 'alpha', + 'displayType': 'Result<`T`, ()> -> ()', + 'displayMappedNames': '', + 'displayWhereClause': 'T: `OtherThingxxxxxxxx`', + }, ], 'returned': [ - { 'path': 'generics_trait', 'name': 'alef' }, + { + 'path': 'generics_trait', + 'name': 'alef', + 'displayType': ' -> Result<`T`, ()>', + 'displayMappedNames': '', + 'displayWhereClause': 'T: `OtherThingxxxxxxxx`', + }, ], }, { 'query': 'OtherThingxxxxxxxy', 'correction': 'OtherThingxxxxxxxx', 'in_args': [ - { 'path': 'generics_trait', 'name': 'alpha' }, + { + 'path': 'generics_trait', + 'name': 'alpha', + 'displayType': 'Result<`T`, ()> -> ()', + 'displayMappedNames': '', + 'displayWhereClause': 'T: `OtherThingxxxxxxxx`', + }, ], 'returned': [ - { 'path': 'generics_trait', 'name': 'alef' }, + { + 'path': 'generics_trait', + 'name': 'alef', + 'displayType': ' -> Result<`T`, ()>', + 'displayMappedNames': '', + 'displayWhereClause': 'T: `OtherThingxxxxxxxx`', + }, ], }, ]; From 042f762200461b7fa4ce167de6df4faa69d8960a Mon Sep 17 00:00:00 2001 From: Noah Bright Date: Tue, 29 Oct 2024 10:57:09 -0400 Subject: [PATCH 15/79] Change futex_wait errno from Scalar to IoError To shift more Scalars to IoErrors, implement this change, allowing for a few other changes in the Linux and Windows shims. This also requires introducing a WindowsError variant in the IoError enum and implementing the VisitProvenance trait for IoErrors. --- src/tools/miri/src/concurrency/sync.rs | 4 ++-- src/tools/miri/src/provenance_gc.rs | 12 ++++++++++++ src/tools/miri/src/shims/io_error.rs | 2 ++ src/tools/miri/src/shims/unix/linux/sync.rs | 2 +- src/tools/miri/src/shims/windows/sync.rs | 2 +- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 199aedfa6d237..b6668ae5e4eb4 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -696,7 +696,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { retval_succ: Scalar, retval_timeout: Scalar, dest: MPlaceTy<'tcx>, - errno_timeout: Scalar, + errno_timeout: IoError, ) { let this = self.eval_context_mut(); let thread = this.active_thread(); @@ -713,7 +713,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { retval_succ: Scalar, retval_timeout: Scalar, dest: MPlaceTy<'tcx>, - errno_timeout: Scalar, + errno_timeout: IoError, } @unblock = |this| { let futex = this.machine.sync.futexes.get(&addr).unwrap(); diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index c5a35bc14f591..6042a9eb2eb52 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -89,6 +89,18 @@ impl VisitProvenance for Scalar { } } +impl VisitProvenance for IoError { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + use crate::shims::io_error::IoError::*; + match self { + LibcError(_name) => (), + WindowsError(_name) => (), + HostError(_io_error) => (), + Raw(scalar) => scalar.visit_provenance(visit), + } + } +} + impl VisitProvenance for Immediate { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self { diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index 04491f0542bd8..a50bba0d2e48b 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -7,6 +7,7 @@ use crate::*; #[derive(Debug)] pub enum IoError { LibcError(&'static str), + WindowsError(&'static str), HostError(io::Error), Raw(Scalar), } @@ -113,6 +114,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let errno = match err.into() { HostError(err) => this.io_error_to_errnum(err)?, LibcError(name) => this.eval_libc(name), + WindowsError(name) => this.eval_windows("c", name), Raw(val) => val, }; let errno_place = this.last_error_place()?; diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index c258be78f7647..9fbf08b0b18fb 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -150,7 +150,7 @@ pub fn futex<'tcx>( Scalar::from_target_isize(0, this), // retval_succ Scalar::from_target_isize(-1, this), // retval_timeout dest.clone(), - this.eval_libc("ETIMEDOUT"), // errno_timeout + LibcError("ETIMEDOUT"), // errno_timeout ); } else { // The futex value doesn't match the expected value, so we return failure diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index f7566a8112da7..bfc83215f9b3c 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -202,7 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Scalar::from_i32(1), // retval_succ Scalar::from_i32(0), // retval_timeout dest.clone(), - this.eval_windows("c", "ERROR_TIMEOUT"), // errno_timeout + IoError::WindowsError("ERROR_TIMEOUT"), // errno_timeout ); } From 12dc24f46007f82b93ed85614347a42d47580afa Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 24 Sep 2024 18:18:01 -0700 Subject: [PATCH 16/79] rustdoc-search: simplify rules for generics and type params This commit is a response to feedback on the displayed type signatures results, by making generics act stricter. Generics are tightened by making order significant. This means `Vec` now matches only with a true vector of allocators, instead of matching the second type param. It also makes unboxing within generics stricter, so `Result` only matches if `B` is in the error type and `A` is in the success type. The top level of the function search is unaffected. Find the discussion on: * * * --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_passes/messages.ftl | 3 + compiler/rustc_passes/src/check_attr.rs | 27 +- compiler/rustc_passes/src/errors.rs | 7 + compiler/rustc_span/src/symbol.rs | 1 + library/alloc/src/boxed.rs | 1 + library/alloc/src/rc.rs | 1 + library/alloc/src/sync.rs | 1 + library/core/src/future/future.rs | 1 + library/core/src/option.rs | 1 + library/core/src/result.rs | 1 + .../rustdoc/src/read-documentation/search.md | 12 +- src/librustdoc/html/render/search_index.rs | 74 +++- src/librustdoc/html/static/js/search.js | 352 ++++++++++++++---- .../rustdoc-gui/search-about-this-result.goml | 4 +- tests/rustdoc-js-std/bufread-fill-buf.js | 11 +- .../rustdoc-js-std/option-type-signatures.js | 31 +- tests/rustdoc-js-std/vec-type-signatures.js | 12 + tests/rustdoc-js/assoc-type-backtrack.js | 48 ++- tests/rustdoc-js/assoc-type-backtrack.rs | 4 + tests/rustdoc-js/assoc-type-unbound.js | 4 +- tests/rustdoc-js/assoc-type.rs | 12 +- tests/rustdoc-js/generics-impl.js | 8 +- tests/rustdoc-js/generics-impl.rs | 4 +- .../generics-match-ambiguity-no-unbox.js | 68 ++++ .../generics-match-ambiguity-no-unbox.rs | 18 + tests/rustdoc-js/generics-match-ambiguity.js | 12 +- tests/rustdoc-js/generics-match-ambiguity.rs | 6 +- tests/rustdoc-js/generics-nested.js | 5 +- tests/rustdoc-js/generics-unbox.js | 4 - tests/rustdoc-js/generics-unbox.rs | 8 + tests/rustdoc-js/generics.js | 16 +- tests/rustdoc-js/hof.js | 25 +- tests/rustdoc-js/looks-like-rustc-interner.js | 18 +- tests/rustdoc-js/nested-unboxed.js | 9 +- tests/rustdoc-js/nested-unboxed.rs | 3 + tests/rustdoc-js/reference.js | 15 +- tests/rustdoc-js/tuple-unit.js | 4 +- .../feature-gate-rustdoc_internals.rs | 3 + .../feature-gate-rustdoc_internals.stderr | 12 +- 40 files changed, 630 insertions(+), 217 deletions(-) create mode 100644 tests/rustdoc-js/generics-match-ambiguity-no-unbox.js create mode 100644 tests/rustdoc-js/generics-match-ambiguity-no-unbox.rs diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index d646150a620cd..396aac3451560 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -204,6 +204,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "meant for internal use only" { keyword => rustdoc_internals fake_variadic => rustdoc_internals + search_unbox => rustdoc_internals } ); } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index e5e70ba203384..3536b3fc4cd60 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -234,6 +234,9 @@ passes_doc_masked_only_extern_crate = passes_doc_rust_logo = the `#[doc(rust_logo)]` attribute is used for Rust branding +passes_doc_search_unbox_invalid = + `#[doc(search_unbox)]` should be used on generic structs and enums + passes_doc_test_literal = `#![doc(test(...)]` does not take a literal passes_doc_test_takes_list = diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0a2926c040447..4cf523b05568a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -16,8 +16,8 @@ use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, B use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self as hir, self, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, Item, ItemKind, - MethodKind, Safety, Target, TraitItem, + self as hir, self, AssocItemKind, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, + Item, ItemKind, MethodKind, Safety, Target, TraitItem, }; use rustc_macros::LintDiagnostic; use rustc_middle::hir::nested_filter; @@ -940,6 +940,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_doc_search_unbox(&self, meta: &MetaItemInner, hir_id: HirId) { + let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else { + self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() }); + return; + }; + match item.kind { + ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics) + if generics.params.len() != 0 => {} + ItemKind::Trait(_, _, generics, _, items) + if generics.params.len() != 0 + || items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {} + _ => { + self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() }); + } + } + } + /// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes. /// /// A doc inlining attribute is invalid if it is applied to a non-`use` item, or @@ -1152,6 +1169,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + sym::search_unbox => { + if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") { + self.check_doc_search_unbox(meta, hir_id); + } + } + sym::test => { if self.check_attr_crate_level(attr, meta, hir_id) { self.check_test_attr(meta, hir_id); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 8bd767c1243d9..494be13b86a45 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -244,6 +244,13 @@ pub(crate) struct DocKeywordOnlyImpl { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_doc_search_unbox_invalid)] +pub(crate) struct DocSearchUnboxInvalid { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_doc_inline_conflict)] #[help] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 890c4fdafef89..b2e8adb060436 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1762,6 +1762,7 @@ symbols! { saturating_add, saturating_div, saturating_sub, + search_unbox, select_unpredictable, self_in_typedefs, self_struct_ctor, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index e4956c7c53c8d..c5024a05ed631 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -225,6 +225,7 @@ pub use thin::ThinBox; #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] +#[cfg_attr(not(bootstrap), doc(search_unbox))] // The declaration of the `Box` struct must be kept in sync with the // compiler or ICEs will happen. pub struct Box< diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index fc8646e96d948..06addb4edb2b4 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -307,6 +307,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { /// `value.get_mut()`. This avoids conflicts with methods of the inner type `T`. /// /// [get_mut]: Rc::get_mut +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 98a2fe242570f..e6a2cf009ce7a 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -235,6 +235,7 @@ macro_rules! acquire { /// counting in general. /// /// [rc_examples]: crate::rc#examples +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index ca1c2d1ca1f2e..234914c20fc31 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -25,6 +25,7 @@ use crate::task::{Context, Poll}; /// [`async`]: ../../std/keyword.async.html /// [`Waker`]: crate::task::Waker #[doc(notable_trait)] +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 2aa4f1723680f..461879386225a 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -563,6 +563,7 @@ use crate::pin::Pin; use crate::{cmp, convert, hint, mem, slice}; /// The `Option` type. See [the module level documentation](self) for more. +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[derive(Copy, Eq, Debug, Hash)] #[rustc_diagnostic_item = "Option"] #[lang = "Option"] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 330d1eb14edb0..b450123c5aa90 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -520,6 +520,7 @@ use crate::{convert, fmt, hint}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// /// See the [module documentation](self) for details. +#[cfg_attr(not(bootstrap), doc(search_unbox))] #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[rustc_diagnostic_item = "Result"] diff --git a/src/doc/rustdoc/src/read-documentation/search.md b/src/doc/rustdoc/src/read-documentation/search.md index e912ca0fe5b45..718d2201c3a5d 100644 --- a/src/doc/rustdoc/src/read-documentation/search.md +++ b/src/doc/rustdoc/src/read-documentation/search.md @@ -130,29 +130,31 @@ pub trait MyTrait { /// This function can be found using the following search queries: /// /// MyTrait -> bool -/// MyTrait -> bool /// MyTrait -> bool -/// MyTrait -> bool /// /// The following queries, however, will *not* match it: /// /// MyTrait -> bool /// MyTrait -> bool +/// MyTrait -> bool +/// MyTrait -> bool pub fn my_fn(x: impl MyTrait) -> bool { true } ``` -Generics and function parameters are order-agnostic, but sensitive to nesting +Function parameters are order-agnostic, but sensitive to nesting and number of matches. For example, a function with the signature `fn read_all(&mut self: impl Read) -> Result, Error>` will match these queries: * `&mut Read -> Result, Error>` * `Read -> Result, Error>` -* `Read -> Result` * `Read -> Result>` * `Read -> u8` -But it *does not* match `Result` or `Result>`. +But it *does not* match `Result` or `Result>`, +because those are nested incorrectly, and it does not match +`Result>` or `Result`, because those are +in the wrong order. To search for a function that accepts a function as a parameter, like `Iterator::all`, wrap the nested signature in parenthesis, diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index ee2fc1f44b345..f91fdfa1fb5f5 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -13,8 +13,8 @@ use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer}; use thin_vec::ThinVec; use tracing::instrument; -use crate::clean; use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; +use crate::clean::{self, utils}; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::format::join_with_double_colon; @@ -66,7 +66,7 @@ pub(crate) fn build_index<'tcx>( let mut associated_types = FxHashMap::default(); // item type, display path, re-exported internal path - let mut crate_paths: Vec<(ItemType, Vec, Option>)> = vec![]; + let mut crate_paths: Vec<(ItemType, Vec, Option>, bool)> = vec![]; // Attach all orphan items to the type's definition if the type // has since been learned. @@ -132,10 +132,11 @@ pub(crate) fn build_index<'tcx>( map: &mut FxHashMap, itemid: F, lastpathid: &mut isize, - crate_paths: &mut Vec<(ItemType, Vec, Option>)>, + crate_paths: &mut Vec<(ItemType, Vec, Option>, bool)>, item_type: ItemType, path: &[Symbol], exact_path: Option<&[Symbol]>, + search_unbox: bool, ) -> RenderTypeId { match map.entry(itemid) { Entry::Occupied(entry) => RenderTypeId::Index(*entry.get()), @@ -147,6 +148,7 @@ pub(crate) fn build_index<'tcx>( item_type, path.to_vec(), exact_path.map(|path| path.to_vec()), + search_unbox, )); RenderTypeId::Index(pathid) } @@ -160,9 +162,21 @@ pub(crate) fn build_index<'tcx>( primitives: &mut FxHashMap, associated_types: &mut FxHashMap, lastpathid: &mut isize, - crate_paths: &mut Vec<(ItemType, Vec, Option>)>, + crate_paths: &mut Vec<(ItemType, Vec, Option>, bool)>, + tcx: TyCtxt<'_>, ) -> Option { + use crate::clean::PrimitiveType; let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache; + let search_unbox = match id { + RenderTypeId::Mut => false, + RenderTypeId::DefId(defid) => utils::has_doc_flag(tcx, defid, sym::search_unbox), + RenderTypeId::Primitive(PrimitiveType::Reference | PrimitiveType::Tuple) => true, + RenderTypeId::Primitive(..) => false, + RenderTypeId::AssociatedType(..) => false, + // this bool is only used by `insert_into_map`, so it doesn't matter what we set here + // because Index means we've already inserted into the map + RenderTypeId::Index(_) => false, + }; match id { RenderTypeId::Mut => Some(insert_into_map( primitives, @@ -172,6 +186,7 @@ pub(crate) fn build_index<'tcx>( ItemType::Keyword, &[kw::Mut], None, + search_unbox, )), RenderTypeId::DefId(defid) => { if let Some(&(ref fqp, item_type)) = @@ -195,6 +210,7 @@ pub(crate) fn build_index<'tcx>( item_type, fqp, exact_fqp.map(|x| &x[..]).filter(|exact_fqp| exact_fqp != fqp), + search_unbox, )) } else { None @@ -210,6 +226,7 @@ pub(crate) fn build_index<'tcx>( ItemType::Primitive, &[sym], None, + search_unbox, )) } RenderTypeId::Index(_) => Some(id), @@ -221,6 +238,7 @@ pub(crate) fn build_index<'tcx>( ItemType::AssocType, &[sym], None, + search_unbox, )), } } @@ -232,7 +250,8 @@ pub(crate) fn build_index<'tcx>( primitives: &mut FxHashMap, associated_types: &mut FxHashMap, lastpathid: &mut isize, - crate_paths: &mut Vec<(ItemType, Vec, Option>)>, + crate_paths: &mut Vec<(ItemType, Vec, Option>, bool)>, + tcx: TyCtxt<'_>, ) { if let Some(generics) = &mut ty.generics { for item in generics { @@ -244,6 +263,7 @@ pub(crate) fn build_index<'tcx>( associated_types, lastpathid, crate_paths, + tcx, ); } } @@ -257,6 +277,7 @@ pub(crate) fn build_index<'tcx>( associated_types, lastpathid, crate_paths, + tcx, ); let Some(converted_associated_type) = converted_associated_type else { return false; @@ -271,6 +292,7 @@ pub(crate) fn build_index<'tcx>( associated_types, lastpathid, crate_paths, + tcx, ); } true @@ -288,6 +310,7 @@ pub(crate) fn build_index<'tcx>( associated_types, lastpathid, crate_paths, + tcx, ); } if let Some(search_type) = &mut item.search_type { @@ -300,6 +323,7 @@ pub(crate) fn build_index<'tcx>( &mut associated_types, &mut lastpathid, &mut crate_paths, + tcx, ); } for item in &mut search_type.output { @@ -311,6 +335,7 @@ pub(crate) fn build_index<'tcx>( &mut associated_types, &mut lastpathid, &mut crate_paths, + tcx, ); } for constraint in &mut search_type.where_clause { @@ -323,6 +348,7 @@ pub(crate) fn build_index<'tcx>( &mut associated_types, &mut lastpathid, &mut crate_paths, + tcx, ); } } @@ -350,7 +376,12 @@ pub(crate) fn build_index<'tcx>( .filter(|exact_fqp| { exact_fqp.last() == Some(&item.name) && *exact_fqp != fqp }); - crate_paths.push((short, fqp.clone(), exact_fqp.cloned())); + crate_paths.push(( + short, + fqp.clone(), + exact_fqp.cloned(), + utils::has_doc_flag(tcx, defid, sym::search_unbox), + )); Some(pathid) } else { None @@ -431,7 +462,7 @@ pub(crate) fn build_index<'tcx>( struct CrateData<'a> { items: Vec<&'a IndexItem>, - paths: Vec<(ItemType, Vec, Option>)>, + paths: Vec<(ItemType, Vec, Option>, bool)>, // The String is alias name and the vec is the list of the elements with this alias. // // To be noted: the `usize` elements are indexes to `items`. @@ -450,6 +481,7 @@ pub(crate) fn build_index<'tcx>( name: Symbol, path: Option, exact_path: Option, + search_unbox: bool, } impl Serialize for Paths { @@ -467,6 +499,15 @@ pub(crate) fn build_index<'tcx>( assert!(self.path.is_some()); seq.serialize_element(path)?; } + if self.search_unbox { + if self.path.is_none() { + seq.serialize_element(&None::)?; + } + if self.exact_path.is_none() { + seq.serialize_element(&None::)?; + } + seq.serialize_element(&1)?; + } seq.end() } } @@ -489,9 +530,15 @@ pub(crate) fn build_index<'tcx>( mod_paths.insert(&item.path, index); } let mut paths = Vec::with_capacity(self.paths.len()); - for (ty, path, exact) in &self.paths { + for &(ty, ref path, ref exact, search_unbox) in &self.paths { if path.len() < 2 { - paths.push(Paths { ty: *ty, name: path[0], path: None, exact_path: None }); + paths.push(Paths { + ty, + name: path[0], + path: None, + exact_path: None, + search_unbox, + }); continue; } let full_path = join_with_double_colon(&path[..path.len() - 1]); @@ -517,10 +564,11 @@ pub(crate) fn build_index<'tcx>( }); if let Some(index) = mod_paths.get(&full_path) { paths.push(Paths { - ty: *ty, + ty, name: *path.last().unwrap(), path: Some(*index), exact_path, + search_unbox, }); continue; } @@ -532,10 +580,11 @@ pub(crate) fn build_index<'tcx>( match extra_paths.entry(full_path.clone()) { Entry::Occupied(entry) => { paths.push(Paths { - ty: *ty, + ty, name: *path.last().unwrap(), path: Some(*entry.get()), exact_path, + search_unbox, }); } Entry::Vacant(entry) => { @@ -544,10 +593,11 @@ pub(crate) fn build_index<'tcx>( revert_extra_paths.insert(index, full_path); } paths.push(Paths { - ty: *ty, + ty, name: *path.last().unwrap(), path: Some(index), exact_path, + search_unbox, }); } } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 0458b81d35257..d269c9322a317 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1327,6 +1327,7 @@ class DocSearch { exactPath: null, generics, bindings, + unboxFlag: true, }; } else if (pathIndex === 0) { // `0` is used as a sentinel because it's fewer bytes than `null` @@ -1338,6 +1339,7 @@ class DocSearch { exactPath: null, generics, bindings, + unboxFlag: true, }; } else { const item = lowercasePaths[pathIndex - 1]; @@ -1353,6 +1355,7 @@ class DocSearch { exactPath: item.exactPath, generics, bindings, + unboxFlag: item.unboxFlag, }; } const cr = this.TYPES_POOL.get(result.id); @@ -1390,6 +1393,7 @@ class DocSearch { if (cr.ty === result.ty && cr.path === result.path && cr.bindings === result.bindings && cr.generics === result.generics && cr.ty === result.ty && cr.name === result.name + && cr.unboxFlag === result.unboxFlag ) { return cr; } @@ -1681,14 +1685,17 @@ class DocSearch { const ty = elem[0]; const name = elem[1]; let path = null; - if (elem.length > 2) { + if (elem.length > 2 && elem[2] !== null) { path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath; lastPath = path; } - const exactPath = elem.length > 3 ? itemPaths.get(elem[3]) : path; + const exactPath = elem.length > 3 && elem[3] !== null ? + itemPaths.get(elem[3]) : + path; + const unboxFlag = elem.length > 4 && !!elem[4]; - lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath }); - paths[i] = { ty, name, path, exactPath }; + lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath, unboxFlag }); + paths[i] = { ty, name, path, exactPath, unboxFlag }; } // convert `item*` into an object form, and construct word indices. @@ -2376,17 +2383,20 @@ class DocSearch { */ const writeFn = (fnType, result) => { if (fnType.id < 0) { - const queryId = mgens && mgens.has(fnType.id) ? mgens.get(fnType.id) : null; if (fnParamNames[-1 - fnType.id] === "") { for (const nested of fnType.generics) { writeFn(nested, result); } return; - } else if (queryId < 0) { - mappedNames.set( - fnParamNames[-1 - fnType.id], - queryParamNames[-1 - queryId], - ); + } else if (mgens) { + for (const [queryId, fnId] of mgens) { + if (fnId === fnType.id) { + mappedNames.set( + queryParamNames[-1 - queryId], + fnParamNames[-1 - fnType.id], + ); + } + } } pushText({ name: fnParamNames[-1 - fnType.id], @@ -2436,15 +2446,15 @@ class DocSearch { } pushText({ name, highlighted: false }, result); pushText({ - name: values.length > 1 ? "=(" : "=", + name: values.length !== 1 ? "=(" : "=", highlighted: false, }, result); onEachBtwn( - values, + values || [], value => writeFn(value, result), () => pushText({ name: " + ", highlighted: false }, result), ); - if (values.length > 1) { + if (values.length !== 1) { pushText({ name: ")", highlighted: false }, result); } }, @@ -2616,8 +2626,8 @@ class DocSearch { * @param {Array} queryElems - The elements from the parsed query. * @param {[FunctionType]} whereClause - Trait bounds for generic items. * @param {Map|null} mgensIn - * - Map functions generics to query generics (never modified). - * @param {null|Map -> bool} solutionCb - Called for each `mgens` solution. + * - Map query generics to function generics (never modified). + * @param {Map -> bool} solutionCb - Called for each `mgens` solution. * @param {number} unboxingDepth * - Limit checks that Ty matches Vec, * but not Vec>>>> @@ -2640,7 +2650,7 @@ class DocSearch { */ const mgens = mgensIn === null ? null : new Map(mgensIn); if (queryElems.length === 0) { - return (!solutionCb || solutionCb(mgens)) ? fnTypesIn : null; + return solutionCb(mgens) ? fnTypesIn : null; } if (!fnTypesIn || fnTypesIn.length === 0) { return null; @@ -2657,12 +2667,12 @@ class DocSearch { continue; } if (fnType.id < 0 && queryElem.id < 0) { - if (mgens && mgens.has(fnType.id) && - mgens.get(fnType.id) !== queryElem.id) { + if (mgens && mgens.has(queryElem.id) && + mgens.get(queryElem.id) !== fnType.id) { continue; } const mgensScratch = new Map(mgens); - mgensScratch.set(fnType.id, queryElem.id); + mgensScratch.set(queryElem.id, fnType.id); if (!solutionCb || solutionCb(mgensScratch)) { const highlighted = [...fnTypesIn]; highlighted[i] = Object.assign({ @@ -2672,13 +2682,13 @@ class DocSearch { }); return highlighted; } - } else if (!solutionCb || solutionCb(mgens ? new Map(mgens) : null)) { + } else if (solutionCb(mgens ? new Map(mgens) : null)) { // unifyFunctionTypeIsMatchCandidate already checks that ids match const highlighted = [...fnTypesIn]; highlighted[i] = Object.assign({ highlighted: true, }, fnType, { - generics: unifyFunctionTypes( + generics: unifyGenericTypes( fnType.generics, queryElem.generics, whereClause, @@ -2701,17 +2711,11 @@ class DocSearch { continue; } if (fnType.id < 0) { - if (mgens && mgens.has(fnType.id) && - mgens.get(fnType.id) !== 0) { - continue; - } - const mgensScratch = new Map(mgens); - mgensScratch.set(fnType.id, 0); const highlightedGenerics = unifyFunctionTypes( whereClause[(-fnType.id) - 1], queryElems, whereClause, - mgensScratch, + mgens, solutionCb, unboxingDepth + 1, ); @@ -2782,11 +2786,11 @@ class DocSearch { let mgensScratch; if (fnType.id < 0) { mgensScratch = new Map(mgens); - if (mgensScratch.has(fnType.id) - && mgensScratch.get(fnType.id) !== queryElem.id) { + if (mgensScratch.has(queryElem.id) + && mgensScratch.get(queryElem.id) !== fnType.id) { continue; } - mgensScratch.set(fnType.id, queryElem.id); + mgensScratch.set(queryElem.id, fnType.id); } else { mgensScratch = mgens; } @@ -2809,7 +2813,7 @@ class DocSearch { mgensScratch => { if (fnType.generics.length === 0 && queryElem.generics.length === 0 && fnType.bindings.size === 0 && queryElem.bindings.size === 0) { - return !solutionCb || solutionCb(mgensScratch); + return solutionCb(mgensScratch); } const solution = unifyFunctionTypeCheckBindings( fnType, @@ -2823,7 +2827,7 @@ class DocSearch { } const simplifiedGenerics = solution.simplifiedGenerics; for (const simplifiedMgens of solution.mgens) { - unifiedGenerics = unifyFunctionTypes( + unifiedGenerics = unifyGenericTypes( simplifiedGenerics, queryElem.generics, whereClause, @@ -2831,7 +2835,7 @@ class DocSearch { solutionCb, unboxingDepth, ); - if (unifiedGenerics) { + if (unifiedGenerics !== null) { unifiedGenericsMgens = simplifiedMgens; return true; } @@ -2875,16 +2879,6 @@ class DocSearch { )) { continue; } - let mgensScratch; - if (fnType.id < 0) { - mgensScratch = new Map(mgens); - if (mgensScratch.has(fnType.id) && mgensScratch.get(fnType.id) !== 0) { - continue; - } - mgensScratch.set(fnType.id, 0); - } else { - mgensScratch = mgens; - } const generics = fnType.id < 0 ? whereClause[(-fnType.id) - 1] : fnType.generics; @@ -2895,7 +2889,7 @@ class DocSearch { fnTypes.toSpliced(i, 1, ...bindings, ...generics), queryElems, whereClause, - mgensScratch, + mgens, solutionCb, unboxingDepth + 1, ); @@ -2919,6 +2913,199 @@ class DocSearch { } return null; } + /** + * This function compares two lists of generics. + * + * This function behaves very similarly to `unifyFunctionTypes`, except that it + * doesn't skip or reorder anything. This is intended to match the behavior of + * the ordinary Rust type system, so that `Vec` only matches an actual + * `Vec` of `Allocators` and not the implicit `Allocator` parameter that every + * `Vec` has. + * + * @param {Array} fnTypesIn - The objects to check. + * @param {Array} queryElems - The elements from the parsed query. + * @param {[FunctionType]} whereClause - Trait bounds for generic items. + * @param {Map|null} mgensIn + * - Map functions generics to query generics (never modified). + * @param {Map -> bool} solutionCb - Called for each `mgens` solution. + * @param {number} unboxingDepth + * - Limit checks that Ty matches Vec, + * but not Vec>>>> + * + * @return {[FunctionType]|null} - Returns highlighed results if a match, null otherwise. + */ + function unifyGenericTypes( + fnTypesIn, + queryElems, + whereClause, + mgensIn, + solutionCb, + unboxingDepth, + ) { + if (unboxingDepth >= UNBOXING_LIMIT) { + return null; + } + /** + * @type Map|null + */ + const mgens = mgensIn === null ? null : new Map(mgensIn); + if (queryElems.length === 0) { + return solutionCb(mgens) ? fnTypesIn : null; + } + if (!fnTypesIn || fnTypesIn.length === 0) { + return null; + } + const fnType = fnTypesIn[0]; + const queryElem = queryElems[0]; + if (unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) { + if (fnType.id < 0 && queryElem.id < 0) { + if (!mgens || !mgens.has(queryElem.id) || + mgens.get(queryElem.id) === fnType.id + ) { + const mgensScratch = new Map(mgens); + mgensScratch.set(queryElem.id, fnType.id); + const fnTypesRemaining = unifyGenericTypes( + fnTypesIn.slice(1), + queryElems.slice(1), + whereClause, + mgensScratch, + solutionCb, + unboxingDepth, + ); + if (fnTypesRemaining) { + const highlighted = [fnType, ...fnTypesRemaining]; + highlighted[0] = Object.assign({ + highlighted: true, + }, fnType, { + generics: whereClause[-1 - fnType.id], + }); + return highlighted; + } + } + } else { + let unifiedGenerics; + const fnTypesRemaining = unifyGenericTypes( + fnTypesIn.slice(1), + queryElems.slice(1), + whereClause, + mgens, + mgensScratch => { + const solution = unifyFunctionTypeCheckBindings( + fnType, + queryElem, + whereClause, + mgensScratch, + unboxingDepth, + ); + if (!solution) { + return false; + } + const simplifiedGenerics = solution.simplifiedGenerics; + for (const simplifiedMgens of solution.mgens) { + unifiedGenerics = unifyGenericTypes( + simplifiedGenerics, + queryElem.generics, + whereClause, + simplifiedMgens, + solutionCb, + unboxingDepth, + ); + if (unifiedGenerics !== null) { + return true; + } + } + }, + unboxingDepth, + ); + if (fnTypesRemaining) { + const highlighted = [fnType, ...fnTypesRemaining]; + highlighted[0] = Object.assign({ + highlighted: true, + }, fnType, { + generics: unifiedGenerics || fnType.generics, + }); + return highlighted; + } + } + } + if (unifyFunctionTypeIsUnboxCandidate( + fnType, + queryElem, + whereClause, + mgens, + unboxingDepth + 1, + )) { + let highlightedRemaining; + if (fnType.id < 0) { + // Where clause corresponds to `F: A + B` + // ^^^^^ + // The order of the constraints doesn't matter, so + // use order-agnostic matching for it. + const highlightedGenerics = unifyFunctionTypes( + whereClause[(-fnType.id) - 1], + [queryElem], + whereClause, + mgens, + mgensScratch => { + const hl = unifyGenericTypes( + fnTypesIn.slice(1), + queryElems.slice(1), + whereClause, + mgensScratch, + solutionCb, + unboxingDepth, + ); + if (hl) { + highlightedRemaining = hl; + } + return hl; + }, + unboxingDepth + 1, + ); + if (highlightedGenerics) { + return [Object.assign({ + highlighted: true, + }, fnType, { + generics: highlightedGenerics, + }), ...highlightedRemaining]; + } + } else { + const highlightedGenerics = unifyGenericTypes( + [ + ...Array.from(fnType.bindings.values()).flat(), + ...fnType.generics, + ], + [queryElem], + whereClause, + mgens, + mgensScratch => { + const hl = unifyGenericTypes( + fnTypesIn.slice(1), + queryElems.slice(1), + whereClause, + mgensScratch, + solutionCb, + unboxingDepth, + ); + if (hl) { + highlightedRemaining = hl; + } + return hl; + }, + unboxingDepth + 1, + ); + if (highlightedGenerics) { + return [Object.assign({}, fnType, { + generics: highlightedGenerics, + bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => { + return [k, highlightedGenerics.splice(0, v.length)]; + })), + }), ...highlightedRemaining]; + } + } + } + return null; + } /** * Check if this function is a match candidate. * @@ -2930,7 +3117,7 @@ class DocSearch { * * @param {FunctionType} fnType * @param {QueryElement} queryElem - * @param {Map|null} mgensIn - Map functions generics to query generics. + * @param {Map|null} mgensIn - Map query generics to function generics. * @returns {boolean} */ const unifyFunctionTypeIsMatchCandidate = (fnType, queryElem, mgensIn) => { @@ -2940,22 +3127,13 @@ class DocSearch { } // fnType.id < 0 means generic // queryElem.id < 0 does too - // mgensIn[fnType.id] = queryElem.id - // or, if mgensIn[fnType.id] = 0, then we've matched this generic with a bare trait - // and should make that same decision everywhere it appears + // mgensIn[queryElem.id] = fnType.id if (fnType.id < 0 && queryElem.id < 0) { - if (mgensIn) { - if (mgensIn.has(fnType.id) && mgensIn.get(fnType.id) !== queryElem.id) { - return false; - } - for (const [fid, qid] of mgensIn.entries()) { - if (fnType.id !== fid && queryElem.id === qid) { - return false; - } - if (fnType.id === fid && queryElem.id !== qid) { - return false; - } - } + if ( + mgensIn && mgensIn.has(queryElem.id) && + mgensIn.get(queryElem.id) !== fnType.id + ) { + return false; } return true; } else { @@ -3032,7 +3210,7 @@ class DocSearch { * @param {FunctionType} fnType * @param {QueryElement} queryElem * @param {[FunctionType]} whereClause - Trait bounds for generic items. - * @param {Map} mgensIn - Map functions generics to query generics. + * @param {Map} mgensIn - Map query generics to function generics. * Never modified. * @param {number} unboxingDepth * @returns {false|{mgens: [Map], simplifiedGenerics: [FunctionType]}} @@ -3100,7 +3278,7 @@ class DocSearch { * @param {FunctionType} fnType * @param {QueryElement} queryElem * @param {[FunctionType]} whereClause - Trait bounds for generic items. - * @param {Map|null} mgens - Map functions generics to query generics. + * @param {Map|null} mgens - Map query generics to function generics. * @param {number} unboxingDepth * @returns {boolean} */ @@ -3114,19 +3292,10 @@ class DocSearch { if (unboxingDepth >= UNBOXING_LIMIT) { return false; } - if (fnType.id < 0 && queryElem.id >= 0) { + if (fnType.id < 0) { if (!whereClause) { return false; } - // mgens[fnType.id] === 0 indicates that we committed to unboxing this generic - // mgens[fnType.id] === null indicates that we haven't decided yet - if (mgens && mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) { - return false; - } - // Where clauses can represent cyclical data. - // `null` prevents it from trying to unbox in an infinite loop - const mgensTmp = new Map(mgens); - mgensTmp.set(fnType.id, null); // This is only a potential unbox if the search query appears in the where clause // for example, searching `Read -> usize` should find // `fn read_all(R) -> Result` @@ -3135,10 +3304,11 @@ class DocSearch { whereClause[(-fnType.id) - 1], queryElem, whereClause, - mgensTmp, + mgens, unboxingDepth, ); - } else if (fnType.generics.length > 0 || fnType.bindings.size > 0) { + } else if (fnType.unboxFlag && + (fnType.generics.length > 0 || fnType.bindings.size > 0)) { const simplifiedGenerics = [ ...fnType.generics, ...Array.from(fnType.bindings.values()).flat(), @@ -3182,7 +3352,7 @@ class DocSearch { * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. * @param {[FunctionType]} whereClause - Trait bounds for generic items. - * @param {Map|null} mgens - Map functions generics to query generics. + * @param {Map|null} mgens - Map query generics to function generics. * * @return {boolean} - Returns true if the type matches, false otherwise. */ @@ -3200,8 +3370,32 @@ class DocSearch { ) { return row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty); } else { - return unifyFunctionTypes([row], [elem], whereClause, mgens, null, unboxingDepth); + return unifyFunctionTypes( + [row], + [elem], + whereClause, + mgens, + () => true, + unboxingDepth, + ); + } + }; + + /** + * Check a query solution for conflicting generics. + */ + const checkTypeMgensForConflict = mgens => { + if (!mgens) { + return true; } + const fnTypes = new Set(); + for (const [_qid, fid] of mgens) { + if (fnTypes.has(fid)) { + return false; + } + fnTypes.add(fid); + } + return true; }; /** @@ -3523,7 +3717,7 @@ class DocSearch { parsedQuery.returned, row.type.where_clause, mgens, - null, + checkTypeMgensForConflict, 0, // unboxing depth ); }, @@ -3973,7 +4167,7 @@ ${item.displayPath}${name}\ displayType.appendChild(line); addWhereLineFn = () => {}; }; - for (const [name, qname] of mappedNames) { + for (const [qname, name] of mappedNames) { // don't care unless the generic name is different if (name === qname) { continue; diff --git a/tests/rustdoc-gui/search-about-this-result.goml b/tests/rustdoc-gui/search-about-this-result.goml index 62780d01ed7e8..1d45c06dc43d4 100644 --- a/tests/rustdoc-gui/search-about-this-result.goml +++ b/tests/rustdoc-gui/search-about-this-result.goml @@ -11,8 +11,8 @@ assert-count: ("#search-tabs button", 1) assert-count: (".search-results > a", 1) assert: "//div[@class='type-signature']/strong[text()='Iterator']" -assert: "//div[@class='type-signature']/strong[text()='(']" -assert: "//div[@class='type-signature']/strong[text()=')']" +assert: "//div[@class='type-signature']/strong[text()='(B']" +assert: "//div[@class='type-signature']/strong[text()='B)']" assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='FnMut']" assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='Iterator::Item']" diff --git a/tests/rustdoc-js-std/bufread-fill-buf.js b/tests/rustdoc-js-std/bufread-fill-buf.js index 3828cf76026ea..6b9309f686408 100644 --- a/tests/rustdoc-js-std/bufread-fill-buf.js +++ b/tests/rustdoc-js-std/bufread-fill-buf.js @@ -2,12 +2,15 @@ const EXPECTED = [ { - 'query': 'bufread -> result', + 'query': 'bufread -> result<[u8]>', 'others': [ - { 'path': 'std::io::Split', 'name': 'next' }, { 'path': 'std::boxed::Box', 'name': 'fill_buf' }, - { 'path': 'std::io::Chain', 'name': 'fill_buf' }, - { 'path': 'std::io::Take', 'name': 'fill_buf' }, + ], + }, + { + 'query': 'split -> option>>', + 'others': [ + { 'path': 'std::io::Split', 'name': 'next' }, ], }, ]; diff --git a/tests/rustdoc-js-std/option-type-signatures.js b/tests/rustdoc-js-std/option-type-signatures.js index 1690d5dc8b5bb..3be18e6adf324 100644 --- a/tests/rustdoc-js-std/option-type-signatures.js +++ b/tests/rustdoc-js-std/option-type-signatures.js @@ -80,11 +80,6 @@ const EXPECTED = [ 'name': 'and', 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<`U`>', }, - { - 'path': 'std::option::Option', - 'name': 'zip', - 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(T, `U`)>', - }, ], }, { @@ -103,12 +98,12 @@ const EXPECTED = [ ], }, { - 'query': 'option, option -> option', + 'query': 'option, option -> option<(t, u)>', 'others': [ { 'path': 'std::option::Option', 'name': 'zip', - 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(`T`, `U`)>', + 'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<`(T`, `U)`>', }, ], }, @@ -174,37 +169,23 @@ const EXPECTED = [ 'path': 'std::option::Option', 'name': 'map', 'displayType': '`Option`<`T`>, F -> `Option`', - 'displayMappedNames': `T = t, U = u`, + 'displayMappedNames': `t = T, u = U`, 'displayWhereClause': "F: `FnOnce` (T) -> `U`", }, { 'path': 'std::option::Option', 'name': 'and_then', 'displayType': '`Option`<`T`>, F -> `Option`', - 'displayMappedNames': `T = t, U = u`, + 'displayMappedNames': `t = T, u = U`, 'displayWhereClause': "F: `FnOnce` (T) -> Option<`U`>", }, { 'path': 'std::option::Option', 'name': 'zip_with', 'displayType': 'Option, `Option`<`U`>, F -> `Option`', - 'displayMappedNames': `U = t, R = u`, + 'displayMappedNames': `t = U, u = R`, 'displayWhereClause': "F: `FnOnce` (T, U) -> `R`", }, - { - 'path': 'std::task::Poll', - 'name': 'map_ok', - 'displayType': 'Poll<`Option`>>, F -> Poll<`Option`>>', - 'displayMappedNames': `T = t, U = u`, - 'displayWhereClause': "F: `FnOnce` (T) -> `U`", - }, - { - 'path': 'std::task::Poll', - 'name': 'map_err', - 'displayType': 'Poll<`Option`>>, F -> Poll<`Option`>>', - 'displayMappedNames': `T = t, U = u`, - 'displayWhereClause': "F: `FnOnce` (E) -> `U`", - }, ], }, { @@ -214,7 +195,7 @@ const EXPECTED = [ 'path': 'std::option::Option', 'name': 'and_then', 'displayType': '`Option`<`T`>, F -> `Option`', - 'displayMappedNames': `T = t, U = u`, + 'displayMappedNames': `t = T, u = U`, 'displayWhereClause': "F: `FnOnce` (T) -> `Option`<`U`>", }, ], diff --git a/tests/rustdoc-js-std/vec-type-signatures.js b/tests/rustdoc-js-std/vec-type-signatures.js index 18cf9d6efd0fd..3c2ff30a83330 100644 --- a/tests/rustdoc-js-std/vec-type-signatures.js +++ b/tests/rustdoc-js-std/vec-type-signatures.js @@ -19,4 +19,16 @@ const EXPECTED = [ { 'path': 'std::vec::IntoIter', 'name': 'next_chunk' }, ], }, + { + 'query': 'vec -> Box<[T]>', + 'others': [ + { + 'path': 'std::boxed::Box', + 'name': 'from', + 'displayType': '`Vec`<`T`, `A`> -> `Box`<`[T]`, A>', + 'displayMappedNames': `T = T`, + 'displayWhereClause': 'A: `Allocator`', + }, + ], + }, ]; diff --git a/tests/rustdoc-js/assoc-type-backtrack.js b/tests/rustdoc-js/assoc-type-backtrack.js index 493e1a9910d18..ccf5c063c8c50 100644 --- a/tests/rustdoc-js/assoc-type-backtrack.js +++ b/tests/rustdoc-js/assoc-type-backtrack.js @@ -6,7 +6,6 @@ const EXPECTED = [ 'correction': null, 'others': [ { 'path': 'assoc_type_backtrack::MyTrait', 'name': 'fold' }, - { 'path': 'assoc_type_backtrack::Cloned', 'name': 'fold' }, ], }, { @@ -14,6 +13,19 @@ const EXPECTED = [ 'correction': null, 'others': [ { 'path': 'assoc_type_backtrack::MyTrait', 'name': 'fold' }, + ], + }, + { + 'query': 'cloned, mytrait2 -> T', + 'correction': null, + 'others': [ + { 'path': 'assoc_type_backtrack::Cloned', 'name': 'fold' }, + ], + }, + { + 'query': 'cloned>, mytrait2 -> T', + 'correction': null, + 'others': [ { 'path': 'assoc_type_backtrack::Cloned', 'name': 'fold' }, ], }, @@ -22,7 +34,6 @@ const EXPECTED = [ 'correction': null, 'others': [ { 'path': 'assoc_type_backtrack::MyTrait', 'name': 'fold' }, - { 'path': 'assoc_type_backtrack::Cloned', 'name': 'fold' }, ], }, { @@ -50,14 +61,14 @@ const EXPECTED = [ ], }, { - 'query': 'mytrait -> Option', + 'query': 'cloned> -> Option', 'correction': null, 'others': [ { 'path': 'assoc_type_backtrack::Cloned', 'name': 'next' }, ], }, { - 'query': 'mytrait -> Option', + 'query': 'cloned> -> Option', 'correction': null, 'others': [ { 'path': 'assoc_type_backtrack::Cloned', 'name': 'next' }, @@ -89,19 +100,21 @@ const EXPECTED = [ ], }, { - 'query': 'myintofuture> -> myfuture', + 'query': 'myintofuture> -> myfuture', 'correction': null, 'others': [ { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future' }, { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' }, ], }, - // Invalid unboxing of the one-argument case. - // If you unbox one of the myfutures, you need to unbox both of them. + // Unboxings of the one-argument case. { 'query': 'myintofuture -> myfuture', 'correction': null, - 'others': [], + 'others': [ + { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future' }, + { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' }, + ], }, // Unboxings of the two-argument case. { @@ -119,7 +132,7 @@ const EXPECTED = [ ], }, { - 'query': 'myintofuture, myintofuture -> myfuture', + 'query': 'myintofuture, myintofuture -> myfuture', 'correction': null, 'others': [ { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' }, @@ -132,24 +145,29 @@ const EXPECTED = [ { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' }, ], }, - // Invalid unboxings of the two-argument case. - // If you unbox one of the myfutures, you need to unbox all of them. + // If you unbox one of the myfutures, you don't need to unbox all of them. { 'query': 'myintofuture, myintofuture> -> myfuture', 'correction': null, - 'others': [], + 'others': [ + { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' }, + ], }, { 'query': 'myintofuture>, myintofuture -> myfuture', 'correction': null, - 'others': [], + 'others': [ + { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' }, + ], }, { 'query': 'myintofuture>, myintofuture> -> t', 'correction': null, - 'others': [], + 'others': [ + { 'path': 'assoc_type_backtrack::MyIntoFuture', 'name': 'into_future_2' }, + ], }, - // different generics don't match up either + // different generics must match up { 'query': 'myintofuture>, myintofuture> -> myfuture', 'correction': null, diff --git a/tests/rustdoc-js/assoc-type-backtrack.rs b/tests/rustdoc-js/assoc-type-backtrack.rs index 2dfede9dc3831..8a74685b30bb3 100644 --- a/tests/rustdoc-js/assoc-type-backtrack.rs +++ b/tests/rustdoc-js/assoc-type-backtrack.rs @@ -1,3 +1,5 @@ +#![feature(rustdoc_internals)] + pub trait MyTrait2 { type Output; } @@ -31,10 +33,12 @@ where } } +#[doc(search_unbox)] pub trait MyFuture { type Output; } +#[doc(search_unbox)] pub trait MyIntoFuture { type Output; type Fut: MyFuture; diff --git a/tests/rustdoc-js/assoc-type-unbound.js b/tests/rustdoc-js/assoc-type-unbound.js index 611b8bd1501c7..9fd14f9d9fb59 100644 --- a/tests/rustdoc-js/assoc-type-unbound.js +++ b/tests/rustdoc-js/assoc-type-unbound.js @@ -13,7 +13,7 @@ const EXPECTED = [ 'path': 'assoc_type_unbound::MyIter', 'name': 'next', 'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>', - 'displayMappedNames': 'MyIter::Item = T', + 'displayMappedNames': 'T = MyIter::Item', 'displayWhereClause': '', }, ], @@ -26,7 +26,7 @@ const EXPECTED = [ 'path': 'assoc_type_unbound::MyIter', 'name': 'next', 'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>', - 'displayMappedNames': 'MyIter::Item = T', + 'displayMappedNames': 'T = MyIter::Item', 'displayWhereClause': '', }, ], diff --git a/tests/rustdoc-js/assoc-type.rs b/tests/rustdoc-js/assoc-type.rs index e12e73cb546df..aee8f4b1c3fa8 100644 --- a/tests/rustdoc-js/assoc-type.rs +++ b/tests/rustdoc-js/assoc-type.rs @@ -1,12 +1,22 @@ -pub fn my_fn>(_x: X) -> u32 { +#![feature(rustdoc_internals)] + +pub fn my_fn>(_x: X) -> u32 { 3 } pub struct Something; pub mod my { + #[doc(search_unbox)] pub trait Iterator {} pub fn other_fn>(_: X) -> u32 { 3 } } + +pub mod other { + #[doc(search_unbox)] + pub trait Iterator { + type Item; + } +} diff --git a/tests/rustdoc-js/generics-impl.js b/tests/rustdoc-js/generics-impl.js index 5e33e224876fe..c104730dcbd53 100644 --- a/tests/rustdoc-js/generics-impl.js +++ b/tests/rustdoc-js/generics-impl.js @@ -14,7 +14,7 @@ const EXPECTED = [ ], }, { - 'query': 'Aaaaaaa -> usize', + 'query': 'Aaaaaaa -> Result', 'others': [ { 'path': 'generics_impl::Aaaaaaa', 'name': 'read' }, ], @@ -23,6 +23,11 @@ const EXPECTED = [ 'query': 'Read -> u64', 'others': [ { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' }, + ], + }, + { + 'query': 'Ddddddd -> u64', + 'others': [ { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' }, ], }, @@ -30,7 +35,6 @@ const EXPECTED = [ 'query': 'trait:Read -> u64', 'others': [ { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' }, - { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' }, ], }, { diff --git a/tests/rustdoc-js/generics-impl.rs b/tests/rustdoc-js/generics-impl.rs index 27d44fdd7e92a..f9fe7f390f3cd 100644 --- a/tests/rustdoc-js/generics-impl.rs +++ b/tests/rustdoc-js/generics-impl.rs @@ -1,4 +1,4 @@ -use std::io::{Read, Result as IoResult}; +use std::io::{self, Read}; pub struct Aaaaaaa; @@ -12,7 +12,7 @@ impl Aaaaaaa { } impl Read for Aaaaaaa { - fn read(&mut self, out: &mut [u8]) -> IoResult { + fn read(&mut self, out: &mut [u8]) -> io::Result { Ok(out.len()) } } diff --git a/tests/rustdoc-js/generics-match-ambiguity-no-unbox.js b/tests/rustdoc-js/generics-match-ambiguity-no-unbox.js new file mode 100644 index 0000000000000..ea4c26d311c3d --- /dev/null +++ b/tests/rustdoc-js/generics-match-ambiguity-no-unbox.js @@ -0,0 +1,68 @@ +// ignore-order +// exact-check + +// Make sure that results are order-agnostic, even when there's search items that only differ +// by generics. + +const EXPECTED = [ + { + 'query': 'Wrap', + 'in_args': [ + { 'path': 'generics_match_ambiguity', 'name': 'bar' }, + { 'path': 'generics_match_ambiguity', 'name': 'foo' }, + ], + }, + { + 'query': 'Wrap', + 'in_args': [ + { 'path': 'generics_match_ambiguity', 'name': 'bar' }, + { 'path': 'generics_match_ambiguity', 'name': 'foo' }, + ], + }, + { + 'query': 'Wrap, Wrap', + 'others': [ + { 'path': 'generics_match_ambiguity', 'name': 'bar' }, + { 'path': 'generics_match_ambiguity', 'name': 'foo' }, + ], + }, + { + 'query': 'Wrap, Wrap', + 'others': [ + { 'path': 'generics_match_ambiguity', 'name': 'bar' }, + { 'path': 'generics_match_ambiguity', 'name': 'foo' }, + ], + }, + { + 'query': 'W3, W3', + 'others': [ + { 'path': 'generics_match_ambiguity', 'name': 'baaa' }, + { 'path': 'generics_match_ambiguity', 'name': 'baab' }, + ], + }, + { + 'query': 'W3, W3', + 'others': [ + { 'path': 'generics_match_ambiguity', 'name': 'baaa' }, + { 'path': 'generics_match_ambiguity', 'name': 'baab' }, + ], + }, + { + // strict generics matching; W2 doesn't match W2>, + // even though W2 works just fine (ignoring the W3) + 'query': 'W2, W2', + 'others': [], + }, + { + 'query': 'W2, W2', + 'others': [], + }, + { + 'query': 'W2, W3', + 'others': [], + }, + { + 'query': 'W2, W2', + 'others': [], + }, +]; diff --git a/tests/rustdoc-js/generics-match-ambiguity-no-unbox.rs b/tests/rustdoc-js/generics-match-ambiguity-no-unbox.rs new file mode 100644 index 0000000000000..43c2896fa2cdf --- /dev/null +++ b/tests/rustdoc-js/generics-match-ambiguity-no-unbox.rs @@ -0,0 +1,18 @@ +#![crate_name = "generics_match_ambiguity"] + +pub struct Wrap(pub T, pub U); + +pub fn foo(a: Wrap, b: Wrap) {} +pub fn bar(a: Wrap, b: Wrap) {} + +pub struct W2(pub T); +pub struct W3(pub T, pub U); + +pub fn baaa(a: W3, b: W3) {} +pub fn baab(a: W3, b: W3) {} +pub fn baac(a: W2>, b: W3) {} +pub fn baad(a: W2>, b: W3) {} +pub fn baae(a: W3, b: W2>) {} +pub fn baaf(a: W3, b: W2>) {} +pub fn baag(a: W2>, b: W2>) {} +pub fn baah(a: W2>, b: W2>) {} diff --git a/tests/rustdoc-js/generics-match-ambiguity.js b/tests/rustdoc-js/generics-match-ambiguity.js index edce4268c5ac7..aadb179321cf2 100644 --- a/tests/rustdoc-js/generics-match-ambiguity.js +++ b/tests/rustdoc-js/generics-match-ambiguity.js @@ -60,18 +60,14 @@ const EXPECTED = [ ], }, { + // strict generics matching; W2 doesn't match W2>, + // even though W2 works just fine (ignoring the W3) 'query': 'W2, W2', - 'others': [ - { 'path': 'generics_match_ambiguity', 'name': 'baag' }, - { 'path': 'generics_match_ambiguity', 'name': 'baah' }, - ], + 'others': [], }, { 'query': 'W2, W2', - 'others': [ - { 'path': 'generics_match_ambiguity', 'name': 'baag' }, - { 'path': 'generics_match_ambiguity', 'name': 'baah' }, - ], + 'others': [], }, { 'query': 'W2, W3', diff --git a/tests/rustdoc-js/generics-match-ambiguity.rs b/tests/rustdoc-js/generics-match-ambiguity.rs index 79c493856ebc7..7aadbbd609caf 100644 --- a/tests/rustdoc-js/generics-match-ambiguity.rs +++ b/tests/rustdoc-js/generics-match-ambiguity.rs @@ -1,9 +1,14 @@ +#![feature(rustdoc_internals)] + +#[doc(search_unbox)] pub struct Wrap(pub T, pub U); pub fn foo(a: Wrap, b: Wrap) {} pub fn bar(a: Wrap, b: Wrap) {} +#[doc(search_unbox)] pub struct W2(pub T); +#[doc(search_unbox)] pub struct W3(pub T, pub U); pub fn baaa(a: W3, b: W3) {} @@ -14,4 +19,3 @@ pub fn baae(a: W3, b: W2>) {} pub fn baaf(a: W3, b: W2>) {} pub fn baag(a: W2>, b: W2>) {} pub fn baah(a: W2>, b: W2>) {} -// diff --git a/tests/rustdoc-js/generics-nested.js b/tests/rustdoc-js/generics-nested.js index 294c194907489..b3184dde0d0c9 100644 --- a/tests/rustdoc-js/generics-nested.js +++ b/tests/rustdoc-js/generics-nested.js @@ -18,9 +18,8 @@ const EXPECTED = [ ], }, { + // can't put generics out of order 'query': '-> Out', - 'others': [ - { 'path': 'generics_nested', 'name': 'bet' }, - ], + 'others': [], }, ]; diff --git a/tests/rustdoc-js/generics-unbox.js b/tests/rustdoc-js/generics-unbox.js index 9cdfc7ac8b6e5..6baf00c814bba 100644 --- a/tests/rustdoc-js/generics-unbox.js +++ b/tests/rustdoc-js/generics-unbox.js @@ -11,20 +11,17 @@ const EXPECTED = [ 'query': 'Inside -> Out3', 'others': [ { 'path': 'generics_unbox', 'name': 'beta' }, - { 'path': 'generics_unbox', 'name': 'gamma' }, ], }, { 'query': 'Inside -> Out4', 'others': [ - { 'path': 'generics_unbox', 'name': 'beta' }, { 'path': 'generics_unbox', 'name': 'gamma' }, ], }, { 'query': 'Inside -> Out3', 'others': [ - { 'path': 'generics_unbox', 'name': 'beta' }, { 'path': 'generics_unbox', 'name': 'gamma' }, ], }, @@ -32,7 +29,6 @@ const EXPECTED = [ 'query': 'Inside -> Out4', 'others': [ { 'path': 'generics_unbox', 'name': 'beta' }, - { 'path': 'generics_unbox', 'name': 'gamma' }, ], }, ]; diff --git a/tests/rustdoc-js/generics-unbox.rs b/tests/rustdoc-js/generics-unbox.rs index bef34f891e95c..c2578575997b3 100644 --- a/tests/rustdoc-js/generics-unbox.rs +++ b/tests/rustdoc-js/generics-unbox.rs @@ -1,26 +1,34 @@ +#![feature(rustdoc_internals)] + +#[doc(search_unbox)] pub struct Out { a: A, b: B, } +#[doc(search_unbox)] pub struct Out1 { a: [A; N], } +#[doc(search_unbox)] pub struct Out2 { a: [A; N], } +#[doc(search_unbox)] pub struct Out3 { a: A, b: B, } +#[doc(search_unbox)] pub struct Out4 { a: A, b: B, } +#[doc(search_unbox)] pub struct Inside(T); pub fn alpha(_: Inside) -> Out, Out2> { diff --git a/tests/rustdoc-js/generics.js b/tests/rustdoc-js/generics.js index b3ca0af3056a5..a6d20538efee5 100644 --- a/tests/rustdoc-js/generics.js +++ b/tests/rustdoc-js/generics.js @@ -30,21 +30,13 @@ const EXPECTED = [ 'others': [ { 'path': 'generics', 'name': 'P' }, ], - 'returned': [ - { 'path': 'generics', 'name': 'alef' }, - ], - 'in_args': [ - { 'path': 'generics', 'name': 'alpha' }, - ], + 'returned': [], + 'in_args': [], }, { 'query': 'P', - 'returned': [ - { 'path': 'generics', 'name': 'alef' }, - ], - 'in_args': [ - { 'path': 'generics', 'name': 'alpha' }, - ], + 'returned': [], + 'in_args': [], }, { 'query': '"ExtraCreditStructMulti"', diff --git a/tests/rustdoc-js/hof.js b/tests/rustdoc-js/hof.js index 5e6c9d83c7c7f..c1142f106688b 100644 --- a/tests/rustdoc-js/hof.js +++ b/tests/rustdoc-js/hof.js @@ -9,19 +9,19 @@ const EXPECTED = [ // ML-style higher-order function notation { - 'query': 'bool, (u32 -> !) -> ()', + 'query': 'bool, (first -> !) -> ()', 'others': [ {"path": "hof", "name": "fn_ptr"}, ], }, { - 'query': 'u8, (u32 -> !) -> ()', + 'query': 'u8, (second -> !) -> ()', 'others': [ {"path": "hof", "name": "fn_once"}, ], }, { - 'query': 'i8, (u32 -> !) -> ()', + 'query': 'i8, (third -> !) -> ()', 'others': [ {"path": "hof", "name": "fn_mut"}, ], @@ -54,9 +54,6 @@ const EXPECTED = [ 'query': '(u32 -> !) -> ()', 'others': [ {"path": "hof", "name": "fn_"}, - {"path": "hof", "name": "fn_ptr"}, - {"path": "hof", "name": "fn_mut"}, - {"path": "hof", "name": "fn_once"}, ], }, { @@ -95,30 +92,30 @@ const EXPECTED = [ // Rust-style higher-order function notation { - 'query': 'bool, fn(u32) -> ! -> ()', + 'query': 'bool, fn(first) -> ! -> ()', 'others': [ {"path": "hof", "name": "fn_ptr"}, ], }, { - 'query': 'u8, fnonce(u32) -> ! -> ()', + 'query': 'u8, fnonce(second) -> ! -> ()', 'others': [ {"path": "hof", "name": "fn_once"}, ], }, { - 'query': 'u8, fn(u32) -> ! -> ()', + 'query': 'u8, fn(second) -> ! -> ()', // fnonce != fn 'others': [], }, { - 'query': 'i8, fnmut(u32) -> ! -> ()', + 'query': 'i8, fnmut(third) -> ! -> ()', 'others': [ {"path": "hof", "name": "fn_mut"}, ], }, { - 'query': 'i8, fn(u32) -> ! -> ()', + 'query': 'i8, fn(third) -> ! -> ()', // fnmut != fn 'others': [], }, @@ -152,7 +149,7 @@ const EXPECTED = [ ], }, { - 'query': 'fn(u32) -> ! -> ()', + 'query': 'fn() -> ! -> ()', 'others': [ // fn matches primitive:fn and trait:Fn {"path": "hof", "name": "fn_"}, @@ -160,14 +157,14 @@ const EXPECTED = [ ], }, { - 'query': 'trait:fn(u32) -> ! -> ()', + 'query': 'trait:fn() -> ! -> ()', 'others': [ // fn matches primitive:fn and trait:Fn {"path": "hof", "name": "fn_"}, ], }, { - 'query': 'primitive:fn(u32) -> ! -> ()', + 'query': 'primitive:fn() -> ! -> ()', 'others': [ // fn matches primitive:fn and trait:Fn {"path": "hof", "name": "fn_ptr"}, diff --git a/tests/rustdoc-js/looks-like-rustc-interner.js b/tests/rustdoc-js/looks-like-rustc-interner.js index a4806d2349929..d6d2764c3aede 100644 --- a/tests/rustdoc-js/looks-like-rustc-interner.js +++ b/tests/rustdoc-js/looks-like-rustc-interner.js @@ -1,9 +1,15 @@ // https://github.com/rust-lang/rust/pull/122247 // exact-check -const EXPECTED = { - 'query': 'canonicalvarinfo, intoiterator -> intoiterator', - 'others': [ - { 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_infos' }, - ], -}; +const EXPECTED = [ + { + 'query': 'canonicalvarinfo, intoiterator -> intoiterator', + 'others': [], + }, + { + 'query': '[canonicalvarinfo], interner -> intoiterator', + 'others': [ + { 'path': 'looks_like_rustc_interner::Interner', 'name': 'mk_canonical_var_infos' }, + ], + }, +]; diff --git a/tests/rustdoc-js/nested-unboxed.js b/tests/rustdoc-js/nested-unboxed.js index 44f784eb1f638..5f9eabc12f60f 100644 --- a/tests/rustdoc-js/nested-unboxed.js +++ b/tests/rustdoc-js/nested-unboxed.js @@ -33,9 +33,8 @@ const EXPECTED = [ }, { 'query': '-> Result', - 'others': [ - { 'path': 'nested_unboxed', 'name': 'something' }, - ], + // can't put nested generics out of order + 'others': [], }, { 'query': '-> Result, bool>', @@ -45,9 +44,7 @@ const EXPECTED = [ }, { 'query': '-> Result, bool>', - 'others': [ - { 'path': 'nested_unboxed', 'name': 'something' }, - ], + 'others': [], }, { 'query': '-> Result, u32, bool>', diff --git a/tests/rustdoc-js/nested-unboxed.rs b/tests/rustdoc-js/nested-unboxed.rs index 57f9592b79147..6c8b1bd6aa144 100644 --- a/tests/rustdoc-js/nested-unboxed.rs +++ b/tests/rustdoc-js/nested-unboxed.rs @@ -1,3 +1,6 @@ +#![feature(rustdoc_internals)] + +#[doc(search_unbox)] pub struct Object(T, U); pub fn something() -> Result, bool> { diff --git a/tests/rustdoc-js/reference.js b/tests/rustdoc-js/reference.js index b4a1fb15d369a..378fc03475b87 100644 --- a/tests/rustdoc-js/reference.js +++ b/tests/rustdoc-js/reference.js @@ -79,9 +79,8 @@ const EXPECTED = [ }, { 'query': 'reference, reference -> ()', - 'others': [ - { 'path': 'reference::Ring', 'name': 'wear' }, - ], + // can't leave out the `mut`, because can't reorder like that + 'others': [], }, { 'query': 'reference, reference -> ()', @@ -102,9 +101,8 @@ const EXPECTED = [ }, { 'query': 'reference, reference -> ()', - 'others': [ - { 'path': 'reference', 'name': 'show' }, - ], + // can't leave out the mut + 'others': [], }, { 'query': 'reference, reference -> ()', @@ -203,9 +201,8 @@ const EXPECTED = [ // middle with shorthand { 'query': '&middle, &middle -> ()', - 'others': [ - { 'path': 'reference', 'name': 'show' }, - ], + // can't leave out the mut + 'others': [], }, { 'query': '&mut middle, &mut middle -> ()', diff --git a/tests/rustdoc-js/tuple-unit.js b/tests/rustdoc-js/tuple-unit.js index d24a3da328c56..6a9b861cf948c 100644 --- a/tests/rustdoc-js/tuple-unit.js +++ b/tests/rustdoc-js/tuple-unit.js @@ -57,7 +57,7 @@ const EXPECTED = [ 'in_args': [], }, { - 'query': '(Q, ())', + 'query': '(Q, R<()>)', 'returned': [ { 'path': 'tuple_unit', 'name': 'nest' }, ], @@ -71,7 +71,7 @@ const EXPECTED = [ 'in_args': [], }, { - 'query': '(u32)', + 'query': 'R<(u32)>', 'returned': [ { 'path': 'tuple_unit', 'name': 'nest' }, ], diff --git a/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs b/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs index 58306a4cfc9c9..57d6b59128703 100644 --- a/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs +++ b/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs @@ -7,4 +7,7 @@ trait Mine {} #[doc(fake_variadic)] //~ ERROR: `#[doc(fake_variadic)]` is meant for internal use only impl Mine for (T,) {} +#[doc(search_unbox)] //~ ERROR: `#[doc(search_unbox)]` is meant for internal use only +struct Wrap (T); + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-rustdoc_internals.stderr b/tests/ui/feature-gates/feature-gate-rustdoc_internals.stderr index bbb9edd58f096..f3c00a2156bf9 100644 --- a/tests/ui/feature-gates/feature-gate-rustdoc_internals.stderr +++ b/tests/ui/feature-gates/feature-gate-rustdoc_internals.stderr @@ -18,6 +18,16 @@ LL | #[doc(fake_variadic)] = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 2 previous errors +error[E0658]: `#[doc(search_unbox)]` is meant for internal use only + --> $DIR/feature-gate-rustdoc_internals.rs:10:1 + | +LL | #[doc(search_unbox)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #90418 for more information + = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. From c5e86c47a1a5b7fe6cc997eb889ea106172c982e Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Thu, 31 Oct 2024 02:32:14 +0300 Subject: [PATCH 17/79] Fixed a typo in the GetThreadDescription shim --- src/tools/miri/src/shims/windows/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index dee778876f6b0..e41ff022549e1 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -523,7 +523,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread = match Handle::from_scalar(handle, this)? { Some(Handle::Thread(thread)) => thread, Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), - _ => this.invalid_handle("SetThreadDescription")?, + _ => this.invalid_handle("GetThreadDescription")?, }; // Looks like the default thread name is empty. let name = this.get_thread_name(thread).unwrap_or(b"").to_owned(); From 1c88af65603b3df97411a9c0c46427100ab997a3 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 31 Oct 2024 04:55:42 +0000 Subject: [PATCH 18/79] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0e3537b185fc2..2ec411b54b186 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -16422dbd8958179379214e8f43fdb73a06b2eada +75eff9a5749411ba5a0b37cc3299116c4e263075 From ef6b9a9513cebe12605352c2a1ecbdcbcc686fa8 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 31 Oct 2024 05:04:44 +0000 Subject: [PATCH 19/79] fmt --- src/tools/miri/src/shims/native_lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 525bcd381d52c..e7a4251242e2a 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -3,9 +3,9 @@ use std::ops::Deref; use libffi::high::call as ffi; use libffi::low::CodePtr; +use rustc_abi::{BackendRepr, HasDataLayout}; use rustc_middle::ty::{self as ty, IntTy, UintTy}; use rustc_span::Symbol; -use rustc_abi::{BackendRepr, HasDataLayout}; use crate::*; From b8bd7becb419084397adc6b797136c20046fdacb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Oct 2024 08:14:56 +0100 Subject: [PATCH 20/79] silence clippy --- src/tools/miri/src/shims/x86/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index e2b02873aefee..2f63876327f7c 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1000,6 +1000,7 @@ fn mask_load<'tcx>( let dest = this.project_index(&dest, i)?; if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + #[allow(clippy::arithmetic_side_effects)] // `Size` arithmetic is checked let ptr = ptr.wrapping_offset(dest.layout.size * i, &this.tcx); // Unaligned copy, which is what we want. this.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; @@ -1035,6 +1036,7 @@ fn mask_store<'tcx>( if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { // *Non-inbounds* pointer arithmetic to compute the destination. // (That's why we can't use a place projection.) + #[allow(clippy::arithmetic_side_effects)] // `Size` arithmetic is checked let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx); // Deref the pointer *unaligned*, and do the copy. let dest = this.ptr_to_mplace_unaligned(ptr, value.layout); From 9900ea48b566656fb12b5fcbd0a1b20aaa96e5ca Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 31 Oct 2024 13:09:37 -0700 Subject: [PATCH 21/79] Adjust ranking so that duplicates count against rank --- src/librustdoc/html/static/js/search.js | 25 +++++++++----------- tests/rustdoc-js-std/simd-type-signatures.js | 20 ++++++++-------- tests/rustdoc-js-std/transmute-fail.js | 13 ++++++++++ tests/rustdoc-js-std/transmute.js | 12 ++++++++++ tests/rustdoc-js/impl-trait.js | 6 ++--- tests/rustdoc-js/type-parameters.js | 6 ++--- 6 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 tests/rustdoc-js-std/transmute-fail.js create mode 100644 tests/rustdoc-js-std/transmute.js diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index d269c9322a317..4e1bbbbf59d89 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1412,7 +1412,7 @@ class DocSearch { * query fingerprint. If any bits are set in the query but not in the function, it can't * match. * - * - The fourth section has the number of distinct items in the set. + * - The fourth section has the number of items in the set. * This is the distance function, used for filtering and for sorting. * * [^1]: Distance is the relatively naive metric of counting the number of distinct items in @@ -1420,9 +1420,8 @@ class DocSearch { * * @param {FunctionType|QueryElement} type - a single type * @param {Uint32Array} output - write the fingerprint to this data structure: uses 128 bits - * @param {Set} fps - Set of distinct items */ - buildFunctionTypeFingerprint(type, output, fps) { + buildFunctionTypeFingerprint(type, output) { let input = type.id; // All forms of `[]`/`()`/`->` get collapsed down to one thing in the bloom filter. // Differentiating between arrays and slices, if the user asks for it, is @@ -1468,10 +1467,11 @@ class DocSearch { output[0] |= (1 << (h0a % 32)) | (1 << (h1b % 32)); output[1] |= (1 << (h1a % 32)) | (1 << (h2b % 32)); output[2] |= (1 << (h2a % 32)) | (1 << (h0b % 32)); - fps.add(input); + // output[3] is the total number of items in the type signature + output[3] += 1; } for (const g of type.generics) { - this.buildFunctionTypeFingerprint(g, output, fps); + this.buildFunctionTypeFingerprint(g, output); } const fb = { id: null, @@ -1482,9 +1482,8 @@ class DocSearch { for (const [k, v] of type.bindings.entries()) { fb.id = k; fb.generics = v; - this.buildFunctionTypeFingerprint(fb, output, fps); + this.buildFunctionTypeFingerprint(fb, output); } - output[3] = fps.size; } /** @@ -1734,16 +1733,15 @@ class DocSearch { if (type !== null) { if (type) { const fp = this.functionTypeFingerprint.subarray(id * 4, (id + 1) * 4); - const fps = new Set(); for (const t of type.inputs) { - this.buildFunctionTypeFingerprint(t, fp, fps); + this.buildFunctionTypeFingerprint(t, fp); } for (const t of type.output) { - this.buildFunctionTypeFingerprint(t, fp, fps); + this.buildFunctionTypeFingerprint(t, fp); } for (const w of type.where_clause) { for (const t of w) { - this.buildFunctionTypeFingerprint(t, fp, fps); + this.buildFunctionTypeFingerprint(t, fp); } } } @@ -3885,14 +3883,13 @@ class DocSearch { ); }; - const fps = new Set(); for (const elem of parsedQuery.elems) { convertNameToId(elem); - this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint, fps); + this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint); } for (const elem of parsedQuery.returned) { convertNameToId(elem); - this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint, fps); + this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint); } if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) { diff --git a/tests/rustdoc-js-std/simd-type-signatures.js b/tests/rustdoc-js-std/simd-type-signatures.js index c07f15dcbe8b1..4fc14e65ac424 100644 --- a/tests/rustdoc-js-std/simd-type-signatures.js +++ b/tests/rustdoc-js-std/simd-type-signatures.js @@ -20,11 +20,6 @@ const EXPECTED = [ 'name': 'simd_min', 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+N%3E/method.simd_min' }, - { - 'path': 'std::simd::prelude::Simd', - 'name': 'simd_clamp', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+N%3E/method.simd_clamp' - }, { 'path': 'std::simd::prelude::Simd', 'name': 'saturating_add', @@ -35,6 +30,11 @@ const EXPECTED = [ 'name': 'saturating_sub', 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+N%3E/method.saturating_sub' }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'simd_clamp', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+N%3E/method.simd_clamp' + }, ], }, { @@ -50,11 +50,6 @@ const EXPECTED = [ 'name': 'simd_min', 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+N%3E/method.simd_min' }, - { - 'path': 'std::simd::prelude::Simd', - 'name': 'simd_clamp', - 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+N%3E/method.simd_clamp' - }, { 'path': 'std::simd::prelude::Simd', 'name': 'saturating_add', @@ -65,6 +60,11 @@ const EXPECTED = [ 'name': 'saturating_sub', 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+N%3E/method.saturating_sub' }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'simd_clamp', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+N%3E/method.simd_clamp' + }, ], }, ]; diff --git a/tests/rustdoc-js-std/transmute-fail.js b/tests/rustdoc-js-std/transmute-fail.js new file mode 100644 index 0000000000000..c4dddf3cf3cee --- /dev/null +++ b/tests/rustdoc-js-std/transmute-fail.js @@ -0,0 +1,13 @@ +// should-fail +const EXPECTED = [ + { + // Keep this test case identical to `transmute`, except the + // should-fail tag and the search query below: + 'query': 'generic:T -> generic:T', + 'others': [ + { 'path': 'std::intrinsics::simd', 'name': 'simd_as' }, + { 'path': 'std::intrinsics::simd', 'name': 'simd_cast' }, + { 'path': 'std::intrinsics', 'name': 'transmute' }, + ], + }, +]; diff --git a/tests/rustdoc-js-std/transmute.js b/tests/rustdoc-js-std/transmute.js new file mode 100644 index 0000000000000..0e52e21e0dead --- /dev/null +++ b/tests/rustdoc-js-std/transmute.js @@ -0,0 +1,12 @@ +const EXPECTED = [ + { + // Keep this test case identical to `transmute-fail`, except the + // should-fail tag and the search query below: + 'query': 'generic:T -> generic:U', + 'others': [ + { 'path': 'std::intrinsics::simd', 'name': 'simd_as' }, + { 'path': 'std::intrinsics::simd', 'name': 'simd_cast' }, + { 'path': 'std::intrinsics', 'name': 'transmute' }, + ], + }, +]; diff --git a/tests/rustdoc-js/impl-trait.js b/tests/rustdoc-js/impl-trait.js index 8bb3f2d3e99a5..3d7d0ca5bcda9 100644 --- a/tests/rustdoc-js/impl-trait.js +++ b/tests/rustdoc-js/impl-trait.js @@ -23,8 +23,8 @@ const EXPECTED = [ 'others': [ { 'path': 'impl_trait', 'name': 'bbbbbbb' }, { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' }, - { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, { 'path': 'impl_trait::Ccccccc', 'name': 'ggggggg' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, ], }, { @@ -39,14 +39,14 @@ const EXPECTED = [ { 'path': 'impl_trait', 'name': 'Aaaaaaa' }, ], 'in_args': [ - { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, ], 'returned': [ { 'path': 'impl_trait', 'name': 'bbbbbbb' }, { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' }, - { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, { 'path': 'impl_trait::Ccccccc', 'name': 'ggggggg' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, ], }, ]; diff --git a/tests/rustdoc-js/type-parameters.js b/tests/rustdoc-js/type-parameters.js index e045409e507e5..fa2b8d2ebfdb6 100644 --- a/tests/rustdoc-js/type-parameters.js +++ b/tests/rustdoc-js/type-parameters.js @@ -11,9 +11,9 @@ const EXPECTED = [ { query: '-> generic:T', others: [ - { path: 'foo', name: 'beta' }, { path: 'foo', name: 'bet' }, { path: 'foo', name: 'alef' }, + { path: 'foo', name: 'beta' }, ], }, { @@ -50,8 +50,8 @@ const EXPECTED = [ { query: 'generic:T', in_args: [ - { path: 'foo', name: 'beta' }, { path: 'foo', name: 'bet' }, + { path: 'foo', name: 'beta' }, { path: 'foo', name: 'alternate' }, { path: 'foo', name: 'other' }, ], @@ -59,8 +59,8 @@ const EXPECTED = [ { query: 'generic:Other', in_args: [ - { path: 'foo', name: 'beta' }, { path: 'foo', name: 'bet' }, + { path: 'foo', name: 'beta' }, { path: 'foo', name: 'alternate' }, { path: 'foo', name: 'other' }, ], From c8b76bcf58298cced4ef3ca9dd823eb318fc11f5 Mon Sep 17 00:00:00 2001 From: Luca Versari Date: Sat, 13 Jul 2024 19:35:05 +0200 Subject: [PATCH 22/79] Emit warning when calling/declaring functions with unavailable vectors. On some architectures, vector types may have a different ABI depending on whether the relevant target features are enabled. (The ABI when the feature is disabled is often not specified, but LLVM implements some de-facto ABI.) As discussed in rust-lang/lang-team#235, this turns out to very easily lead to unsound code. This commit makes it a post-monomorphization future-incompat warning to declare or call functions using those vector types in a context in which the corresponding target features are disabled, if using an ABI for which the difference is relevant. This ensures that these functions are always called with a consistent ABI. See the [nomination comment](https://github.com/rust-lang/rust/pull/127731#issuecomment-2288558187) for more discussion. Part of #116558 --- compiler/rustc_lint_defs/src/builtin.rs | 67 ++++++++ compiler/rustc_middle/src/query/mod.rs | 8 + compiler/rustc_monomorphize/messages.ftl | 9 + compiler/rustc_monomorphize/src/collector.rs | 4 + .../src/collector/abi_check.rs | 162 ++++++++++++++++++ compiler/rustc_monomorphize/src/errors.rs | 18 ++ compiler/rustc_target/src/target_features.rs | 17 ++ tests/crashes/131342-2.rs | 40 ----- tests/crashes/131342.rs | 17 +- tests/ui/layout/post-mono-layout-cycle-2.rs | 1 - .../ui/layout/post-mono-layout-cycle-2.stderr | 10 +- tests/ui/layout/post-mono-layout-cycle.rs | 1 - tests/ui/layout/post-mono-layout-cycle.stderr | 10 +- tests/ui/simd-abi-checks.rs | 81 +++++++++ tests/ui/simd-abi-checks.stderr | 93 ++++++++++ tests/ui/sse-abi-checks.rs | 24 +++ tests/ui/sse-abi-checks.stderr | 13 ++ 17 files changed, 514 insertions(+), 61 deletions(-) create mode 100644 compiler/rustc_monomorphize/src/collector/abi_check.rs delete mode 100644 tests/crashes/131342-2.rs create mode 100644 tests/ui/simd-abi-checks.rs create mode 100644 tests/ui/simd-abi-checks.stderr create mode 100644 tests/ui/sse-abi-checks.rs create mode 100644 tests/ui/sse-abi-checks.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 06a3e4a674303..51146cfd2e9aa 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -16,6 +16,7 @@ declare_lint_pass! { /// that are used by other parts of the compiler. HardwiredLints => [ // tidy-alphabetical-start + ABI_UNSUPPORTED_VECTOR_TYPES, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_ASSOCIATED_ITEMS, AMBIGUOUS_GLOB_IMPORTS, @@ -5031,3 +5032,69 @@ declare_lint! { }; crate_level_only } + +declare_lint! { + /// The `abi_unsupported_vector_types` lint detects function definitions and calls + /// whose ABI depends on enabling certain target features, but those features are not enabled. + /// + /// ### Example + /// + /// ```rust,ignore (fails on non-x86_64) + /// extern "C" fn missing_target_feature(_: std::arch::x86_64::__m256) { + /// todo!() + /// } + /// + /// #[target_feature(enable = "avx")] + /// unsafe extern "C" fn with_target_feature(_: std::arch::x86_64::__m256) { + /// todo!() + /// } + /// + /// fn main() { + /// let v = unsafe { std::mem::zeroed() }; + /// unsafe { with_target_feature(v); } + /// } + /// ``` + /// + /// ```text + /// warning: ABI error: this function call uses a avx vector type, which is not enabled in the caller + /// --> lint_example.rs:18:12 + /// | + /// | unsafe { with_target_feature(v); } + /// | ^^^^^^^^^^^^^^^^^^^^^^ function called here + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #116558 + /// = help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) + /// = note: `#[warn(abi_unsupported_vector_types)]` on by default + /// + /// + /// warning: ABI error: this function definition uses a avx vector type, which is not enabled + /// --> lint_example.rs:3:1 + /// | + /// | pub extern "C" fn with_target_feature(_: std::arch::x86_64::__m256) { + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #116558 + /// = help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) + /// ``` + /// + /// + /// + /// ### Explanation + /// + /// The C ABI for `__m256` requires the value to be passed in an AVX register, + /// which is only possible when the `avx` target feature is enabled. + /// Therefore, `missing_target_feature` cannot be compiled without that target feature. + /// A similar (but complementary) message is triggered when `with_target_feature` is called + /// by a function that does not enable the `avx` target feature. + /// + /// Note that this lint is very similar to the `-Wpsabi` warning in `gcc`/`clang`. + pub ABI_UNSUPPORTED_VECTOR_TYPES, + Warn, + "this function call or definition uses a vector type which is not enabled", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reference: "issue #116558 ", + }; +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 088b5d4ec965f..3f61d7cc66f7b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2315,6 +2315,14 @@ rustc_queries! { desc { "whether the item should be made inlinable across crates" } separate_provide_extern } + + /// Check the signature of this function as well as all the call expressions inside of it + /// to ensure that any target features required by the ABI are enabled. + /// Should be called on a fully monomorphized instance. + query check_feature_dependent_abi(key: ty::Instance<'tcx>) { + desc { "check for feature-dependent ABI" } + cache_on_disk_if { true } + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 7210701d4828c..6da387bbebcc7 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -1,3 +1,12 @@ +monomorphize_abi_error_disabled_vector_type_call = + ABI error: this function call uses a vector type that requires the `{$required_feature}` target feature, which is not enabled in the caller + .label = function called here + .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) +monomorphize_abi_error_disabled_vector_type_def = + ABI error: this function definition uses a vector type that requires the `{$required_feature}` target feature, which is not enabled + .label = function defined here + .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) + monomorphize_couldnt_dump_mono_stats = unexpected error occurred while dumping monomorphization stats: {$error} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8df6e63deeb18..63afad5df4971 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,6 +205,7 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. +mod abi_check; mod move_check; use std::path::PathBuf; @@ -1207,6 +1208,8 @@ fn collect_items_of_instance<'tcx>( mentioned_items: &mut MonoItems<'tcx>, mode: CollectionMode, ) { + tcx.ensure().check_feature_dependent_abi(instance); + let body = tcx.instance_mir(instance.def); // Naively, in "used" collection mode, all functions get added to *both* `used_items` and // `mentioned_items`. Mentioned items processing will then notice that they have already been @@ -1623,4 +1626,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>( pub(crate) fn provide(providers: &mut Providers) { providers.hooks.should_codegen_locally = should_codegen_locally; + abi_check::provide(providers); } diff --git a/compiler/rustc_monomorphize/src/collector/abi_check.rs b/compiler/rustc_monomorphize/src/collector/abi_check.rs new file mode 100644 index 0000000000000..f1c57f1e9975f --- /dev/null +++ b/compiler/rustc_monomorphize/src/collector/abi_check.rs @@ -0,0 +1,162 @@ +//! This module ensures that if a function's ABI requires a particular target feature, +//! that target feature is enabled both on the callee and all callers. +use rustc_hir::CRATE_HIR_ID; +use rustc_middle::mir::visit::Visitor as MirVisitor; +use rustc_middle::mir::{self, Location, traversal}; +use rustc_middle::query::Providers; +use rustc_middle::ty::inherent::*; +use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; +use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES; +use rustc_span::def_id::DefId; +use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_target::abi::call::{FnAbi, PassMode}; +use rustc_target::abi::{BackendRepr, RegKind}; + +use crate::errors::{AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef}; + +fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool { + match mode { + PassMode::Ignore | PassMode::Indirect { .. } => false, + PassMode::Cast { pad_i32: _, cast } => { + cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) + || cast.rest.unit.kind == RegKind::Vector + } + PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::Vector { .. }), + } +} + +fn do_check_abi<'tcx>( + tcx: TyCtxt<'tcx>, + abi: &FnAbi<'tcx, Ty<'tcx>>, + target_feature_def: DefId, + mut emit_err: impl FnMut(&'static str), +) { + let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else { + return; + }; + let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def); + for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { + let size = arg_abi.layout.size; + if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { + // Find the first feature that provides at least this vector size. + let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { + Some((_, feature)) => feature, + None => { + emit_err(""); + continue; + } + }; + let feature_sym = Symbol::intern(feature); + if !tcx.sess.unstable_target_features.contains(&feature_sym) + && !codegen_attrs.target_features.iter().any(|x| x.name == feature_sym) + { + emit_err(feature); + } + } + } +} + +/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments +/// or return values for which the corresponding target feature is not enabled. +fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { + let param_env = ParamEnv::reveal_all(); + let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else { + // An error will be reported during codegen if we cannot determine the ABI of this + // function. + return; + }; + do_check_abi(tcx, abi, instance.def_id(), |required_feature| { + let span = tcx.def_span(instance.def_id()); + tcx.emit_node_span_lint( + ABI_UNSUPPORTED_VECTOR_TYPES, + CRATE_HIR_ID, + span, + AbiErrorDisabledVectorTypeDef { span, required_feature }, + ); + }) +} + +/// Checks that a call expression does not try to pass a vector-passed argument which requires a +/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch. +fn check_call_site_abi<'tcx>( + tcx: TyCtxt<'tcx>, + callee: Ty<'tcx>, + span: Span, + caller: InstanceKind<'tcx>, +) { + if callee.fn_sig(tcx).abi().is_rust() { + // "Rust" ABI never passes arguments in vector registers. + return; + } + let param_env = ParamEnv::reveal_all(); + let callee_abi = match *callee.kind() { + ty::FnPtr(..) => { + tcx.fn_abi_of_fn_ptr(param_env.and((callee.fn_sig(tcx), ty::List::empty()))) + } + ty::FnDef(def_id, args) => { + // Intrinsics are handled separately by the compiler. + if tcx.intrinsic(def_id).is_some() { + return; + } + let instance = ty::Instance::expect_resolve(tcx, param_env, def_id, args, DUMMY_SP); + tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) + } + _ => { + panic!("Invalid function call"); + } + }; + + let Ok(callee_abi) = callee_abi else { + // ABI failed to compute; this will not get through codegen. + return; + }; + do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| { + tcx.emit_node_span_lint( + ABI_UNSUPPORTED_VECTOR_TYPES, + CRATE_HIR_ID, + span, + AbiErrorDisabledVectorTypeCall { span, required_feature }, + ); + }); +} + +struct MirCallesAbiCheck<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + instance: Instance<'tcx>, +} + +impl<'a, 'tcx> MirVisitor<'tcx> for MirCallesAbiCheck<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, _: Location) { + match terminator.kind { + mir::TerminatorKind::Call { ref func, ref fn_span, .. } + | mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => { + let callee_ty = func.ty(self.body, self.tcx); + let callee_ty = self.instance.instantiate_mir_and_normalize_erasing_regions( + self.tcx, + ty::ParamEnv::reveal_all(), + ty::EarlyBinder::bind(callee_ty), + ); + check_call_site_abi(self.tcx, callee_ty, *fn_span, self.body.source.instance); + } + _ => {} + } + } +} + +fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { + let body = tcx.instance_mir(instance.def); + let mut visitor = MirCallesAbiCheck { tcx, body, instance }; + for (bb, data) in traversal::mono_reachable(body, tcx, instance) { + visitor.visit_basic_block_data(bb, data) + } +} + +fn check_feature_dependent_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { + check_instance_abi(tcx, instance); + check_callees_abi(tcx, instance); +} + +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { check_feature_dependent_abi, ..*providers } +} diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index d5fae6e23cb45..5048a8d5d993f 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -92,3 +92,21 @@ pub(crate) struct StartNotFound; pub(crate) struct UnknownCguCollectionMode<'a> { pub mode: &'a str, } + +#[derive(LintDiagnostic)] +#[diag(monomorphize_abi_error_disabled_vector_type_def)] +#[help] +pub(crate) struct AbiErrorDisabledVectorTypeDef<'a> { + #[label] + pub span: Span, + pub required_feature: &'a str, +} + +#[derive(LintDiagnostic)] +#[diag(monomorphize_abi_error_disabled_vector_type_call)] +#[help] +pub(crate) struct AbiErrorDisabledVectorTypeCall<'a> { + #[label] + pub span: Span, + pub required_feature: &'a str, +} diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 3df8f0590a354..94f771954e145 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -524,6 +524,13 @@ pub fn all_known_features() -> impl Iterator { .map(|(f, s, _)| (f, s)) } +// These arrays represent the least-constraining feature that is required for vector types up to a +// certain size to have their "proper" ABI on each architecture. +// Note that they must be kept sorted by vector size. +const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "sse"), (256, "avx"), (512, "avx512f")]; +const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; + impl super::spec::Target { pub fn supported_target_features( &self, @@ -545,6 +552,16 @@ impl super::spec::Target { } } + // Returns None if we do not support ABI checks on the given target yet. + pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> { + match &*self.arch { + "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI), + "aarch64" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI), + // FIXME: add support for non-tier1 architectures + _ => None, + } + } + pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] { match &*self.arch { "aarch64" | "arm64ec" => AARCH64_TIED_FEATURES, diff --git a/tests/crashes/131342-2.rs b/tests/crashes/131342-2.rs deleted file mode 100644 index 79b6a837a49fb..0000000000000 --- a/tests/crashes/131342-2.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ known-bug: #131342 -// see also: 131342.rs - -fn main() { - problem_thingy(Once); -} - -struct Once; - -impl Iterator for Once { - type Item = (); -} - -fn problem_thingy(items: impl Iterator) { - let peeker = items.peekable(); - problem_thingy(&peeker); -} - -trait Iterator { - type Item; - - fn peekable(self) -> Peekable - where - Self: Sized, - { - loop {} - } -} - -struct Peekable { - _peeked: I::Item, -} - -impl Iterator for Peekable { - type Item = I::Item; -} - -impl Iterator for &I { - type Item = I::Item; -} diff --git a/tests/crashes/131342.rs b/tests/crashes/131342.rs index 7f7ee9c9ac110..f4404092917a4 100644 --- a/tests/crashes/131342.rs +++ b/tests/crashes/131342.rs @@ -1,16 +1,15 @@ //@ known-bug: #131342 -// see also: 131342-2.rs fn main() { - let mut items = vec![1, 2, 3, 4, 5].into_iter(); - problem_thingy(&mut items); + let mut items = vec![1, 2, 3, 4, 5].into_iter(); + problem_thingy(&mut items); } fn problem_thingy(items: &mut impl Iterator) { - let mut peeker = items.peekable(); - match peeker.peek() { - Some(_) => (), - None => return (), - } - problem_thingy(&mut peeker); + let mut peeker = items.peekable(); + match peeker.peek() { + Some(_) => (), + None => return (), + } + problem_thingy(&mut peeker); } diff --git a/tests/ui/layout/post-mono-layout-cycle-2.rs b/tests/ui/layout/post-mono-layout-cycle-2.rs index 356f1e777c7d0..e9a5292fbbdfb 100644 --- a/tests/ui/layout/post-mono-layout-cycle-2.rs +++ b/tests/ui/layout/post-mono-layout-cycle-2.rs @@ -45,7 +45,6 @@ where T: Blah, { async fn ice(&mut self) { - //~^ ERROR a cycle occurred during layout computation let arr: [(); 0] = []; self.t.iter(arr.into_iter()).await; } diff --git a/tests/ui/layout/post-mono-layout-cycle-2.stderr b/tests/ui/layout/post-mono-layout-cycle-2.stderr index ad01c2694faf5..2e8d237844e8e 100644 --- a/tests/ui/layout/post-mono-layout-cycle-2.stderr +++ b/tests/ui/layout/post-mono-layout-cycle-2.stderr @@ -12,12 +12,12 @@ LL | Blah::iter(self, iterator).await | = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future -error: a cycle occurred during layout computation - --> $DIR/post-mono-layout-cycle-2.rs:47:5 +note: the above error was encountered while instantiating `fn Wrap::<()>::ice` + --> $DIR/post-mono-layout-cycle-2.rs:56:9 | -LL | async fn ice(&mut self) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | t.ice(); + | ^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/layout/post-mono-layout-cycle.rs b/tests/ui/layout/post-mono-layout-cycle.rs index 8d136190c0052..6753c01267ecd 100644 --- a/tests/ui/layout/post-mono-layout-cycle.rs +++ b/tests/ui/layout/post-mono-layout-cycle.rs @@ -14,7 +14,6 @@ struct Wrapper { } fn abi(_: Option>) {} -//~^ ERROR a cycle occurred during layout computation fn indirect() { abi::(None); diff --git a/tests/ui/layout/post-mono-layout-cycle.stderr b/tests/ui/layout/post-mono-layout-cycle.stderr index 47f7f30b1cb4c..7f246b3d409ad 100644 --- a/tests/ui/layout/post-mono-layout-cycle.stderr +++ b/tests/ui/layout/post-mono-layout-cycle.stderr @@ -5,12 +5,12 @@ error[E0391]: cycle detected when computing layout of `Wrapper<()>` = note: cycle used when computing layout of `core::option::Option>` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: a cycle occurred during layout computation - --> $DIR/post-mono-layout-cycle.rs:16:1 +note: the above error was encountered while instantiating `fn abi::<()>` + --> $DIR/post-mono-layout-cycle.rs:19:5 | -LL | fn abi(_: Option>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | abi::(None); + | ^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/simd-abi-checks.rs b/tests/ui/simd-abi-checks.rs new file mode 100644 index 0000000000000..094c89930b752 --- /dev/null +++ b/tests/ui/simd-abi-checks.rs @@ -0,0 +1,81 @@ +//@ only-x86_64 +//@ build-pass +//@ ignore-pass (test emits codegen-time warnings) + +#![feature(avx512_target_feature)] +#![feature(portable_simd)] +#![allow(improper_ctypes_definitions)] + +use std::arch::x86_64::*; + +#[repr(transparent)] +struct Wrapper(__m256); + +unsafe extern "C" fn w(_: Wrapper) { + //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + //~| WARNING this was previously accepted by the compiler + todo!() +} + +unsafe extern "C" fn f(_: __m256) { + //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + //~| WARNING this was previously accepted by the compiler + todo!() +} + +unsafe extern "C" fn g() -> __m256 { + //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + //~| WARNING this was previously accepted by the compiler + todo!() +} + +#[target_feature(enable = "avx")] +unsafe extern "C" fn favx() -> __m256 { + todo!() +} + +// avx2 implies avx, so no error here. +#[target_feature(enable = "avx2")] +unsafe extern "C" fn gavx(_: __m256) { + todo!() +} + +// No error because of "Rust" ABI. +fn as_f64x8(d: __m512d) -> std::simd::f64x8 { + unsafe { std::mem::transmute(d) } +} + +unsafe fn test() { + let arg = std::mem::transmute([0.0f64; 8]); + as_f64x8(arg); +} + +fn main() { + unsafe { + f(g()); + //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING this was previously accepted by the compiler + //~| WARNING this was previously accepted by the compiler + } + + unsafe { + gavx(favx()); + //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING this was previously accepted by the compiler + //~| WARNING this was previously accepted by the compiler + } + + unsafe { + test(); + } + + unsafe { + w(Wrapper(g())); + //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING this was previously accepted by the compiler + //~| WARNING this was previously accepted by the compiler + } +} diff --git a/tests/ui/simd-abi-checks.stderr b/tests/ui/simd-abi-checks.stderr new file mode 100644 index 0000000000000..aa7e940016981 --- /dev/null +++ b/tests/ui/simd-abi-checks.stderr @@ -0,0 +1,93 @@ +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:55:11 + | +LL | f(g()); + | ^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + = note: `#[warn(abi_unsupported_vector_types)]` on by default + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:55:9 + | +LL | f(g()); + | ^^^^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:63:14 + | +LL | gavx(favx()); + | ^^^^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:63:9 + | +LL | gavx(favx()); + | ^^^^^^^^^^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:75:19 + | +LL | w(Wrapper(g())); + | ^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:75:9 + | +LL | w(Wrapper(g())); + | ^^^^^^^^^^^^^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + --> $DIR/simd-abi-checks.rs:26:1 + | +LL | unsafe extern "C" fn g() -> __m256 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + --> $DIR/simd-abi-checks.rs:20:1 + | +LL | unsafe extern "C" fn f(_: __m256) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + --> $DIR/simd-abi-checks.rs:14:1 + | +LL | unsafe extern "C" fn w(_: Wrapper) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: 9 warnings emitted + diff --git a/tests/ui/sse-abi-checks.rs b/tests/ui/sse-abi-checks.rs new file mode 100644 index 0000000000000..d2afd38fcc85f --- /dev/null +++ b/tests/ui/sse-abi-checks.rs @@ -0,0 +1,24 @@ +//! Ensure we trigger abi_unsupported_vector_types for target features that are usually enabled +//! on a target, but disabled in this file via a `-C` flag. +//@ compile-flags: --crate-type=rlib --target=i686-unknown-linux-gnu -C target-feature=-sse,-sse2 +//@ build-pass +//@ ignore-pass (test emits codegen-time warnings) +//@ needs-llvm-components: x86 +#![feature(no_core, lang_items, repr_simd)] +#![no_core] +#![allow(improper_ctypes_definitions)] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +#[repr(simd)] +pub struct SseVector([i64; 2]); + +#[no_mangle] +pub unsafe extern "C" fn f(_: SseVector) { + //~^ ABI error: this function definition uses a vector type that requires the `sse` target feature, which is not enabled + //~| WARNING this was previously accepted by the compiler +} diff --git a/tests/ui/sse-abi-checks.stderr b/tests/ui/sse-abi-checks.stderr new file mode 100644 index 0000000000000..77c4e1fc07ab4 --- /dev/null +++ b/tests/ui/sse-abi-checks.stderr @@ -0,0 +1,13 @@ +warning: ABI error: this function definition uses a vector type that requires the `sse` target feature, which is not enabled + --> $DIR/sse-abi-checks.rs:21:1 + | +LL | pub unsafe extern "C" fn f(_: SseVector) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+sse`) or locally (`#[target_feature(enable="sse")]`) + = note: `#[warn(abi_unsupported_vector_types)]` on by default + +warning: 1 warning emitted + From 06d869b495270c76ebc05c3bd512820b3f4d6ba9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 21:53:33 +0100 Subject: [PATCH 23/79] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2ec411b54b186..3ff5b22b1cad4 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -75eff9a5749411ba5a0b37cc3299116c4e263075 +00ed73cdc09a6452cb58202d56a9211fb3c73031 From c1b8d6611e7a29ed0ad700c28d2873a16760a448 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 22:02:38 +0100 Subject: [PATCH 24/79] teach clippy about IeeeFloat, and make all 'allow' into 'expect' --- src/tools/miri/clippy.toml | 2 +- .../miri/src/borrow_tracker/stacked_borrows/stack.rs | 2 +- src/tools/miri/src/concurrency/weak_memory.rs | 1 - src/tools/miri/src/eval.rs | 2 +- src/tools/miri/src/helpers.rs | 2 +- src/tools/miri/src/intrinsics/mod.rs | 2 -- src/tools/miri/src/intrinsics/simd.rs | 4 +--- src/tools/miri/src/shims/foreign_items.rs | 8 ++++---- src/tools/miri/src/shims/io_error.rs | 2 +- src/tools/miri/src/shims/tls.rs | 2 +- src/tools/miri/src/shims/unix/fs.rs | 2 +- src/tools/miri/src/shims/unix/linux/mem.rs | 2 +- src/tools/miri/src/shims/unix/linux/sync.rs | 2 +- src/tools/miri/src/shims/unix/mem.rs | 2 +- src/tools/miri/src/shims/unix/sync.rs | 1 - src/tools/miri/src/shims/windows/foreign_items.rs | 2 +- src/tools/miri/src/shims/windows/handle.rs | 12 +++++------- src/tools/miri/src/shims/x86/gfni.rs | 4 ++-- src/tools/miri/src/shims/x86/mod.rs | 7 ++----- src/tools/miri/src/shims/x86/sse42.rs | 4 ++-- .../miri/tests/pass/shims/x86/intrinsics-sha.rs | 2 +- 21 files changed, 28 insertions(+), 39 deletions(-) diff --git a/src/tools/miri/clippy.toml b/src/tools/miri/clippy.toml index c11912d6e68ce..504be47459c23 100644 --- a/src/tools/miri/clippy.toml +++ b/src/tools/miri/clippy.toml @@ -1 +1 @@ -arithmetic-side-effects-allowed = ["rustc_abi::Size"] +arithmetic-side-effects-allowed = ["rustc_abi::Size", "rustc_apfloat::ieee::IeeeFloat"] diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index f024796c0a722..dc3370f125104 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -354,7 +354,7 @@ impl<'tcx> Stack { self.borrows.get(idx).cloned() } - #[allow(clippy::len_without_is_empty)] // Stacks are never empty + #[expect(clippy::len_without_is_empty)] // Stacks are never empty pub fn len(&self) -> usize { self.borrows.len() } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 800c301a82175..c610f1999f7d7 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -300,7 +300,6 @@ impl<'tcx> StoreBuffer { interp_ok(()) } - #[allow(clippy::if_same_then_else, clippy::needless_bool)] /// Selects a valid store element in the buffer. fn fetch_store( &self, diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index cbd93fbd047e3..1e56e1049187f 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -423,7 +423,7 @@ pub fn create_ecx<'tcx>( /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occurred. -#[allow(clippy::needless_lifetimes)] +#[expect(clippy::needless_lifetimes)] pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 74439d36e32f4..526030bef2e39 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -156,7 +156,7 @@ pub fn iter_exported_symbols<'tcx>( for cnum in dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| { // We add 1 to the number because that's what rustc also does everywhere it // calls `CrateNum::new`... - #[allow(clippy::arithmetic_side_effects)] + #[expect(clippy::arithmetic_side_effects)] (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) }) { // We can ignore `_export_info` here: we are a Rust crate, and everything is exported diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 895beec507b4e..272dca1594ed9 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -292,7 +292,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; let fuse: bool = this.machine.rng.get_mut().gen(); - #[allow(clippy::arithmetic_side_effects)] // float ops don't overflow let res = if fuse { // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() @@ -308,7 +307,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; let fuse: bool = this.machine.rng.get_mut().gen(); - #[allow(clippy::arithmetic_side_effects)] // float ops don't overflow let res = if fuse { // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 38a678027496a..d5c417e723142 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -750,7 +750,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if simd_element_to_bool(mask)? { // Size * u64 is implemented as always checked - #[allow(clippy::arithmetic_side_effects)] let ptr = ptr.wrapping_offset(dest.layout.size * i, this); let place = this.ptr_to_mplace(ptr, dest.layout); this.read_immediate(&place)? @@ -774,7 +773,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if simd_element_to_bool(mask)? { // Size * u64 is implemented as always checked - #[allow(clippy::arithmetic_side_effects)] let ptr = ptr.wrapping_offset(val.layout.size * i, this); let place = this.ptr_to_mplace(ptr, val.layout); this.write_immediate(*val, &place)? @@ -831,7 +829,7 @@ fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 { assert!(idx < vec_len); match endianness { Endian::Little => idx, - #[allow(clippy::arithmetic_side_effects)] // idx < vec_len + #[expect(clippy::arithmetic_side_effects)] // idx < vec_len Endian::Big => vec_len - 1 - idx, // reverse order of bits } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 18578c7acc963..8f7c56a290769 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -21,7 +21,7 @@ use crate::*; #[derive(Debug, Copy, Clone)] pub struct DynSym(Symbol); -#[allow(clippy::should_implement_trait)] +#[expect(clippy::should_implement_trait)] impl DynSym { pub fn from_str(name: &str) -> Self { DynSym(Symbol::intern(name)) @@ -648,7 +648,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; // The docs say val is "interpreted as unsigned char". - #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)] let val = val as u8; // C requires that this must always be a valid pointer (C18 §7.1.4). @@ -661,7 +661,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .position(|&c| c == val) { let idx = u64::try_from(idx).unwrap(); - #[allow(clippy::arithmetic_side_effects)] // idx < num, so this never wraps + #[expect(clippy::arithmetic_side_effects)] // idx < num, so this never wraps let new_ptr = ptr.wrapping_offset(Size::from_bytes(num - idx - 1), this); this.write_pointer(new_ptr, dest)?; } else { @@ -675,7 +675,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; // The docs say val is "interpreted as unsigned char". - #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)] let val = val as u8; // C requires that this must always be a valid pointer (C18 §7.1.4). diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index a50bba0d2e48b..0cbb4850b7fd9 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -188,7 +188,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// The inverse of `io_error_to_errnum`. - #[allow(clippy::needless_return)] + #[expect(clippy::needless_return)] fn try_errnum_to_io_error( &self, errnum: Scalar, diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 6e147c58571df..46a417689a246 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -53,7 +53,7 @@ impl<'tcx> Default for TlsData<'tcx> { impl<'tcx> TlsData<'tcx> { /// Generate a new TLS key with the given destructor. /// `max_size` determines the integer size the key has to fit in. - #[allow(clippy::arithmetic_side_effects)] + #[expect(clippy::arithmetic_side_effects)] pub fn create_tls_key( &mut self, dtor: Option>, diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 7eaf33ace0f97..091def7ac65a0 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -385,7 +385,7 @@ pub struct DirTable { } impl DirTable { - #[allow(clippy::arithmetic_side_effects)] + #[expect(clippy::arithmetic_side_effects)] fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; self.next_id += 1; diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index 7597df273263a..8e796d5dce557 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let flags = this.read_scalar(flags)?.to_i32()?; // old_address must be a multiple of the page size - #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero + #[expect(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 { this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index 9fbf08b0b18fb..6d5747d7c159b 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -182,7 +182,7 @@ pub fn futex<'tcx>( // before doing the syscall. this.atomic_fence(AtomicFenceOrd::SeqCst)?; let mut n = 0; - #[allow(clippy::arithmetic_side_effects)] + #[expect(clippy::arithmetic_side_effects)] for _ in 0..val { if this.futex_wake(addr_usize, bitset)? { n += 1; diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 88e04240b1197..5531b944e17d1 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -132,7 +132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // addr must be a multiple of the page size, but apart from that munmap is just implemented // as a dealloc. - #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero + #[expect(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if addr.addr().bytes() % this.machine.page_size != 0 { return this.set_last_error_and_return_i32(LibcError("EINVAL")); } diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 677002e79d2d4..850626d89ac15 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -685,7 +685,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let id = rwlock_get_data(this, rwlock_op)?.id; - #[allow(clippy::if_same_then_else)] if this.rwlock_reader_unlock(id)? || this.rwlock_writer_unlock(id)? { interp_ok(()) } else { diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 2225010d17f39..fe11aa8da4a69 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -25,7 +25,7 @@ fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { } #[cfg(unix)] -#[allow(clippy::get_first, clippy::arithmetic_side_effects)] +#[expect(clippy::get_first, clippy::arithmetic_side_effects)] fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { // We are on Unix, so we need to implement parts of the logic ourselves. let bytes = path.as_os_str().as_encoded_bytes(); diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 21da3d3cdb520..437a21534c96b 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -63,7 +63,7 @@ impl Handle { let floor_log2 = variant_count.ilog2(); // we need to add one for non powers of two to compensate for the difference - #[allow(clippy::arithmetic_side_effects)] // cannot overflow + #[expect(clippy::arithmetic_side_effects)] // cannot overflow if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 } } @@ -88,8 +88,7 @@ impl Handle { // packs the data into the lower `data_size` bits // and packs the discriminant right above the data - #[allow(clippy::arithmetic_side_effects)] // cannot overflow - return discriminant << data_size | data; + discriminant << data_size | data } fn new(discriminant: u32, data: u32) -> Option { @@ -107,11 +106,10 @@ impl Handle { let data_size = u32::BITS.strict_sub(disc_size); // the lower `data_size` bits of this mask are 1 - #[allow(clippy::arithmetic_side_effects)] // cannot overflow + #[expect(clippy::arithmetic_side_effects)] // cannot overflow let data_mask = 2u32.pow(data_size) - 1; // the discriminant is stored right above the lower `data_size` bits - #[allow(clippy::arithmetic_side_effects)] // cannot overflow let discriminant = handle >> data_size; // the data is stored in the lower `data_size` bits @@ -123,7 +121,7 @@ impl Handle { pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication - #[allow(clippy::cast_possible_wrap)] // we want it to wrap + #[expect(clippy::cast_possible_wrap)] // we want it to wrap let signed_handle = self.to_packed() as i32; Scalar::from_target_isize(signed_handle.into(), cx) } @@ -134,7 +132,7 @@ impl Handle { ) -> InterpResult<'tcx, Option> { let sign_extended_handle = handle.to_target_isize(cx)?; - #[allow(clippy::cast_sign_loss)] // we want to lose the sign + #[expect(clippy::cast_sign_loss)] // we want to lose the sign let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) { signed_handle as u32 } else { diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs index 5edbcbac3f627..7b92d422cc535 100644 --- a/src/tools/miri/src/shims/x86/gfni.rs +++ b/src/tools/miri/src/shims/x86/gfni.rs @@ -136,7 +136,7 @@ fn affine_transform<'tcx>( // This is a evaluated at compile time. Trait based conversion is not available. /// See for the /// definition of `gf_inv` which was used for the creation of this table. -#[allow(clippy::cast_possible_truncation)] +#[expect(clippy::cast_possible_truncation)] static TABLE: [u8; 256] = { let mut array = [0; 256]; @@ -163,7 +163,7 @@ static TABLE: [u8; 256] = { /// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1. /// See for details. // This is a const function. Trait based conversion is not available. -#[allow(clippy::cast_possible_truncation)] +#[expect(clippy::cast_possible_truncation)] const fn gf2p8_mul(left: u8, right: u8) -> u8 { // This implementation is based on the `gf2p8mul_byte` definition found inside the Intel intrinsics guide. // See https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 97052c77b38fc..433e9e966f2a2 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -397,7 +397,6 @@ enum FloatUnaryOp { } /// Performs `which` scalar operation on `op` and returns the result. -#[allow(clippy::arithmetic_side_effects)] // floating point operations without side effects fn unary_op_f32<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatUnaryOp, @@ -426,7 +425,7 @@ fn unary_op_f32<'tcx>( } /// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale). -#[allow(clippy::arithmetic_side_effects)] // floating point arithmetic cannot panic +#[expect(clippy::arithmetic_side_effects)] // floating point arithmetic cannot panic fn apply_random_float_error( this: &mut crate::MiriInterpCx<'_>, val: F, @@ -1000,7 +999,6 @@ fn mask_load<'tcx>( let dest = this.project_index(&dest, i)?; if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { - #[allow(clippy::arithmetic_side_effects)] // `Size` arithmetic is checked let ptr = ptr.wrapping_offset(dest.layout.size * i, &this.tcx); // Unaligned copy, which is what we want. this.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; @@ -1036,7 +1034,6 @@ fn mask_store<'tcx>( if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { // *Non-inbounds* pointer arithmetic to compute the destination. // (That's why we can't use a place projection.) - #[allow(clippy::arithmetic_side_effects)] // `Size` arithmetic is checked let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx); // Deref the pointer *unaligned*, and do the copy. let dest = this.ptr_to_mplace_unaligned(ptr, value.layout); @@ -1135,7 +1132,7 @@ fn pmulhrsw<'tcx>( // The result of this operation can overflow a signed 16-bit integer. // When `left` and `right` are -0x8000, the result is 0x8000. - #[allow(clippy::cast_possible_truncation)] + #[expect(clippy::cast_possible_truncation)] let res = res as i16; this.write_scalar(Scalar::from_i16(res), &dest)?; diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 4bd87b719b0ce..cc7cfab504195 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -68,7 +68,7 @@ const USE_SIGNED: u8 = 2; /// The mask may be negated if negation flags inside the immediate byte are set. /// /// For more information, see the Intel Software Developer's Manual, Vol. 2b, Chapter 4.1. -#[allow(clippy::arithmetic_side_effects)] +#[expect(clippy::arithmetic_side_effects)] fn compare_strings<'tcx>( this: &mut MiriInterpCx<'tcx>, str1: &OpTy<'tcx>, @@ -444,7 +444,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let crc = if bit_size == 64 { // The 64-bit version will only consider the lower 32 bits, // while the upper 32 bits get discarded. - #[allow(clippy::cast_possible_truncation)] + #[expect(clippy::cast_possible_truncation)] u128::from((left.to_u64()? as u32).reverse_bits()) } else { u128::from(left.to_u32()?.reverse_bits()) diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs index 4e892e6e3cb38..ae5731bc8a6a3 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs @@ -181,7 +181,7 @@ unsafe fn schedule(v0: __m128i, v1: __m128i, v2: __m128i, v3: __m128i) -> __m128 } // we use unaligned loads with `__m128i` pointers -#[allow(clippy::cast_ptr_alignment)] +#[expect(clippy::cast_ptr_alignment)] #[target_feature(enable = "sha,sse2,ssse3,sse4.1")] unsafe fn digest_blocks(state: &mut [u32; 8], blocks: &[[u8; 64]]) { #[allow(non_snake_case)] From 9c75effc6c744b53f0ced3b935e1de3065b8c3f6 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 3 Nov 2024 05:09:57 +0000 Subject: [PATCH 25/79] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 3ff5b22b1cad4..96d5acd27ad25 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -00ed73cdc09a6452cb58202d56a9211fb3c73031 +67395551d07b0eaf6a45ed3bf1759530ca2235d7 From 0bc622d251f8606ca86d4a5ccdbedd52afef247a Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 31 Oct 2024 23:03:09 +0100 Subject: [PATCH 26/79] Prefer `pub(super)` in `unreachable_pub` lint suggestion --- compiler/rustc_lint/src/builtin.rs | 18 ++++ compiler/rustc_lint/src/lints.rs | 3 +- tests/ui/lint/unreachable_pub.fixed | 116 ++++++++++++++++++++++ tests/ui/lint/unreachable_pub.rs | 46 +++++++++ tests/ui/lint/unreachable_pub.stderr | 140 ++++++++++++++++++++++++--- 5 files changed, 307 insertions(+), 16 deletions(-) create mode 100644 tests/ui/lint/unreachable_pub.fixed diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 02d22ee49bd60..130f3cb7c2a78 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1298,12 +1298,30 @@ impl UnreachablePub { let mut applicability = Applicability::MachineApplicable; if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id) { + // prefer suggesting `pub(super)` instead of `pub(crate)` when possible, + // except when `pub(super) == pub(crate)` + let new_vis = if let Some(ty::Visibility::Restricted(restricted_did)) = + cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| { + effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable) + }) + && let parent_parent = cx.tcx.parent_module_from_def_id( + cx.tcx.parent_module_from_def_id(def_id.into()).into(), + ) + && *restricted_did == parent_parent.to_local_def_id() + && !restricted_did.to_def_id().is_crate_root() + { + "pub(super)" + } else { + "pub(crate)" + }; + if vis_span.from_expansion() { applicability = Applicability::MaybeIncorrect; } let def_span = cx.tcx.def_span(def_id); cx.emit_span_lint(UNREACHABLE_PUB, def_span, BuiltinUnreachablePub { what, + new_vis, suggestion: (vis_span, applicability), help: exportable, }); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 38e52570e53e6..352155729e51c 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -254,7 +254,8 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { #[diag(lint_builtin_unreachable_pub)] pub(crate) struct BuiltinUnreachablePub<'a> { pub what: &'a str, - #[suggestion(code = "pub(crate)")] + pub new_vis: &'a str, + #[suggestion(code = "{new_vis}")] pub suggestion: (Span, Applicability), #[help] pub help: bool, diff --git a/tests/ui/lint/unreachable_pub.fixed b/tests/ui/lint/unreachable_pub.fixed new file mode 100644 index 0000000000000..163e8d24b3255 --- /dev/null +++ b/tests/ui/lint/unreachable_pub.fixed @@ -0,0 +1,116 @@ +//@ check-pass +//@ edition: 2018 +//@ run-rustfix + +#![allow(unused)] +#![warn(unreachable_pub)] + +mod private_mod { + // non-leaked `pub` items in private module should be linted + pub(crate) use std::fmt; //~ WARNING unreachable_pub + pub(crate) use std::env::{Args}; // braced-use has different item spans than unbraced + //~^ WARNING unreachable_pub + + // we lint on struct definition + pub(crate) struct Hydrogen { //~ WARNING unreachable_pub + // but not on fields, even if they are `pub` as putting `pub(crate)` + // it would clutter the source code for little value + pub neutrons: usize, + pub(crate) electrons: usize + } + pub(crate) struct Calcium { + pub neutrons: usize, + } + impl Hydrogen { + // impls, too + pub(crate) fn count_neutrons(&self) -> usize { self.neutrons } //~ WARNING unreachable_pub + pub(crate) fn count_electrons(&self) -> usize { self.electrons } + } + impl Clone for Hydrogen { + fn clone(&self) -> Hydrogen { + Hydrogen { neutrons: self.neutrons, electrons: self.electrons } + } + } + + pub(crate) enum Helium {} //~ WARNING unreachable_pub + pub(crate) union Lithium { c1: usize, c2: u8 } //~ WARNING unreachable_pub + pub(crate) fn beryllium() {} //~ WARNING unreachable_pub + pub(crate) trait Boron {} //~ WARNING unreachable_pub + pub(crate) const CARBON: usize = 1; //~ WARNING unreachable_pub + pub(crate) static NITROGEN: usize = 2; //~ WARNING unreachable_pub + pub(crate) type Oxygen = bool; //~ WARNING unreachable_pub + + macro_rules! define_empty_struct_with_visibility { + ($visibility: vis, $name: ident) => { $visibility struct $name {} } + //~^ WARNING unreachable_pub + } + define_empty_struct_with_visibility!(pub(crate), Fluorine); + + extern "C" { + pub(crate) fn catalyze() -> bool; //~ WARNING unreachable_pub + } + + mod private_in_private { + pub(super) enum Helium {} //~ WARNING unreachable_pub + pub(super) fn beryllium() {} //~ WARNING unreachable_pub + } + + pub(crate) mod crate_in_private { + pub(crate) const CARBON: usize = 1; //~ WARNING unreachable_pub + } + + pub(crate) mod pub_in_private { //~ WARNING unreachable_pub + pub(crate) static NITROGEN: usize = 2; //~ WARNING unreachable_pub + } + + fn foo() { + const { + pub(crate) struct Foo; //~ WARNING unreachable_pub + }; + } + + enum Weird { + Variant = { + pub(crate) struct Foo; //~ WARNING unreachable_pub + + mod tmp { + pub(crate) struct Bar; //~ WARNING unreachable_pub + } + + let _ = tmp::Bar; + + 0 + }, + } + + pub(crate) use fpu_precision::set_precision; //~ WARNING unreachable_pub + + mod fpu_precision { + pub(crate) fn set_precision() {} //~ WARNING unreachable_pub + pub(super) fn set_micro_precision() {} //~ WARNING unreachable_pub + } + + // items leaked through signatures (see `get_neon` below) are OK + pub struct Neon {} + + // crate-visible items are OK + pub(crate) struct Sodium {} +} + +pub mod public_mod { + // module is public: these are OK, too + pub struct Magnesium {} + pub(crate) struct Aluminum {} +} + +pub fn get_neon() -> private_mod::Neon { + private_mod::Neon {} +} + +fn main() { + let _ = get_neon(); + let _ = private_mod::beryllium(); + let _ = private_mod::crate_in_private::CARBON; + let _ = private_mod::pub_in_private::NITROGEN; + let _ = unsafe { private_mod::catalyze() }; +} diff --git a/tests/ui/lint/unreachable_pub.rs b/tests/ui/lint/unreachable_pub.rs index f21f6640342c4..8524820bcfbc9 100644 --- a/tests/ui/lint/unreachable_pub.rs +++ b/tests/ui/lint/unreachable_pub.rs @@ -1,4 +1,6 @@ //@ check-pass +//@ edition: 2018 +//@ run-rustfix #![allow(unused)] #![warn(unreachable_pub)] @@ -48,6 +50,46 @@ mod private_mod { pub fn catalyze() -> bool; //~ WARNING unreachable_pub } + mod private_in_private { + pub enum Helium {} //~ WARNING unreachable_pub + pub fn beryllium() {} //~ WARNING unreachable_pub + } + + pub(crate) mod crate_in_private { + pub const CARBON: usize = 1; //~ WARNING unreachable_pub + } + + pub mod pub_in_private { //~ WARNING unreachable_pub + pub static NITROGEN: usize = 2; //~ WARNING unreachable_pub + } + + fn foo() { + const { + pub struct Foo; //~ WARNING unreachable_pub + }; + } + + enum Weird { + Variant = { + pub struct Foo; //~ WARNING unreachable_pub + + mod tmp { + pub struct Bar; //~ WARNING unreachable_pub + } + + let _ = tmp::Bar; + + 0 + }, + } + + pub use fpu_precision::set_precision; //~ WARNING unreachable_pub + + mod fpu_precision { + pub fn set_precision() {} //~ WARNING unreachable_pub + pub fn set_micro_precision() {} //~ WARNING unreachable_pub + } + // items leaked through signatures (see `get_neon` below) are OK pub struct Neon {} @@ -67,4 +109,8 @@ pub fn get_neon() -> private_mod::Neon { fn main() { let _ = get_neon(); + let _ = private_mod::beryllium(); + let _ = private_mod::crate_in_private::CARBON; + let _ = private_mod::pub_in_private::NITROGEN; + let _ = unsafe { private_mod::catalyze() }; } diff --git a/tests/ui/lint/unreachable_pub.stderr b/tests/ui/lint/unreachable_pub.stderr index 65f45fbd81689..5173ff1f0264d 100644 --- a/tests/ui/lint/unreachable_pub.stderr +++ b/tests/ui/lint/unreachable_pub.stderr @@ -1,5 +1,5 @@ warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:8:13 + --> $DIR/unreachable_pub.rs:10:13 | LL | pub use std::fmt; | --- ^^^^^^^^ @@ -8,13 +8,13 @@ LL | pub use std::fmt; | = help: or consider exporting it for use by other crates note: the lint level is defined here - --> $DIR/unreachable_pub.rs:4:9 + --> $DIR/unreachable_pub.rs:6:9 | LL | #![warn(unreachable_pub)] | ^^^^^^^^^^^^^^^ warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:9:24 + --> $DIR/unreachable_pub.rs:11:24 | LL | pub use std::env::{Args}; // braced-use has different item spans than unbraced | --- ^^^^ @@ -24,7 +24,7 @@ LL | pub use std::env::{Args}; // braced-use has different item spans than u = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:13:5 + --> $DIR/unreachable_pub.rs:15:5 | LL | pub struct Hydrogen { | ---^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | pub struct Hydrogen { = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:24:9 + --> $DIR/unreachable_pub.rs:26:9 | LL | pub fn count_neutrons(&self) -> usize { self.neutrons } | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | pub fn count_neutrons(&self) -> usize { self.neutrons } | help: consider restricting its visibility: `pub(crate)` warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:33:5 + --> $DIR/unreachable_pub.rs:35:5 | LL | pub enum Helium {} | ---^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | pub enum Helium {} = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:34:5 + --> $DIR/unreachable_pub.rs:36:5 | LL | pub union Lithium { c1: usize, c2: u8 } | ---^^^^^^^^^^^^^^ @@ -62,7 +62,7 @@ LL | pub union Lithium { c1: usize, c2: u8 } = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:35:5 + --> $DIR/unreachable_pub.rs:37:5 | LL | pub fn beryllium() {} | ---^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | pub fn beryllium() {} = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:36:5 + --> $DIR/unreachable_pub.rs:38:5 | LL | pub trait Boron {} | ---^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | pub trait Boron {} = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:37:5 + --> $DIR/unreachable_pub.rs:39:5 | LL | pub const CARBON: usize = 1; | ---^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | pub const CARBON: usize = 1; = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:38:5 + --> $DIR/unreachable_pub.rs:40:5 | LL | pub static NITROGEN: usize = 2; | ---^^^^^^^^^^^^^^^^^^^^^^^ @@ -102,7 +102,7 @@ LL | pub static NITROGEN: usize = 2; = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:39:5 + --> $DIR/unreachable_pub.rs:41:5 | LL | pub type Oxygen = bool; | ---^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | pub type Oxygen = bool; = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:42:47 + --> $DIR/unreachable_pub.rs:44:47 | LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | define_empty_struct_with_visibility!(pub, Fluorine); = note: this warning originates in the macro `define_empty_struct_with_visibility` (in Nightly builds, run with -Z macro-backtrace for more info) warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:48:9 + --> $DIR/unreachable_pub.rs:50:9 | LL | pub fn catalyze() -> bool; | ---^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,5 +136,115 @@ LL | pub fn catalyze() -> bool; | = help: or consider exporting it for use by other crates -warning: 13 warnings emitted +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:62:5 + | +LL | pub mod pub_in_private { + | ---^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:68:13 + | +LL | pub struct Foo; + | ---^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:74:13 + | +LL | pub struct Foo; + | ---^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:86:13 + | +LL | pub use fpu_precision::set_precision; + | --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:54:9 + | +LL | pub enum Helium {} + | ---^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(super)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:55:9 + | +LL | pub fn beryllium() {} + | ---^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(super)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:59:9 + | +LL | pub const CARBON: usize = 1; + | ---^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:63:9 + | +LL | pub static NITROGEN: usize = 2; + | ---^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:77:17 + | +LL | pub struct Bar; + | ---^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:89:9 + | +LL | pub fn set_precision() {} + | ---^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | + = help: or consider exporting it for use by other crates + +warning: unreachable `pub` item + --> $DIR/unreachable_pub.rs:90:9 + | +LL | pub fn set_micro_precision() {} + | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(super)` + | + = help: or consider exporting it for use by other crates + +warning: 24 warnings emitted From cf9cec3d843b1b6daae76e99027d180b11530bff Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 7 Nov 2024 19:39:18 +0800 Subject: [PATCH 27/79] Only copy, rename and link `llvm-objcopy` if llvm tools are enabled Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- src/bootstrap/src/core/build_steps/compile.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3394f2a84a047..24be705f48194 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1976,9 +1976,13 @@ impl Step for Assemble { } } - { - // `llvm-strip` is used by rustc, which is actually just a symlink to `llvm-objcopy`, - // so copy and rename `llvm-objcopy`. + if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled { + // `llvm-strip` is used by rustc, which is actually just a symlink to `llvm-objcopy`, so + // copy and rename `llvm-objcopy`. + // + // But only do so if llvm-tools are enabled, as bootstrap compiler might not contain any + // LLVM tools, e.g. for cg_clif. + // See . let src_exe = exe("llvm-objcopy", target_compiler.host); let dst_exe = exe("rust-objcopy", target_compiler.host); builder.copy_link(&libdir_bin.join(src_exe), &libdir_bin.join(dst_exe)); From dc62c3488600b9bb56f2f236dc795ed65d3f30db Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Thu, 7 Nov 2024 15:36:52 +0300 Subject: [PATCH 28/79] Renamed ecx variales to this --- src/tools/miri/src/alloc_addresses/mod.rs | 72 +++++++++++------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 7b377a1c4cdfc..f1b7811f9054c 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -111,8 +111,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Returns the exposed `AllocId` that corresponds to the specified addr, // or `None` if the addr is out of bounds fn alloc_id_from_addr(&self, addr: u64, size: i64) -> Option { - let ecx = self.eval_context_ref(); - let global_state = ecx.machine.alloc_addresses.borrow(); + let this = self.eval_context_ref(); + let global_state = this.machine.alloc_addresses.borrow(); assert!(global_state.provenance_mode != ProvenanceMode::Strict); // We always search the allocation to the right of this address. So if the size is structly @@ -134,7 +134,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // entered for addresses that are not the base address, so even zero-sized // allocations will get recognized at their base address -- but all other // allocations will *not* be recognized at their "end" address. - let size = ecx.get_alloc_info(alloc_id).0; + let size = this.get_alloc_info(alloc_id).0; if offset < size.bytes() { Some(alloc_id) } else { None } } }?; @@ -142,7 +142,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // We only use this provenance if it has been exposed. if global_state.exposed.contains(&alloc_id) { // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed. - debug_assert!(ecx.is_alloc_live(alloc_id)); + debug_assert!(this.is_alloc_live(alloc_id)); Some(alloc_id) } else { None @@ -155,9 +155,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { alloc_id: AllocId, memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { - let ecx = self.eval_context_ref(); - let mut rng = ecx.machine.rng.borrow_mut(); - let (size, align, kind) = ecx.get_alloc_info(alloc_id); + let this = self.eval_context_ref(); + let mut rng = this.machine.rng.borrow_mut(); + let (size, align, kind) = this.get_alloc_info(alloc_id); // This is either called immediately after allocation (and then cached), or when // adjusting `tcx` pointers (which never get freed). So assert that we are looking // at a live allocation. This also ensures that we never re-assign an address to an @@ -166,12 +166,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { assert!(!matches!(kind, AllocKind::Dead)); // This allocation does not have a base address yet, pick or reuse one. - if ecx.machine.native_lib.is_some() { + if this.machine.native_lib.is_some() { // In native lib mode, we use the "real" address of the bytes for this allocation. // This ensures the interpreted program and native code have the same view of memory. let base_ptr = match kind { AllocKind::LiveData => { - if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { + if this.tcx.try_get_global_alloc(alloc_id).is_some() { // For new global allocations, we always pre-allocate the memory to be able use the machine address directly. let prepared_bytes = MiriAllocBytes::zeroed(size, align) .unwrap_or_else(|| { @@ -185,7 +185,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .unwrap(); ptr } else { - ecx.get_alloc_bytes_unchecked_raw(alloc_id)? + this.get_alloc_bytes_unchecked_raw(alloc_id)? } } AllocKind::Function | AllocKind::VTable => { @@ -204,10 +204,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } // We are not in native lib mode, so we control the addresses ourselves. if let Some((reuse_addr, clock)) = - global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, ecx.active_thread()) + global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, this.active_thread()) { if let Some(clock) = clock { - ecx.acquire_clock(&clock); + this.acquire_clock(&clock); } interp_ok(reuse_addr) } else { @@ -230,7 +230,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .checked_add(max(size.bytes(), 1)) .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; // Even if `Size` didn't overflow, we might still have filled up the address space. - if global_state.next_base_addr > ecx.target_usize_max() { + if global_state.next_base_addr > this.target_usize_max() { throw_exhaust!(AddressSpaceFull); } @@ -243,8 +243,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { alloc_id: AllocId, memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { - let ecx = self.eval_context_ref(); - let mut global_state = ecx.machine.alloc_addresses.borrow_mut(); + let this = self.eval_context_ref(); + let mut global_state = this.machine.alloc_addresses.borrow_mut(); let global_state = &mut *global_state; match global_state.base_addr.get(&alloc_id) { @@ -283,22 +283,22 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn expose_ptr(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { - let ecx = self.eval_context_mut(); - let global_state = ecx.machine.alloc_addresses.get_mut(); + let this = self.eval_context_mut(); + let global_state = this.machine.alloc_addresses.get_mut(); // In strict mode, we don't need this, so we can save some cycles by not tracking it. if global_state.provenance_mode == ProvenanceMode::Strict { return interp_ok(()); } // Exposing a dead alloc is a no-op, because it's not possible to get a dead allocation // via int2ptr. - if !ecx.is_alloc_live(alloc_id) { + if !this.is_alloc_live(alloc_id) { return interp_ok(()); } trace!("Exposing allocation id {alloc_id:?}"); - let global_state = ecx.machine.alloc_addresses.get_mut(); + let global_state = this.machine.alloc_addresses.get_mut(); global_state.exposed.insert(alloc_id); - if ecx.machine.borrow_tracker.is_some() { - ecx.expose_tag(alloc_id, tag)?; + if this.machine.borrow_tracker.is_some() { + this.expose_tag(alloc_id, tag)?; } interp_ok(()) } @@ -306,8 +306,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer> { trace!("Casting {:#x} to a pointer", addr); - let ecx = self.eval_context_ref(); - let global_state = ecx.machine.alloc_addresses.borrow(); + let this = self.eval_context_ref(); + let global_state = this.machine.alloc_addresses.borrow(); // Potentially emit a warning. match global_state.provenance_mode { @@ -319,9 +319,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } PAST_WARNINGS.with_borrow_mut(|past_warnings| { let first = past_warnings.is_empty(); - if past_warnings.insert(ecx.cur_span()) { + if past_warnings.insert(this.cur_span()) { // Newly inserted, so first time we see this span. - ecx.emit_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); + this.emit_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); } }); } @@ -347,19 +347,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { tag: BorTag, kind: MemoryKind, ) -> InterpResult<'tcx, interpret::Pointer> { - let ecx = self.eval_context_ref(); + let this = self.eval_context_ref(); let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) let alloc_id = prov.alloc_id(); // Get a pointer to the beginning of this allocation. - let base_addr = ecx.addr_from_alloc_id(alloc_id, kind)?; + let base_addr = this.addr_from_alloc_id(alloc_id, kind)?; let base_ptr = interpret::Pointer::new( Provenance::Concrete { alloc_id, tag }, Size::from_bytes(base_addr), ); // Add offset with the right kind of pointer-overflowing arithmetic. - interp_ok(base_ptr.wrapping_offset(offset, ecx)) + interp_ok(base_ptr.wrapping_offset(offset, this)) } // This returns some prepared `MiriAllocBytes`, either because `addr_from_alloc_id` reserved @@ -371,16 +371,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { bytes: &[u8], align: Align, ) -> InterpResult<'tcx, MiriAllocBytes> { - let ecx = self.eval_context_ref(); - if ecx.machine.native_lib.is_some() { + let this = self.eval_context_ref(); + if this.machine.native_lib.is_some() { // In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`. // This additional call ensures that some `MiriAllocBytes` are always prepared, just in case // this function gets called before the first time `addr_from_alloc_id` gets called. - ecx.addr_from_alloc_id(id, kind)?; + this.addr_from_alloc_id(id, kind)?; // The memory we need here will have already been allocated during an earlier call to // `addr_from_alloc_id` for this allocation. So don't create a new `MiriAllocBytes` here, instead // fetch the previously prepared bytes from `prepared_alloc_bytes`. - let mut global_state = ecx.machine.alloc_addresses.borrow_mut(); + let mut global_state = this.machine.alloc_addresses.borrow_mut(); let mut prepared_alloc_bytes = global_state .prepared_alloc_bytes .remove(&id) @@ -403,7 +403,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ptr: interpret::Pointer, size: i64, ) -> Option<(AllocId, Size)> { - let ecx = self.eval_context_ref(); + let this = self.eval_context_ref(); let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) @@ -411,15 +411,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { alloc_id } else { // A wildcard pointer. - ecx.alloc_id_from_addr(addr.bytes(), size)? + this.alloc_id_from_addr(addr.bytes(), size)? }; // This cannot fail: since we already have a pointer with that provenance, adjust_alloc_root_pointer // must have been called in the past, so we can just look up the address in the map. - let base_addr = *ecx.machine.alloc_addresses.borrow().base_addr.get(&alloc_id).unwrap(); + let base_addr = *this.machine.alloc_addresses.borrow().base_addr.get(&alloc_id).unwrap(); // Wrapping "addr - base_addr" - let rel_offset = ecx.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr)); + let rel_offset = this.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr)); Some((alloc_id, Size::from_bytes(rel_offset))) } } From 90fa5b608ddf6b8715dbd780e7f986e741ac9bf3 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 7 Nov 2024 14:23:53 -0600 Subject: [PATCH 29/79] add regression test for #90781 --- tests/rustdoc/hidden-implementors-90781.rs | 78 ++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 tests/rustdoc/hidden-implementors-90781.rs diff --git a/tests/rustdoc/hidden-implementors-90781.rs b/tests/rustdoc/hidden-implementors-90781.rs new file mode 100644 index 0000000000000..960a85b91f001 --- /dev/null +++ b/tests/rustdoc/hidden-implementors-90781.rs @@ -0,0 +1,78 @@ +//@ compile-flags: -Z unstable-options --document-hidden-items --document-private-items + +// regression test for https://github.com/rust-lang/rust/issues/90781 +#![crate_name = "foo"] + +//@ has foo/trait.TPubVis.html +//@ has - '//*[@id="implementors-list"]' 'HidPriv' +//@ has - '//*[@id="implementors-list"]' 'HidPub' +//@ has - '//*[@id="implementors-list"]' 'VisPriv' +//@ has - '//*[@id="implementors-list"]' 'VisPub' +pub trait TPubVis {} + +//@ has foo/trait.TPubHidden.html +//@ has - '//*[@id="implementors-list"]' 'HidPriv' +//@ has - '//*[@id="implementors-list"]' 'HidPub' +//@ has - '//*[@id="implementors-list"]' 'VisPriv' +//@ has - '//*[@id="implementors-list"]' 'VisPub' +#[doc(hidden)] +pub trait TPubHidden {} + +//@ has foo/trait.TPrivVis.html +//@ has - '//*[@id="implementors-list"]' 'HidPriv' +//@ has - '//*[@id="implementors-list"]' 'HidPub' +//@ has - '//*[@id="implementors-list"]' 'VisPriv' +//@ has - '//*[@id="implementors-list"]' 'VisPub' +trait TPrivVis {} + +#[doc(hidden)] +//@ has foo/trait.TPrivHidden.html +//@ has - '//*[@id="impl-TPrivHidden-for-HidPriv"]' 'HidPriv' +//@ has - '//*[@id="impl-TPrivHidden-for-HidPub"]' 'HidPub' +//@ has - '//*[@id="impl-TPrivHidden-for-VisPriv"]' 'VisPriv' +//@ has - '//*[@id="impl-TPrivHidden-for-VisPub"]' 'VisPub' +trait TPrivHidden {} + +//@ has foo/struct.VisPub.html +//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden' +//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis' +//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden' +//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis' +pub struct VisPub; + +//@ has foo/struct.VisPriv.html +//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden' +//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis' +//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden' +//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis' +struct VisPriv; + +//@ has foo/struct.HidPub.html +//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden' +//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis' +//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden' +//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis' +#[doc(hidden)] +pub struct HidPub; + +//@ has foo/struct.HidPriv.html +//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden' +//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis' +//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden' +//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis' +#[doc(hidden)] +struct HidPriv; + +macro_rules! implement { + ($trait:ident - $($struct:ident)+) => { + $( + impl $trait for $struct {} + )+ + } +} + + +implement!(TPubVis - VisPub VisPriv HidPub HidPriv); +implement!(TPubHidden - VisPub VisPriv HidPub HidPriv); +implement!(TPrivVis - VisPub VisPriv HidPub HidPriv); +implement!(TPrivHidden - VisPub VisPriv HidPub HidPriv); From ab62a352ba5eeae79ff3dab0788a2134eac3f674 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 2 Oct 2024 05:26:15 +0900 Subject: [PATCH 30/79] Stabilize s390x inline assembly --- compiler/rustc_ast_lowering/src/asm.rs | 1 + .../asm-experimental-arch.md | 21 ++----------------- tests/assembly/asm/s390x-types.rs | 2 +- tests/codegen/asm/s390x-clobbers.rs | 2 +- 4 files changed, 5 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 6585a7de24591..3acca94a54bdf 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -48,6 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | asm::InlineAsmArch::RiscV32 | asm::InlineAsmArch::RiscV64 | asm::InlineAsmArch::LoongArch64 + | asm::InlineAsmArch::S390x ); if !is_stable && !self.tcx.features().asm_experimental_arch() { feature_err( diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 3029c3989c9fa..f00a0fe72876e 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -18,7 +18,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - MSP430 - M68k - CSKY -- s390x - Arm64EC - SPARC @@ -52,11 +51,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `reg_addr` | `a[0-3]` | `a` | | CSKY | `reg` | `r[0-31]` | `r` | | CSKY | `freg` | `f[0-31]` | `f` | -| s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` | -| s390x | `reg_addr` | `r[1-10]`, `r[12-14]` | `a` | -| s390x | `freg` | `f[0-15]` | `f` | -| s390x | `vreg` | `v[0-31]` | Only clobbers | -| s390x | `areg` | `a[2-15]` | Only clobbers | | SPARC | `reg` | `r[2-29]` | `r` | | SPARC | `yreg` | `y` | Only clobbers | | Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` | @@ -96,10 +90,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `reg_data` | None | `i8`, `i16`, `i32` | | CSKY | `reg` | None | `i8`, `i16`, `i32` | | CSKY | `freg` | None | `f32`, | -| s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` | -| s390x | `freg` | None | `f32`, `f64` | -| s390x | `vreg` | N/A | Only clobbers | -| s390x | `areg` | N/A | Only clobbers | | SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) | | SPARC | `yreg` | N/A | Only clobbers | | Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | @@ -159,8 +149,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| All | `sp`, `r15` (s390x), `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | +| All | `sp`, `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block. | +| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | | All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | @@ -181,8 +171,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r15` | This is the link register. | | CSKY | `r[26-30]` | Reserved by its ABI. | | CSKY | `r31` | This is the TLS register. | -| s390x | `c[0-15]` | Reserved by the kernel. | -| s390x | `a[0-1]` | Reserved for system use. | | SPARC | `r0`/`g0` | This is always zero and cannot be used as inputs or outputs. | | SPARC | `r1`/`g1` | Used internally by LLVM. | | SPARC | `r5`/`g5` | Reserved for system. (SPARC32 only) | @@ -206,9 +194,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | PowerPC | `reg` | None | `0` | None | | PowerPC | `reg_nonzero` | None | `3` | None | | PowerPC | `freg` | None | `0` | None | -| s390x | `reg` | None | `%r0` | None | -| s390x | `reg_addr` | None | `%r1` | None | -| s390x | `freg` | None | `%f0` | None | | SPARC | `reg` | None | `%o0` | None | | CSKY | `reg` | None | `r0` | None | | CSKY | `freg` | None | `f0` | None | @@ -232,8 +217,6 @@ These flags registers must be restored upon exiting the asm block if the `preser - The status register `r2`. - M68k - The condition code register `ccr`. -- s390x - - The condition code register `cc`. - SPARC - Integer condition codes (`icc` and `xcc`) - Floating-point condition codes (`fcc[0-3]`) diff --git a/tests/assembly/asm/s390x-types.rs b/tests/assembly/asm/s390x-types.rs index e68b18d7aa690..b1522198a087a 100644 --- a/tests/assembly/asm/s390x-types.rs +++ b/tests/assembly/asm/s390x-types.rs @@ -4,7 +4,7 @@ //@[s390x] needs-llvm-components: systemz //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] diff --git a/tests/codegen/asm/s390x-clobbers.rs b/tests/codegen/asm/s390x-clobbers.rs index 45f72206bdfab..56d82b4b04400 100644 --- a/tests/codegen/asm/s390x-clobbers.rs +++ b/tests/codegen/asm/s390x-clobbers.rs @@ -3,7 +3,7 @@ //@[s390x] needs-llvm-components: systemz #![crate_type = "rlib"] -#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] +#![feature(no_core, rustc_attrs, lang_items)] #![no_core] #[lang = "sized"] From 8f7f9b93b2cf1f16d4ded534ff14ce9a673177c0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 8 Nov 2024 00:11:21 +1100 Subject: [PATCH 31/79] Add a run-make test for `rustc --help` and similar --- src/tools/run-make-support/src/lib.rs | 1 + tests/run-make/rustc-help/help-v.diff | 29 ++++++++++ tests/run-make/rustc-help/help-v.stdout | 77 +++++++++++++++++++++++++ tests/run-make/rustc-help/help.stdout | 60 +++++++++++++++++++ tests/run-make/rustc-help/rmake.rs | 21 +++++++ 5 files changed, 188 insertions(+) create mode 100644 tests/run-make/rustc-help/help-v.diff create mode 100644 tests/run-make/rustc-help/help-v.stdout create mode 100644 tests/run-make/rustc-help/help.stdout create mode 100644 tests/run-make/rustc-help/rmake.rs diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 368b98c9f0dfd..5765cb97a7ef7 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -41,6 +41,7 @@ pub use libc; pub use object; pub use regex; pub use serde_json; +pub use similar; pub use wasmparser; // tidy-alphabetical-end diff --git a/tests/run-make/rustc-help/help-v.diff b/tests/run-make/rustc-help/help-v.diff new file mode 100644 index 0000000000000..22c5dd81bdb05 --- /dev/null +++ b/tests/run-make/rustc-help/help-v.diff @@ -0,0 +1,29 @@ +@@ -51,10 +51,27 @@ + Set a codegen option + -V, --version Print version info and exit + -v, --verbose Use verbose output ++ --extern NAME[=PATH] ++ Specify where an external rust library is located ++ --sysroot PATH Override the system root ++ --error-format human|json|short ++ How errors and other messages are produced ++ --json CONFIG Configure the JSON output of the compiler ++ --color auto|always|never ++ Configure coloring of output: ++ auto = colorize, if output goes to a tty (default); ++ always = always colorize output; ++ never = never colorize output ++ --diagnostic-width WIDTH ++ Inform rustc of the width of the output so that ++ diagnostics can be truncated to fit ++ --remap-path-prefix FROM=TO ++ Remap source names in all output (compiler messages ++ and output files) ++ @path Read newline separated options from `path` + + Additional help: + -C help Print codegen options + -W help Print 'lint' options and default settings + -Z help Print unstable compiler options +- --help -v Print the full set of options rustc accepts + diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout new file mode 100644 index 0000000000000..dbd67b57df2f0 --- /dev/null +++ b/tests/run-make/rustc-help/help-v.stdout @@ -0,0 +1,77 @@ +Usage: rustc [OPTIONS] INPUT + +Options: + -h, --help Display this message + --cfg SPEC Configure the compilation environment. + SPEC supports the syntax `NAME[="VALUE"]`. + --check-cfg SPEC + Provide list of expected cfgs for checking + -L [KIND=]PATH Add a directory to the library search path. The + optional KIND can be one of dependency, crate, native, + framework, or all (the default). + -l [KIND[:MODIFIERS]=]NAME[:RENAME] + Link the generated crate(s) to the specified native + library NAME. The optional KIND can be one of + static, framework, or dylib (the default). + Optional comma separated MODIFIERS + (bundle|verbatim|whole-archive|as-needed) + may be specified each with a prefix of either '+' to + enable or '-' to disable. + --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] + Comma separated list of types of crates + for the compiler to emit + --crate-name NAME + Specify the name of the crate being built + --edition 2015|2018|2021|2024 + Specify which edition of the compiler to use when + compiling code. The default is 2015 and the latest + stable edition is 2021. + --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] + Comma separated list of types of output for the + compiler to emit + --print [crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|all-target-specs-json|native-static-libs|stack-protector-strategies|link-args|deployment-target] + Compiler information to print on stdout + -g Equivalent to -C debuginfo=2 + -O Equivalent to -C opt-level=2 + -o FILENAME Write output to + --out-dir DIR Write output to compiler-chosen filename in + --explain OPT Provide a detailed explanation of an error message + --test Build a test harness + --target TARGET Target triple for which the code is compiled + -A, --allow LINT Set lint allowed + -W, --warn LINT Set lint warnings + --force-warn LINT + Set lint force-warn + -D, --deny LINT Set lint denied + -F, --forbid LINT Set lint forbidden + --cap-lints LEVEL + Set the most restrictive lint level. More restrictive + lints are capped at this level + -C, --codegen OPT[=VALUE] + Set a codegen option + -V, --version Print version info and exit + -v, --verbose Use verbose output + --extern NAME[=PATH] + Specify where an external rust library is located + --sysroot PATH Override the system root + --error-format human|json|short + How errors and other messages are produced + --json CONFIG Configure the JSON output of the compiler + --color auto|always|never + Configure coloring of output: + auto = colorize, if output goes to a tty (default); + always = always colorize output; + never = never colorize output + --diagnostic-width WIDTH + Inform rustc of the width of the output so that + diagnostics can be truncated to fit + --remap-path-prefix FROM=TO + Remap source names in all output (compiler messages + and output files) + @path Read newline separated options from `path` + +Additional help: + -C help Print codegen options + -W help Print 'lint' options and default settings + -Z help Print unstable compiler options + diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout new file mode 100644 index 0000000000000..a7d07162799b0 --- /dev/null +++ b/tests/run-make/rustc-help/help.stdout @@ -0,0 +1,60 @@ +Usage: rustc [OPTIONS] INPUT + +Options: + -h, --help Display this message + --cfg SPEC Configure the compilation environment. + SPEC supports the syntax `NAME[="VALUE"]`. + --check-cfg SPEC + Provide list of expected cfgs for checking + -L [KIND=]PATH Add a directory to the library search path. The + optional KIND can be one of dependency, crate, native, + framework, or all (the default). + -l [KIND[:MODIFIERS]=]NAME[:RENAME] + Link the generated crate(s) to the specified native + library NAME. The optional KIND can be one of + static, framework, or dylib (the default). + Optional comma separated MODIFIERS + (bundle|verbatim|whole-archive|as-needed) + may be specified each with a prefix of either '+' to + enable or '-' to disable. + --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro] + Comma separated list of types of crates + for the compiler to emit + --crate-name NAME + Specify the name of the crate being built + --edition 2015|2018|2021|2024 + Specify which edition of the compiler to use when + compiling code. The default is 2015 and the latest + stable edition is 2021. + --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir] + Comma separated list of types of output for the + compiler to emit + --print [crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|all-target-specs-json|native-static-libs|stack-protector-strategies|link-args|deployment-target] + Compiler information to print on stdout + -g Equivalent to -C debuginfo=2 + -O Equivalent to -C opt-level=2 + -o FILENAME Write output to + --out-dir DIR Write output to compiler-chosen filename in + --explain OPT Provide a detailed explanation of an error message + --test Build a test harness + --target TARGET Target triple for which the code is compiled + -A, --allow LINT Set lint allowed + -W, --warn LINT Set lint warnings + --force-warn LINT + Set lint force-warn + -D, --deny LINT Set lint denied + -F, --forbid LINT Set lint forbidden + --cap-lints LEVEL + Set the most restrictive lint level. More restrictive + lints are capped at this level + -C, --codegen OPT[=VALUE] + Set a codegen option + -V, --version Print version info and exit + -v, --verbose Use verbose output + +Additional help: + -C help Print codegen options + -W help Print 'lint' options and default settings + -Z help Print unstable compiler options + --help -v Print the full set of options rustc accepts + diff --git a/tests/run-make/rustc-help/rmake.rs b/tests/run-make/rustc-help/rmake.rs new file mode 100644 index 0000000000000..85e90e6352d09 --- /dev/null +++ b/tests/run-make/rustc-help/rmake.rs @@ -0,0 +1,21 @@ +// Tests `rustc --help` and similar invocations against snapshots and each other. + +use run_make_support::{bare_rustc, diff, similar}; + +fn main() { + // `rustc --help` + let help = bare_rustc().arg("--help").run().stdout_utf8(); + diff().expected_file("help.stdout").actual_text("(rustc --help)", &help).run(); + + // `rustc` should be the same as `rustc --help` + let bare = bare_rustc().run().stdout_utf8(); + diff().expected_text("(rustc --help)", &help).actual_text("(rustc)", &bare).run(); + + // `rustc --help -v` should give a similar but longer help message + let help_v = bare_rustc().arg("--help").arg("-v").run().stdout_utf8(); + diff().expected_file("help-v.stdout").actual_text("(rustc --help -v)", &help_v).run(); + + // Check the diff between `rustc --help` and `rustc --help -v`. + let help_v_diff = similar::TextDiff::from_lines(&help, &help_v).unified_diff().to_string(); + diff().expected_file("help-v.diff").actual_text("actual", &help_v_diff).run(); +} From 584c8200de3c83078d7cbb271a16ef4962be761e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 8 Nov 2024 12:20:51 +1100 Subject: [PATCH 32/79] Use a method to apply `RustcOptGroup` to `getopts::Options` --- compiler/rustc_driver_impl/src/lib.rs | 6 +++--- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_session/src/config.rs | 6 +++++- src/librustdoc/lib.rs | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index d2c4335cf2b44..78ba841d89f4b 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -937,7 +937,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() }; let mut options = getopts::Options::new(); for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) { - (option.apply)(&mut options); + option.apply(&mut options); } let message = "Usage: rustc [OPTIONS] INPUT"; let nightly_help = if nightly_build { @@ -1219,7 +1219,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option = match e { @@ -1233,7 +1233,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option getopts::Options { let mut opts = getopts::Options::new(); for group in rustc_optgroups() { - (group.apply)(&mut opts); + group.apply(&mut opts); } return opts; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index fe05605c1b9a1..0c4827ef54d2f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1373,7 +1373,7 @@ enum OptionStability { } pub struct RustcOptGroup { - pub apply: Box &mut getopts::Options>, + apply: Box &mut getopts::Options>, pub name: &'static str, stability: OptionStability, } @@ -1383,6 +1383,10 @@ impl RustcOptGroup { self.stability == OptionStability::Stable } + pub fn apply(&self, options: &mut getopts::Options) { + (self.apply)(options); + } + pub fn stable(name: &'static str, f: F) -> RustcOptGroup where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 7c9dcd41e6a06..40e649915cfca 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -685,7 +685,7 @@ fn opts() -> Vec { fn usage(argv0: &str) { let mut options = getopts::Options::new(); for option in opts() { - (option.apply)(&mut options); + option.apply(&mut options); } println!("{}", options.usage(&format!("{argv0} [options] "))); println!(" @path Read newline separated options from `path`\n"); @@ -769,7 +769,7 @@ fn main_args( let mut options = getopts::Options::new(); for option in opts() { - (option.apply)(&mut options); + option.apply(&mut options); } let matches = match options.parse(&args) { Ok(m) => m, From 001013c63cccb3ca88b547596cec5b891e09151a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 7 Nov 2024 22:47:15 +1100 Subject: [PATCH 33/79] Simplify command-line-option declarations in the compiler --- compiler/rustc_session/src/config.rs | 264 +++++++++++++++------------ 1 file changed, 147 insertions(+), 117 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0c4827ef54d2f..979db9424f3e9 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,7 +12,7 @@ use std::hash::Hash; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; use std::sync::LazyLock; -use std::{fmt, fs, iter}; +use std::{cmp, fmt, fs, iter}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; @@ -1367,11 +1367,36 @@ pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: & } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum OptionStability { +pub enum OptionStability { Stable, Unstable, } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum OptionKind { + /// An option that takes a value, and cannot appear more than once (e.g. `--out-dir`). + /// + /// Corresponds to [`getopts::Options::optopt`]. + Opt, + + /// An option that takes a value, and can appear multiple times (e.g. `--emit`). + /// + /// Corresponds to [`getopts::Options::optmulti`]. + Multi, + + /// An option that does not take a value, and cannot appear more than once (e.g. `--help`). + /// + /// Corresponds to [`getopts::Options::optflag`]. + /// The `hint` string must be empty. + Flag, + + /// An option that does not take a value, and can appear multiple times (e.g. `-O`). + /// + /// Corresponds to [`getopts::Options::optflagmulti`]. + /// The `hint` string must be empty. + FlagMulti, +} + pub struct RustcOptGroup { apply: Box &mut getopts::Options>, pub name: &'static str, @@ -1402,58 +1427,37 @@ impl RustcOptGroup { } } -// The `opt` local module holds wrappers around the `getopts` API that -// adds extra rustc-specific metadata to each option; such metadata -// is exposed by . The public -// functions below ending with `_u` are the functions that return -// *unstable* options, i.e., options that are only enabled when the -// user also passes the `-Z unstable-options` debugging flag. -mod opt { - // The `fn flag*` etc below are written so that we can use them - // in the future; do not warn about them not being used right now. - #![allow(dead_code)] - - use super::RustcOptGroup; - - type R = RustcOptGroup; - type S = &'static str; - - fn stable(name: S, f: F) -> R - where - F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, - { - RustcOptGroup::stable(name, f) - } - - fn unstable(name: S, f: F) -> R - where - F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, - { - RustcOptGroup::unstable(name, f) - } - - fn longer(a: S, b: S) -> S { - if a.len() > b.len() { a } else { b } - } - - pub(crate) fn opt_s(a: S, b: S, c: S, d: S) -> R { - stable(longer(a, b), move |opts| opts.optopt(a, b, c, d)) - } - pub(crate) fn multi_s(a: S, b: S, c: S, d: S) -> R { - stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) - } - pub(crate) fn flag_s(a: S, b: S, c: S) -> R { - stable(longer(a, b), move |opts| opts.optflag(a, b, c)) - } - pub(crate) fn flagmulti_s(a: S, b: S, c: S) -> R { - stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c)) - } - - fn opt(a: S, b: S, c: S, d: S) -> R { - unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d)) - } - pub(crate) fn multi(a: S, b: S, c: S, d: S) -> R { - unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) +pub fn make_opt( + stability: OptionStability, + kind: OptionKind, + short_name: &'static str, + long_name: &'static str, + desc: &'static str, + hint: &'static str, +) -> RustcOptGroup { + RustcOptGroup { + name: cmp::max_by_key(short_name, long_name, |s| s.len()), + stability, + apply: match kind { + OptionKind::Opt => Box::new(move |opts: &mut getopts::Options| { + opts.optopt(short_name, long_name, desc, hint) + }), + OptionKind::Multi => Box::new(move |opts: &mut getopts::Options| { + opts.optmulti(short_name, long_name, desc, hint) + }), + OptionKind::Flag => { + assert_eq!(hint, ""); + Box::new(move |opts: &mut getopts::Options| { + opts.optflag(short_name, long_name, desc) + }) + } + OptionKind::FlagMulti => { + assert_eq!(hint, ""); + Box::new(move |opts: &mut getopts::Options| { + opts.optflagmulti(short_name, long_name, desc) + }) + } + }, } } @@ -1468,46 +1472,60 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE /// including metadata for each option, such as whether the option is /// part of the stable long-term interface for rustc. pub fn rustc_short_optgroups() -> Vec { + use OptionKind::{Flag, FlagMulti, Multi, Opt}; + use OptionStability::Stable; + + use self::make_opt as opt; + vec![ - opt::flag_s("h", "help", "Display this message"), - opt::multi_s("", "cfg", "Configure the compilation environment. - SPEC supports the syntax `NAME[=\"VALUE\"]`.", "SPEC"), - opt::multi_s("", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"), - opt::multi_s( + opt(Stable, Flag, "h", "help", "Display this message", ""), + opt( + Stable, + Multi, + "", + "cfg", + "Configure the compilation environment.\n\ + SPEC supports the syntax `NAME[=\"VALUE\"]`.", + "SPEC", + ), + opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"), + opt( + Stable, + Multi, "L", "", - "Add a directory to the library search path. The - optional KIND can be one of dependency, crate, native, - framework, or all (the default).", + "Add a directory to the library search path. \ + The optional KIND can be one of dependency, crate, native, framework, or all (the default).", "[KIND=]PATH", ), - opt::multi_s( + opt( + Stable, + Multi, "l", "", - "Link the generated crate(s) to the specified native - library NAME. The optional KIND can be one of - static, framework, or dylib (the default). - Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed) - may be specified each with a prefix of either '+' to - enable or '-' to disable.", + "Link the generated crate(s) to the specified native\n\ + library NAME. The optional KIND can be one of\n\ + static, framework, or dylib (the default).\n\ + Optional comma separated MODIFIERS\n\ + (bundle|verbatim|whole-archive|as-needed)\n\ + may be specified each with a prefix of either '+' to\n\ + enable or '-' to disable.", "[KIND[:MODIFIERS]=]NAME[:RENAME]", ), make_crate_type_option(), - opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"), - opt::opt_s( - "", - "edition", - &EDITION_STRING, - EDITION_NAME_LIST, - ), - opt::multi_s( + opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "NAME"), + opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST), + opt( + Stable, + Multi, "", "emit", - "Comma separated list of types of output for \ - the compiler to emit", + "Comma separated list of types of output for the compiler to emit", "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]", ), - opt::multi_s( + opt( + Stable, + Multi, "", "print", "Compiler information to print on stdout", @@ -1516,41 +1534,36 @@ pub fn rustc_short_optgroups() -> Vec { tls-models|target-spec-json|all-target-specs-json|native-static-libs|\ stack-protector-strategies|link-args|deployment-target]", ), - opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), - opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), - opt::opt_s("o", "", "Write output to ", "FILENAME"), - opt::opt_s( - "", - "out-dir", - "Write output to compiler-chosen filename \ - in ", - "DIR", - ), - opt::opt_s( + opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""), + opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=2", ""), + opt(Stable, Opt, "o", "", "Write output to ", "FILENAME"), + opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in ", "DIR"), + opt( + Stable, + Opt, "", "explain", - "Provide a detailed explanation of an error \ - message", + "Provide a detailed explanation of an error message", "OPT", ), - opt::flag_s("", "test", "Build a test harness"), - opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"), - opt::multi_s("A", "allow", "Set lint allowed", "LINT"), - opt::multi_s("W", "warn", "Set lint warnings", "LINT"), - opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"), - opt::multi_s("D", "deny", "Set lint denied", "LINT"), - opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"), - opt::multi_s( + opt(Stable, Flag, "", "test", "Build a test harness", ""), + opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "TARGET"), + opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"), + opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"), + opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"), + opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"), + opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"), + opt( + Stable, + Multi, "", "cap-lints", - "Set the most restrictive lint level. \ - More restrictive lints are capped at this \ - level", + "Set the most restrictive lint level. More restrictive lints are capped at this level", "LEVEL", ), - opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"), - opt::flag_s("V", "version", "Print version info and exit"), - opt::flag_s("v", "verbose", "Use verbose output"), + opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"), + opt(Stable, Flag, "V", "version", "Print version info and exit", ""), + opt(Stable, Flag, "v", "verbose", "Use verbose output", ""), ] } @@ -1558,25 +1571,36 @@ pub fn rustc_short_optgroups() -> Vec { /// each option, such as whether the option is part of the stable /// long-term interface for rustc. pub fn rustc_optgroups() -> Vec { + use OptionKind::{Multi, Opt}; + use OptionStability::{Stable, Unstable}; + + use self::make_opt as opt; + let mut opts = rustc_short_optgroups(); // FIXME: none of these descriptions are actually used opts.extend(vec![ - opt::multi_s( + opt( + Stable, + Multi, "", "extern", "Specify where an external rust library is located", "NAME[=PATH]", ), - opt::opt_s("", "sysroot", "Override the system root", "PATH"), - opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"), - opt::opt_s( + opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"), + opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "FLAG"), + opt( + Stable, + Opt, "", "error-format", "How errors and other messages are produced", "human|json|short", ), - opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"), - opt::opt_s( + opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "CONFIG"), + opt( + Stable, + Opt, "", "color", "Configure coloring of output: @@ -1585,19 +1609,23 @@ pub fn rustc_optgroups() -> Vec { never = never colorize output", "auto|always|never", ), - opt::opt_s( + opt( + Stable, + Opt, "", "diagnostic-width", "Inform rustc of the width of the output so that diagnostics can be truncated to fit", "WIDTH", ), - opt::multi_s( + opt( + Stable, + Multi, "", "remap-path-prefix", "Remap source names in all output (compiler messages and output files)", "FROM=TO", ), - opt::multi("", "env-set", "Inject an environment variable", "VAR=VALUE"), + opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"), ]); opts } @@ -2760,7 +2788,9 @@ fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> O } pub fn make_crate_type_option() -> RustcOptGroup { - opt::multi_s( + make_opt( + OptionStability::Stable, + OptionKind::Multi, "", "crate-type", "Comma separated list of types of crates From b8377e58445fe5488664bcbbedd04a686cfdad03 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 7 Nov 2024 23:27:20 +1100 Subject: [PATCH 34/79] Simplify command-line-argument declarations in librustdoc --- compiler/rustc_session/src/config.rs | 14 - src/librustdoc/lib.rs | 921 ++++++++++++++------------- 2 files changed, 463 insertions(+), 472 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 979db9424f3e9..fa2403db92551 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1411,20 +1411,6 @@ impl RustcOptGroup { pub fn apply(&self, options: &mut getopts::Options) { (self.apply)(options); } - - pub fn stable(name: &'static str, f: F) -> RustcOptGroup - where - F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, - { - RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable } - } - - pub fn unstable(name: &'static str, f: F) -> RustcOptGroup - where - F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, - { - RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable } - } } pub fn make_opt( diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 40e649915cfca..78dc0b8e2f98a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -215,470 +215,475 @@ fn init_logging(early_dcx: &EarlyDiagCtxt) { } fn opts() -> Vec { - let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable; - let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable; + use rustc_session::config::OptionKind::{Flag, FlagMulti, Multi, Opt}; + use rustc_session::config::OptionStability::{Stable, Unstable}; + use rustc_session::config::make_opt as opt; + vec![ - stable("h", |o| o.optflagmulti("h", "help", "show this help message")), - stable("V", |o| o.optflagmulti("V", "version", "print rustdoc's version")), - stable("v", |o| o.optflagmulti("v", "verbose", "use verbose output")), - stable("w", |o| o.optopt("w", "output-format", "the output type to write", "[html]")), - stable("output", |o| { - o.optopt( - "", - "output", - "Which directory to place the output. \ - This option is deprecated, use --out-dir instead.", - "PATH", - ) - }), - stable("o", |o| o.optopt("o", "out-dir", "which directory to place the output", "PATH")), - stable("crate-name", |o| { - o.optopt("", "crate-name", "specify the name of this crate", "NAME") - }), + opt(Stable, FlagMulti, "h", "help", "show this help message", ""), + opt(Stable, FlagMulti, "V", "version", "print rustdoc's version", ""), + opt(Stable, FlagMulti, "v", "verbose", "use verbose output", ""), + opt(Stable, Opt, "w", "output-format", "the output type to write", "[html]"), + opt( + Stable, + Opt, + "", + "output", + "Which directory to place the output. This option is deprecated, use --out-dir instead.", + "PATH", + ), + opt(Stable, Opt, "o", "out-dir", "which directory to place the output", "PATH"), + opt(Stable, Opt, "", "crate-name", "specify the name of this crate", "NAME"), make_crate_type_option(), - stable("L", |o| { - o.optmulti("L", "library-path", "directory to add to crate search path", "DIR") - }), - stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")), - stable("check-cfg", |o| o.optmulti("", "check-cfg", "pass a --check-cfg to rustc", "")), - stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")), - unstable("extern-html-root-url", |o| { - o.optmulti( - "", - "extern-html-root-url", - "base URL to use for dependencies; for example, \ - \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html", - "NAME=URL", - ) - }), - unstable("extern-html-root-takes-precedence", |o| { - o.optflagmulti( - "", - "extern-html-root-takes-precedence", - "give precedence to `--extern-html-root-url`, not `html_root_url`", - ) - }), - stable("C", |o| { - o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]") - }), - stable("document-private-items", |o| { - o.optflagmulti("", "document-private-items", "document private items") - }), - unstable("document-hidden-items", |o| { - o.optflagmulti("", "document-hidden-items", "document items that have doc(hidden)") - }), - stable("test", |o| o.optflagmulti("", "test", "run code examples as tests")), - stable("test-args", |o| { - o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS") - }), - stable("test-run-directory", |o| { - o.optopt( - "", - "test-run-directory", - "The working directory in which to run tests", - "PATH", - ) - }), - stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")), - stable("markdown-css", |o| { - o.optmulti( - "", - "markdown-css", - "CSS files to include via in a rendered Markdown file", - "FILES", - ) - }), - stable("html-in-header", |o| { - o.optmulti( - "", - "html-in-header", - "files to include inline in the section of a rendered Markdown file \ - or generated documentation", - "FILES", - ) - }), - stable("html-before-content", |o| { - o.optmulti( - "", - "html-before-content", - "files to include inline between and the content of a rendered \ - Markdown file or generated documentation", - "FILES", - ) - }), - stable("html-after-content", |o| { - o.optmulti( - "", - "html-after-content", - "files to include inline between the content and of a rendered \ - Markdown file or generated documentation", - "FILES", - ) - }), - unstable("markdown-before-content", |o| { - o.optmulti( - "", - "markdown-before-content", - "files to include inline between and the content of a rendered \ - Markdown file or generated documentation", - "FILES", - ) - }), - unstable("markdown-after-content", |o| { - o.optmulti( - "", - "markdown-after-content", - "files to include inline between the content and of a rendered \ - Markdown file or generated documentation", - "FILES", - ) - }), - stable("markdown-playground-url", |o| { - o.optopt("", "markdown-playground-url", "URL to send code snippets to", "URL") - }), - stable("markdown-no-toc", |o| { - o.optflagmulti("", "markdown-no-toc", "don't include table of contents") - }), - stable("e", |o| { - o.optopt( - "e", - "extend-css", - "To add some CSS rules with a given file to generate doc with your \ - own theme. However, your theme might break if the rustdoc's generated HTML \ - changes, so be careful!", - "PATH", - ) - }), - unstable("Z", |o| { - o.optmulti("Z", "", "unstable / perma-unstable options (only on nightly build)", "FLAG") - }), - stable("sysroot", |o| o.optopt("", "sysroot", "Override the system root", "PATH")), - unstable("playground-url", |o| { - o.optopt( - "", - "playground-url", - "URL to send code snippets to, may be reset by --markdown-playground-url \ - or `#![doc(html_playground_url=...)]`", - "URL", - ) - }), - unstable("display-doctest-warnings", |o| { - o.optflagmulti( - "", - "display-doctest-warnings", - "show warnings that originate in doctests", - ) - }), - stable("crate-version", |o| { - o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") - }), - unstable("sort-modules-by-appearance", |o| { - o.optflagmulti( - "", - "sort-modules-by-appearance", - "sort modules by where they appear in the program, rather than alphabetically", - ) - }), - stable("default-theme", |o| { - o.optopt( - "", - "default-theme", - "Set the default theme. THEME should be the theme name, generally lowercase. \ - If an unknown default theme is specified, the builtin default is used. \ - The set of themes, and the rustdoc built-in default, are not stable.", - "THEME", - ) - }), - unstable("default-setting", |o| { - o.optmulti( - "", - "default-setting", - "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \ - from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \ - Supported SETTINGs and VALUEs are not documented and not stable.", - "SETTING[=VALUE]", - ) - }), - stable("theme", |o| { - o.optmulti( - "", - "theme", - "additional themes which will be added to the generated docs", - "FILES", - ) - }), - stable("check-theme", |o| { - o.optmulti("", "check-theme", "check if given theme is valid", "FILES") - }), - unstable("resource-suffix", |o| { - o.optopt( - "", - "resource-suffix", - "suffix to add to CSS and JavaScript files, e.g., \"search-index.js\" will \ - become \"search-index-suffix.js\"", - "PATH", - ) - }), - stable("edition", |o| { - o.optopt( - "", - "edition", - "edition to use when compiling rust code (default: 2015)", - "EDITION", - ) - }), - stable("color", |o| { - o.optopt( - "", - "color", - "Configure coloring of output: + opt(Stable, Multi, "L", "library-path", "directory to add to crate search path", "DIR"), + opt(Stable, Multi, "", "cfg", "pass a --cfg to rustc", ""), + opt(Stable, Multi, "", "check-cfg", "pass a --check-cfg to rustc", ""), + opt(Stable, Multi, "", "extern", "pass an --extern to rustc", "NAME[=PATH]"), + opt( + Unstable, + Multi, + "", + "extern-html-root-url", + "base URL to use for dependencies; for example, \ + \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html", + "NAME=URL", + ), + opt( + Unstable, + FlagMulti, + "", + "extern-html-root-takes-precedence", + "give precedence to `--extern-html-root-url`, not `html_root_url`", + "", + ), + opt(Stable, Multi, "C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]"), + opt(Stable, FlagMulti, "", "document-private-items", "document private items", ""), + opt( + Unstable, + FlagMulti, + "", + "document-hidden-items", + "document items that have doc(hidden)", + "", + ), + opt(Stable, FlagMulti, "", "test", "run code examples as tests", ""), + opt(Stable, Multi, "", "test-args", "arguments to pass to the test runner", "ARGS"), + opt( + Stable, + Opt, + "", + "test-run-directory", + "The working directory in which to run tests", + "PATH", + ), + opt(Stable, Opt, "", "target", "target triple to document", "TRIPLE"), + opt( + Stable, + Multi, + "", + "markdown-css", + "CSS files to include via in a rendered Markdown file", + "FILES", + ), + opt( + Stable, + Multi, + "", + "html-in-header", + "files to include inline in the section of a rendered Markdown file \ + or generated documentation", + "FILES", + ), + opt( + Stable, + Multi, + "", + "html-before-content", + "files to include inline between and the content of a rendered \ + Markdown file or generated documentation", + "FILES", + ), + opt( + Stable, + Multi, + "", + "html-after-content", + "files to include inline between the content and of a rendered \ + Markdown file or generated documentation", + "FILES", + ), + opt( + Unstable, + Multi, + "", + "markdown-before-content", + "files to include inline between and the content of a rendered \ + Markdown file or generated documentation", + "FILES", + ), + opt( + Unstable, + Multi, + "", + "markdown-after-content", + "files to include inline between the content and of a rendered \ + Markdown file or generated documentation", + "FILES", + ), + opt(Stable, Opt, "", "markdown-playground-url", "URL to send code snippets to", "URL"), + opt(Stable, FlagMulti, "", "markdown-no-toc", "don't include table of contents", ""), + opt( + Stable, + Opt, + "e", + "extend-css", + "To add some CSS rules with a given file to generate doc with your own theme. \ + However, your theme might break if the rustdoc's generated HTML changes, so be careful!", + "PATH", + ), + opt( + Unstable, + Multi, + "Z", + "", + "unstable / perma-unstable options (only on nightly build)", + "FLAG", + ), + opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"), + opt( + Unstable, + Opt, + "", + "playground-url", + "URL to send code snippets to, may be reset by --markdown-playground-url \ + or `#![doc(html_playground_url=...)]`", + "URL", + ), + opt( + Unstable, + FlagMulti, + "", + "display-doctest-warnings", + "show warnings that originate in doctests", + "", + ), + opt( + Stable, + Opt, + "", + "crate-version", + "crate version to print into documentation", + "VERSION", + ), + opt( + Unstable, + FlagMulti, + "", + "sort-modules-by-appearance", + "sort modules by where they appear in the program, rather than alphabetically", + "", + ), + opt( + Stable, + Opt, + "", + "default-theme", + "Set the default theme. THEME should be the theme name, generally lowercase. \ + If an unknown default theme is specified, the builtin default is used. \ + The set of themes, and the rustdoc built-in default, are not stable.", + "THEME", + ), + opt( + Unstable, + Multi, + "", + "default-setting", + "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \ + from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \ + Supported SETTINGs and VALUEs are not documented and not stable.", + "SETTING[=VALUE]", + ), + opt( + Stable, + Multi, + "", + "theme", + "additional themes which will be added to the generated docs", + "FILES", + ), + opt(Stable, Multi, "", "check-theme", "check if given theme is valid", "FILES"), + opt( + Unstable, + Opt, + "", + "resource-suffix", + "suffix to add to CSS and JavaScript files, \ + e.g., \"search-index.js\" will become \"search-index-suffix.js\"", + "PATH", + ), + opt( + Stable, + Opt, + "", + "edition", + "edition to use when compiling rust code (default: 2015)", + "EDITION", + ), + opt( + Stable, + Opt, + "", + "color", + "Configure coloring of output: auto = colorize, if output goes to a tty (default); always = always colorize output; never = never colorize output", - "auto|always|never", - ) - }), - stable("error-format", |o| { - o.optopt( - "", - "error-format", - "How errors and other messages are produced", - "human|json|short", - ) - }), - stable("diagnostic-width", |o| { - o.optopt( - "", - "diagnostic-width", - "Provide width of the output for truncated error messages", - "WIDTH", - ) - }), - stable("json", |o| { - o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG") - }), - stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "LINT")), - stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "LINT")), - stable("force-warn", |o| o.optmulti("", "force-warn", "Set lint force-warn", "LINT")), - stable("deny", |o| o.optmulti("D", "deny", "Set lint denied", "LINT")), - stable("forbid", |o| o.optmulti("F", "forbid", "Set lint forbidden", "LINT")), - stable("cap-lints", |o| { - o.optmulti( - "", - "cap-lints", - "Set the most restrictive lint level. \ - More restrictive lints are capped at this \ - level. By default, it is at `forbid` level.", - "LEVEL", - ) - }), - unstable("index-page", |o| { - o.optopt("", "index-page", "Markdown file to be used as index page", "PATH") - }), - unstable("enable-index-page", |o| { - o.optflagmulti("", "enable-index-page", "To enable generation of the index page") - }), - unstable("static-root-path", |o| { - o.optopt( - "", - "static-root-path", - "Path string to force loading static files from in output pages. \ - If not set, uses combinations of '../' to reach the documentation root.", - "PATH", - ) - }), - unstable("persist-doctests", |o| { - o.optopt( - "", - "persist-doctests", - "Directory to persist doctest executables into", - "PATH", - ) - }), - unstable("show-coverage", |o| { - o.optflagmulti( - "", - "show-coverage", - "calculate percentage of public items with documentation", - ) - }), - unstable("enable-per-target-ignores", |o| { - o.optflagmulti( - "", - "enable-per-target-ignores", - "parse ignore-foo for ignoring doctests on a per-target basis", - ) - }), - unstable("runtool", |o| { - o.optopt( - "", - "runtool", - "", - "The tool to run tests with when building for a different target than host", - ) - }), - unstable("runtool-arg", |o| { - o.optmulti( - "", - "runtool-arg", - "", - "One (of possibly many) arguments to pass to the runtool", - ) - }), - unstable("test-builder", |o| { - o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH") - }), - unstable("test-builder-wrapper", |o| { - o.optmulti( - "", - "test-builder-wrapper", - "Wrapper program to pass test-builder and arguments", - "PATH", - ) - }), - unstable("check", |o| o.optflagmulti("", "check", "Run rustdoc checks")), - unstable("generate-redirect-map", |o| { - o.optflagmulti( - "", - "generate-redirect-map", - "Generate JSON file at the top level instead of generating HTML redirection files", - ) - }), - unstable("emit", |o| { - o.optmulti( - "", - "emit", - "Comma separated list of types of output for rustdoc to emit", - "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]", - ) - }), - unstable("no-run", |o| { - o.optflagmulti("", "no-run", "Compile doctests without running them") - }), - unstable("remap-path-prefix", |o| { - o.optmulti( - "", - "remap-path-prefix", - "Remap source names in compiler messages", - "FROM=TO", - ) - }), - unstable("show-type-layout", |o| { - o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs") - }), - unstable("nocapture", |o| { - o.optflag("", "nocapture", "Don't capture stdout and stderr of tests") - }), - unstable("generate-link-to-definition", |o| { - o.optflag( - "", - "generate-link-to-definition", - "Make the identifiers in the HTML source code pages navigable", - ) - }), - unstable("scrape-examples-output-path", |o| { - o.optopt( - "", - "scrape-examples-output-path", - "", - "collect function call information and output at the given path", - ) - }), - unstable("scrape-examples-target-crate", |o| { - o.optmulti( - "", - "scrape-examples-target-crate", - "", - "collect function call information for functions from the target crate", - ) - }), - unstable("scrape-tests", |o| { - o.optflag("", "scrape-tests", "Include test code when scraping examples") - }), - unstable("with-examples", |o| { - o.optmulti( - "", - "with-examples", - "", - "path to function call information (for displaying examples in the documentation)", - ) - }), - unstable("merge", |o| { - o.optopt( - "", - "merge", - "Controls how rustdoc handles files from previously documented crates in the doc root - none = Do not write cross-crate information to the --out-dir - shared = Append current crate's info to files found in the --out-dir - finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files", - "none|shared|finalize", - ) - }), - unstable("parts-out-dir", |o| { - o.optopt( - "", - "parts-out-dir", - "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none", - "path/to/doc.parts/", - ) - }), - unstable("include-parts-dir", |o| { - o.optmulti( - "", - "include-parts-dir", - "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize", - "path/to/doc.parts/", - ) - }), + "auto|always|never", + ), + opt( + Stable, + Opt, + "", + "error-format", + "How errors and other messages are produced", + "human|json|short", + ), + opt( + Stable, + Opt, + "", + "diagnostic-width", + "Provide width of the output for truncated error messages", + "WIDTH", + ), + opt(Stable, Opt, "", "json", "Configure the structure of JSON diagnostics", "CONFIG"), + opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"), + opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"), + opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"), + opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"), + opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"), + opt( + Stable, + Multi, + "", + "cap-lints", + "Set the most restrictive lint level. \ + More restrictive lints are capped at this level. \ + By default, it is at `forbid` level.", + "LEVEL", + ), + opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"), + opt( + Unstable, + FlagMulti, + "", + "enable-index-page", + "To enable generation of the index page", + "", + ), + opt( + Unstable, + Opt, + "", + "static-root-path", + "Path string to force loading static files from in output pages. \ + If not set, uses combinations of '../' to reach the documentation root.", + "PATH", + ), + opt( + Unstable, + Opt, + "", + "persist-doctests", + "Directory to persist doctest executables into", + "PATH", + ), + opt( + Unstable, + FlagMulti, + "", + "show-coverage", + "calculate percentage of public items with documentation", + "", + ), + opt( + Unstable, + FlagMulti, + "", + "enable-per-target-ignores", + "parse ignore-foo for ignoring doctests on a per-target basis", + "", + ), + opt( + Unstable, + Opt, + "", + "runtool", + "", + "The tool to run tests with when building for a different target than host", + ), + opt( + Unstable, + Multi, + "", + "runtool-arg", + "", + "One (of possibly many) arguments to pass to the runtool", + ), + opt( + Unstable, + Opt, + "", + "test-builder", + "The rustc-like binary to use as the test builder", + "PATH", + ), + opt( + Unstable, + Multi, + "", + "test-builder-wrapper", + "Wrapper program to pass test-builder and arguments", + "PATH", + ), + opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""), + opt( + Unstable, + FlagMulti, + "", + "generate-redirect-map", + "Generate JSON file at the top level instead of generating HTML redirection files", + "", + ), + opt( + Unstable, + Multi, + "", + "emit", + "Comma separated list of types of output for rustdoc to emit", + "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]", + ), + opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""), + opt( + Unstable, + Multi, + "", + "remap-path-prefix", + "Remap source names in compiler messages", + "FROM=TO", + ), + opt( + Unstable, + FlagMulti, + "", + "show-type-layout", + "Include the memory layout of types in the docs", + "", + ), + opt(Unstable, Flag, "", "nocapture", "Don't capture stdout and stderr of tests", ""), + opt( + Unstable, + Flag, + "", + "generate-link-to-definition", + "Make the identifiers in the HTML source code pages navigable", + "", + ), + opt( + Unstable, + Opt, + "", + "scrape-examples-output-path", + "", + "collect function call information and output at the given path", + ), + opt( + Unstable, + Multi, + "", + "scrape-examples-target-crate", + "", + "collect function call information for functions from the target crate", + ), + opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""), + opt( + Unstable, + Multi, + "", + "with-examples", + "", + "path to function call information (for displaying examples in the documentation)", + ), + opt( + Unstable, + Opt, + "", + "merge", + "Controls how rustdoc handles files from previously documented crates in the doc root\n\ + none = Do not write cross-crate information to the --out-dir\n\ + shared = Append current crate's info to files found in the --out-dir\n\ + finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files", + "none|shared|finalize", + ), + opt( + Unstable, + Opt, + "", + "parts-out-dir", + "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none", + "path/to/doc.parts/", + ), + opt( + Unstable, + Multi, + "", + "include-parts-dir", + "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize", + "path/to/doc.parts/", + ), // deprecated / removed options - unstable("disable-minification", |o| o.optflagmulti("", "disable-minification", "removed")), - stable("plugin-path", |o| { - o.optmulti( - "", - "plugin-path", - "removed, see issue #44136 \ - for more information", - "DIR", - ) - }), - stable("passes", |o| { - o.optmulti( - "", - "passes", - "removed, see issue #44136 \ - for more information", - "PASSES", - ) - }), - stable("plugins", |o| { - o.optmulti( - "", - "plugins", - "removed, see issue #44136 \ - for more information", - "PLUGINS", - ) - }), - stable("no-default", |o| { - o.optflagmulti( - "", - "no-defaults", - "removed, see issue #44136 \ - for more information", - ) - }), - stable("r", |o| { - o.optopt( - "r", - "input-format", - "removed, see issue #44136 \ - for more information", - "[rust]", - ) - }), - unstable("html-no-source", |o| { - o.optflag("", "html-no-source", "Disable HTML source code pages generation") - }), + opt(Unstable, FlagMulti, "", "disable-minification", "removed", ""), + opt( + Stable, + Multi, + "", + "plugin-path", + "removed, see issue #44136 for more information", + "DIR", + ), + opt( + Stable, + Multi, + "", + "passes", + "removed, see issue #44136 for more information", + "PASSES", + ), + opt( + Stable, + Multi, + "", + "plugins", + "removed, see issue #44136 for more information", + "PLUGINS", + ), + opt( + Stable, + FlagMulti, + "", + "no-defaults", + "removed, see issue #44136 for more information", + "", + ), + opt( + Stable, + Opt, + "r", + "input-format", + "removed, see issue #44136 for more information", + "[rust]", + ), + opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""), ] } From 7c769959505efaf8d6717e67e8def06b5f1a515d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 6 Nov 2024 13:05:21 +1100 Subject: [PATCH 35/79] coverage: Pass `ExtractedHirInfo` to `make_source_region` This isn't strictly necessary, but makes it easier to distinguish `body_span` from the specific `span` being processed. --- compiler/rustc_mir_transform/src/coverage/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 2e4c503f3ce5b..bc698e9ebf613 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; -use tracing::{debug, debug_span, instrument, trace}; +use tracing::{debug, debug_span, trace}; use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; use crate::coverage::graph::CoverageGraph; @@ -154,7 +154,7 @@ fn create_mappings<'tcx>( let term_for_bcb = |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters"); - let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span); + let region_for_span = |span: Span| make_source_region(source_map, hir_info, file_name, span); // Fully destructure the mappings struct to make sure we don't miss any kinds. let ExtractedMappings { @@ -408,12 +408,11 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb /// but it's hard to rule out entirely (especially in the presence of complex macros /// or other expansions), and if it does happen then skipping a span or function is /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid. -#[instrument(level = "debug", skip(source_map))] fn make_source_region( source_map: &SourceMap, + hir_info: &ExtractedHirInfo, file_name: Symbol, span: Span, - body_span: Span, ) -> Option { let lo = span.lo(); let hi = span.hi(); @@ -441,6 +440,7 @@ fn make_source_region( // worth of bytes, so that it is more visible in `llvm-cov` reports. // We do this after resolving line/column numbers, so that empty spans at the // end of a line get an extra column instead of wrapping to the next line. + let body_span = hir_info.body_span; if span.is_empty() && body_span.contains(span) && let Some(src) = &file.src From 3f9c54caf04f74529c178326fa594a8464071f0a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 29 Aug 2024 15:56:21 +1000 Subject: [PATCH 36/79] coverage: Add `GlobalFileId` for stricter type-checking of file IDs We already had a dedicated `LocalFileId` index type, but previously we used a raw `u32` for global file IDs, because index types were harder to pass through FFI. --- .../src/coverageinfo/mapgen.rs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index f6378199fe26e..9effcaede1cdb 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -163,13 +163,13 @@ impl GlobalFileTable { Self { raw_file_table } } - fn global_file_id_for_file_name(&self, file_name: Symbol) -> u32 { + fn global_file_id_for_file_name(&self, file_name: Symbol) -> GlobalFileId { let raw_id = self.raw_file_table.get_index_of(&file_name).unwrap_or_else(|| { bug!("file name not found in prepared global file table: {file_name}"); }); // The raw file table doesn't include an entry for the working dir // (which has ID 0), so add 1 to get the correct ID. - (raw_id + 1) as u32 + GlobalFileId::from_usize(raw_id + 1) } fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec { @@ -198,6 +198,14 @@ impl GlobalFileTable { } rustc_index::newtype_index! { + /// An index into the CGU's overall list of file paths. The underlying paths + /// will be embedded in the `__llvm_covmap` linker section. + struct GlobalFileId {} +} +rustc_index::newtype_index! { + /// An index into a function's list of global file IDs. That underlying list + /// of local-to-global mappings will be embedded in the function's record in + /// the `__llvm_covfun` linker section. struct LocalFileId {} } @@ -205,12 +213,12 @@ rustc_index::newtype_index! { /// file IDs. #[derive(Default)] struct VirtualFileMapping { - local_to_global: IndexVec, - global_to_local: FxIndexMap, + local_to_global: IndexVec, + global_to_local: FxIndexMap, } impl VirtualFileMapping { - fn local_id_for_global(&mut self, global_file_id: u32) -> LocalFileId { + fn local_id_for_global(&mut self, global_file_id: GlobalFileId) -> LocalFileId { *self .global_to_local .entry(global_file_id) @@ -218,7 +226,9 @@ impl VirtualFileMapping { } fn into_vec(self) -> Vec { - self.local_to_global.raw + // This conversion should be optimized away to ~zero overhead. + // In any case, it's probably not hot enough to worry about. + self.local_to_global.into_iter().map(|global| global.as_u32()).collect() } } @@ -256,7 +266,7 @@ fn encode_mappings_for_function( // Associate that global file ID with a local file ID for this function. let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id); - debug!(" file id: {local_file_id:?} => global {global_file_id} = '{file_name:?}'"); + debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'"); // For each counter/region pair in this function+file, convert it to a // form suitable for FFI. From 996bdabc2a31cd86086b6f9beba3a8c58c8ceb8a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 4 Nov 2024 14:53:52 +1100 Subject: [PATCH 37/79] coverage: Remove unhelpful code for handling multiple files per function Functions currently can't have mappings in multiple files, and if that ever changes (e.g. to properly support expansion regions), this code will need to be completely overhauled anyway. --- .../src/coverageinfo/ffi.rs | 2 +- .../src/coverageinfo/map_data.rs | 8 +- .../src/coverageinfo/mapgen.rs | 106 +++++++++--------- compiler/rustc_middle/src/mir/coverage.rs | 11 +- compiler/rustc_middle/src/mir/pretty.rs | 4 +- .../rustc_mir_transform/src/coverage/mod.rs | 28 ++--- ...ch_match_arms.main.InstrumentCoverage.diff | 13 ++- ...ument_coverage.bar.InstrumentCoverage.diff | 3 +- ...ment_coverage.main.InstrumentCoverage.diff | 11 +- ...rage_cleanup.main.CleanupPostBorrowck.diff | 11 +- ...erage_cleanup.main.InstrumentCoverage.diff | 11 +- 11 files changed, 98 insertions(+), 110 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index feac97f3e2b62..a73ee0a3e07cd 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -138,7 +138,7 @@ pub(crate) struct CoverageSpan { impl CoverageSpan { pub(crate) fn from_source_region(file_id: u32, code_region: &SourceRegion) -> Self { - let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region; + let &SourceRegion { start_line, start_col, end_line, end_col } = code_region; // Internally, LLVM uses the high bit of `end_col` to distinguish between // code regions and gap regions, so it can't be used by the column number. assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}"); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index 5ed640b840e76..e3c0df278836e 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -6,7 +6,6 @@ use rustc_middle::mir::coverage::{ SourceRegion, }; use rustc_middle::ty::Instance; -use rustc_span::Symbol; use tracing::{debug, instrument}; use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind}; @@ -180,7 +179,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> { } pub(crate) struct FunctionCoverage<'tcx> { - function_coverage_info: &'tcx FunctionCoverageInfo, + pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo, is_used: bool, counters_seen: BitSet, @@ -199,11 +198,6 @@ impl<'tcx> FunctionCoverage<'tcx> { if self.is_used { self.function_coverage_info.function_source_hash } else { 0 } } - /// Returns an iterator over all filenames used by this function's mappings. - pub(crate) fn all_file_names(&self) -> impl Iterator + Captures<'_> { - self.function_coverage_info.mappings.iter().map(|mapping| mapping.source_region.file_name) - } - /// Convert this function's coverage expression data into a form that can be /// passed through FFI to LLVM. pub(crate) fn counter_expressions( diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 9effcaede1cdb..488ce62074624 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -11,8 +11,10 @@ use rustc_index::IndexVec; use rustc_middle::mir::coverage::MappingKind; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, mir}; -use rustc_span::Symbol; +use rustc_session::RemapFileNameExt; +use rustc_session::config::RemapPathScopeComponents; use rustc_span::def_id::DefIdSet; +use rustc_span::{Span, Symbol}; use rustc_target::spec::HasTargetSpec; use tracing::debug; @@ -69,8 +71,10 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { .map(|(instance, function_coverage)| (instance, function_coverage.into_finished())) .collect::>(); - let all_file_names = - function_coverage_entries.iter().flat_map(|(_, fn_cov)| fn_cov.all_file_names()); + let all_file_names = function_coverage_entries + .iter() + .map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span) + .map(|span| span_file_name(tcx, span)); let global_file_table = GlobalFileTable::new(all_file_names); // Encode all filenames referenced by coverage mappings in this CGU. @@ -95,7 +99,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { let is_used = function_coverage.is_used(); let coverage_mapping_buffer = - encode_mappings_for_function(&global_file_table, &function_coverage); + encode_mappings_for_function(tcx, &global_file_table, &function_coverage); if coverage_mapping_buffer.is_empty() { if function_coverage.is_used() { @@ -232,12 +236,20 @@ impl VirtualFileMapping { } } +fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol { + let source_file = tcx.sess.source_map().lookup_source_file(span.lo()); + let name = + source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(); + Symbol::intern(&name) +} + /// Using the expressions and counter regions collected for a single function, /// generate the variable-sized payload of its corresponding `__llvm_covfun` /// entry. The payload is returned as a vector of bytes. /// /// Newly-encountered filenames will be added to the global file table. fn encode_mappings_for_function( + tcx: TyCtxt<'_>, global_file_table: &GlobalFileTable, function_coverage: &FunctionCoverage<'_>, ) -> Vec { @@ -254,53 +266,45 @@ fn encode_mappings_for_function( let mut mcdc_branch_regions = vec![]; let mut mcdc_decision_regions = vec![]; - // Group mappings into runs with the same filename, preserving the order - // yielded by `FunctionCoverage`. - // Prepare file IDs for each filename, and prepare the mapping data so that - // we can pass it through FFI to LLVM. - for (file_name, counter_regions_for_file) in - &counter_regions.group_by(|(_, region)| region.file_name) - { - // Look up the global file ID for this filename. - let global_file_id = global_file_table.global_file_id_for_file_name(file_name); - - // Associate that global file ID with a local file ID for this function. - let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id); - debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'"); - - // For each counter/region pair in this function+file, convert it to a - // form suitable for FFI. - for (mapping_kind, region) in counter_regions_for_file { - debug!("Adding counter {mapping_kind:?} to map for {region:?}"); - let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region); - match mapping_kind { - MappingKind::Code(term) => { - code_regions - .push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); - } - MappingKind::Branch { true_term, false_term } => { - branch_regions.push(ffi::BranchRegion { - span, - true_counter: ffi::Counter::from_term(true_term), - false_counter: ffi::Counter::from_term(false_term), - }); - } - MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => { - mcdc_branch_regions.push(ffi::MCDCBranchRegion { - span, - true_counter: ffi::Counter::from_term(true_term), - false_counter: ffi::Counter::from_term(false_term), - mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params), - }); - } - MappingKind::MCDCDecision(mcdc_decision_params) => { - mcdc_decision_regions.push(ffi::MCDCDecisionRegion { - span, - mcdc_decision_params: ffi::mcdc::DecisionParameters::from( - mcdc_decision_params, - ), - }); - } + // Currently a function's mappings must all be in the same file as its body span. + let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span); + + // Look up the global file ID for that filename. + let global_file_id = global_file_table.global_file_id_for_file_name(file_name); + + // Associate that global file ID with a local file ID for this function. + let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id); + debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'"); + + // For each counter/region pair in this function+file, convert it to a + // form suitable for FFI. + for (mapping_kind, region) in counter_regions { + debug!("Adding counter {mapping_kind:?} to map for {region:?}"); + let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region); + match mapping_kind { + MappingKind::Code(term) => { + code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); + } + MappingKind::Branch { true_term, false_term } => { + branch_regions.push(ffi::BranchRegion { + span, + true_counter: ffi::Counter::from_term(true_term), + false_counter: ffi::Counter::from_term(false_term), + }); + } + MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => { + mcdc_branch_regions.push(ffi::MCDCBranchRegion { + span, + true_counter: ffi::Counter::from_term(true_term), + false_counter: ffi::Counter::from_term(false_term), + mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params), + }); + } + MappingKind::MCDCDecision(mcdc_decision_params) => { + mcdc_decision_regions.push(ffi::MCDCDecisionRegion { + span, + mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params), + }); } } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 4a876dc1228e5..11a4e7f89a7c7 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter}; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; rustc_index::newtype_index! { /// Used by [`CoverageKind::BlockMarker`] to mark blocks during THIR-to-MIR @@ -158,7 +158,6 @@ impl Debug for CoverageKind { #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)] #[derive(TypeFoldable, TypeVisitable)] pub struct SourceRegion { - pub file_name: Symbol, pub start_line: u32, pub start_col: u32, pub end_line: u32, @@ -167,11 +166,8 @@ pub struct SourceRegion { impl Debug for SourceRegion { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - write!( - fmt, - "{}:{}:{} - {}:{}", - self.file_name, self.start_line, self.start_col, self.end_line, self.end_col - ) + let &Self { start_line, start_col, end_line, end_col } = self; + write!(fmt, "{start_line}:{start_col} - {end_line}:{end_col}") } } @@ -246,6 +242,7 @@ pub struct Mapping { #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct FunctionCoverageInfo { pub function_source_hash: u64, + pub body_span: Span, pub num_counters: usize, pub mcdc_bitmap_bits: usize, pub expressions: IndexVec, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index d0f93c19e44e6..f0e2b7a376cd3 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -596,8 +596,10 @@ fn write_function_coverage_info( function_coverage_info: &coverage::FunctionCoverageInfo, w: &mut dyn io::Write, ) -> io::Result<()> { - let coverage::FunctionCoverageInfo { expressions, mappings, .. } = function_coverage_info; + let coverage::FunctionCoverageInfo { body_span, expressions, mappings, .. } = + function_coverage_info; + writeln!(w, "{INDENT}coverage body span: {body_span:?}")?; for (id, expression) in expressions.iter_enumerated() { writeln!(w, "{INDENT}coverage {id:?} => {expression:?};")?; } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index bc698e9ebf613..39ad1fd23b2d6 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -22,7 +22,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; +use rustc_span::{BytePos, Pos, RelativeBytePos, SourceFile, Span}; use tracing::{debug, debug_span, trace}; use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; @@ -122,6 +122,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, + body_span: hir_info.body_span, num_counters: coverage_counters.num_counters(), mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits, expressions: coverage_counters.into_expressions(), @@ -142,19 +143,11 @@ fn create_mappings<'tcx>( coverage_counters: &CoverageCounters, ) -> Vec { let source_map = tcx.sess.source_map(); - let body_span = hir_info.body_span; - - let source_file = source_map.lookup_source_file(body_span.lo()); - - use rustc_session::RemapFileNameExt; - use rustc_session::config::RemapPathScopeComponents; - let file_name = Symbol::intern( - &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), - ); + let file = source_map.lookup_source_file(hir_info.body_span.lo()); let term_for_bcb = |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters"); - let region_for_span = |span: Span| make_source_region(source_map, hir_info, file_name, span); + let region_for_span = |span: Span| make_source_region(source_map, hir_info, &file, span); // Fully destructure the mappings struct to make sure we don't miss any kinds. let ExtractedMappings { @@ -398,7 +391,7 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb data.statements.insert(0, statement); } -/// Convert the Span into its file name, start line and column, and end line and column. +/// Converts the span into its start line and column, and end line and column. /// /// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by /// the compiler, these column numbers are denoted in **bytes**, because that's what @@ -411,18 +404,12 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb fn make_source_region( source_map: &SourceMap, hir_info: &ExtractedHirInfo, - file_name: Symbol, + file: &SourceFile, span: Span, ) -> Option { let lo = span.lo(); let hi = span.hi(); - let file = source_map.lookup_source_file(lo); - if !file.contains(hi) { - debug!(?span, ?file, ?lo, ?hi, "span crosses multiple files; skipping"); - return None; - } - // Column numbers need to be in bytes, so we can't use the more convenient // `SourceMap` methods for looking up file coordinates. let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> { @@ -465,7 +452,6 @@ fn make_source_region( end_line = source_map.doctest_offset_line(&file.name, end_line); check_source_region(SourceRegion { - file_name, start_line: start_line as u32, start_col: start_col as u32, end_line: end_line as u32, @@ -478,7 +464,7 @@ fn make_source_region( /// discard regions that are improperly ordered, or might be interpreted in a /// way that makes them improperly ordered. fn check_source_region(source_region: SourceRegion) -> Option { - let SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = source_region; + let SourceRegion { start_line, start_col, end_line, end_col } = source_region; // Line/column coordinates are supposed to be 1-based. If we ever emit // coordinates of 0, `llvm-cov` might misinterpret them. diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index eeeac70b5b8e7..cbb11d50f7974 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -26,18 +26,19 @@ debug a => _9; } ++ coverage body span: $DIR/branch_match_arms.rs:14:11: 21:2 (#0) + coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) }; + coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) }; + coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) }; + coverage ExpressionId(3) => Expression { lhs: Counter(3), op: Add, rhs: Counter(2) }; + coverage ExpressionId(4) => Expression { lhs: Expression(3), op: Add, rhs: Counter(1) }; + coverage ExpressionId(5) => Expression { lhs: Expression(4), op: Add, rhs: Expression(2) }; -+ coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:14:1 - 15:21; -+ coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:16:17 - 16:33; -+ coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:17:17 - 17:33; -+ coverage Code(Counter(1)) => $DIR/branch_match_arms.rs:18:17 - 18:33; -+ coverage Code(Expression(2)) => $DIR/branch_match_arms.rs:19:17 - 19:33; -+ coverage Code(Expression(5)) => $DIR/branch_match_arms.rs:21:1 - 21:2; ++ coverage Code(Counter(0)) => 14:1 - 15:21; ++ coverage Code(Counter(3)) => 16:17 - 16:33; ++ coverage Code(Counter(2)) => 17:17 - 17:33; ++ coverage Code(Counter(1)) => 18:17 - 18:33; ++ coverage Code(Expression(2)) => 19:17 - 19:33; ++ coverage Code(Expression(5)) => 21:1 - 21:2; + bb0: { + Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff index 01b01ea5c1756..2efb1fd0a17a3 100644 --- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff @@ -4,7 +4,8 @@ fn bar() -> bool { let mut _0: bool; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:19:1 - 21:2; ++ coverage body span: $DIR/instrument_coverage.rs:19:18: 21:2 (#0) ++ coverage Code(Counter(0)) => 19:1 - 21:2; + bb0: { + Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff index a594c44c316af..510aa07f32d7c 100644 --- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff @@ -7,12 +7,13 @@ let mut _2: bool; let mut _3: !; ++ coverage body span: $DIR/instrument_coverage.rs:10:11: 16:2 (#0) + coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) }; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1 - 10:11; -+ coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:12:12 - 12:17; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13 - 13:18; -+ coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2; ++ coverage Code(Counter(0)) => 10:1 - 10:11; ++ coverage Code(Expression(0)) => 12:12 - 12:17; ++ coverage Code(Counter(0)) => 13:13 - 13:18; ++ coverage Code(Counter(1)) => 14:10 - 14:11; ++ coverage Code(Counter(0)) => 16:1 - 16:2; + bb0: { + Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff index efb1559baf5eb..23cdb3d77171e 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff @@ -7,12 +7,13 @@ coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) + coverage body span: $DIR/instrument_coverage_cleanup.rs:13:11: 15:2 (#0) coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) }; - coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36; - coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39; - coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40; - coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2; - coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36; + coverage Code(Counter(0)) => 13:1 - 14:36; + coverage Code(Expression(0)) => 14:37 - 14:39; + coverage Code(Counter(1)) => 14:39 - 14:40; + coverage Code(Counter(0)) => 15:1 - 15:2; + coverage Branch { true_term: Expression(0), false_term: Counter(1) } => 14:8 - 14:36; bb0: { Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff index a0fe9a5c05cd1..f6aa42f3eeecf 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff @@ -7,12 +7,13 @@ coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) ++ coverage body span: $DIR/instrument_coverage_cleanup.rs:13:11: 15:2 (#0) + coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) }; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36; -+ coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39; -+ coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2; -+ coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36; ++ coverage Code(Counter(0)) => 13:1 - 14:36; ++ coverage Code(Expression(0)) => 14:37 - 14:39; ++ coverage Code(Counter(1)) => 14:39 - 14:40; ++ coverage Code(Counter(0)) => 15:1 - 15:2; ++ coverage Branch { true_term: Expression(0), false_term: Counter(1) } => 14:8 - 14:36; + bb0: { + Coverage::CounterIncrement(0); From 3c30fe3423b1e7d92584436493bd8fa6f17e13d0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 5 Nov 2024 21:59:10 +1100 Subject: [PATCH 38/79] coverage: Restrict empty-span expansion to only cover `{` and `}` --- .../rustc_mir_transform/src/coverage/mod.rs | 70 +++++++++++-------- compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_span/src/source_map.rs | 2 +- tests/coverage-run-rustdoc/doctest.coverage | 4 +- tests/coverage/abort.cov-map | 8 +-- tests/coverage/abort.coverage | 4 +- tests/coverage/assert.cov-map | 4 +- tests/coverage/async2.cov-map | 8 +-- tests/coverage/async2.coverage | 4 +- tests/coverage/branch/if.cov-map | 18 ++--- tests/coverage/branch/if.coverage | 4 +- tests/coverage/closure.cov-map | 38 +++++----- tests/coverage/closure.coverage | 4 +- tests/coverage/closure_bug.cov-map | 10 +-- tests/coverage/closure_bug.coverage | 8 +-- tests/coverage/conditions.cov-map | 22 +++--- tests/coverage/conditions.coverage | 8 +-- tests/coverage/dead_code.cov-map | 12 ++-- tests/coverage/dead_code.coverage | 2 +- tests/coverage/if.cov-map | 4 +- tests/coverage/if.coverage | 2 +- tests/coverage/if_not.cov-map | 6 +- tests/coverage/inner_items.cov-map | 6 +- tests/coverage/inner_items.coverage | 4 +- tests/coverage/lazy_boolean.cov-map | 8 +-- tests/coverage/lazy_boolean.coverage | 2 +- tests/coverage/loop-break.cov-map | 4 +- tests/coverage/loops_branches.cov-map | 12 ++-- tests/coverage/match_or_pattern.cov-map | 10 +-- tests/coverage/match_or_pattern.coverage | 8 +-- tests/coverage/mcdc/condition-limit.cov-map | 4 +- tests/coverage/mcdc/if.cov-map | 4 +- tests/coverage/nested_loops.cov-map | 4 +- tests/coverage/overflow.cov-map | 8 +-- tests/coverage/panic_unwind.cov-map | 4 +- tests/coverage/simple_loop.cov-map | 4 +- tests/coverage/simple_loop.coverage | 2 +- tests/coverage/simple_match.cov-map | 4 +- tests/coverage/simple_match.coverage | 2 +- tests/coverage/sort_groups.cov-map | 20 +++--- tests/coverage/sort_groups.coverage | 2 +- tests/coverage/unicode.cov-map | 4 +- tests/coverage/unicode.coverage | 2 +- tests/coverage/unused.cov-map | 12 ++-- tests/coverage/uses_crate.coverage | 2 +- tests/coverage/uses_inline_crate.cov-map | 4 +- tests/coverage/uses_inline_crate.coverage | 4 +- ...ment_coverage.main.InstrumentCoverage.diff | 2 +- ...rage_cleanup.main.CleanupPostBorrowck.diff | 2 +- ...erage_cleanup.main.InstrumentCoverage.diff | 2 +- 50 files changed, 200 insertions(+), 189 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 39ad1fd23b2d6..e8b3d80be0212 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -22,7 +22,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Pos, RelativeBytePos, SourceFile, Span}; +use rustc_span::{BytePos, Pos, SourceFile, Span}; use tracing::{debug, debug_span, trace}; use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; @@ -391,6 +391,41 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb data.statements.insert(0, statement); } +fn ensure_non_empty_span( + source_map: &SourceMap, + hir_info: &ExtractedHirInfo, + span: Span, +) -> Option { + if !span.is_empty() { + return Some(span); + } + + let lo = span.lo(); + let hi = span.hi(); + + // The span is empty, so try to expand it to cover an adjacent '{' or '}', + // but only within the bounds of the body span. + let try_next = hi < hir_info.body_span.hi(); + let try_prev = hir_info.body_span.lo() < lo; + if !(try_next || try_prev) { + return None; + } + + source_map + .span_to_source(span, |src, start, end| try { + // We're only checking for specific ASCII characters, so we don't + // have to worry about multi-byte code points. + if try_next && src.as_bytes()[end] == b'{' { + Some(span.with_hi(hi + BytePos(1))) + } else if try_prev && src.as_bytes()[start - 1] == b'}' { + Some(span.with_lo(lo - BytePos(1))) + } else { + None + } + }) + .ok()? +} + /// Converts the span into its start line and column, and end line and column. /// /// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by @@ -407,44 +442,23 @@ fn make_source_region( file: &SourceFile, span: Span, ) -> Option { + let span = ensure_non_empty_span(source_map, hir_info, span)?; + let lo = span.lo(); let hi = span.hi(); // Column numbers need to be in bytes, so we can't use the more convenient // `SourceMap` methods for looking up file coordinates. - let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> { + let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> { let rpos = file.relative_position(pos); let line_index = file.lookup_line(rpos)?; let line_start = file.lines()[line_index]; // Line numbers and column numbers are 1-based, so add 1 to each. - Some((rpos, line_index + 1, (rpos - line_start).to_usize() + 1)) + Some((line_index + 1, (rpos - line_start).to_usize() + 1)) }; - let (lo_rpos, mut start_line, mut start_col) = rpos_and_line_and_byte_column(lo)?; - let (hi_rpos, mut end_line, mut end_col) = rpos_and_line_and_byte_column(hi)?; - - // If the span is empty, try to expand it horizontally by one character's - // worth of bytes, so that it is more visible in `llvm-cov` reports. - // We do this after resolving line/column numbers, so that empty spans at the - // end of a line get an extra column instead of wrapping to the next line. - let body_span = hir_info.body_span; - if span.is_empty() - && body_span.contains(span) - && let Some(src) = &file.src - { - // Prefer to expand the end position, if it won't go outside the body span. - if hi < body_span.hi() { - let hi_rpos = hi_rpos.to_usize(); - let nudge_bytes = src.ceil_char_boundary(hi_rpos + 1) - hi_rpos; - end_col += nudge_bytes; - } else if lo > body_span.lo() { - let lo_rpos = lo_rpos.to_usize(); - let nudge_bytes = lo_rpos - src.floor_char_boundary(lo_rpos - 1); - // Subtract the nudge, but don't go below column 1. - start_col = start_col.saturating_sub(nudge_bytes).max(1); - } - // If neither nudge could be applied, stick with the empty span coordinates. - } + let (mut start_line, start_col) = line_and_byte_column(lo)?; + let (mut end_line, end_col) = line_and_byte_column(hi)?; // Apply an offset so that code in doctests has correct line numbers. // FIXME(#79417): Currently we have no way to offset doctest _columns_. diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index d184328748f84..e18f66ac0a3bb 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -9,7 +9,6 @@ #![feature(let_chains)] #![feature(map_try_insert)] #![feature(never_type)] -#![feature(round_char_boundary)] #![feature(try_blocks)] #![feature(yeet_expr)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f36bb38623e5d..e74a5c2d8fe75 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -534,7 +534,7 @@ impl SourceMap { /// Extracts the source surrounding the given `Span` using the `extract_source` function. The /// extract function takes three arguments: a string slice containing the source, an index in /// the slice for the beginning of the span and an index in the slice for the end of the span. - fn span_to_source(&self, sp: Span, extract_source: F) -> Result + pub fn span_to_source(&self, sp: Span, extract_source: F) -> Result where F: Fn(&str, usize, usize) -> Result, { diff --git a/tests/coverage-run-rustdoc/doctest.coverage b/tests/coverage-run-rustdoc/doctest.coverage index 396811c5487c1..f007eb0cadea6 100644 --- a/tests/coverage-run-rustdoc/doctest.coverage +++ b/tests/coverage-run-rustdoc/doctest.coverage @@ -45,11 +45,11 @@ $DIR/doctest.rs: LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { LL| 1|//! println!("{:?}", res); LL| 1|//! } - ^0 + ^0 LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { LL| 1|//! res = Ok(1); LL| 1|//! } - ^0 + ^0 LL| 1|//! res = Ok(0); LL| |//! } LL| |//! // need to be explicit because rustdoc cant infer the return type diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 06dce43c3cabc..c121fa551dcfa 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -1,5 +1,5 @@ Function name: abort::main -Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02] +Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 09, 00, 0a, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 30, 00, 31, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 30, 00, 31, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 10 @@ -20,17 +20,17 @@ Number of file 0 mappings: 13 - Code(Expression(8, Sub)) at (prev + 1, 12) to (start + 0, 25) = ((c0 + (c1 + c2)) - c3) - Code(Counter(4)) at (prev + 0, 26) to (start + 2, 10) -- Code(Expression(3, Sub)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(3, Sub)) at (prev + 2, 9) to (start + 0, 10) = (((c0 + (c1 + c2)) - c3) - c4) - Code(Expression(8, Sub)) at (prev + 2, 12) to (start + 0, 25) = ((c0 + (c1 + c2)) - c3) - Code(Counter(5)) at (prev + 0, 26) to (start + 0, 49) -- Code(Expression(6, Sub)) at (prev + 0, 49) to (start + 0, 50) +- Code(Expression(6, Sub)) at (prev + 0, 48) to (start + 0, 49) = (((c0 + (c1 + c2)) - c3) - c5) - Code(Expression(8, Sub)) at (prev + 4, 12) to (start + 0, 25) = ((c0 + (c1 + c2)) - c3) - Code(Counter(1)) at (prev + 0, 26) to (start + 0, 49) -- Code(Counter(2)) at (prev + 0, 49) to (start + 0, 50) +- Code(Counter(2)) at (prev + 0, 48) to (start + 0, 49) - Code(Expression(9, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + c2) - Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2) diff --git a/tests/coverage/abort.coverage b/tests/coverage/abort.coverage index 29e3ad5eda7aa..be3dadab4878b 100644 --- a/tests/coverage/abort.coverage +++ b/tests/coverage/abort.coverage @@ -18,12 +18,12 @@ LL| 6| } LL| | // See discussion (below the `Notes` section) on coverage results for the closing brace. LL| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line. - ^4 ^6 + ^4 ^6 LL| | // For the following example, the closing brace is the last character on the line. LL| | // This shows the character after the closing brace is highlighted, even if that next LL| | // character is a newline. LL| 10| if countdown < 5 { might_abort(false); } - ^4 ^6 + ^4 ^6 LL| 10| countdown -= 1; LL| | } LL| 1| Ok(()) diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map index 018fcc2c3dbb3..b3cec3901197b 100644 --- a/tests/coverage/assert.cov-map +++ b/tests/coverage/assert.cov-map @@ -1,5 +1,5 @@ Function name: assert::main -Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 09, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 09, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 09, 00, 0a, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -21,7 +21,7 @@ Number of file 0 mappings: 9 - Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32) = (((c0 + (c1 + (c2 + c3))) - c4) - c1) - Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10) -- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(3)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map index ed61e91efc29a..d6462fded130a 100644 --- a/tests/coverage/async2.cov-map +++ b/tests/coverage/async2.cov-map @@ -8,14 +8,14 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: async2::async_func::{closure#0} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 16, 23) to (start + 3, 9) - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 @@ -47,14 +47,14 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: async2::non_async_func -Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 9) - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/async2.coverage b/tests/coverage/async2.coverage index ed9bc4c239d98..cdc171180b8d6 100644 --- a/tests/coverage/async2.coverage +++ b/tests/coverage/async2.coverage @@ -11,7 +11,7 @@ LL| 1| if b { LL| 1| println!("non_async_func println in block"); LL| 1| } - ^0 + ^0 LL| 1|} LL| | LL| 1|async fn async_func() { @@ -20,7 +20,7 @@ LL| 1| if b { LL| 1| println!("async_func println in block"); LL| 1| } - ^0 + ^0 LL| 1|} LL| | LL| 1|async fn async_func_just_println() { diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index 4a8cb664dd831..0ad78a720a797 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -25,7 +25,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c4 Function name: if::branch_not -Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 06, 00, 07, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 05, 01, 01, 00, 02] +Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 05, 00, 06, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 05, 00, 06, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 05, 00, 06, 05, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -43,7 +43,7 @@ Number of file 0 mappings: 18 true = c2 false = (c1 - c2) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 17) -- Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c1 - c2) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 10) - Branch { true: Expression(2, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10) @@ -51,13 +51,13 @@ Number of file 0 mappings: 18 false = c3 - Code(Expression(2, Sub)) at (prev + 0, 11) to (start + 2, 6) = (c1 - c3) -- Code(Counter(3)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 11) - Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 0, 8) to (start + 0, 11) true = c4 false = (c1 - c4) - Code(Counter(4)) at (prev + 0, 12) to (start + 2, 6) -- Code(Expression(4, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(4, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c1 - c4) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 12) - Branch { true: Expression(6, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12) @@ -65,12 +65,12 @@ Number of file 0 mappings: 18 false = c5 - Code(Expression(6, Sub)) at (prev + 0, 13) to (start + 2, 6) = (c1 - c5) -- Code(Counter(5)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(5)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c5 Function name: if::branch_not_as -Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 06, 00, 07, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 06, 00, 07, 05, 01, 01, 00, 02] +Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 05, 00, 06, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 05, 00, 06, 05, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 @@ -87,13 +87,13 @@ Number of file 0 mappings: 14 false = c2 - Code(Expression(0, Sub)) at (prev + 0, 21) to (start + 2, 6) = (c1 - c2) -- Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 21) - Branch { true: Counter(3), false: Expression(2, Sub) } at (prev + 0, 8) to (start + 0, 21) true = c3 false = (c1 - c3) - Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6) -- Code(Expression(2, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(2, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c1 - c3) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 22) - Branch { true: Expression(4, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22) @@ -101,7 +101,7 @@ Number of file 0 mappings: 14 false = c4 - Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 2, 6) = (c1 - c4) -- Code(Counter(4)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(4)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 diff --git a/tests/coverage/branch/if.coverage b/tests/coverage/branch/if.coverage index 2a9a408b16aff..3d107188ca682 100644 --- a/tests/coverage/branch/if.coverage +++ b/tests/coverage/branch/if.coverage @@ -30,7 +30,7 @@ ------------------ LL| 2| say("not not a"); LL| 2| } - ^1 + ^1 LL| 3| if !!!a { ------------------ | Branch (LL:8): [True: 1, False: 2] @@ -54,7 +54,7 @@ ------------------ LL| 2| say("not not (a as bool)"); LL| 2| } - ^1 + ^1 LL| 3| if !!!(a as bool) { ------------------ | Branch (LL:8): [True: 1, False: 2] diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index d50f9f8e7afaa..adf4aba0c23a2 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -1,5 +1,5 @@ Function name: closure::main -Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 01, 01, 05, 03, 02] +Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 05, 00, 06, 01, 01, 05, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -27,13 +27,13 @@ Number of file 0 mappings: 24 - Code(Counter(0)) at (prev + 8, 9) to (start + 0, 68) - Code(Counter(0)) at (prev + 10, 8) to (start + 0, 16) - Code(Counter(1)) at (prev + 0, 17) to (start + 4, 6) -- Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2) Highest counter ID seen: c1 Function name: closure::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -41,7 +41,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 40, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) Highest counter ID seen: c1 @@ -83,17 +83,16 @@ Number of file 0 mappings: 1 Highest counter ID seen: (none) Function name: closure::main::{closure#14} -Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e] +Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] 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 +Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 179, 13) to (start + 2, 27) - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#15} @@ -113,17 +112,16 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: closure::main::{closure#16} -Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e] +Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] 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 +Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 197, 13) to (start + 2, 27) - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#17} @@ -143,19 +141,19 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: closure::main::{closure#18} (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 12, 00, 13, 00, 01, 11, 01, 0e] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 25, 13) to (start + 2, 28) - Code(Zero) at (prev + 2, 29) to (start + 2, 18) -- Code(Zero) at (prev + 2, 18) to (start + 0, 19) +- Code(Zero) at (prev + 2, 17) to (start + 0, 18) - Code(Zero) at (prev + 1, 17) to (start + 1, 14) Highest counter ID seen: (none) Function name: closure::main::{closure#19} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 01, 01, 11, 01, 0e] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -163,13 +161,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 67, 13) to (start + 2, 28) - Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) -- Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#1} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -177,13 +175,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 82, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#2} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -191,20 +189,20 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 104, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#3} (unused) -Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] +Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 129, 5) to (start + 1, 20) - Code(Zero) at (prev + 1, 21) to (start + 2, 10) -- Code(Zero) at (prev + 2, 10) to (start + 0, 11) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Zero) at (prev + 1, 9) to (start + 1, 6) Highest counter ID seen: (none) diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage index 2f040b39f88a1..3eac52eb72363 100644 --- a/tests/coverage/closure.coverage +++ b/tests/coverage/closure.coverage @@ -183,7 +183,7 @@ LL| 0| println!( LL| 0| "not called: {}", LL| 0| if is_true { "check" } else { "me" } - LL| 0| ) + LL| | ) LL| | ; LL| | LL| 1| let short_used_not_covered_closure_line_break_block_embedded_branch = @@ -202,7 +202,7 @@ LL| 1| "not called: {}", LL| 1| if is_true { "check" } else { "me" } ^0 - LL| 1| ) + LL| | ) LL| | ; LL| | LL| 1| let short_used_covered_closure_line_break_block_embedded_branch = diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map index 96e1e339e569e..40a8bdf9c1d61 100644 --- a/tests/coverage/closure_bug.cov-map +++ b/tests/coverage/closure_bug.cov-map @@ -1,5 +1,5 @@ Function name: closure_bug::main -Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 17, 00, 18, 01, 01, 01, 00, 02] +Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 16, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -11,22 +11,22 @@ Number of file 0 mappings: 17 - Code(Counter(0)) at (prev + 7, 1) to (start + 3, 10) - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 14) - Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23) -- Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(0, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) - Code(Counter(2)) at (prev + 1, 15) to (start + 0, 23) -- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(1, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c2) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) - Code(Counter(3)) at (prev + 1, 15) to (start + 0, 23) -- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(2, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c3) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) - Code(Counter(4)) at (prev + 1, 15) to (start + 0, 23) -- Code(Expression(3, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(3, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c4) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 diff --git a/tests/coverage/closure_bug.coverage b/tests/coverage/closure_bug.coverage index 3bf19f28072f5..cc64470baa77f 100644 --- a/tests/coverage/closure_bug.coverage +++ b/tests/coverage/closure_bug.coverage @@ -16,7 +16,7 @@ LL| | LL| 1| a(); LL| 1| if truthy { a(); } - ^0 + ^0 LL| | LL| 1| let b LL| | = @@ -27,7 +27,7 @@ LL| | LL| 1| b(); LL| 1| if truthy { b(); } - ^0 + ^0 LL| | LL| 1| let c LL| | = @@ -38,7 +38,7 @@ LL| | LL| 1| c(); LL| 1| if truthy { c(); } - ^0 + ^0 LL| | LL| 1| let d LL| | = @@ -49,6 +49,6 @@ LL| | LL| 1| d(); LL| 1| if truthy { d(); } - ^0 + ^0 LL| 1|} diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index a392d1b70288e..938e440401392 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,5 +1,5 @@ Function name: conditions::main -Raw bytes (799): 0x[01, 01, 94, 01, 09, 2b, 2f, 41, 33, 3d, 35, 39, 01, 09, 0d, 35, 1e, 39, 0d, 35, 33, 3d, 35, 39, 2f, 41, 33, 3d, 35, 39, ce, 04, 0d, 01, 09, 03, 49, 62, 31, 03, 49, 5e, 4d, 62, 31, 03, 49, 5a, 51, 5e, 4d, 62, 31, 03, 49, 87, 01, 55, 4d, 51, 83, 01, 59, 87, 01, 55, 4d, 51, 49, 7f, 83, 01, 59, 87, 01, 55, 4d, 51, 5d, 65, ae, 01, 2d, 5d, 65, aa, 01, 69, ae, 01, 2d, 5d, 65, a6, 01, 6d, aa, 01, 69, ae, 01, 2d, 5d, 65, f3, 02, 71, 69, 6d, ef, 02, 75, f3, 02, 71, 69, 6d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, d6, 02, 85, 01, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 8f, 04, 89, 01, 81, 01, 85, 01, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, f6, 03, 19, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, b7, 04, 1d, 15, 19, b3, 04, 21, b7, 04, 1d, 15, 19, ab, 04, bb, 04, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, bf, 04, ca, 04, c3, 04, 31, c7, 04, 2d, 25, 29, ce, 04, 0d, 01, 09, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, ce, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 1e, 00, 1d, 00, 2a, 1a, 00, 2e, 00, 3c, 2f, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 2b, 01, 09, 01, 12, ca, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 02, 08, 00, 15, 49, 00, 16, 02, 06, 62, 02, 0f, 00, 1c, 5e, 01, 0c, 00, 19, 5a, 00, 1d, 00, 2a, 56, 00, 2e, 00, 3c, 83, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 7f, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 7b, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, 5d, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, ae, 01, 04, 11, 00, 1e, aa, 01, 01, 10, 00, 1d, a6, 01, 00, 21, 00, 2e, a2, 01, 00, 32, 00, 40, ef, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, eb, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, e3, 02, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 04, 02, 09, 00, 0a, e3, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, de, 02, 02, 0f, 00, 1c, da, 02, 01, 0c, 00, 19, d6, 02, 00, 1d, 00, 2a, d2, 02, 00, 2e, 00, 3c, 8b, 04, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, 87, 04, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, ab, 04, 05, 09, 00, 0a, 83, 04, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, fe, 03, 02, 0f, 00, 1c, fa, 03, 01, 0c, 00, 19, f6, 03, 00, 1d, 00, 2a, f2, 03, 00, 2e, 00, 3c, b3, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, af, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, a7, 04, 02, 01, 00, 02] +Raw bytes (799): 0x[01, 01, 94, 01, 09, 2b, 2f, 41, 33, 3d, 35, 39, 01, 09, 0d, 35, 1e, 39, 0d, 35, 33, 3d, 35, 39, 2f, 41, 33, 3d, 35, 39, ce, 04, 0d, 01, 09, 03, 49, 62, 31, 03, 49, 5e, 4d, 62, 31, 03, 49, 5a, 51, 5e, 4d, 62, 31, 03, 49, 87, 01, 55, 4d, 51, 83, 01, 59, 87, 01, 55, 4d, 51, 49, 7f, 83, 01, 59, 87, 01, 55, 4d, 51, 5d, 65, ae, 01, 2d, 5d, 65, aa, 01, 69, ae, 01, 2d, 5d, 65, a6, 01, 6d, aa, 01, 69, ae, 01, 2d, 5d, 65, f3, 02, 71, 69, 6d, ef, 02, 75, f3, 02, 71, 69, 6d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, d6, 02, 85, 01, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 8f, 04, 89, 01, 81, 01, 85, 01, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, f6, 03, 19, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, b7, 04, 1d, 15, 19, b3, 04, 21, b7, 04, 1d, 15, 19, ab, 04, bb, 04, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, bf, 04, ca, 04, c3, 04, 31, c7, 04, 2d, 25, 29, ce, 04, 0d, 01, 09, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, ce, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 1e, 00, 1d, 00, 2a, 1a, 00, 2e, 00, 3c, 2f, 00, 3d, 02, 0a, 41, 02, 09, 00, 0a, 2b, 01, 09, 01, 12, ca, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 49, 00, 16, 02, 06, 62, 02, 0f, 00, 1c, 5e, 01, 0c, 00, 19, 5a, 00, 1d, 00, 2a, 56, 00, 2e, 00, 3c, 83, 01, 00, 3d, 02, 0a, 59, 02, 09, 00, 0a, 7f, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 7b, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 5d, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, ae, 01, 04, 11, 00, 1e, aa, 01, 01, 10, 00, 1d, a6, 01, 00, 21, 00, 2e, a2, 01, 00, 32, 00, 40, ef, 02, 00, 41, 02, 0e, 75, 02, 0d, 00, 0e, eb, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 05, 00, 06, e3, 02, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 83, 04, 02, 09, 00, 0a, e3, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, de, 02, 02, 0f, 00, 1c, da, 02, 01, 0c, 00, 19, d6, 02, 00, 1d, 00, 2a, d2, 02, 00, 2e, 00, 3c, 8b, 04, 00, 3d, 02, 0a, 8d, 01, 02, 09, 00, 0a, 87, 04, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, ab, 04, 05, 09, 00, 0a, 83, 04, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, fe, 03, 02, 0f, 00, 1c, fa, 03, 01, 0c, 00, 19, f6, 03, 00, 1d, 00, 2a, f2, 03, 00, 2e, 00, 3c, b3, 04, 00, 3d, 02, 0a, 21, 02, 09, 00, 0a, af, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, a7, 04, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 148 @@ -154,7 +154,7 @@ Number of expressions: 148 Number of file 0 mappings: 68 - Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12) - Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10) = (c2 + (((c13 + c14) + c15) + c16)) - Code(Counter(0)) at (prev + 0, 16) to (start + 0, 29) @@ -168,7 +168,7 @@ Number of file 0 mappings: 68 = ((c3 - c13) - c14) - Code(Expression(11, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c13 + c14) + c15) -- Code(Counter(16)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(16)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 18) = (((c13 + c14) + c15) + c16) - Code(Expression(146, Sub)) at (prev + 3, 9) to (start + 0, 15) @@ -176,7 +176,7 @@ Number of file 0 mappings: 68 - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12) = (c2 + (((c13 + c14) + c15) + c16)) - Code(Counter(17)) at (prev + 1, 13) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21) = (c2 + (((c13 + c14) + c15) + c16)) - Code(Counter(18)) at (prev + 0, 22) to (start + 2, 6) @@ -190,7 +190,7 @@ Number of file 0 mappings: 68 = (((((c2 + (((c13 + c14) + c15) + c16)) - c18) - c12) - c19) - c20) - Code(Expression(32, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c19 + c20) + c21) -- Code(Counter(22)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(22)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(31, Add)) at (prev + 1, 9) to (start + 0, 23) = (((c19 + c20) + c21) + c22) - Code(Counter(12)) at (prev + 2, 9) to (start + 0, 15) @@ -198,7 +198,7 @@ Number of file 0 mappings: 68 = (c18 + (((c19 + c20) + c21) + c22)) - Code(Counter(23)) at (prev + 1, 13) to (start + 1, 16) - Code(Counter(24)) at (prev + 1, 17) to (start + 2, 10) -- Code(Zero) at (prev + 2, 10) to (start + 0, 11) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(23)) at (prev + 2, 12) to (start + 0, 25) - Code(Counter(25)) at (prev + 0, 26) to (start + 2, 10) - Code(Expression(43, Sub)) at (prev + 4, 17) to (start + 0, 30) @@ -211,15 +211,15 @@ Number of file 0 mappings: 68 = ((((c23 - c25) - c11) - c26) - c27) - Code(Expression(91, Add)) at (prev + 0, 65) to (start + 2, 14) = ((c26 + c27) + c28) -- Code(Counter(29)) at (prev + 2, 14) to (start + 0, 15) +- Code(Counter(29)) at (prev + 2, 13) to (start + 0, 14) - Code(Expression(90, Add)) at (prev + 1, 13) to (start + 0, 27) = (((c26 + c27) + c28) + c29) - Code(Counter(11)) at (prev + 2, 13) to (start + 0, 19) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(88, Add)) at (prev + 2, 9) to (start + 1, 12) = ((c25 + (((c26 + c27) + c28) + c29)) + Zero) - Code(Counter(30)) at (prev + 1, 13) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(128, Add)) at (prev + 2, 9) to (start + 0, 10) = (c31 + (((c32 + c33) + c34) + c35)) - Code(Expression(88, Add)) at (prev + 0, 16) to (start + 0, 29) @@ -235,7 +235,7 @@ Number of file 0 mappings: 68 = ((((((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31) - c10) - c32) - c33) - Code(Expression(130, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c32 + c33) + c34) -- Code(Counter(35)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(35)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(129, Add)) at (prev + 1, 9) to (start + 0, 23) = (((c32 + c33) + c34) + c35) - Code(Counter(10)) at (prev + 2, 13) to (start + 2, 15) @@ -254,7 +254,7 @@ Number of file 0 mappings: 68 = (((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5) - c6) - Code(Expression(140, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c5 + c6) + c7) -- Code(Counter(8)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(8)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(139, Add)) at (prev + 1, 9) to (start + 0, 23) = (((c5 + c6) + c7) + c8) - Code(Counter(9)) at (prev + 2, 9) to (start + 0, 15) diff --git a/tests/coverage/conditions.coverage b/tests/coverage/conditions.coverage index 48516217592e7..83944d37c9808 100644 --- a/tests/coverage/conditions.coverage +++ b/tests/coverage/conditions.coverage @@ -5,7 +5,7 @@ LL| 1| if true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| | LL| | const B: u32 = 100; LL| 1| let x = if countdown > 7 { @@ -25,7 +25,7 @@ LL| 1| if true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| | LL| 1| if countdown > 7 { LL| 1| countdown -= 4; @@ -44,7 +44,7 @@ LL| 1| if true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| | LL| 1| if countdown > 7 { LL| 1| countdown -= 4; @@ -64,7 +64,7 @@ LL| 1| if true { LL| 1| countdown = 1; LL| 1| } - ^0 + ^0 LL| | LL| 1| let z = if countdown > 7 { ^0 diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map index b94c6e656abfb..897372fe0b5e4 100644 --- a/tests/coverage/dead_code.cov-map +++ b/tests/coverage/dead_code.cov-map @@ -1,5 +1,5 @@ Function name: dead_code::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -7,32 +7,32 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 27, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: dead_code::unused_fn (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 15, 1) to (start + 7, 15) - Code(Zero) at (prev + 7, 16) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: dead_code::unused_pub_fn_not_in_library (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 3, 1) to (start + 7, 15) - Code(Zero) at (prev + 7, 16) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/dead_code.coverage b/tests/coverage/dead_code.coverage index c4ee9f23f082f..55d196f816043 100644 --- a/tests/coverage/dead_code.coverage +++ b/tests/coverage/dead_code.coverage @@ -34,6 +34,6 @@ LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| 1|} diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map index 8f12afac02721..a77ba8194a447 100644 --- a/tests/coverage/if.cov-map +++ b/tests/coverage/if.cov-map @@ -1,5 +1,5 @@ Function name: if::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -7,7 +7,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 4, 1) to (start + 18, 16) - Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6) -- Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 5, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/if.coverage b/tests/coverage/if.coverage index 77db24ef51bf3..0762418347c22 100644 --- a/tests/coverage/if.coverage +++ b/tests/coverage/if.coverage @@ -26,6 +26,6 @@ LL| 1| 10 LL| 1| ; LL| 1| } - ^0 + ^0 LL| 1|} diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map index a2c276b7bb77b..f47139ce5a484 100644 --- a/tests/coverage/if_not.cov-map +++ b/tests/coverage/if_not.cov-map @@ -1,5 +1,5 @@ Function name: if_not::if_not -Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 06, 00, 07, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -10,11 +10,11 @@ Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 5, 1) to (start + 3, 13) - Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 2, 6) = (c0 - c1) -- Code(Counter(1)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(1)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13) - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 2, 6) = (c0 - c2) -- Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13) - Code(Expression(2, Sub)) at (prev + 2, 5) to (start + 2, 6) = (c0 - c3) diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map index 16e86b2cadea9..a12cce25b6435 100644 --- a/tests/coverage/inner_items.cov-map +++ b/tests/coverage/inner_items.cov-map @@ -17,7 +17,7 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: inner_items::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 06, 00, 07, 01, 02, 09, 05, 02] +Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 05, 00, 06, 01, 02, 09, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -26,11 +26,11 @@ Number of expressions: 2 Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 36, 8) to (start + 0, 15) - Code(Counter(2)) at (prev + 0, 16) to (start + 2, 6) -- Code(Expression(1, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c2) - Code(Counter(0)) at (prev + 2, 9) to (start + 5, 2) Highest counter ID seen: c2 diff --git a/tests/coverage/inner_items.coverage b/tests/coverage/inner_items.coverage index 152f3da1a2217..8244d347b59c2 100644 --- a/tests/coverage/inner_items.coverage +++ b/tests/coverage/inner_items.coverage @@ -10,7 +10,7 @@ LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| | LL| | mod in_mod { LL| | const IN_MOD_CONST: u32 = 1000; @@ -49,7 +49,7 @@ LL| 1| if is_true { LL| 1| in_func(countdown); LL| 1| } - ^0 + ^0 LL| | LL| 1| let mut val = InStruct { LL| 1| in_struct_field: 101, // diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map index fcb9d8f1ff5cc..b0c2d736573a7 100644 --- a/tests/coverage/lazy_boolean.cov-map +++ b/tests/coverage/lazy_boolean.cov-map @@ -1,5 +1,5 @@ Function name: lazy_boolean::main -Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 09, 01, 0d, 01, 19, 01, 1d, 01, 21, 01, 25, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 11, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 15, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 19, 03, 06, 00, 07, 01, 03, 09, 00, 10, 1d, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 21, 02, 06, 00, 07, 01, 02, 08, 00, 0f, 25, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 09, 01, 0d, 01, 19, 01, 1d, 01, 21, 01, 25, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 05, 00, 06, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 11, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 15, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 19, 03, 05, 00, 06, 01, 03, 09, 00, 10, 1d, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 21, 02, 05, 00, 06, 01, 02, 08, 00, 0f, 25, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -13,7 +13,7 @@ Number of expressions: 7 Number of file 0 mappings: 28 - Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6) -- Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 17) - Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18) @@ -32,7 +32,7 @@ Number of file 0 mappings: 28 - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 16) - Code(Expression(3, Sub)) at (prev + 2, 5) to (start + 3, 6) = (c0 - c6) -- Code(Counter(6)) at (prev + 3, 6) to (start + 0, 7) +- Code(Counter(6)) at (prev + 3, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16) - Code(Counter(7)) at (prev + 1, 5) to (start + 3, 6) - Code(Expression(4, Sub)) at (prev + 5, 5) to (start + 3, 6) @@ -40,7 +40,7 @@ Number of file 0 mappings: 28 - Code(Counter(0)) at (prev + 5, 8) to (start + 0, 16) - Code(Expression(5, Sub)) at (prev + 0, 17) to (start + 2, 6) = (c0 - c8) -- Code(Counter(8)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(8)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 2, 8) to (start + 0, 15) - Code(Counter(9)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6) diff --git a/tests/coverage/lazy_boolean.coverage b/tests/coverage/lazy_boolean.coverage index f058be8390082..828ba2a581162 100644 --- a/tests/coverage/lazy_boolean.coverage +++ b/tests/coverage/lazy_boolean.coverage @@ -13,7 +13,7 @@ LL| 1| b = 10; LL| 1| c = 100; LL| 1| } - ^0 + ^0 LL| | let LL| 1| somebool LL| | = diff --git a/tests/coverage/loop-break.cov-map b/tests/coverage/loop-break.cov-map index 63280a0bf7cbe..0b4c42a43da0c 100644 --- a/tests/coverage/loop-break.cov-map +++ b/tests/coverage/loop-break.cov-map @@ -1,5 +1,5 @@ Function name: loop_break::main -Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 03, 01, 00, 0b, 03, 02, 0c, 00, 27, 01, 01, 0d, 00, 12, 05, 01, 0a, 00, 0b, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 03, 01, 00, 0b, 03, 02, 0c, 00, 27, 01, 01, 0d, 00, 12, 05, 01, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -9,7 +9,7 @@ Number of file 0 mappings: 5 - Code(Expression(0, Add)) at (prev + 2, 12) to (start + 0, 39) = (c0 + c1) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18) -- Code(Counter(1)) at (prev + 1, 10) to (start + 0, 11) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index 1d263611a3abc..61a6bda676a90 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -1,5 +1,5 @@ Function name: ::fmt -Raw bytes (228): 0x[01, 01, 2a, 05, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, a3, 01, a7, 01, 0d, 00, 11, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 8f, 01, 19, 25, 92, 01, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 05, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 9a, 01, 03, 0d, 00, 0e, 9f, 01, 00, 12, 00, 17, 9a, 01, 01, 10, 00, 14, 96, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 46, 01, 12, 00, 13, 96, 01, 01, 11, 00, 22, 92, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 8b, 01, 01, 05, 00, 06] +Raw bytes (228): 0x[01, 01, 2a, 05, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, a3, 01, a7, 01, 0d, 00, 11, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 8f, 01, 19, 25, 92, 01, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0d, 00, 0e, 05, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 9a, 01, 03, 0d, 00, 0e, 9f, 01, 00, 12, 00, 17, 9a, 01, 01, 10, 00, 14, 96, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 46, 01, 11, 00, 12, 96, 01, 01, 11, 00, 22, 92, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 8b, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 42 @@ -50,7 +50,7 @@ Number of file 0 mappings: 20 - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) -- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 14) = (c1 - Zero) - Code(Counter(1)) at (prev + 1, 13) to (start + 0, 30) - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) @@ -65,7 +65,7 @@ Number of file 0 mappings: 20 = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(17, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(17, Sub)) at (prev + 1, 17) to (start + 0, 18) = (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero) - Code(Expression(37, Sub)) at (prev + 1, 17) to (start + 0, 34) = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) @@ -78,7 +78,7 @@ Number of file 0 mappings: 20 Highest counter ID seen: c9 Function name: ::fmt -Raw bytes (230): 0x[01, 01, 2b, 01, 00, 02, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, a7, 01, ab, 01, 00, 0d, 00, 15, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 00, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 93, 01, 25, 96, 01, 19, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0e, 00, 0f, 02, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 9e, 01, 02, 0d, 00, 0e, a3, 01, 00, 12, 00, 17, 9e, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 9a, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4a, 01, 12, 00, 13, 9a, 01, 01, 11, 00, 22, 96, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, 8f, 01, 01, 05, 00, 06] +Raw bytes (230): 0x[01, 01, 2b, 01, 00, 02, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, a7, 01, ab, 01, 00, 0d, 00, 15, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 00, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 93, 01, 25, 96, 01, 19, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0d, 00, 0e, 02, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 9e, 01, 02, 0d, 00, 0e, a3, 01, 00, 12, 00, 17, 9e, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 9a, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4a, 01, 11, 00, 12, 9a, 01, 01, 11, 00, 22, 96, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, 8f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 43 @@ -132,7 +132,7 @@ Number of file 0 mappings: 20 = (c0 - Zero) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) -- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(1, Sub)) at (prev + 1, 13) to (start + 0, 14) = ((c0 - Zero) - Zero) - Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 30) = (c0 - Zero) @@ -148,7 +148,7 @@ Number of file 0 mappings: 20 = ((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(18, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(18, Sub)) at (prev + 1, 17) to (start + 0, 18) = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero) - Code(Expression(38, Sub)) at (prev + 1, 17) to (start + 0, 34) = ((((Zero + c3) + (Zero + c5)) - c6) - Zero) diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map index f6491ea262dc5..2beb327bc0594 100644 --- a/tests/coverage/match_or_pattern.cov-map +++ b/tests/coverage/match_or_pattern.cov-map @@ -1,5 +1,5 @@ Function name: match_or_pattern::main -Raw bytes (185): 0x[01, 01, 1c, 01, 05, 09, 0d, 23, 11, 09, 0d, 1f, 15, 23, 11, 09, 0d, 23, 11, 09, 0d, 19, 1d, 43, 21, 19, 1d, 3f, 25, 43, 21, 19, 1d, 43, 21, 19, 1d, 29, 2d, 63, 31, 29, 2d, 5f, 35, 63, 31, 29, 2d, 63, 31, 29, 2d, 39, 3d, 6f, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 01, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 23, 01, 0e, 00, 10, 1f, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 06, 00, 07, 1f, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 43, 01, 0e, 00, 10, 3f, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 32, 03, 06, 00, 07, 3f, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 63, 01, 0e, 00, 10, 5f, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 52, 03, 06, 00, 07, 5f, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 6f, 01, 0e, 00, 10, 6b, 02, 01, 00, 02] +Raw bytes (185): 0x[01, 01, 1c, 01, 05, 09, 0d, 23, 11, 09, 0d, 1f, 15, 23, 11, 09, 0d, 23, 11, 09, 0d, 19, 1d, 43, 21, 19, 1d, 3f, 25, 43, 21, 19, 1d, 43, 21, 19, 1d, 29, 2d, 63, 31, 29, 2d, 5f, 35, 63, 31, 29, 2d, 63, 31, 29, 2d, 39, 3d, 6f, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 23, 01, 0e, 00, 10, 1f, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 05, 00, 06, 1f, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 43, 01, 0e, 00, 10, 3f, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 32, 03, 05, 00, 06, 3f, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 63, 01, 0e, 00, 10, 5f, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 52, 03, 05, 00, 06, 5f, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 6f, 01, 0e, 00, 10, 6b, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 28 @@ -34,7 +34,7 @@ Number of expressions: 28 Number of file 0 mappings: 25 - Code(Counter(0)) at (prev + 1, 1) to (start + 8, 15) - Code(Counter(1)) at (prev + 8, 16) to (start + 3, 6) -- Code(Expression(0, Sub)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 11) to (start + 0, 17) - Code(Counter(4)) at (prev + 3, 27) to (start + 0, 29) @@ -43,7 +43,7 @@ Number of file 0 mappings: 25 - Code(Expression(7, Add)) at (prev + 2, 8) to (start + 0, 15) = ((c2 + c3) + c4) - Code(Counter(5)) at (prev + 0, 16) to (start + 3, 6) -- Code(Expression(4, Sub)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(4, Sub)) at (prev + 3, 5) to (start + 0, 6) = (((c2 + c3) + c4) - c5) - Code(Expression(7, Add)) at (prev + 1, 11) to (start + 0, 17) = ((c2 + c3) + c4) @@ -53,7 +53,7 @@ Number of file 0 mappings: 25 - Code(Expression(15, Add)) at (prev + 2, 8) to (start + 0, 15) = ((c6 + c7) + c8) - Code(Counter(9)) at (prev + 0, 16) to (start + 3, 6) -- Code(Expression(12, Sub)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(12, Sub)) at (prev + 3, 5) to (start + 0, 6) = (((c6 + c7) + c8) - c9) - Code(Expression(15, Add)) at (prev + 1, 11) to (start + 0, 17) = ((c6 + c7) + c8) @@ -63,7 +63,7 @@ Number of file 0 mappings: 25 - Code(Expression(23, Add)) at (prev + 2, 8) to (start + 0, 15) = ((c10 + c11) + c12) - Code(Counter(13)) at (prev + 0, 16) to (start + 3, 6) -- Code(Expression(20, Sub)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(20, Sub)) at (prev + 3, 5) to (start + 0, 6) = (((c10 + c11) + c12) - c13) - Code(Expression(23, Add)) at (prev + 1, 11) to (start + 0, 17) = ((c10 + c11) + c12) diff --git a/tests/coverage/match_or_pattern.coverage b/tests/coverage/match_or_pattern.coverage index 94c7967215c1b..a65c226e56727 100644 --- a/tests/coverage/match_or_pattern.coverage +++ b/tests/coverage/match_or_pattern.coverage @@ -10,7 +10,7 @@ LL| 1| a = 2; LL| 1| b = 0; LL| 1| } - ^0 + ^0 LL| 1| match (a, b) { LL| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. LL| | // This test confirms a fix for Issue #79569. @@ -21,7 +21,7 @@ LL| 1| a = 0; LL| 1| b = 0; LL| 1| } - ^0 + ^0 LL| 1| match (a, b) { LL| 0| (0 | 1, 2 | 3) => {} LL| 1| _ => {} @@ -30,7 +30,7 @@ LL| 1| a = 2; LL| 1| b = 2; LL| 1| } - ^0 + ^0 LL| 1| match (a, b) { LL| 0| (0 | 1, 2 | 3) => {} LL| 1| _ => {} @@ -39,7 +39,7 @@ LL| 1| a = 0; LL| 1| b = 2; LL| 1| } - ^0 + ^0 LL| 1| match (a, b) { LL| 1| (0 | 1, 2 | 3) => {} LL| 0| _ => {} diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map index a3e3b1d09c4d1..e3f5b49d3636c 100644 --- a/tests/coverage/mcdc/condition-limit.cov-map +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -1,5 +1,5 @@ Function name: condition_limit::accept_7_conditions -Raw bytes (232): 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, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 7a, 1d, 07, 06, 00, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 30, 76, 19, 06, 05, 00, 00, 12, 00, 13, 76, 00, 17, 00, 18, 30, 72, 15, 05, 04, 00, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 30, 6e, 11, 04, 03, 00, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 30, 6a, 0d, 03, 02, 00, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 30, 21, 09, 02, 00, 00, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02] +Raw bytes (232): 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, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 7a, 1d, 07, 06, 00, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 30, 76, 19, 06, 05, 00, 00, 12, 00, 13, 76, 00, 17, 00, 18, 30, 72, 15, 05, 04, 00, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 30, 6e, 11, 04, 03, 00, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 30, 6a, 0d, 03, 02, 00, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 30, 21, 09, 02, 00, 00, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 05, 00, 06, 97, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 44 @@ -83,7 +83,7 @@ Number of file 0 mappings: 18 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) +- Code(Expression(38, Add)) at (prev + 2, 5) to (start + 0, 6) = ((((((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))) diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map index 46960d31c01e6..c0e7d08bb0280 100644 --- a/tests/coverage/mcdc/if.cov-map +++ b/tests/coverage/mcdc/if.cov-map @@ -175,7 +175,7 @@ Number of file 0 mappings: 10 Highest counter ID seen: c4 Function name: if::mcdc_nested_if -Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 0a, 00, 0b, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02] +Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 09, 00, 0a, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 13 @@ -215,7 +215,7 @@ Number of file 0 mappings: 14 true = c3 false = c4 - Code(Counter(3)) at (prev + 0, 19) to (start + 2, 10) -- Code(Expression(11, Add)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(11, Add)) at (prev + 2, 9) to (start + 0, 10) = (c4 + c5) - Code(Expression(12, Sub)) at (prev + 1, 12) to (start + 2, 6) = ((c0 - c1) - c2) diff --git a/tests/coverage/nested_loops.cov-map b/tests/coverage/nested_loops.cov-map index c145d4c58433b..21871ef320646 100644 --- a/tests/coverage/nested_loops.cov-map +++ b/tests/coverage/nested_loops.cov-map @@ -1,5 +1,5 @@ Function name: nested_loops::main -Raw bytes (115): 0x[01, 01, 17, 01, 57, 05, 09, 03, 0d, 4e, 53, 03, 0d, 15, 19, 4b, 09, 4e, 53, 03, 0d, 15, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 42, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 05, 09, 11, 0d, 0d, 01, 01, 01, 02, 1b, 03, 04, 13, 00, 20, 4e, 01, 0d, 01, 18, 4b, 02, 12, 00, 17, 46, 01, 10, 00, 16, 05, 01, 11, 00, 16, 42, 01, 0e, 03, 16, 3e, 04, 11, 01, 1b, 11, 02, 15, 00, 21, 15, 01, 18, 02, 12, 19, 03, 0e, 00, 0f, 57, 02, 09, 00, 17, 5b, 02, 01, 00, 02] +Raw bytes (115): 0x[01, 01, 17, 01, 57, 05, 09, 03, 0d, 4e, 53, 03, 0d, 15, 19, 4b, 09, 4e, 53, 03, 0d, 15, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 42, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 05, 09, 11, 0d, 0d, 01, 01, 01, 02, 1b, 03, 04, 13, 00, 20, 4e, 01, 0d, 01, 18, 4b, 02, 12, 00, 17, 46, 01, 10, 00, 16, 05, 01, 11, 00, 16, 42, 01, 0e, 03, 16, 3e, 04, 11, 01, 1b, 11, 02, 15, 00, 21, 15, 01, 18, 02, 12, 19, 03, 0d, 00, 0e, 57, 02, 09, 00, 17, 5b, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 23 @@ -43,7 +43,7 @@ Number of file 0 mappings: 13 = ((((((c0 + (c1 + c2)) - c3) + (c5 + c6)) - c2) - c1) - c6) - Code(Counter(4)) at (prev + 2, 21) to (start + 0, 33) - Code(Counter(5)) at (prev + 1, 24) to (start + 2, 18) -- Code(Counter(6)) at (prev + 3, 14) to (start + 0, 15) +- Code(Counter(6)) at (prev + 3, 13) to (start + 0, 14) - Code(Expression(21, Add)) at (prev + 2, 9) to (start + 0, 23) = (c1 + c2) - Code(Expression(22, Add)) at (prev + 2, 1) to (start + 0, 2) diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map index f842ce3e896b1..f6bfb465bf9a0 100644 --- a/tests/coverage/overflow.cov-map +++ b/tests/coverage/overflow.cov-map @@ -1,5 +1,5 @@ Function name: overflow::main -Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 10, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 03, 0a, 12, 03, 13, 00, 20, 09, 00, 21, 03, 0a, 0d, 03, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 10, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 03, 0a, 12, 03, 13, 00, 20, 09, 00, 21, 03, 0a, 0d, 03, 09, 00, 0a, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -21,14 +21,14 @@ Number of file 0 mappings: 9 - Code(Expression(4, Sub)) at (prev + 3, 19) to (start + 0, 32) = (((c0 + (c1 + (c2 + c3))) - c4) - c1) - Code(Counter(2)) at (prev + 0, 33) to (start + 3, 10) -- Code(Counter(3)) at (prev + 3, 10) to (start + 0, 11) +- Code(Counter(3)) at (prev + 3, 9) to (start + 0, 10) - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) Highest counter ID seen: c4 Function name: overflow::might_overflow -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 01, 01, 09, 05, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 05, 00, 06, 01, 01, 09, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -36,7 +36,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 5, 1) to (start + 1, 18) - Code(Counter(1)) at (prev + 1, 19) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 5, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/panic_unwind.cov-map index f4a7894cc1cc1..58a796ff3a2c3 100644 --- a/tests/coverage/panic_unwind.cov-map +++ b/tests/coverage/panic_unwind.cov-map @@ -1,5 +1,5 @@ Function name: panic_unwind::main -Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 09, 00, 0a, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -21,7 +21,7 @@ Number of file 0 mappings: 9 - Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32) = (((c0 + (c1 + (c2 + c3))) - c4) - c1) - Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10) -- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(3)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map index b6f1e8f6afe6a..d1e684efbbcd5 100644 --- a/tests/coverage/simple_loop.cov-map +++ b/tests/coverage/simple_loop.cov-map @@ -1,5 +1,5 @@ Function name: simple_loop::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 07, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 01, 06, 01, 00, 02] +Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 05, 00, 06, 07, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 01, 06, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -8,7 +8,7 @@ Number of expressions: 2 Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 4, 1) to (start + 9, 16) - Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6) -- Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 5, 5) to (start + 0, 6) = (c0 - c1) - Code(Expression(1, Add)) at (prev + 5, 13) to (start + 2, 14) = (c0 + c2) diff --git a/tests/coverage/simple_loop.coverage b/tests/coverage/simple_loop.coverage index b6552c62ff909..237e509f42e10 100644 --- a/tests/coverage/simple_loop.coverage +++ b/tests/coverage/simple_loop.coverage @@ -17,7 +17,7 @@ LL| 1| 10 LL| 1| ; LL| 1| } - ^0 + ^0 LL| | LL| | loop LL| | { diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map index b62edf12650ca..d8bf9eae4bc61 100644 --- a/tests/coverage/simple_match.cov-map +++ b/tests/coverage/simple_match.cov-map @@ -1,5 +1,5 @@ Function name: simple_match::main -Raw bytes (72): 0x[01, 01, 09, 01, 05, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 1f, 05, 09, 00, 0d, 1a, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 1a, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02] +Raw bytes (72): 0x[01, 01, 09, 01, 05, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 1f, 05, 09, 00, 0d, 1a, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 1a, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 9 @@ -15,7 +15,7 @@ Number of expressions: 9 Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Expression(7, Add)) at (prev + 5, 9) to (start + 0, 13) = (c0 + (c2 + c3)) diff --git a/tests/coverage/simple_match.coverage b/tests/coverage/simple_match.coverage index 3a4fc6743f5e0..e1d5e48a2bf1f 100644 --- a/tests/coverage/simple_match.coverage +++ b/tests/coverage/simple_match.coverage @@ -11,7 +11,7 @@ LL| 1| if is_true { LL| 1| countdown = 0; LL| 1| } - ^0 + ^0 LL| | LL| | for LL| | _ diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map index 4e7ed059c879d..69e1342229609 100644 --- a/tests/coverage/sort_groups.cov-map +++ b/tests/coverage/sort_groups.cov-map @@ -1,5 +1,5 @@ Function name: sort_groups::generic_fn::<&str> -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -7,13 +7,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn::<()> -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -21,13 +21,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -35,13 +35,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -49,13 +49,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 02, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -63,7 +63,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 6, 1) to (start + 4, 35) - Code(Counter(1)) at (prev + 4, 36) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 2, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/sort_groups.coverage b/tests/coverage/sort_groups.coverage index 33a4d9546ce99..6e8a4eda09f1e 100644 --- a/tests/coverage/sort_groups.coverage +++ b/tests/coverage/sort_groups.coverage @@ -27,7 +27,7 @@ | LL| 1| if cond { | LL| 1| println!("{}", std::any::type_name::()); | LL| 1| } - | ^0 + | ^0 | LL| 1|} ------------------ | sort_groups::generic_fn::<()>: diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index ac4e691ea7abf..769930110d67e 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -1,5 +1,5 @@ Function name: unicode::main -Raw bytes (61): 0x[01, 01, 06, 01, 05, 16, 0d, 01, 09, 11, 13, 16, 0d, 01, 09, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 13, 02, 06, 00, 07, 0f, 02, 05, 01, 02] +Raw bytes (61): 0x[01, 01, 06, 01, 05, 16, 0d, 01, 09, 11, 13, 16, 0d, 01, 09, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 13, 02, 05, 00, 06, 0f, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 6 @@ -18,7 +18,7 @@ Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 2, 8) to (start + 0, 37) - Code(Counter(2)) at (prev + 0, 41) to (start + 0, 70) - Code(Counter(4)) at (prev + 0, 71) to (start + 2, 6) -- Code(Expression(4, Add)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(4, Add)) at (prev + 2, 5) to (start + 0, 6) = ((c0 - c2) + c3) - Code(Expression(3, Add)) at (prev + 2, 5) to (start + 1, 2) = (c4 + ((c0 - c2) + c3)) diff --git a/tests/coverage/unicode.coverage b/tests/coverage/unicode.coverage index 305591c706258..84c5f05a8c4e2 100644 --- a/tests/coverage/unicode.coverage +++ b/tests/coverage/unicode.coverage @@ -18,7 +18,7 @@ LL| 1| if 申し訳ございません() && 申し訳ございません() { ^0 LL| 0| println!("true"); - LL| 1| } + LL| 1| } LL| | LL| 1| サビ(); LL| 1|} diff --git a/tests/coverage/unused.cov-map b/tests/coverage/unused.cov-map index 9f1ad59ce83dd..e865ac3ee6227 100644 --- a/tests/coverage/unused.cov-map +++ b/tests/coverage/unused.cov-map @@ -50,38 +50,38 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: unused::unused_func (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 19, 1) to (start + 1, 14) - Code(Zero) at (prev + 1, 15) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_func2 (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 25, 1) to (start + 1, 14) - Code(Zero) at (prev + 1, 15) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_func3 (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 31, 1) to (start + 1, 14) - Code(Zero) at (prev + 1, 15) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/uses_crate.coverage index d001eeffd8636..d1b0dadda768e 100644 --- a/tests/coverage/uses_crate.coverage +++ b/tests/coverage/uses_crate.coverage @@ -14,7 +14,7 @@ $DIR/auxiliary/used_crate.rs: LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| 1| use_this_lib_crate(); LL| 1|} LL| | diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map index a6909768162bd..a482d20e3b4bc 100644 --- a/tests/coverage/uses_inline_crate.cov-map +++ b/tests/coverage/uses_inline_crate.cov-map @@ -8,7 +8,7 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: used_inline_crate::used_inline_function -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 01, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -16,7 +16,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 20, 1) to (start + 6, 15) - Code(Counter(1)) at (prev + 6, 16) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/uses_inline_crate.coverage b/tests/coverage/uses_inline_crate.coverage index 832a5a6a62b44..4671c95aefa49 100644 --- a/tests/coverage/uses_inline_crate.coverage +++ b/tests/coverage/uses_inline_crate.coverage @@ -14,7 +14,7 @@ $DIR/auxiliary/used_inline_crate.rs: LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| 1| use_this_lib_crate(); LL| 1|} LL| | @@ -28,7 +28,7 @@ $DIR/auxiliary/used_inline_crate.rs: LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| 1| use_this_lib_crate(); LL| 1|} LL| | diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff index 510aa07f32d7c..a179824d6c736 100644 --- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff @@ -12,7 +12,7 @@ + coverage Code(Counter(0)) => 10:1 - 10:11; + coverage Code(Expression(0)) => 12:12 - 12:17; + coverage Code(Counter(0)) => 13:13 - 13:18; -+ coverage Code(Counter(1)) => 14:10 - 14:11; ++ coverage Code(Counter(1)) => 14:9 - 14:10; + coverage Code(Counter(0)) => 16:1 - 16:2; + bb0: { diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff index 23cdb3d77171e..082539369f707 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff @@ -11,7 +11,7 @@ coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) }; coverage Code(Counter(0)) => 13:1 - 14:36; coverage Code(Expression(0)) => 14:37 - 14:39; - coverage Code(Counter(1)) => 14:39 - 14:40; + coverage Code(Counter(1)) => 14:38 - 14:39; coverage Code(Counter(0)) => 15:1 - 15:2; coverage Branch { true_term: Expression(0), false_term: Counter(1) } => 14:8 - 14:36; diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff index f6aa42f3eeecf..8635818c6a7a1 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff @@ -11,7 +11,7 @@ + coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) }; + coverage Code(Counter(0)) => 13:1 - 14:36; + coverage Code(Expression(0)) => 14:37 - 14:39; -+ coverage Code(Counter(1)) => 14:39 - 14:40; ++ coverage Code(Counter(1)) => 14:38 - 14:39; + coverage Code(Counter(0)) => 15:1 - 15:2; + coverage Branch { true_term: Expression(0), false_term: Counter(1) } => 14:8 - 14:36; + From 76b6090df593ee41c76e519649fba7acc930bd43 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 8 Nov 2024 16:23:07 +0300 Subject: [PATCH 39/79] read repository information configs at an earlier stage Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 39 ++++++++++++------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 8115aea033d93..e222a11065a11 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1663,10 +1663,26 @@ impl Config { let mut debuginfo_level_tools = None; let mut debuginfo_level_tests = None; let mut optimize = None; - let mut omit_git_hash = None; let mut lld_enabled = None; let mut std_features = None; + let default = config.channel == "dev"; + config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default); + + config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); + config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo")); + config.rust_analyzer_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer")); + config.clippy_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy")); + config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri")); + config.rustfmt_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt")); + config.enzyme_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme")); + config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); + config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); + let mut is_user_configured_rust_channel = false; if let Some(rust) = toml.rust { @@ -1697,7 +1713,7 @@ impl Config { verbose_tests, optimize_tests, codegen_tests, - omit_git_hash: omit_git_hash_toml, + omit_git_hash: _, // already handled above dist_src, save_toolstates, codegen_backends, @@ -1748,7 +1764,6 @@ impl Config { std_features = std_features_toml; optimize = optimize_toml; - omit_git_hash = omit_git_hash_toml; config.rust_new_symbol_mangling = new_symbol_mangling; set(&mut config.rust_optimize_tests, optimize_tests); set(&mut config.codegen_tests, codegen_tests); @@ -1824,24 +1839,6 @@ impl Config { config.reproducible_artifacts = flags.reproducible_artifact; - // rust_info must be set before is_ci_llvm_available() is called. - let default = config.channel == "dev"; - config.omit_git_hash = omit_git_hash.unwrap_or(default); - config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); - - config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo")); - config.rust_analyzer_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer")); - config.clippy_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy")); - config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri")); - config.rustfmt_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt")); - config.enzyme_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme")); - config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); - config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); - // We need to override `rust.channel` if it's manually specified when using the CI rustc. // This is because if the compiler uses a different channel than the one specified in config.toml, // tests may fail due to using a different channel than the one used by the compiler during tests. From cce6f03754f096f8a2bdfb357e3739b855e29366 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 8 Nov 2024 16:23:59 +0300 Subject: [PATCH 40/79] use `download-rustc="if-unchanged"` as default whenever possible "whenever possible" means applying it if `download-rustc` isn't explicitly set and the source is Git-managed. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index e222a11065a11..b1fa7da071223 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2756,9 +2756,19 @@ impl Config { // If `download-rustc` is not set, default to rebuilding. let if_unchanged = match download_rustc { - None | Some(StringOrBool::Bool(false)) => return None, + None => self.rust_info.is_managed_git_subrepository(), + Some(StringOrBool::Bool(false)) => return None, Some(StringOrBool::Bool(true)) => false, - Some(StringOrBool::String(s)) if s == "if-unchanged" => true, + Some(StringOrBool::String(s)) if s == "if-unchanged" => { + if !self.rust_info.is_managed_git_subrepository() { + println!( + "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources." + ); + crate::exit!(1); + } + + true + } Some(StringOrBool::String(other)) => { panic!("unrecognized option for download-rustc: {other}") } @@ -2785,7 +2795,7 @@ impl Config { } println!("ERROR: could not find commit hash for downloading rustc"); println!("HELP: maybe your repository history is too shallow?"); - println!("HELP: consider disabling `download-rustc`"); + println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); println!("HELP: or fetch enough history to include one upstream commit"); crate::exit!(1); } From 2e0afc8b71d9908911f424ff9893b52b3c642ab4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 8 Nov 2024 16:26:00 +0300 Subject: [PATCH 41/79] respect to global `download-rustc` default in non-dist profiles Signed-off-by: onur-ozkan --- src/bootstrap/defaults/config.dist.toml | 1 + src/bootstrap/defaults/config.library.toml | 3 --- src/bootstrap/defaults/config.tools.toml | 5 ----- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/bootstrap/defaults/config.dist.toml b/src/bootstrap/defaults/config.dist.toml index d4feffe02271c..4346a9c2dd11a 100644 --- a/src/bootstrap/defaults/config.dist.toml +++ b/src/bootstrap/defaults/config.dist.toml @@ -11,6 +11,7 @@ extended = true # Most users installing from source want to build all parts of the project from source. [llvm] download-ci-llvm = false + [rust] # We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`). # Make sure they don't get set when installing from source. diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml index 3d697be815658..5447565a4b04c 100644 --- a/src/bootstrap/defaults/config.library.toml +++ b/src/bootstrap/defaults/config.library.toml @@ -8,9 +8,6 @@ bench-stage = 0 [rust] # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true -# Download rustc from CI instead of building it from source. -# For stage > 1 builds, this cuts compile times significantly when there are no changes on "compiler" tree. -download-rustc = "if-unchanged" # Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown. lto = "off" diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml index 27c1d1cf26dac..76b47a841b3f2 100644 --- a/src/bootstrap/defaults/config.tools.toml +++ b/src/bootstrap/defaults/config.tools.toml @@ -3,11 +3,6 @@ [rust] # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true -# Download rustc from CI instead of building it from source. -# For stage > 1 builds, this cuts compile times significantly when there are no changes on "compiler" tree. -# Using these defaults will download the stage2 compiler (see `download-rustc` -# setting) and the stage2 toolchain should therefore be used for these defaults. -download-rustc = "if-unchanged" [build] # Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile. From 6ffab47e553f6fcd5590a3c86c646860bace5823 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:16:37 +0100 Subject: [PATCH 42/79] Use lld with non-LLVM backends On arm64, Cranelift used to produce object files that don't work with lld. This has since been fixed. The GCC backend should always produce object files that work with lld unless lld for whatever reason drops GCC support. Most of the other more niche backends don't use cg_ssa's linker code at all. If they do and don't work with lld, they can always disable lld usage using a cli argument. Without this commit using cg_clif is by default in a non-trivial amount of cases a perf regression on Linux due to ld.bfd being a fair bit slower than lld. It is possible to explicitly enable it without this commit, but most users are unlikely to do this. --- compiler/rustc_codegen_ssa/src/back/link.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8f754debaf0d2..3120b5bf0af67 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3305,23 +3305,6 @@ fn add_lld_args( let self_contained_cli = sess.opts.cg.link_self_contained.is_linker_enabled(); let self_contained_target = self_contained_components.is_linker_enabled(); - // FIXME: in the future, codegen backends may need to have more control over this process: they - // don't always support all the features the linker expects here, and vice versa. For example, - // at the time of writing this, lld expects a newer style of aarch64 TLS relocations that - // cranelift doesn't implement yet. That in turn can impact whether linking would succeed on - // such a target when using the `cg_clif` backend and lld. - // - // Until interactions between backends and linker features are expressible, we limit target - // specs to opt-in to lld only when we're on the llvm backend, where it's expected to work and - // tested on CI. As usual, the CLI still has precedence over this, so that users and developers - // can still override this default when needed (e.g. for tests). - let uses_llvm_backend = - matches!(sess.opts.unstable_opts.codegen_backend.as_deref(), None | Some("llvm")); - if !uses_llvm_backend && !self_contained_cli && sess.opts.cg.linker_flavor.is_none() { - // We bail if we're not using llvm and lld was not explicitly requested on the CLI. - return; - } - let self_contained_linker = self_contained_cli || self_contained_target; if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() { let mut linker_path_exists = false; From 1254d8e75ea4aa5fa06030ee55959c0d40737ec5 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Thu, 31 Oct 2024 02:30:44 +0300 Subject: [PATCH 43/79] Get/set thread name shims return errors for invalid handles --- src/tools/miri/src/concurrency/thread.rs | 44 +++++++------ .../miri/src/shims/unix/android/thread.rs | 6 +- .../miri/src/shims/unix/foreign_items.rs | 8 +-- .../src/shims/unix/linux/foreign_items.rs | 20 ++++-- .../src/shims/unix/macos/foreign_items.rs | 22 +++---- src/tools/miri/src/shims/unix/mod.rs | 2 +- .../src/shims/unix/solarish/foreign_items.rs | 21 ++++--- src/tools/miri/src/shims/unix/thread.rs | 62 +++++++++++++------ .../miri/src/shims/windows/foreign_items.rs | 56 ++++++++++------- src/tools/miri/src/shims/windows/handle.rs | 25 +++++--- src/tools/miri/src/shims/windows/thread.rs | 10 ++- .../tests/pass-dep/libc/pthread-threadname.rs | 25 ++++++++ 12 files changed, 192 insertions(+), 109 deletions(-) diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 281242bf373d5..7477494281dc9 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -1,7 +1,6 @@ //! Implements threads. use std::mem; -use std::num::TryFromIntError; use std::sync::atomic::Ordering::Relaxed; use std::task::Poll; use std::time::{Duration, SystemTime}; @@ -127,26 +126,6 @@ impl Idx for ThreadId { } } -impl TryFrom for ThreadId { - type Error = TryFromIntError; - fn try_from(id: u64) -> Result { - u32::try_from(id).map(Self) - } -} - -impl TryFrom for ThreadId { - type Error = TryFromIntError; - fn try_from(id: i128) -> Result { - u32::try_from(id).map(Self) - } -} - -impl From for ThreadId { - fn from(id: u32) -> Self { - Self(id) - } -} - impl From for u64 { fn from(t: ThreadId) -> Self { t.0.into() @@ -448,6 +427,10 @@ pub enum TimeoutAnchor { Absolute, } +/// An error signaling that the requested thread doesn't exist. +#[derive(Debug, Copy, Clone)] +pub struct ThreadNotFound; + /// A set of threads. #[derive(Debug)] pub struct ThreadManager<'tcx> { @@ -509,6 +492,16 @@ impl<'tcx> ThreadManager<'tcx> { } } + pub fn thread_id_try_from(&self, id: impl TryInto) -> Result { + if let Ok(id) = id.try_into() + && usize::try_from(id).is_ok_and(|id| id < self.threads.len()) + { + Ok(ThreadId(id)) + } else { + Err(ThreadNotFound) + } + } + /// Check if we have an allocation for the given thread local static for the /// active thread. fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { @@ -534,6 +527,7 @@ impl<'tcx> ThreadManager<'tcx> { ) -> &mut Vec>> { &mut self.threads[self.active_thread].stack } + pub fn all_stacks( &self, ) -> impl Iterator>])> { @@ -868,6 +862,11 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { // Public interface to thread management. impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + #[inline] + fn thread_id_try_from(&self, id: impl TryInto) -> Result { + self.eval_context_ref().machine.threads.thread_id_try_from(id) + } + /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. fn get_or_create_thread_local_alloc( @@ -1160,8 +1159,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Set the name of the current thread. The buffer must not include the null terminator. #[inline] fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { - let this = self.eval_context_mut(); - this.machine.threads.set_thread_name(thread, new_thread_name); + self.eval_context_mut().machine.threads.set_thread_name(thread, new_thread_name); } #[inline] diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index 1da13d48252b0..093b7405ccda6 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -2,7 +2,7 @@ use rustc_abi::{ExternAbi, Size}; use rustc_span::Symbol; use crate::helpers::check_min_arg_count; -use crate::shims::unix::thread::EvalContextExt as _; +use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult}; use crate::*; const TASK_COMM_LEN: usize = 16; @@ -32,7 +32,7 @@ pub fn prctl<'tcx>( // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html let res = this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?; - assert!(res); + assert_eq!(res, ThreadNameResult::Ok); Scalar::from_u32(0) } op if op == pr_get_name => { @@ -46,7 +46,7 @@ pub fn prctl<'tcx>( CheckInAllocMsg::MemoryAccessTest, )?; let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?; - assert!(res); + assert_eq!(res, ThreadNameResult::Ok); Scalar::from_u32(0) } op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op), diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index d59d6712c4ff2..55202a0814922 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -603,13 +603,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_join" => { let [thread, retval] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - this.pthread_join(thread, retval)?; - this.write_null(dest)?; + let res = this.pthread_join(thread, retval)?; + this.write_scalar(res, dest)?; } "pthread_detach" => { let [thread] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - this.pthread_detach(thread)?; - this.write_null(dest)?; + let res = this.pthread_detach(thread)?; + this.write_scalar(res, dest)?; } "pthread_self" => { let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 35658ebc2f23a..85f0d6e13307f 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -81,13 +81,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pthread_setname_np" => { let [thread, name] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - let res = this.pthread_setname_np( + let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, TASK_COMM_LEN, /* truncate */ false, - )?; - let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"), + // Act like we faild to open `/proc/self/task/$tid/comm`. + ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"), + }; this.write_scalar(res, dest)?; } "pthread_getname_np" => { @@ -97,14 +101,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // In case of glibc, the length of the output buffer must // be not shorter than TASK_COMM_LEN. let len = this.read_scalar(len)?; - let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64 - && this.pthread_getname_np( + let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64 { + match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, len, /* truncate*/ false, )? { - Scalar::from_u32(0) + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => unreachable!(), + // Act like we faild to open `/proc/self/task/$tid/comm`. + ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"), + } } else { this.eval_libc("ERANGE") }; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index b77b46e325d88..003025916cd42 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -181,18 +181,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // are met, then the name is set and 0 is returned. Otherwise, if // the specified name is lomnger than MAXTHREADNAMESIZE, then // ENAMETOOLONG is returned. - // - // FIXME: the real implementation maybe returns ESRCH if the thread ID is invalid. let thread = this.pthread_self()?; - let res = if this.pthread_setname_np( + let res = match this.pthread_setname_np( thread, this.read_scalar(name)?, this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(), /* truncate */ false, )? { - Scalar::from_u32(0) - } else { - this.eval_libc("ENAMETOOLONG") + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => this.eval_libc("ENAMETOOLONG"), + ThreadNameResult::ThreadNotFound => unreachable!(), }; // Contrary to the manpage, `pthread_setname_np` on macOS still // returns an integer indicating success. @@ -210,15 +208,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1160-L1175. // The key part is the strlcpy, which truncates the resulting value, // but always null terminates (except for zero sized buffers). - // - // FIXME: the real implementation returns ESRCH if the thread ID is invalid. - let res = Scalar::from_u32(0); - this.pthread_getname_np( + let res = match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, this.read_scalar(len)?, /* truncate */ true, - )?; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + // `NameTooLong` is possible when the buffer is zero sized, + ThreadNameResult::NameTooLong => Scalar::from_u32(0), + ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"), + }; this.write_scalar(res, dest)?; } diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 9bc310e8d0a5d..c8c25c636eee3 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -21,7 +21,7 @@ pub use self::fs::{DirTable, EvalContextExt as _}; pub use self::linux::epoll::EpollInterestTable; pub use self::mem::EvalContextExt as _; pub use self::sync::EvalContextExt as _; -pub use self::thread::EvalContextExt as _; +pub use self::thread::{EvalContextExt as _, ThreadNameResult}; pub use self::unnamed_socket::EvalContextExt as _; // Make up some constants. diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index efdc64f45fcfa..526b64cff695a 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -26,26 +26,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // THREAD_NAME_MAX allows a thread name of 31+1 length // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613 let max_len = 32; - let res = this.pthread_setname_np( + // See https://illumos.org/man/3C/pthread_setname_np for the error codes. + let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, max_len, /* truncate */ false, - )?; - let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"), + ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"), + }; this.write_scalar(res, dest)?; } "pthread_getname_np" => { let [thread, name, len] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - // https://github.com/illumos/illumos-gate/blob/c56822be04b6c157c8b6f2281e47214c3b86f657/usr/src/lib/libc/port/threads/thr.c#L2449-L2480 - let res = this.pthread_getname_np( + // See https://illumos.org/man/3C/pthread_getname_np for the error codes. + let res = match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, this.read_scalar(len)?, /* truncate */ false, - )?; - let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"), + ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"), + }; this.write_scalar(res, dest)?; } diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 52c135f85409a..3d990a1a04201 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -2,6 +2,13 @@ use rustc_abi::ExternAbi; use crate::*; +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ThreadNameResult { + Ok, + NameTooLong, + ThreadNotFound, +} + impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_create( @@ -30,7 +37,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(()) } - fn pthread_join(&mut self, thread: &OpTy<'tcx>, retval: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { + fn pthread_join( + &mut self, + thread: &OpTy<'tcx>, + retval: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !this.ptr_is_null(this.read_pointer(retval)?)? { @@ -38,22 +49,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } - let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; - this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?; + let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; + let Ok(thread) = this.thread_id_try_from(thread) else { + return interp_ok(this.eval_libc("ESRCH")); + }; - interp_ok(()) + this.join_thread_exclusive(thread)?; + + interp_ok(Scalar::from_u32(0)) } - fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { + fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; - this.detach_thread( - thread_id.try_into().expect("thread ID should fit in u32"), - /*allow_terminated_joined*/ false, - )?; + let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; + let Ok(thread) = this.thread_id_try_from(thread) else { + return interp_ok(this.eval_libc("ESRCH")); + }; + this.detach_thread(thread, /*allow_terminated_joined*/ false)?; - interp_ok(()) + interp_ok(Scalar::from_u32(0)) } fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { @@ -65,18 +80,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Set the name of the specified thread. If the name including the null terminator /// is longer or equals to `name_max_len`, then if `truncate` is set the truncated name - /// is used as the thread name, otherwise `false` is returned. + /// is used as the thread name, otherwise [`ThreadNameResult::NameTooLong`] is returned. + /// If the specified thread wasn't found, [`ThreadNameResult::ThreadNotFound`] is returned. fn pthread_setname_np( &mut self, thread: Scalar, name: Scalar, name_max_len: usize, truncate: bool, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, ThreadNameResult> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; - let thread = ThreadId::try_from(thread).unwrap(); + let Ok(thread) = this.thread_id_try_from(thread) else { + return interp_ok(ThreadNameResult::ThreadNotFound); + }; let name = name.to_pointer(this)?; let mut name = this.read_c_str(name)?.to_owned(); @@ -85,29 +103,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if truncate { name.truncate(name_max_len.saturating_sub(1)); } else { - return interp_ok(false); + return interp_ok(ThreadNameResult::NameTooLong); } } this.set_thread_name(thread, name); - interp_ok(true) + interp_ok(ThreadNameResult::Ok) } /// Get the name of the specified thread. If the thread name doesn't fit /// the buffer, then if `truncate` is set the truncated name is written out, - /// otherwise `false` is returned. + /// otherwise [`ThreadNameResult::NameTooLong`] is returned. If the specified + /// thread wasn't found, [`ThreadNameResult::ThreadNotFound`] is returned. fn pthread_getname_np( &mut self, thread: Scalar, name_out: Scalar, len: Scalar, truncate: bool, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, ThreadNameResult> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; - let thread = ThreadId::try_from(thread).unwrap(); + let Ok(thread) = this.thread_id_try_from(thread) else { + return interp_ok(ThreadNameResult::ThreadNotFound); + }; let name_out = name_out.to_pointer(this)?; let len = len.to_target_usize(this)?; @@ -119,8 +140,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let (success, _written) = this.write_c_str(name, name_out, len)?; + let res = if success { ThreadNameResult::Ok } else { ThreadNameResult::NameTooLong }; - interp_ok(success) + interp_ok(res) } fn sched_yield(&mut self) -> InterpResult<'tcx, ()> { diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index fe11aa8da4a69..504efed3cfd53 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -10,6 +10,10 @@ use crate::shims::os_str::bytes_to_os_str; use crate::shims::windows::*; use crate::*; +// The NTSTATUS STATUS_INVALID_HANDLE (0xC0000008) encoded as a HRESULT by setting the N bit. +// (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a) +const STATUS_INVALID_HANDLE: u32 = 0xD0000008; + pub fn is_dyn_sym(name: &str) -> bool { // std does dynamic detection for these symbols matches!( @@ -484,14 +488,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread_id = this.CreateThread(security, stacksize, start, arg, flags, thread)?; - this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?; + this.write_scalar(Handle::Thread(thread_id.to_u32()).to_scalar(this), dest)?; } "WaitForSingleObject" => { let [handle, timeout] = this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; let ret = this.WaitForSingleObject(handle, timeout)?; - this.write_scalar(Scalar::from_u32(ret), dest)?; + this.write_scalar(ret, dest)?; } "GetCurrentThread" => { let [] = @@ -510,15 +514,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name = this.read_wide_str(this.read_pointer(name)?)?; let thread = match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => thread, - Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), + Some(Handle::Thread(thread)) => this.thread_id_try_from(thread), + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()), _ => this.invalid_handle("SetThreadDescription")?, }; + let res = match thread { + Ok(thread) => { + // FIXME: use non-lossy conversion + this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes()); + Scalar::from_u32(0) + } + Err(_) => Scalar::from_u32(STATUS_INVALID_HANDLE), + }; - // FIXME: use non-lossy conversion - this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes()); - - this.write_null(dest)?; + this.write_scalar(res, dest)?; } "GetThreadDescription" => { let [handle, name_ptr] = @@ -528,20 +537,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name let thread = match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => thread, - Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), + Some(Handle::Thread(thread)) => this.thread_id_try_from(thread), + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()), _ => this.invalid_handle("GetThreadDescription")?, }; - // Looks like the default thread name is empty. - let name = this.get_thread_name(thread).unwrap_or(b"").to_owned(); - let name = this.alloc_os_str_as_wide_str( - bytes_to_os_str(&name)?, - MiriMemoryKind::WinLocal.into(), - )?; - - this.write_scalar(Scalar::from_maybe_pointer(name, this), &name_ptr)?; + let (name, res) = match thread { + Ok(thread) => { + // Looks like the default thread name is empty. + let name = this.get_thread_name(thread).unwrap_or(b"").to_owned(); + let name = this.alloc_os_str_as_wide_str( + bytes_to_os_str(&name)?, + MiriMemoryKind::WinLocal.into(), + )?; + (Scalar::from_maybe_pointer(name, this), Scalar::from_u32(0)) + } + Err(_) => (Scalar::null_ptr(this), Scalar::from_u32(STATUS_INVALID_HANDLE)), + }; - this.write_null(dest)?; + this.write_scalar(name, &name_ptr)?; + this.write_scalar(res, dest)?; } // Miscellaneous @@ -630,9 +644,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [handle] = this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; - this.CloseHandle(handle)?; + let ret = this.CloseHandle(handle)?; - this.write_int(1, dest)?; + this.write_scalar(ret, dest)?; } "GetModuleFileNameW" => { let [handle, filename, size] = diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 437a21534c96b..b40c00efeddf4 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -14,7 +14,7 @@ pub enum PseudoHandle { pub enum Handle { Null, Pseudo(PseudoHandle), - Thread(ThreadId), + Thread(u32), } impl PseudoHandle { @@ -51,7 +51,7 @@ impl Handle { match self { Self::Null => 0, Self::Pseudo(pseudo_handle) => pseudo_handle.value(), - Self::Thread(thread) => thread.to_u32(), + Self::Thread(thread) => thread, } } @@ -95,7 +95,7 @@ impl Handle { match discriminant { Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null), Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)), - Self::THREAD_DISCRIMINANT => Some(Self::Thread(data.into())), + Self::THREAD_DISCRIMINANT => Some(Self::Thread(data)), _ => None, } } @@ -154,17 +154,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ))) } - fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let handle = this.read_scalar(handle_op)?; - - match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => - this.detach_thread(thread, /*allow_terminated_joined*/ true)?, + let ret = match Handle::from_scalar(handle, this)? { + Some(Handle::Thread(thread)) => { + if let Ok(thread) = this.thread_id_try_from(thread) { + this.detach_thread(thread, /*allow_terminated_joined*/ true)?; + this.eval_windows("c", "TRUE") + } else { + this.invalid_handle("CloseHandle")? + } + } _ => this.invalid_handle("CloseHandle")?, - } + }; - interp_ok(()) + interp_ok(ret) } } diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index fd3ef1413ed48..7af15fc647ce3 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -59,14 +59,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, handle_op: &OpTy<'tcx>, timeout_op: &OpTy<'tcx>, - ) -> InterpResult<'tcx, u32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let handle = this.read_scalar(handle_op)?; let timeout = this.read_scalar(timeout_op)?.to_u32()?; let thread = match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => thread, + Some(Handle::Thread(thread)) => + match this.thread_id_try_from(thread) { + Ok(thread) => thread, + Err(_) => this.invalid_handle("WaitForSingleObject")?, + }, // Unlike on posix, the outcome of joining the current thread is not documented. // On current Windows, it just deadlocks. Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), @@ -79,6 +83,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.join_thread(thread)?; - interp_ok(0) + interp_ok(this.eval_windows("c", "WAIT_OBJECT_0")) } } diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs index 0e5b501bbccdc..cf634bc689093 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs @@ -199,4 +199,29 @@ fn main() { .unwrap() .join() .unwrap(); + + // Now set the name for a non-existing thread and verify error codes. + // (FreeBSD doesn't return an error code.) + #[cfg(not(target_os = "freebsd"))] + { + let invalid_thread = 0xdeadbeef; + let error = { + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + libc::ENOENT + } else { + libc::ESRCH + } + } + }; + #[cfg(not(target_os = "macos"))] + { + // macOS has no `setname` function accepting a thread id as the first argument. + let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) }; + assert_eq!(res, error); + } + let mut buf = [0; 64]; + let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) }; + assert_eq!(res, error); + } } From 2a381086bbaf2ba29bbac33be0805d8a1d20f9fb Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 8 Nov 2024 20:25:54 +0300 Subject: [PATCH 44/79] fix `core::config::tests::override_toml` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/tests.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 1f02757682c22..b6523a458e2b2 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -135,6 +135,7 @@ change-id = 0 [rust] lto = "off" deny-warnings = true +download-rustc=false [build] gdb = "foo" @@ -200,6 +201,8 @@ runner = "x86_64-runner" .collect(), "setting dictionary value" ); + assert!(!config.llvm_from_ci); + assert!(!config.download_rustc()); } #[test] From beb8d6fac180a48381e7c7c21d94ba4e1cfab1be Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 9 Nov 2024 05:04:45 +0000 Subject: [PATCH 45/79] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 96d5acd27ad25..5adbfbfebfb0a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -67395551d07b0eaf6a45ed3bf1759530ca2235d7 +328b759142ddeae96da83176f103200009d3e3f1 From d37e6dfee8afcf0482dd12dbe82d2caf26606675 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 9 Nov 2024 00:18:47 -0600 Subject: [PATCH 46/79] Add str to "expected primitive, found type" diagnostic --- compiler/rustc_middle/src/ty/sty.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e27bb2fd1350a..142db8a17f04f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1933,6 +1933,7 @@ impl<'tcx> Ty<'tcx> { ty::UintTy::U64 => Some(sym::u64), ty::UintTy::U128 => Some(sym::u128), }, + ty::Str => Some(sym::str), _ => None, } } From 5f6645dc51e0e8dbb57bf815e19e59007f25d762 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sat, 9 Nov 2024 00:23:53 -0600 Subject: [PATCH 47/79] Add test for str for "expected primitive, found type" --- .../similar_paths_primitive.rs | 4 +++ .../similar_paths_primitive.stderr | 27 ++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs index 8f5b7cce46908..98890a15d98b1 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.rs +++ b/tests/ui/mismatched_types/similar_paths_primitive.rs @@ -1,10 +1,14 @@ #![allow(non_camel_case_types)] struct bool; +struct str; fn foo(_: bool) {} +fn bar(_: &str) {} fn main() { foo(true); //~^ ERROR mismatched types [E0308] + bar("hello"); + //~^ ERROR mismatched types [E0308] } diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr index c9881891319d3..0530bf5863e69 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.stderr +++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:8:9 + --> $DIR/similar_paths_primitive.rs:10:9 | LL | foo(true); | --- ^^^^ expected `bool`, found a different `bool` @@ -14,11 +14,32 @@ note: `bool` is defined in the current crate LL | struct bool; | ^^^^^^^^^^^ note: function defined here - --> $DIR/similar_paths_primitive.rs:5:4 + --> $DIR/similar_paths_primitive.rs:6:4 | LL | fn foo(_: bool) {} | ^^^ ------- -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/similar_paths_primitive.rs:12:9 + | +LL | bar("hello"); + | --- ^^^^^^^ expected `str`, found a different `str` + | | + | arguments to this function are incorrect + | + = note: str and `str` have similar names, but are actually distinct types + = note: str is a primitive defined by the language +note: `str` is defined in the current crate + --> $DIR/similar_paths_primitive.rs:4:1 + | +LL | struct str; + | ^^^^^^^^^^ +note: function defined here + --> $DIR/similar_paths_primitive.rs:7:4 + | +LL | fn bar(_: &str) {} + | ^^^ ------- + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. From fe398880e0c6d94a1bdca6d7809cb4c2b30b7d49 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Nov 2024 10:52:01 +0100 Subject: [PATCH 48/79] pthread-sync: avoid confusing error when running with preemption --- .../miri/tests/pass-dep/libc/pthread-sync.rs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs index 75848bd44db70..fa11b5b129906 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs @@ -22,6 +22,22 @@ fn main() { check_condattr(); } +// We want to only use pthread APIs here for easier testing. +// So we can't use `thread::scope`. That means panics can lead +// to a failure to join threads which can lead to further issues, +// so let's turn such unwinding into aborts. +struct AbortOnDrop; +impl AbortOnDrop { + fn defuse(self) { + mem::forget(self); + } +} +impl Drop for AbortOnDrop { + fn drop(&mut self) { + std::process::abort(); + } +} + fn test_mutex_libc_init_recursive() { unsafe { let mut attr: libc::pthread_mutexattr_t = mem::zeroed(); @@ -122,6 +138,7 @@ impl Clone for SendPtr { } fn check_mutex() { + let bomb = AbortOnDrop; // Specifically *not* using `Arc` to make sure there is no synchronization apart from the mutex. unsafe { let data = SyncUnsafeCell::new((libc::PTHREAD_MUTEX_INITIALIZER, 0)); @@ -148,9 +165,11 @@ fn check_mutex() { assert_eq!(libc::pthread_mutex_trylock(mutexptr), 0); assert_eq!((*ptr.ptr).1, 3); } + bomb.defuse(); } fn check_rwlock_write() { + let bomb = AbortOnDrop; unsafe { let data = SyncUnsafeCell::new((libc::PTHREAD_RWLOCK_INITIALIZER, 0)); let ptr = SendPtr { ptr: data.get() }; @@ -187,9 +206,11 @@ fn check_rwlock_write() { assert_eq!(libc::pthread_rwlock_tryrdlock(rwlockptr), 0); assert_eq!((*ptr.ptr).1, 3); } + bomb.defuse(); } fn check_rwlock_read_no_deadlock() { + let bomb = AbortOnDrop; unsafe { let l1 = SyncUnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); let l1 = SendPtr { ptr: l1.get() }; @@ -213,9 +234,11 @@ fn check_rwlock_read_no_deadlock() { assert_eq!(libc::pthread_rwlock_rdlock(l2.ptr), 0); handle.join().unwrap(); } + bomb.defuse(); } fn check_cond() { + let bomb = AbortOnDrop; unsafe { let mut cond: MaybeUninit = MaybeUninit::uninit(); assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), ptr::null()), 0); @@ -260,6 +283,7 @@ fn check_cond() { t.join().unwrap(); } + bomb.defuse(); } fn check_condattr() { From 30a2ae6f05ff9e0abbaa9cd308bbceb6ddeede32 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Nov 2024 11:13:44 +0100 Subject: [PATCH 49/79] interpret: get_alloc_info: also return mutability --- .../src/const_eval/eval_queries.rs | 2 +- .../rustc_const_eval/src/interpret/memory.rs | 39 ++++++++++++------- .../src/interpret/validity.rs | 2 +- src/tools/miri/src/alloc_addresses/mod.rs | 2 +- src/tools/miri/src/borrow_tracker/mod.rs | 2 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 4 +- .../src/borrow_tracker/tree_borrows/mod.rs | 2 +- src/tools/miri/src/machine.rs | 2 +- src/tools/miri/src/shims/foreign_items.rs | 2 +- 9 files changed, 34 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 81b9d73b9528c..4055e3f0d505e 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -472,7 +472,7 @@ fn report_validation_error<'tcx>( backtrace.print_backtrace(); let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); - let (size, align, _) = ecx.get_alloc_info(alloc_id); + let (size, align, ..) = ecx.get_alloc_info(alloc_id); let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes }; crate::const_eval::report( diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 1ad8ffa4b53fc..cc7ce1df92305 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -524,7 +524,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { match self.ptr_try_get_alloc_id(ptr, 0) { Err(addr) => is_offset_misaligned(addr, align), Ok((alloc_id, offset, _prov)) => { - let (_size, alloc_align, kind) = self.get_alloc_info(alloc_id); + let (_size, alloc_align, kind, _mutbl) = self.get_alloc_info(alloc_id); if let Some(misalign) = M::alignment_check(self, alloc_id, alloc_align, kind, offset, align) { @@ -818,19 +818,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Obtain the size and alignment of an allocation, even if that allocation has /// been deallocated. - pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { + pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind, Mutability) { // # Regular allocations // Don't use `self.get_raw` here as that will // a) cause cycles in case `id` refers to a static // b) duplicate a global's allocation in miri if let Some((_, alloc)) = self.memory.alloc_map.get(id) { - return (alloc.size(), alloc.align, AllocKind::LiveData); + return (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability); } // # Function pointers // (both global from `alloc_map` and local from `extra_fn_ptr_map`) if self.get_fn_alloc(id).is_some() { - return (Size::ZERO, Align::ONE, AllocKind::Function); + return (Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not); } // # Statics @@ -842,17 +842,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value. assert!(!self.tcx.is_thread_local_static(def_id)); - let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { + let DefKind::Static { nested, mutability, .. } = self.tcx.def_kind(def_id) else { bug!("GlobalAlloc::Static is not a static") }; - let (size, align) = if nested { + let (size, align, mutability) = if nested { // Nested anonymous statics are untyped, so let's get their // size and alignment from the allocation itself. This always // succeeds, as the query is fed at DefId creation time, so no // evaluation actually occurs. let alloc = self.tcx.eval_static_initializer(def_id).unwrap(); - (alloc.0.size(), alloc.0.align) + (alloc.0.size(), alloc.0.align, alloc.0.mutability) } else { // Use size and align of the type for everything else. We need // to do that to @@ -865,22 +865,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .expect("statics should not have generic parameters"); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); assert!(layout.is_sized()); - (layout.size, layout.align.abi) + let mutability = match mutability { + Mutability::Not if !ty.is_freeze(*self.tcx, ParamEnv::empty()) => { + Mutability::Not + } + _ => Mutability::Mut, + }; + (layout.size, layout.align.abi, mutability) }; - (size, align, AllocKind::LiveData) + (size, align, AllocKind::LiveData, mutability) } Some(GlobalAlloc::Memory(alloc)) => { // Need to duplicate the logic here, because the global allocations have // different associated types than the interpreter-local ones. let alloc = alloc.inner(); - (alloc.size(), alloc.align, AllocKind::LiveData) + (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability) } Some(GlobalAlloc::Function { .. }) => { bug!("We already checked function pointers above") } Some(GlobalAlloc::VTable(..)) => { // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); + return ( + Size::ZERO, + self.tcx.data_layout.pointer_align.abi, + AllocKind::VTable, + Mutability::Not, + ); } // The rest must be dead. None => { @@ -891,7 +902,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .dead_alloc_map .get(&id) .expect("deallocated pointers should all be recorded in `dead_alloc_map`"); - (size, align, AllocKind::Dead) + (size, align, AllocKind::Dead, Mutability::Not) } } } @@ -902,7 +913,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, msg: CheckInAllocMsg, ) -> InterpResult<'tcx, (Size, Align)> { - let (size, align, kind) = self.get_alloc_info(id); + let (size, align, kind, _mutbl) = self.get_alloc_info(id); if matches!(kind, AllocKind::Dead) { throw_ub!(PointerUseAfterFree(id, msg)) } @@ -1458,7 +1469,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr = scalar.to_pointer(self)?; match self.ptr_try_get_alloc_id(ptr, 0) { Ok((alloc_id, offset, _)) => { - let (size, _align, _kind) = self.get_alloc_info(alloc_id); + let (size, _align, _kind, _mutbl) = self.get_alloc_info(alloc_id); // If the pointer is out-of-bounds, it may be null. // Note that one-past-the-end (offset == size) is still inbounds, and never null. offset > size diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index cd2c1ef36132e..d7532c6e01a7d 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -594,7 +594,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Dangling and Mutability check. - let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); + let (size, _align, alloc_kind, _mutbl) = self.ecx.get_alloc_info(alloc_id); if alloc_kind == AllocKind::Dead { // This can happen for zero-sized references. We can't have *any* references to // non-existing allocations in const-eval though, interning rejects them all as diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 7b377a1c4cdfc..8b59ca63a4348 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -157,7 +157,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, u64> { let ecx = self.eval_context_ref(); let mut rng = ecx.machine.rng.borrow_mut(); - let (size, align, kind) = ecx.get_alloc_info(alloc_id); + let (size, align, kind, _mutbl) = ecx.get_alloc_info(alloc_id); // This is either called immediately after allocation (and then cached), or when // adjusting `tcx` pointers (which never get freed). So assert that we are looking // at a live allocation. This also ensures that we never re-assign an address to an diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 72319decb9430..3ee00a1dcf46d 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -363,7 +363,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If it does exist, then we have the guarantee that the // pointer is readable, and the implicit read access inserted // will never cause UB on the pointer itself. - let (_, _, kind) = this.get_alloc_info(*alloc_id); + let (_, _, kind, _mutbl) = this.get_alloc_info(*alloc_id); if matches!(kind, AllocKind::LiveData) { let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static` let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap(); diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 47fe41d9ecdd8..b42b70b4d2f27 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -626,7 +626,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(()) }; - let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); + let (_size, _align, alloc_kind, _mutbl) = this.get_alloc_info(alloc_id); match alloc_kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail @@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - let (_size, _align, kind) = this.get_alloc_info(alloc_id); + let (_size, _align, kind, _mutbl) = this.get_alloc_info(alloc_id); match kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 40467aa4bc1be..799950e4c94e7 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -538,7 +538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Tree Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - let (_size, _align, kind) = this.get_alloc_info(alloc_id); + let (_size, _align, kind, _mutbl) = this.get_alloc_info(alloc_id); match kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 72e8952c5437f..c8c9070f29028 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1125,7 +1125,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let Provenance::Concrete { alloc_id, .. } = ptr.provenance else { panic!("extern_statics cannot contain wildcards") }; - let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id); + let (shim_size, shim_align, _kind, _mutbl) = ecx.get_alloc_info(alloc_id); let def_ty = ecx.tcx.type_of(def_id).instantiate_identity(); let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap(); if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 18578c7acc963..a6733af9faa79 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -409,7 +409,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr, 0) { - let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id); + let (_size, alloc_align, _kind, _mutbl) = this.get_alloc_info(alloc_id); // If the newly promised alignment is bigger than the native alignment of this // allocation, and bigger than the previously promised alignment, then set it. if align > alloc_align From 4a54ec8c18be3e1b66b9efc627e356904201a348 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Nov 2024 13:13:31 +0100 Subject: [PATCH 50/79] make return type of get_alloc_info a struct, and reduce some code duplication with validity checking --- .../src/const_eval/eval_queries.rs | 5 +- .../rustc_const_eval/src/interpret/memory.rs | 143 +++++++----------- .../rustc_const_eval/src/interpret/mod.rs | 2 +- .../src/interpret/validity.rs | 91 ++++------- .../rustc_middle/src/mir/interpret/mod.rs | 86 ++++++++++- src/tools/miri/src/alloc_addresses/mod.rs | 18 +-- src/tools/miri/src/borrow_tracker/mod.rs | 2 +- .../src/borrow_tracker/stacked_borrows/mod.rs | 4 +- .../src/borrow_tracker/tree_borrows/mod.rs | 4 +- src/tools/miri/src/machine.rs | 8 +- src/tools/miri/src/shims/foreign_items.rs | 4 +- 11 files changed, 190 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 4055e3f0d505e..a430d9dc797f1 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -472,8 +472,9 @@ fn report_validation_error<'tcx>( backtrace.print_backtrace(); let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); - let (size, align, ..) = ecx.get_alloc_info(alloc_id); - let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes }; + let info = ecx.get_alloc_info(alloc_id); + let raw_bytes = + errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes }; crate::const_eval::report( *ecx.tcx, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index cc7ce1df92305..09635c96e57cd 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -14,10 +14,9 @@ use std::{fmt, mem, ptr}; use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_hir::def::DefKind; use rustc_middle::bug; use rustc_middle::mir::display_allocation; -use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use tracing::{debug, instrument, trace}; use super::{ @@ -72,6 +71,21 @@ pub enum AllocKind { Dead, } +/// Metadata about an `AllocId`. +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct AllocInfo { + pub size: Size, + pub align: Align, + pub kind: AllocKind, + pub mutbl: Mutability, +} + +impl AllocInfo { + fn new(size: Size, align: Align, kind: AllocKind, mutbl: Mutability) -> Self { + Self { size, align, kind, mutbl } + } +} + /// The value of a function pointer. #[derive(Debug, Copy, Clone)] pub enum FnVal<'tcx, Other> { @@ -524,17 +538,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { match self.ptr_try_get_alloc_id(ptr, 0) { Err(addr) => is_offset_misaligned(addr, align), Ok((alloc_id, offset, _prov)) => { - let (_size, alloc_align, kind, _mutbl) = self.get_alloc_info(alloc_id); - if let Some(misalign) = - M::alignment_check(self, alloc_id, alloc_align, kind, offset, align) - { + let alloc_info = self.get_alloc_info(alloc_id); + if let Some(misalign) = M::alignment_check( + self, + alloc_id, + alloc_info.align, + alloc_info.kind, + offset, + align, + ) { Some(misalign) } else if M::Provenance::OFFSET_IS_ADDR { is_offset_misaligned(ptr.addr().bytes(), align) } else { // Check allocation alignment and offset alignment. - if alloc_align.bytes() < align.bytes() { - Some(Misalignment { has: alloc_align, required: align }) + if alloc_info.align.bytes() < align.bytes() { + Some(Misalignment { has: alloc_info.align, required: align }) } else { is_offset_misaligned(offset.bytes(), align) } @@ -818,93 +837,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Obtain the size and alignment of an allocation, even if that allocation has /// been deallocated. - pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind, Mutability) { + pub fn get_alloc_info(&self, id: AllocId) -> AllocInfo { // # Regular allocations // Don't use `self.get_raw` here as that will // a) cause cycles in case `id` refers to a static // b) duplicate a global's allocation in miri if let Some((_, alloc)) = self.memory.alloc_map.get(id) { - return (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability); + return AllocInfo::new( + alloc.size(), + alloc.align, + AllocKind::LiveData, + alloc.mutability, + ); } // # Function pointers // (both global from `alloc_map` and local from `extra_fn_ptr_map`) if self.get_fn_alloc(id).is_some() { - return (Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not); + return AllocInfo::new(Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not); } - // # Statics - // Can't do this in the match argument, we may get cycle errors since the lock would - // be held throughout the match. - match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Static(def_id)) => { - // Thread-local statics do not have a constant address. They *must* be accessed via - // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value. - assert!(!self.tcx.is_thread_local_static(def_id)); - - let DefKind::Static { nested, mutability, .. } = self.tcx.def_kind(def_id) else { - bug!("GlobalAlloc::Static is not a static") - }; - - let (size, align, mutability) = if nested { - // Nested anonymous statics are untyped, so let's get their - // size and alignment from the allocation itself. This always - // succeeds, as the query is fed at DefId creation time, so no - // evaluation actually occurs. - let alloc = self.tcx.eval_static_initializer(def_id).unwrap(); - (alloc.0.size(), alloc.0.align, alloc.0.mutability) - } else { - // Use size and align of the type for everything else. We need - // to do that to - // * avoid cycle errors in case of self-referential statics, - // * be able to get information on extern statics. - let ty = self - .tcx - .type_of(def_id) - .no_bound_vars() - .expect("statics should not have generic parameters"); - let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); - assert!(layout.is_sized()); - let mutability = match mutability { - Mutability::Not if !ty.is_freeze(*self.tcx, ParamEnv::empty()) => { - Mutability::Not - } - _ => Mutability::Mut, - }; - (layout.size, layout.align.abi, mutability) - }; - (size, align, AllocKind::LiveData, mutability) - } - Some(GlobalAlloc::Memory(alloc)) => { - // Need to duplicate the logic here, because the global allocations have - // different associated types than the interpreter-local ones. - let alloc = alloc.inner(); - (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability) - } - Some(GlobalAlloc::Function { .. }) => { - bug!("We already checked function pointers above") - } - Some(GlobalAlloc::VTable(..)) => { - // No data to be accessed here. But vtables are pointer-aligned. - return ( - Size::ZERO, - self.tcx.data_layout.pointer_align.abi, - AllocKind::VTable, - Mutability::Not, - ); - } - // The rest must be dead. - None => { - // Deallocated pointers are allowed, we should be able to find - // them in the map. - let (size, align) = *self - .memory - .dead_alloc_map - .get(&id) - .expect("deallocated pointers should all be recorded in `dead_alloc_map`"); - (size, align, AllocKind::Dead, Mutability::Not) - } + // # Global allocations + if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) { + let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env); + let mutbl = global_alloc.mutability(*self.tcx, self.param_env); + let kind = match global_alloc { + GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, + GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), + GlobalAlloc::VTable { .. } => AllocKind::VTable, + }; + return AllocInfo::new(size, align, kind, mutbl); } + + // # Dead pointers + let (size, align) = *self + .memory + .dead_alloc_map + .get(&id) + .expect("deallocated pointers should all be recorded in `dead_alloc_map`"); + AllocInfo::new(size, align, AllocKind::Dead, Mutability::Not) } /// Obtain the size and alignment of a *live* allocation. @@ -913,11 +884,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, msg: CheckInAllocMsg, ) -> InterpResult<'tcx, (Size, Align)> { - let (size, align, kind, _mutbl) = self.get_alloc_info(id); - if matches!(kind, AllocKind::Dead) { + let info = self.get_alloc_info(id); + if matches!(info.kind, AllocKind::Dead) { throw_ub!(PointerUseAfterFree(id, msg)) } - interp_ok((size, align)) + interp_ok((info.size, info.align)) } fn get_fn_alloc(&self, id: AllocId) -> Option> { @@ -1469,7 +1440,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr = scalar.to_pointer(self)?; match self.ptr_try_get_alloc_id(ptr, 0) { Ok((alloc_id, offset, _)) => { - let (size, _align, _kind, _mutbl) = self.get_alloc_info(alloc_id); + let size = self.get_alloc_info(alloc_id).size; // If the pointer is out-of-bounds, it may be null. // Note that one-past-the-end (offset == size) is still inbounds, and never null. offset > size diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 5e84626f77e7a..f5792aba2075c 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -31,7 +31,7 @@ pub use self::intern::{ }; pub(crate) use self::intrinsics::eval_nullary_intrinsic; pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine}; -pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; +pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; use self::operand::Operand; pub use self::operand::{ImmTy, Immediate, OpTy}; pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable}; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d7532c6e01a7d..3a68db9f7f74b 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -31,8 +31,8 @@ use tracing::trace; use super::machine::AllocMap; use super::{ - AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, - MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, + AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, + Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, format_interp_error, }; @@ -557,9 +557,20 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr(), 0) { - if let Some(GlobalAlloc::Static(did)) = - self.ecx.tcx.try_get_global_alloc(alloc_id) - { + // Everything should be already interned. + let Some(global_alloc) = self.ecx.tcx.try_get_global_alloc(alloc_id) else { + assert!(self.ecx.memory.alloc_map.get(alloc_id).is_none()); + // We can't have *any* references to non-existing allocations in const-eval + // as the rest of rustc isn't happy with them... so we throw an error, even + // though for zero-sized references this isn't really UB. + // A potential future alternative would be to resurrect this as a zero-sized allocation + // (which codegen will then compile to an aligned dummy pointer anyway). + throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); + }; + let (size, _align) = + global_alloc.size_and_align(*self.ecx.tcx, self.ecx.param_env); + + if let GlobalAlloc::Static(did) = global_alloc { let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() }; @@ -593,17 +604,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } } - // Dangling and Mutability check. - let (size, _align, alloc_kind, _mutbl) = self.ecx.get_alloc_info(alloc_id); - if alloc_kind == AllocKind::Dead { - // This can happen for zero-sized references. We can't have *any* references to - // non-existing allocations in const-eval though, interning rejects them all as - // the rest of rustc isn't happy with them... so we throw an error, even though - // this isn't really UB. - // A potential future alternative would be to resurrect this as a zero-sized allocation - // (which codegen will then compile to an aligned dummy pointer anyway). - throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); - } // If this allocation has size zero, there is no actual mutability here. if size != Size::ZERO { // Determine whether this pointer expects to be pointing to something mutable. @@ -618,7 +618,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } }; // Determine what it actually points to. - let alloc_actual_mutbl = mutability(self.ecx, alloc_id); + let alloc_actual_mutbl = + global_alloc.mutability(*self.ecx.tcx, self.ecx.param_env); // Mutable pointer to immutable memory is no good. if ptr_expected_mutbl == Mutability::Mut && alloc_actual_mutbl == Mutability::Not @@ -842,9 +843,16 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } fn in_mutable_memory(&self, val: &PlaceTy<'tcx, M::Provenance>) -> bool { + debug_assert!(self.ctfe_mode.is_some()); if let Some(mplace) = val.as_mplace_or_local().left() { if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { - mutability(self.ecx, alloc_id).is_mut() + let tcx = *self.ecx.tcx; + // Everything must be already interned. + let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.param_env); + if let Some((_, alloc)) = self.ecx.memory.alloc_map.get(alloc_id) { + assert_eq!(alloc.mutability, mutbl); + } + mutbl.is_mut() } else { // No memory at all. false @@ -1016,53 +1024,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } } -/// Returns whether the allocation is mutable, and whether it's actually a static. -/// For "root" statics we look at the type to account for interior -/// mutability; for nested statics we have no type and directly use the annotated mutability. -fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) -> Mutability { - // Let's see what kind of memory this points to. - // We're not using `try_global_alloc` since dangling pointers have already been handled. - match ecx.tcx.global_alloc(alloc_id) { - GlobalAlloc::Static(did) => { - let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else { - bug!() - }; - if nested { - assert!( - ecx.memory.alloc_map.get(alloc_id).is_none(), - "allocations of nested statics are already interned: {alloc_id:?}, {did:?}" - ); - // Nested statics in a `static` are never interior mutable, - // so just use the declared mutability. - mutability - } else { - let mutability = match mutability { - Mutability::Not - if !ecx - .tcx - .type_of(did) - .no_bound_vars() - .expect("statics should not have generic parameters") - .is_freeze(*ecx.tcx, ty::ParamEnv::reveal_all()) => - { - Mutability::Mut - } - _ => mutability, - }; - if let Some((_, alloc)) = ecx.memory.alloc_map.get(alloc_id) { - assert_eq!(alloc.mutability, mutability); - } - mutability - } - } - GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { - // These are immutable, we better don't allow mutable pointers here. - Mutability::Not - } - } -} - impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, 'tcx, M> { type V = PlaceTy<'tcx, M::Provenance>; diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b0c0e1be50064..f225ad94aa704 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -12,11 +12,12 @@ use std::io::{Read, Write}; use std::num::NonZero; use std::{fmt, io}; -use rustc_abi::{AddressSpace, Endian, HasDataLayout}; -use rustc_ast::LitKind; +use rustc_abi::{AddressSpace, Align, Endian, HasDataLayout, Size}; +use rustc_ast::{LitKind, Mutability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; use rustc_errors::ErrorGuaranteed; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -45,7 +46,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::{self, Instance, Ty, TyCtxt}; +use crate::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; /// Uniquely identifies one of the following: /// - A constant @@ -310,6 +311,85 @@ impl<'tcx> GlobalAlloc<'tcx> { } } } + + pub fn mutability(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Mutability { + // Let's see what kind of memory we are. + match self { + GlobalAlloc::Static(did) => { + let DefKind::Static { safety: _, mutability, nested } = tcx.def_kind(did) else { + bug!() + }; + if nested { + // Nested statics in a `static` are never interior mutable, + // so just use the declared mutability. + if cfg!(debug_assertions) { + let alloc = tcx.eval_static_initializer(did).unwrap(); + assert_eq!(alloc.0.mutability, mutability); + } + mutability + } else { + let mutability = match mutability { + Mutability::Not + if !tcx + .type_of(did) + .no_bound_vars() + .expect("statics should not have generic parameters") + .is_freeze(tcx, param_env) => + { + Mutability::Mut + } + _ => mutability, + }; + mutability + } + } + GlobalAlloc::Memory(alloc) => alloc.inner().mutability, + GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { + // These are immutable. + Mutability::Not + } + } + } + + pub fn size_and_align(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> (Size, Align) { + match self { + GlobalAlloc::Static(def_id) => { + let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { + bug!("GlobalAlloc::Static is not a static") + }; + + if nested { + // Nested anonymous statics are untyped, so let's get their + // size and alignment from the allocation itself. This always + // succeeds, as the query is fed at DefId creation time, so no + // evaluation actually occurs. + let alloc = tcx.eval_static_initializer(def_id).unwrap(); + (alloc.0.size(), alloc.0.align) + } else { + // Use size and align of the type for everything else. We need + // to do that to + // * avoid cycle errors in case of self-referential statics, + // * be able to get information on extern statics. + let ty = tcx + .type_of(def_id) + .no_bound_vars() + .expect("statics should not have generic parameters"); + let layout = tcx.layout_of(param_env.and(ty)).unwrap(); + assert!(layout.is_sized()); + (layout.size, layout.align.abi) + } + } + GlobalAlloc::Memory(alloc) => { + let alloc = alloc.inner(); + (alloc.size(), alloc.align) + } + GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE), + GlobalAlloc::VTable(..) => { + // No data to be accessed here. But vtables are pointer-aligned. + return (Size::ZERO, tcx.data_layout.pointer_align.abi); + } + } + } } pub const CTFE_ALLOC_SALT: usize = 0; diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 8b59ca63a4348..b9d82a086203d 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -134,7 +134,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // entered for addresses that are not the base address, so even zero-sized // allocations will get recognized at their base address -- but all other // allocations will *not* be recognized at their "end" address. - let size = ecx.get_alloc_info(alloc_id).0; + let size = ecx.get_alloc_info(alloc_id).size; if offset < size.bytes() { Some(alloc_id) } else { None } } }?; @@ -157,25 +157,25 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, u64> { let ecx = self.eval_context_ref(); let mut rng = ecx.machine.rng.borrow_mut(); - let (size, align, kind, _mutbl) = ecx.get_alloc_info(alloc_id); + let info = ecx.get_alloc_info(alloc_id); // This is either called immediately after allocation (and then cached), or when // adjusting `tcx` pointers (which never get freed). So assert that we are looking // at a live allocation. This also ensures that we never re-assign an address to an // allocation that previously had an address, but then was freed and the address // information was removed. - assert!(!matches!(kind, AllocKind::Dead)); + assert!(!matches!(info.kind, AllocKind::Dead)); // This allocation does not have a base address yet, pick or reuse one. if ecx.machine.native_lib.is_some() { // In native lib mode, we use the "real" address of the bytes for this allocation. // This ensures the interpreted program and native code have the same view of memory. - let base_ptr = match kind { + let base_ptr = match info.kind { AllocKind::LiveData => { if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { // For new global allocations, we always pre-allocate the memory to be able use the machine address directly. - let prepared_bytes = MiriAllocBytes::zeroed(size, align) + let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align) .unwrap_or_else(|| { - panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes") + panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes", size = info.size) }); let ptr = prepared_bytes.as_ptr(); // Store prepared allocation space to be picked up for use later. @@ -204,7 +204,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } // We are not in native lib mode, so we control the addresses ourselves. if let Some((reuse_addr, clock)) = - global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, ecx.active_thread()) + global_state.reuse.take_addr(&mut *rng, info.size, info.align, memory_kind, ecx.active_thread()) { if let Some(clock) = clock { ecx.acquire_clock(&clock); @@ -220,14 +220,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .next_base_addr .checked_add(slack) .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - let base_addr = align_addr(base_addr, align.bytes()); + let base_addr = align_addr(base_addr, info.align.bytes()); // Remember next base address. If this allocation is zero-sized, leave a gap of at // least 1 to avoid two allocations having the same base address. (The logic in // `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers // need to be distinguishable!) global_state.next_base_addr = base_addr - .checked_add(max(size.bytes(), 1)) + .checked_add(max(info.size.bytes(), 1)) .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; // Even if `Size` didn't overflow, we might still have filled up the address space. if global_state.next_base_addr > ecx.target_usize_max() { diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 3ee00a1dcf46d..4883613dea504 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -363,7 +363,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If it does exist, then we have the guarantee that the // pointer is readable, and the implicit read access inserted // will never cause UB on the pointer itself. - let (_, _, kind, _mutbl) = this.get_alloc_info(*alloc_id); + let kind = this.get_alloc_info(*alloc_id).kind; if matches!(kind, AllocKind::LiveData) { let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static` let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap(); diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index b42b70b4d2f27..16fcc26be33a1 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -626,7 +626,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(()) }; - let (_size, _align, alloc_kind, _mutbl) = this.get_alloc_info(alloc_id); + let alloc_kind = this.get_alloc_info(alloc_id).kind; match alloc_kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail @@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - let (_size, _align, kind, _mutbl) = this.get_alloc_info(alloc_id); + let kind = this.get_alloc_info(alloc_id).kind; match kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 799950e4c94e7..f92150758dc39 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -274,7 +274,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .insert(new_tag, protect); } - let alloc_kind = this.get_alloc_info(alloc_id).2; + let alloc_kind = this.get_alloc_info(alloc_id).kind; if !matches!(alloc_kind, AllocKind::LiveData) { assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here // There's not actually any bytes here where accesses could even be tracked. @@ -538,7 +538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Tree Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - let (_size, _align, kind, _mutbl) = this.get_alloc_info(alloc_id); + let kind = this.get_alloc_info(alloc_id).kind; match kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index c8c9070f29028..9668998aaa3a4 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1125,10 +1125,10 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let Provenance::Concrete { alloc_id, .. } = ptr.provenance else { panic!("extern_statics cannot contain wildcards") }; - let (shim_size, shim_align, _kind, _mutbl) = ecx.get_alloc_info(alloc_id); + let info = ecx.get_alloc_info(alloc_id); let def_ty = ecx.tcx.type_of(def_id).instantiate_identity(); let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap(); - if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align { + if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align { throw_unsup_format!( "extern static `{link_name}` has been declared as `{krate}::{name}` \ with a size of {decl_size} bytes and alignment of {decl_align} bytes, \ @@ -1138,8 +1138,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { krate = ecx.tcx.crate_name(def_id.krate), decl_size = extern_decl_layout.size.bytes(), decl_align = extern_decl_layout.align.abi.bytes(), - shim_size = shim_size.bytes(), - shim_align = shim_align.bytes(), + shim_size = info.size.bytes(), + shim_align = info.align.bytes(), ) } interp_ok(ptr) diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index a6733af9faa79..b903433692437 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -300,7 +300,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let id = this.read_scalar(id)?.to_u64()?; let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; if let Some(id) = std::num::NonZero::new(id).map(AllocId) - && this.get_alloc_info(id).2 == AllocKind::LiveData + && this.get_alloc_info(id).kind == AllocKind::LiveData { this.print_borrow_state(id, show_unnamed)?; } else { @@ -409,7 +409,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr, 0) { - let (_size, alloc_align, _kind, _mutbl) = this.get_alloc_info(alloc_id); + let alloc_align = this.get_alloc_info(alloc_id).align; // If the newly promised alignment is bigger than the native alignment of this // allocation, and bigger than the previously promised alignment, then set it. if align > alloc_align From 1dc106121b62562ead6e7d612fa136dc4b35cd5d Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Mon, 4 Nov 2024 11:38:14 -0800 Subject: [PATCH 51/79] Add discriminators to DILocations when multiple functions are inlined into a single point. LLVM does not expect to ever see multiple dbg_declares for the same variable at the same location with different values. proc-macros make it possible for arbitrary code, including multiple calls that get inlined, to happen at any given location in the source code. Add discriminators when that happens so these locations are different to LLVM. This may interfere with the AddDiscriminators pass in LLVM, which is added by the unstable flag -Zdebug-info-for-profiling. Fixes #131944 --- .../src/debuginfo/create_scope_map.rs | 60 ++++++++++++++++++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 ++ .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 8 +++ .../auxiliary/macro_def.rs | 11 ++++ .../mir_inlined_twice_var_locs.rs | 53 ++++++++++++++++ 5 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs create mode 100644 tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index ac6c2fb1b83a6..0f1909486ec7e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -1,11 +1,15 @@ +use std::collections::hash_map::Entry; + use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext}; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::fx::FxHashMap; use rustc_index::Idx; use rustc_index::bit_set::BitSet; use rustc_middle::mir::{Body, SourceScope}; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance}; use rustc_session::config::DebugInfo; +use rustc_span::BytePos; use super::metadata::file_metadata; use super::utils::DIB; @@ -37,10 +41,20 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>( None }; let mut instantiated = BitSet::new_empty(mir.source_scopes.len()); + let mut discriminators = FxHashMap::default(); // Instantiate all scopes. for idx in 0..mir.source_scopes.len() { let scope = SourceScope::new(idx); - make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope); + make_mir_scope( + cx, + instance, + mir, + &variables, + debug_context, + &mut instantiated, + &mut discriminators, + scope, + ); } assert!(instantiated.count() == mir.source_scopes.len()); } @@ -52,6 +66,7 @@ fn make_mir_scope<'ll, 'tcx>( variables: &Option>, debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, instantiated: &mut BitSet, + discriminators: &mut FxHashMap, scope: SourceScope, ) { if instantiated.contains(scope) { @@ -60,7 +75,16 @@ fn make_mir_scope<'ll, 'tcx>( let scope_data = &mir.source_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { - make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent); + make_mir_scope( + cx, + instance, + mir, + variables, + debug_context, + instantiated, + discriminators, + parent, + ); debug_context.scopes[parent] } else { // The root is the function itself. @@ -117,7 +141,37 @@ fn make_mir_scope<'ll, 'tcx>( // FIXME(eddyb) this doesn't account for the macro-related // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does. let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span); - cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span) + let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span); + + // NB: In order to produce proper debug info for variables (particularly + // arguments) in multiply-inline functions, LLVM expects to see a single + // DILocalVariable with multiple different DILocations in the IR. While + // the source information for each DILocation would be identical, their + // inlinedAt attributes will be unique to the particular callsite. + // + // We generate DILocations here based on the callsite's location in the + // source code. A single location in the source code usually can't + // produce multiple distinct calls so this mostly works, until + // proc-macros get involved. A proc-macro can generate multiple calls + // at the same span, which breaks the assumption that we're going to + // produce a unique DILocation for every scope we process here. We + // have to explicitly add discriminators if we see inlines into the + // same source code location. + // + // Note further that we can't key this hashtable on the span itself, + // because these spans could have distinct SyntaxContexts. We have + // to key on exactly what we're giving to LLVM. + match discriminators.entry(callsite_span.lo()) { + Entry::Occupied(mut o) => { + *o.get_mut() += 1; + unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) } + .expect("Failed to encode discriminator in DILocation") + } + Entry::Vacant(v) => { + v.insert(0); + loc + } + } }); debug_context.scopes[scope] = DebugScope { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3d2e270a3868e..75a5ec44c2285 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2174,6 +2174,10 @@ unsafe extern "C" { Scope: &'a DIScope, InlinedAt: Option<&'a DILocation>, ) -> &'a DILocation; + pub fn LLVMRustDILocationCloneWithBaseDiscriminator<'a>( + Location: &'a DILocation, + BD: c_uint, + ) -> Option<&'a DILocation>; pub fn LLVMRustDIBuilderCreateOpDeref() -> u64; pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64; pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 9330c83b7f230..cd70c3f266920 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1305,6 +1305,14 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column, return wrap(Loc); } +extern "C" LLVMMetadataRef +LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location, + unsigned BD) { + DILocation *Loc = unwrapDIPtr(Location); + auto NewLoc = Loc->cloneWithBaseDiscriminator(BD); + return wrap(NewLoc.has_value() ? NewLoc.value() : nullptr); +} + extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() { return dwarf::DW_OP_deref; } diff --git a/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs b/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs new file mode 100644 index 0000000000000..159ecfd09743d --- /dev/null +++ b/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs @@ -0,0 +1,11 @@ +//@ force-host +//@ no-prefer-dynamic +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +pub fn square_twice(_item: TokenStream) -> TokenStream { + "(square(env::vars().count() as i32), square(env::vars().count() as i32))".parse().unwrap() +} diff --git a/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs b/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs new file mode 100644 index 0000000000000..c3858044c0c9f --- /dev/null +++ b/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs @@ -0,0 +1,53 @@ +//@ min-llvm-version: 19 +//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline +// MSVC is different because of the individual allocas. +//@ ignore-msvc + +//@ aux-build:macro_def.rs + +// Find the variable. +// CHECK-DAG: ![[#var_dbg:]] = !DILocalVariable(name: "n",{{( arg: 1,)?}} scope: ![[#var_scope:]] + +// Find both dbg_declares. These will proceed the variable metadata, of course, so we're looking +// backwards. +// CHECK-DAG: dbg_declare(ptr %n.dbg.spill{{[0-9]}}, ![[#var_dbg]], !DIExpression(), ![[#var_loc2:]]) +// CHECK-DAG: dbg_declare(ptr %n.dbg.spill, ![[#var_dbg]], !DIExpression(), ![[#var_loc1:]]) + +// Find the first location definition, looking forwards again. +// CHECK: ![[#var_loc1]] = !DILocation +// CHECK-SAME: scope: ![[#var_scope:]], inlinedAt: ![[#var_inlinedAt1:]] + +// Find the first location's inlinedAt +// NB: If we fail here it's *probably* because we failed to produce two +// different locations and ended up reusing an earlier one. +// CHECK: ![[#var_inlinedAt1]] = !DILocation +// CHECK-SAME: scope: ![[var_inlinedAt1_scope:]] + +// Find the second location definition, still looking forwards. +// NB: If we failed to produce two different locations, the test will +// definitely fail by this point (if it hasn't already) because we won't +// be able to find the same line again. +// CHECK: ![[#var_loc2]] = !DILocation +// CHECK-SAME: scope: ![[#var_scope]], inlinedAt: ![[#var_inlinedAt2:]] + +// Find the second location's inlinedAt. +// CHECK: ![[#var_inlinedAt2]] = !DILocation +// CHECK-SAME: scope: ![[#var_inlinedAt2_scope:]] + +// Finally, check that a discriminator was emitted for the second scope. +// FIXMEkhuey ideally we would check that *either* scope has a discriminator +// but I don't know that it's possible to check that with FileCheck. +// CHECK: ![[#var_inlinedAt2_scope]] = !DILexicalBlockFile +// CHECK-SAME: discriminator: [[#]] +extern crate macro_def; + +use std::env; + +fn square(n: i32) -> i32 { + n * n +} + +fn main() { + let (z1, z2) = macro_def::square_twice!(); + println!("{z1} == {z2}"); +} From ad209060650deea966c9f272c75a7d41e51df4d7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 9 Nov 2024 19:16:43 +0000 Subject: [PATCH 52/79] Suggest turning APITs into generics in opaque overcaptures --- compiler/rustc_lint/messages.ftl | 1 - .../rustc_lint/src/impl_trait_overcaptures.rs | 46 ++----- compiler/rustc_trait_selection/messages.ftl | 6 +- compiler/rustc_trait_selection/src/errors.rs | 124 +++++++++++++++++- .../precise-capturing/overcaptures-2024.fixed | 8 ++ .../precise-capturing/overcaptures-2024.rs | 8 ++ .../overcaptures-2024.stderr | 50 ++++++- 7 files changed, 202 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 9187f6caad43c..6e35d89b48800 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -346,7 +346,6 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos *[other] these lifetimes are } in scope but not mentioned in the type's bounds .note2 = all lifetimes in scope will be captured by `impl Trait`s in edition 2024 - .suggestion = use the precise capturing `use<...>` syntax to make the captures explicit lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant .suggestion = remove the `use<...>` syntax diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 002ab027982eb..62eaa51392b39 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -3,7 +3,7 @@ use std::cell::LazyCell; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{Applicability, LintDiagnostic}; +use rustc_errors::{LintDiagnostic, Subdiagnostic}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -22,6 +22,7 @@ use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; use rustc_span::{Span, Symbol}; +use rustc_trait_selection::errors::{impl_trait_overcapture_suggestion, AddPreciseCapturingForOvercapture}; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt; @@ -334,32 +335,12 @@ where // If we have uncaptured args, and if the opaque doesn't already have // `use<>` syntax on it, and we're < edition 2024, then warn the user. if !uncaptured_args.is_empty() { - let suggestion = if let Ok(snippet) = - self.tcx.sess.source_map().span_to_snippet(opaque_span) - && snippet.starts_with("impl ") - { - let (lifetimes, others): (Vec<_>, Vec<_>) = - captured.into_iter().partition(|def_id| { - self.tcx.def_kind(*def_id) == DefKind::LifetimeParam - }); - // Take all lifetime params first, then all others (ty/ct). - let generics: Vec<_> = lifetimes - .into_iter() - .chain(others) - .map(|def_id| self.tcx.item_name(def_id).to_string()) - .collect(); - // Make sure that we're not trying to name any APITs - if generics.iter().all(|name| !name.starts_with("impl ")) { - Some(( - format!(" + use<{}>", generics.join(", ")), - opaque_span.shrink_to_hi(), - )) - } else { - None - } - } else { - None - }; + let suggestion = impl_trait_overcapture_suggestion( + self.tcx, + opaque_def_id, + self.parent_def_id, + captured, + ); let uncaptured_spans: Vec<_> = uncaptured_args .into_iter() @@ -451,7 +432,7 @@ struct ImplTraitOvercapturesLint<'tcx> { uncaptured_spans: Vec, self_ty: Ty<'tcx>, num_captured: usize, - suggestion: Option<(String, Span)>, + suggestion: Option, } impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> { @@ -461,13 +442,8 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> { .arg("num_captured", self.num_captured) .span_note(self.uncaptured_spans, fluent::lint_note) .note(fluent::lint_note2); - if let Some((suggestion, span)) = self.suggestion { - diag.span_suggestion( - span, - fluent::lint_suggestion, - suggestion, - Applicability::MachineApplicable, - ); + if let Some(suggestion) = self.suggestion { + suggestion.add_to_diag(diag); } } } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 3ddd23924b5f4..6ca1db3a1dea1 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -280,6 +280,8 @@ trait_selection_outlives_content = lifetime of reference outlives lifetime of bo trait_selection_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it trait_selection_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` +trait_selection_precise_capturing_overcaptures = use the precise capturing `use<...>` syntax to make the captures explicit + trait_selection_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate trait_selection_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... @@ -455,7 +457,9 @@ trait_selection_unable_to_construct_constant_value = unable to construct a const trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}` .help = expect either a generic argument name or {"`{Self}`"} as format argument -trait_selection_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable +trait_selection_warn_removing_apit_params_for_undercapture = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable + +trait_selection_warn_removing_apit_params_for_overcapture = you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable trait_selection_where_copy_predicates = copy the `where` clause predicates from the trait diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 455e3ec751e63..bd723cad5116b 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,13 +1,14 @@ use std::path::PathBuf; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; +use rustc_hir::def::DefKind; use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{FnRetTy, GenericParamKind}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -1792,6 +1793,123 @@ impl Subdiagnostic for AddPreciseCapturingAndParams { self.suggs, Applicability::MaybeIncorrect, ); - diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params); + diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params_for_undercapture); } } + +pub fn impl_trait_overcapture_suggestion<'tcx>( + tcx: TyCtxt<'tcx>, + opaque_def_id: LocalDefId, + fn_def_id: LocalDefId, + captured_args: FxIndexSet, +) -> Option { + let generics = tcx.generics_of(fn_def_id); + + let mut captured_lifetimes = FxIndexSet::default(); + let mut captured_non_lifetimes = FxIndexSet::default(); + let mut synthetics = vec![]; + + for arg in captured_args { + if tcx.def_kind(arg) == DefKind::LifetimeParam { + captured_lifetimes.insert(tcx.item_name(arg)); + } else { + let idx = generics.param_def_id_to_index(tcx, arg).expect("expected arg in scope"); + let param = generics.param_at(idx as usize, tcx); + if param.kind.is_synthetic() { + synthetics.push((tcx.def_span(arg), param.name)); + } else { + captured_non_lifetimes.insert(tcx.item_name(arg)); + } + } + } + + let mut next_fresh_param = || { + ["T", "U", "V", "W", "X", "Y", "A", "B", "C"] + .into_iter() + .map(Symbol::intern) + .chain((0..).map(|i| Symbol::intern(&format!("T{i}")))) + .find(|s| captured_non_lifetimes.insert(*s)) + .unwrap() + }; + + let mut suggs = vec![]; + let mut apit_spans = vec![]; + + if !synthetics.is_empty() { + let mut new_params = String::new(); + for (i, (span, name)) in synthetics.into_iter().enumerate() { + apit_spans.push(span); + + let fresh_param = next_fresh_param(); + + // Suggest renaming. + suggs.push((span, fresh_param.to_string())); + + // Super jank. Turn `impl Trait` into `T: Trait`. + // + // This currently involves stripping the `impl` from the name of + // the parameter, since APITs are always named after how they are + // rendered in the AST. This sucks! But to recreate the bound list + // from the APIT itself would be miserable, so we're stuck with + // this for now! + if i > 0 { + new_params += ", "; + } + let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start(); + new_params += fresh_param.as_str(); + new_params += ": "; + new_params += name_as_bounds; + } + + let Some(generics) = tcx.hir().get_generics(fn_def_id) else { + // This shouldn't happen, but don't ICE. + return None; + }; + + // Add generics or concatenate to the end of the list. + suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() { + (params_span, format!(", {new_params}")) + } else { + (generics.span, format!("<{new_params}>")) + }); + } + + let concatenated_bounds = captured_lifetimes + .into_iter() + .chain(captured_non_lifetimes) + .map(|sym| sym.to_string()) + .collect::>() + .join(", "); + + suggs.push(( + tcx.def_span(opaque_def_id).shrink_to_hi(), + format!(" + use<{concatenated_bounds}>"), + )); + + Some(AddPreciseCapturingForOvercapture { + suggs, + apit_spans, + }) +} + +pub struct AddPreciseCapturingForOvercapture { + pub suggs: Vec<(Span, String)>, + pub apit_spans: Vec, +} + +impl Subdiagnostic for AddPreciseCapturingForOvercapture { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + diag.multipart_suggestion_verbose( + fluent::trait_selection_precise_capturing_overcaptures, + self.suggs, + Applicability::MaybeIncorrect, + ); + if !self.apit_spans.is_empty() { + diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params_for_overcapture); + } + } +} \ No newline at end of file diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed index 89a3f3136c82a..6a9d72d028c85 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed @@ -29,4 +29,12 @@ fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +fn apit(_: &T) -> impl Sized + use {} +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + +fn apit2(_: &T, _: U) -> impl Sized + use {} +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs index 18c04f9f799cb..3a4f5ebb7fb1a 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs @@ -29,4 +29,12 @@ fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +fn apit(_: &impl Sized) -> impl Sized {} +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + +fn apit2(_: &impl Sized, _: U) -> impl Sized {} +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index 94dafb04d64ad..c101b980c71ae 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -79,5 +79,53 @@ help: use the precise capturing `use<...>` syntax to make the captures explicit LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} | +++++++ -error: aborting due to 4 previous errors +error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 + --> $DIR/overcaptures-2024.rs:32:28 + | +LL | fn apit(_: &impl Sized) -> impl Sized {} + | ^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: specifically, this lifetime is in scope but not mentioned in the type's bounds + --> $DIR/overcaptures-2024.rs:32:12 + | +LL | fn apit(_: &impl Sized) -> impl Sized {} + | ^ + = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 +note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable + --> $DIR/overcaptures-2024.rs:32:13 + | +LL | fn apit(_: &impl Sized) -> impl Sized {} + | ^^^^^^^^^^ +help: use the precise capturing `use<...>` syntax to make the captures explicit + | +LL | fn apit(_: &T) -> impl Sized + use {} + | ++++++++++ ~ ++++++++ + +error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 + --> $DIR/overcaptures-2024.rs:36:38 + | +LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} + | ^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: specifically, this lifetime is in scope but not mentioned in the type's bounds + --> $DIR/overcaptures-2024.rs:36:16 + | +LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} + | ^ + = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 +note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable + --> $DIR/overcaptures-2024.rs:36:17 + | +LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} + | ^^^^^^^^^^ +help: use the precise capturing `use<...>` syntax to make the captures explicit + | +LL | fn apit2(_: &T, _: U) -> impl Sized + use {} + | ++++++++++ ~ +++++++++++ + +error: aborting due to 6 previous errors From a1f9d5bfbaa967ac91b862894d84e7b27b85d971 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 9 Nov 2024 19:41:28 +0000 Subject: [PATCH 53/79] Dont suggest use --- .../src/diagnostics/opaque_suggestions.rs | 71 ++++++++++++------- .../rustc_lint/src/impl_trait_overcaptures.rs | 4 +- compiler/rustc_trait_selection/messages.ftl | 8 +-- compiler/rustc_trait_selection/src/errors.rs | 33 +++++---- .../precise-capturing/migration-note.rs | 15 ++++ .../precise-capturing/migration-note.stderr | 58 +++++++++++---- 6 files changed, 133 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs index bfd7e83501c7d..d77c53a398447 100644 --- a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs +++ b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs @@ -4,15 +4,16 @@ use std::ops::ControlFlow; use either::Either; +use itertools::Itertools as _; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, Diag}; +use rustc_errors::{Diag, Subdiagnostic}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::{self, ConstraintCategory, Location}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_span::Symbol; +use rustc_trait_selection::errors::impl_trait_overcapture_suggestion; use crate::MirBorrowckCtxt; use crate::borrow_set::BorrowData; @@ -61,6 +62,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // *does* mention. We'll use that for the `+ use<'a>` suggestion below. let mut visitor = CheckExplicitRegionMentionAndCollectGenerics { tcx, + generics: tcx.generics_of(opaque_def_id), offending_region_idx, seen_opaques: [opaque_def_id].into_iter().collect(), seen_lifetimes: Default::default(), @@ -83,34 +85,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { "this call may capture more lifetimes than intended, \ because Rust 2024 has adjusted the `impl Trait` lifetime capture rules", ); - let mut seen_generics: Vec<_> = - visitor.seen_lifetimes.iter().map(ToString::to_string).collect(); - // Capture all in-scope ty/const params. - seen_generics.extend( - ty::GenericArgs::identity_for_item(tcx, opaque_def_id) - .iter() - .filter(|arg| { - matches!( - arg.unpack(), - ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) - ) - }) - .map(|arg| arg.to_string()), - ); - if opaque_def_id.is_local() { - diag.span_suggestion_verbose( - tcx.def_span(opaque_def_id).shrink_to_hi(), - "add a precise capturing bound to avoid overcapturing", - format!(" + use<{}>", seen_generics.join(", ")), - Applicability::MaybeIncorrect, - ); + let mut captured_args = visitor.seen_lifetimes; + // Add in all of the type and const params, too. + // Ordering here is kinda strange b/c we're walking backwards, + // but we're trying to provide *a* suggestion, not a nice one. + let mut next_generics = Some(visitor.generics); + let mut any_synthetic = false; + while let Some(generics) = next_generics { + for param in &generics.own_params { + if param.kind.is_ty_or_const() { + captured_args.insert(param.def_id); + } + if param.kind.is_synthetic() { + any_synthetic = true; + } + } + next_generics = generics.parent.map(|def_id| tcx.generics_of(def_id)); + } + + if let Some(opaque_def_id) = opaque_def_id.as_local() + && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = + tcx.hir().expect_opaque_ty(opaque_def_id).origin + { + if let Some(sugg) = impl_trait_overcapture_suggestion( + tcx, + opaque_def_id, + parent, + captured_args, + ) { + sugg.add_to_diag(diag); + } } else { diag.span_help( tcx.def_span(opaque_def_id), format!( "if you can modify this crate, add a precise \ capturing bound to avoid overcapturing: `+ use<{}>`", - seen_generics.join(", ") + if any_synthetic { + "/* Args */".to_string() + } else { + captured_args + .into_iter() + .map(|def_id| tcx.item_name(def_id)) + .join(", ") + } ), ); } @@ -182,9 +200,10 @@ impl<'tcx> TypeVisitor> for FindOpaqueRegion<'_, 'tcx> { struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> { tcx: TyCtxt<'tcx>, + generics: &'tcx ty::Generics, offending_region_idx: usize, seen_opaques: FxIndexSet, - seen_lifetimes: FxIndexSet, + seen_lifetimes: FxIndexSet, } impl<'tcx> TypeVisitor> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> { @@ -214,7 +233,7 @@ impl<'tcx> TypeVisitor> for CheckExplicitRegionMentionAndCollectGen if param.index as usize == self.offending_region_idx { ControlFlow::Break(()) } else { - self.seen_lifetimes.insert(param.name); + self.seen_lifetimes.insert(self.generics.region_param(param, self.tcx).def_id); ControlFlow::Continue(()) } } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 62eaa51392b39..036e0381a067c 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -22,7 +22,9 @@ use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; use rustc_span::{Span, Symbol}; -use rustc_trait_selection::errors::{impl_trait_overcapture_suggestion, AddPreciseCapturingForOvercapture}; +use rustc_trait_selection::errors::{ + AddPreciseCapturingForOvercapture, impl_trait_overcapture_suggestion, +}; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt; diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 6ca1db3a1dea1..1ab89ecde7a44 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -280,10 +280,10 @@ trait_selection_outlives_content = lifetime of reference outlives lifetime of bo trait_selection_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it trait_selection_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` -trait_selection_precise_capturing_overcaptures = use the precise capturing `use<...>` syntax to make the captures explicit - trait_selection_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate +trait_selection_precise_capturing_overcaptures = use the precise capturing `use<...>` syntax to make the captures explicit + trait_selection_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... trait_selection_prlf_defined_without_sub = the lifetime defined here... trait_selection_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 for more information) @@ -457,10 +457,10 @@ trait_selection_unable_to_construct_constant_value = unable to construct a const trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}` .help = expect either a generic argument name or {"`{Self}`"} as format argument -trait_selection_warn_removing_apit_params_for_undercapture = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable - trait_selection_warn_removing_apit_params_for_overcapture = you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable +trait_selection_warn_removing_apit_params_for_undercapture = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable + trait_selection_where_copy_predicates = copy the `where` clause predicates from the trait trait_selection_where_remove = remove the `where` clause diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index bd723cad5116b..3e06d0807d81b 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -6,8 +6,8 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; -use rustc_hir::def::DefKind; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{Visitor, walk_ty}; use rustc_hir::{FnRetTy, GenericParamKind}; @@ -1793,10 +1793,17 @@ impl Subdiagnostic for AddPreciseCapturingAndParams { self.suggs, Applicability::MaybeIncorrect, ); - diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params_for_undercapture); + diag.span_note( + self.apit_spans, + fluent::trait_selection_warn_removing_apit_params_for_undercapture, + ); } } +/// Given a set of captured `DefId` for an RPIT (opaque_def_id) and a given +/// function (fn_def_id), try to suggest adding `+ use<...>` to capture just +/// the specified parameters. If one of those parameters is an APIT, then try +/// to suggest turning it into a regular type parameter. pub fn impl_trait_overcapture_suggestion<'tcx>( tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId, @@ -1839,12 +1846,12 @@ pub fn impl_trait_overcapture_suggestion<'tcx>( let mut new_params = String::new(); for (i, (span, name)) in synthetics.into_iter().enumerate() { apit_spans.push(span); - + let fresh_param = next_fresh_param(); - + // Suggest renaming. suggs.push((span, fresh_param.to_string())); - + // Super jank. Turn `impl Trait` into `T: Trait`. // // This currently involves stripping the `impl` from the name of @@ -1860,12 +1867,12 @@ pub fn impl_trait_overcapture_suggestion<'tcx>( new_params += ": "; new_params += name_as_bounds; } - + let Some(generics) = tcx.hir().get_generics(fn_def_id) else { // This shouldn't happen, but don't ICE. return None; }; - + // Add generics or concatenate to the end of the list. suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() { (params_span, format!(", {new_params}")) @@ -1886,10 +1893,7 @@ pub fn impl_trait_overcapture_suggestion<'tcx>( format!(" + use<{concatenated_bounds}>"), )); - Some(AddPreciseCapturingForOvercapture { - suggs, - apit_spans, - }) + Some(AddPreciseCapturingForOvercapture { suggs, apit_spans }) } pub struct AddPreciseCapturingForOvercapture { @@ -1909,7 +1913,10 @@ impl Subdiagnostic for AddPreciseCapturingForOvercapture { Applicability::MaybeIncorrect, ); if !self.apit_spans.is_empty() { - diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params_for_overcapture); + diag.span_note( + self.apit_spans, + fluent::trait_selection_warn_removing_apit_params_for_overcapture, + ); } } -} \ No newline at end of file +} diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs index a5bade4ddc53a..1d98750f6dde2 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.rs +++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs @@ -187,4 +187,19 @@ fn returned() -> impl Sized { } //~^ NOTE `x` dropped here while still borrowed +fn capture_apit(x: &impl Sized) -> impl Sized {} +//~^ NOTE you could use a `use<...>` bound to explicitly specify captures, but + +fn test_apit() { + let x = String::new(); + //~^ NOTE binding `x` declared here + let y = capture_apit(&x); + //~^ NOTE borrow of `x` occurs here + //~| NOTE this call may capture more lifetimes than intended + drop(x); + //~^ ERROR cannot move out of `x` because it is borrowed + //~| NOTE move out of `x` occurs here +} +//~^ NOTE borrow might be used here, when `y` is dropped + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr index 3ac47ed1bcd38..a859a114dbc55 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.stderr +++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr @@ -30,7 +30,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_len(&x); | ^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_len(x: &Vec) -> impl Display + use { | ++++++++ @@ -55,7 +55,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_len(&x); | ^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_len(x: &Vec) -> impl Display + use { | ++++++++ @@ -80,7 +80,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_len(&x); | ^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_len(x: &Vec) -> impl Display + use { | ++++++++ @@ -106,7 +106,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_len_mut(&mut x); | ^^^^^^^^^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { | ++++++++ @@ -131,7 +131,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_len_mut(&mut x); | ^^^^^^^^^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { | ++++++++ @@ -156,7 +156,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_len_mut(&mut x); | ^^^^^^^^^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { | ++++++++ @@ -182,7 +182,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_field(&s.f); | ^^^^^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_field(t: &T) -> impl Display + use { | ++++++++ @@ -204,7 +204,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_field(&mut s.f); | ^^^^^^^^^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_field(t: &T) -> impl Display + use { | ++++++++ @@ -226,7 +226,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | let a = display_field(&mut s.f); | ^^^^^^^^^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_field(t: &T) -> impl Display + use { | ++++++++ @@ -252,7 +252,7 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has | LL | x = display_len(&z.f); | ^^^^^^^^^^^^^^^^^ -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_len(x: &Vec) -> impl Display + use { | ++++++++ @@ -273,12 +273,46 @@ note: this call may capture more lifetimes than intended, because Rust 2024 has LL | let x = { let x = display_len(&mut vec![0]); x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) -help: add a precise capturing bound to avoid overcapturing +help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn display_len(x: &Vec) -> impl Display + use { | ++++++++ -error: aborting due to 12 previous errors +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/migration-note.rs:199:10 + | +LL | let x = String::new(); + | - binding `x` declared here +LL | +LL | let y = capture_apit(&x); + | -- borrow of `x` occurs here +... +LL | drop(x); + | ^ move out of `x` occurs here +... +LL | } + | - borrow might be used here, when `y` is dropped and runs the destructor for type `impl Sized` + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:196:13 + | +LL | let y = capture_apit(&x); + | ^^^^^^^^^^^^^^^^ +note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable + --> $DIR/migration-note.rs:190:21 + | +LL | fn capture_apit(x: &impl Sized) -> impl Sized {} + | ^^^^^^^^^^ +help: use the precise capturing `use<...>` syntax to make the captures explicit + | +LL | fn capture_apit(x: &T) -> impl Sized + use {} + | ++++++++++ ~ ++++++++ +help: consider cloning the value if the performance cost is acceptable + | +LL | let y = capture_apit(&x.clone()); + | ++++++++ + +error: aborting due to 13 previous errors Some errors have detailed explanations: E0499, E0502, E0503, E0505, E0506, E0597, E0716. For more information about an error, try `rustc --explain E0499`. From 2b469607b4337e2c8996e755570202feb33124fe Mon Sep 17 00:00:00 2001 From: nora <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 9 Nov 2024 22:45:17 +0100 Subject: [PATCH 54/79] Exclude relnotes-tracking-issue from needs-triage --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 5d80b9e656ea0..a7ae754aefd66 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -395,6 +395,7 @@ new_issue = true exclude_labels = [ "C-tracking-issue", "A-diagnostics", + "relnotes-tracking-issue", ] [autolabel."WG-trait-system-refactor"] From 822762c966b0c8e85c0a552929a5a9c53bf93a97 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Nov 2024 22:19:35 +0100 Subject: [PATCH 55/79] require const_impl_trait gate for all conditional and trait const calls --- compiler/rustc_const_eval/messages.ftl | 4 + .../src/check_consts/check.rs | 89 ++++------- .../rustc_const_eval/src/check_consts/ops.rs | 39 +++-- compiler/rustc_const_eval/src/errors.rs | 10 ++ tests/ui/traits/const-traits/cross-crate.rs | 4 +- .../const-traits/cross-crate.stock.stderr | 28 +--- .../const-traits/cross-crate.stocknc.stderr | 53 +------ .../const-traits/staged-api-user-crate.rs | 3 +- .../const-traits/staged-api-user-crate.stderr | 24 +-- tests/ui/traits/const-traits/staged-api.rs | 50 +++---- .../const-traits/staged-api.stable.stderr | 89 ----------- .../ui/traits/const-traits/staged-api.stderr | 139 ++++++++++++++++++ .../const-traits/staged-api.unstable.stderr | 108 -------------- 13 files changed, 250 insertions(+), 390 deletions(-) delete mode 100644 tests/ui/traits/const-traits/staged-api.stable.stderr create mode 100644 tests/ui/traits/const-traits/staged-api.stderr delete mode 100644 tests/ui/traits/const-traits/staged-api.unstable.stderr diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 826e34930eae7..15027ae0c187a 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -25,6 +25,10 @@ const_eval_closure_fndef_not_const = function defined here, but it is not `const` const_eval_closure_non_const = cannot call non-const closure in {const_eval_const_context}s + +const_eval_conditionally_const_call = + cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s + const_eval_consider_dereferencing = consider dereferencing here diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index aea3d5bd3e70f..8cd0ecb3e4e6e 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -15,7 +15,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; @@ -361,31 +361,21 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { !is_transient } + /// Returns whether there are const-conditions. fn revalidate_conditional_constness( &mut self, callee: DefId, callee_args: ty::GenericArgsRef<'tcx>, - call_source: CallSource, call_span: Span, - ) { + ) -> bool { let tcx = self.tcx; if !tcx.is_conditionally_const(callee) { - return; + return false; } let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args); - // If there are any const conditions on this fn and `const_trait_impl` - // is not enabled, simply bail. We shouldn't be able to call conditionally - // const functions on stable. - if !const_conditions.is_empty() && !tcx.features().const_trait_impl() { - self.check_op(ops::FnCallNonConst { - callee, - args: callee_args, - span: call_span, - call_source, - feature: Some(sym::const_trait_impl), - }); - return; + if const_conditions.is_empty() { + return false; } let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx)); @@ -421,6 +411,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { tcx.dcx() .span_delayed_bug(call_span, "this should have reported a ~const error in HIR"); } + + true } } @@ -627,11 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { _ => unreachable!(), }; - let ConstCx { tcx, body, param_env, .. } = *self.ccx; + let ConstCx { tcx, body, .. } = *self.ccx; let fn_ty = func.ty(body, tcx); - let (mut callee, mut fn_args) = match *fn_ty.kind() { + let (callee, fn_args) = match *fn_ty.kind() { ty::FnDef(def_id, fn_args) => (def_id, fn_args), ty::FnPtr(..) => { @@ -645,57 +637,38 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } }; - self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span); + let has_const_conditions = + self.revalidate_conditional_constness(callee, fn_args, *fn_span); - let mut is_trait = false; // Attempting to call a trait method? if let Some(trait_did) = tcx.trait_of_item(callee) { - trace!("attempting to call a trait method"); + // We can't determine the actual callee here, so we have to do different checks + // than usual. + trace!("attempting to call a trait method"); let trait_is_const = tcx.is_const_trait(trait_did); - // trait method calls are only permitted when `effects` is enabled. - // typeck ensures the conditions for calling a const trait method are met, - // so we only error if the trait isn't const. We try to resolve the trait - // into the concrete method, and uses that for const stability checks. - // FIXME(const_trait_impl) we might consider moving const stability checks - // to typeck as well. - if tcx.features().const_trait_impl() && trait_is_const { - // This skips the check below that ensures we only call `const fn`. - is_trait = true; - - if let Ok(Some(instance)) = - Instance::try_resolve(tcx, param_env, callee, fn_args) - && let InstanceKind::Item(def) = instance.def - { - // Resolve a trait method call to its concrete implementation, which may be in a - // `const` trait impl. This is only used for the const stability check below, since - // we want to look at the concrete impl's stability. - fn_args = instance.args; - callee = def; - } + + if trait_is_const { + // Trait calls are always conditionally-const. + self.check_op(ops::ConditionallyConstCall { callee, args: fn_args }); + // FIXME(const_trait_impl): do a more fine-grained check whether this + // particular trait can be const-stably called. } else { - // if the trait is const but the user has not enabled the feature(s), - // suggest them. - let feature = if trait_is_const { - Some(if tcx.features().const_trait_impl() { - sym::effects - } else { - sym::const_trait_impl - }) - } else { - None - }; + // Not even a const trait. self.check_op(ops::FnCallNonConst { callee, args: fn_args, span: *fn_span, call_source, - feature, }); - // If we allowed this, we're in miri-unleashed mode, so we might - // as well skip the remaining checks. - return; } + // That's all we can check here. + return; + } + + // Even if we know the callee, ensure we can use conditionally-const calls. + if has_const_conditions { + self.check_op(ops::ConditionallyConstCall { callee, args: fn_args }); } // At this point, we are calling a function, `callee`, whose `DefId` is known... @@ -783,14 +756,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { return; } - // Trait functions are not `const fn` so we have to skip them here. - if !tcx.is_const_fn(callee) && !is_trait { + if !tcx.is_const_fn(callee) { self.check_op(ops::FnCallNonConst { callee, args: fn_args, span: *fn_span, call_source, - feature: None, }); // If we allowed this, we're in miri-unleashed mode, so we might // as well skip the remaining checks. diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 2931159842f95..5b745e6dffd6c 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -70,6 +70,34 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { } } +/// A call to a function that is in a trait, or has trait bounds that make it conditionally-const. +#[derive(Debug)] +pub(crate) struct ConditionallyConstCall<'tcx> { + pub callee: DefId, + pub args: GenericArgsRef<'tcx>, +} + +impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { + fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { + // We use the `const_trait_impl` gate for all conditionally-const calls. + Status::Unstable { + gate: sym::const_trait_impl, + safe_to_expose_on_stable: false, + // We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint + is_function_call: false, + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { + ccx.dcx().create_err(errors::ConditionallyConstCall { + span, + def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args), + def_descr: ccx.tcx.def_descr(self.callee), + kind: ccx.const_kind(), + }) + } +} + /// A function call where the callee is not marked as `const`. #[derive(Debug, Clone, Copy)] pub(crate) struct FnCallNonConst<'tcx> { @@ -77,7 +105,6 @@ pub(crate) struct FnCallNonConst<'tcx> { pub args: GenericArgsRef<'tcx>, pub span: Span, pub call_source: CallSource, - pub feature: Option, } impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { @@ -85,7 +112,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> { - let FnCallNonConst { callee, args, span, call_source, feature } = *self; + let FnCallNonConst { callee, args, span, call_source } = *self; let ConstCx { tcx, param_env, .. } = *ccx; let caller = ccx.def_id(); @@ -285,14 +312,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx.const_kind(), )); - if let Some(feature) = feature { - ccx.tcx.disabled_nightly_features( - &mut err, - Some(ccx.tcx.local_def_id_to_hir_id(caller)), - [(String::new(), feature)], - ); - } - if let ConstContext::Static(_) = ccx.const_kind() { err.note(fluent_generated::const_eval_lazy_lock); } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 14e8bebbb180b..604e5ed61a35b 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -176,6 +176,16 @@ pub(crate) struct NonConstFmtMacroCall { pub kind: ConstContext, } +#[derive(Diagnostic)] +#[diag(const_eval_conditionally_const_call)] +pub(crate) struct ConditionallyConstCall { + #[primary_span] + pub span: Span, + pub def_path_str: String, + pub def_descr: &'static str, + pub kind: ConstContext, +} + #[derive(Diagnostic)] #[diag(const_eval_non_const_fn_call, code = E0015)] pub(crate) struct NonConstFnCall { diff --git a/tests/ui/traits/const-traits/cross-crate.rs b/tests/ui/traits/const-traits/cross-crate.rs index 9558ec6164ede..b07aa8944c05d 100644 --- a/tests/ui/traits/const-traits/cross-crate.rs +++ b/tests/ui/traits/const-traits/cross-crate.rs @@ -18,11 +18,9 @@ const fn const_context() { #[cfg(any(stocknc, gatednc))] NonConst.func(); //[stocknc]~^ ERROR: cannot call - //[stocknc]~| ERROR: cannot call - //[gatednc]~^^^ ERROR: the trait bound + //[gatednc]~^^ ERROR: the trait bound Const.func(); //[stock,stocknc]~^ ERROR: cannot call - //[stock,stocknc]~| ERROR: cannot call } fn main() {} diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr index b35891071b0f0..d26228f6958fc 100644 --- a/tests/ui/traits/const-traits/cross-crate.stock.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr @@ -1,28 +1,8 @@ -error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:23:11 +error: cannot call conditionally-const method `::func` in constant functions + --> $DIR/cross-crate.rs:22:5 | LL | Const.func(); - | ^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | - -error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:23:11 - | -LL | Const.func(); - | ^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | + | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr index 89de89159dbf1..9b37286026216 100644 --- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr @@ -1,53 +1,14 @@ -error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:19:14 +error: cannot call conditionally-const method `::func` in constant functions + --> $DIR/cross-crate.rs:19:5 | LL | NonConst.func(); - | ^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | - -error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:19:14 - | -LL | NonConst.func(); - | ^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | + | ^^^^^^^^^^^^^^^ -error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:23:11 +error: cannot call conditionally-const method `::func` in constant functions + --> $DIR/cross-crate.rs:22:5 | LL | Const.func(); - | ^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | - -error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/cross-crate.rs:23:11 - | -LL | Const.func(); - | ^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | + | ^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.rs b/tests/ui/traits/const-traits/staged-api-user-crate.rs index c820d1ff47cb4..7587042cf276d 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.rs +++ b/tests/ui/traits/const-traits/staged-api-user-crate.rs @@ -10,8 +10,7 @@ fn non_const_context() { const fn stable_const_context() { Unstable::func(); - //~^ ERROR cannot call non-const fn `::func` in constant functions - //~| ERROR cannot call non-const fn `::func` in constant functions + //~^ ERROR cannot call conditionally-const associated function `::func` in constant functions } fn main() {} diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr index 24cdb1d3d5a30..2bce230ffdf4f 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -1,28 +1,8 @@ -error[E0015]: cannot call non-const fn `::func` in constant functions +error: cannot call conditionally-const associated function `::func` in constant functions --> $DIR/staged-api-user-crate.rs:12:5 | LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | - -error[E0015]: cannot call non-const fn `::func` in constant functions - --> $DIR/staged-api-user-crate.rs:12:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - | -LL + #![feature(const_trait_impl)] - | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs index 401a81d81425e..755a4e456bcf9 100644 --- a/tests/ui/traits/const-traits/staged-api.rs +++ b/tests/ui/traits/const-traits/staged-api.rs @@ -1,10 +1,11 @@ -//@ revisions: stable unstable +//! Checks whether we are properly enforcing recursive const stability for trait calls. //@ compile-flags: -Znext-solver -#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file. -#![cfg_attr(unstable, feature(local_feature))] +#![feature(unstable)] // The feature from the ./auxiliary/staged-api.rs file. +#![feature(local_feature)] #![feature(const_trait_impl)] #![feature(staged_api)] +#![feature(rustc_allow_const_fn_unstable)] #![stable(feature = "rust1", since = "1.0.0")] //@ aux-build: staged-api.rs @@ -16,13 +17,16 @@ use staged_api::*; pub struct Foo; #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))] -#[cfg_attr(stable, rustc_const_stable(feature = "local_feature", since = "1.0.0"))] +#[rustc_const_unstable(feature = "local_feature", issue = "none")] impl const MyTrait for Foo { - //[stable]~^ ERROR trait implementations cannot be const stable yet fn func() {} } +#[rustc_allow_const_fn_unstable(const_trait_impl)] +const fn conditionally_const() { + T::func(); +} + // Const stability has no impact on usage in non-const contexts. fn non_const_context() { Unstable::func(); @@ -32,43 +36,35 @@ fn non_const_context() { #[unstable(feature = "none", issue = "none")] const fn const_context() { Unstable::func(); - //[unstable]~^ ERROR cannot use `#[feature(unstable)]` - //[stable]~^^ ERROR not yet stable as a const fn + //~^ ERROR cannot use `#[feature(const_trait_impl)]` Foo::func(); - //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` - //[stable]~^^ cannot be (indirectly) exposed to stable - // We get the error on `stable` since this is a trait function. + //~^ ERROR cannot use `#[feature(const_trait_impl)]` Unstable2::func(); - //~^ ERROR not yet stable as a const fn - // ^ fails, because the `unstable2` feature is not active + //~^ ERROR cannot use `#[feature(const_trait_impl)]` + conditionally_const::(); + //~^ ERROR cannot use `#[feature(const_trait_impl)]` } #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))] +#[rustc_const_unstable(feature = "local_feature", issue = "none")] pub const fn const_context_not_const_stable() { - //[stable]~^ ERROR function has missing const stability attribute Unstable::func(); - //[stable]~^ ERROR not yet stable as a const fn Foo::func(); - //[stable]~^ cannot be (indirectly) exposed to stable - // We get the error on `stable` since this is a trait function. Unstable2::func(); - //~^ ERROR not yet stable as a const fn - // ^ fails, because the `unstable2` feature is not active + conditionally_const::(); } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "cheese", since = "1.0.0")] const fn stable_const_context() { Unstable::func(); - //[unstable]~^ ERROR cannot use `#[feature(unstable)]` - //[stable]~^^ ERROR not yet stable as a const fn + //~^ ERROR cannot use `#[feature(const_trait_impl)]` Foo::func(); - //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` - //[stable]~^^ cannot be (indirectly) exposed to stable - // We get the error on `stable` since this is a trait function. - const_context_not_const_stable() - //[unstable]~^ ERROR cannot use `#[feature(local_feature)]` + //~^ ERROR cannot use `#[feature(const_trait_impl)]` + const_context_not_const_stable(); + //~^ ERROR cannot use `#[feature(local_feature)]` + conditionally_const::(); + //~^ ERROR cannot use `#[feature(const_trait_impl)]` } fn main() {} diff --git a/tests/ui/traits/const-traits/staged-api.stable.stderr b/tests/ui/traits/const-traits/staged-api.stable.stderr deleted file mode 100644 index 8f491b2f18238..0000000000000 --- a/tests/ui/traits/const-traits/staged-api.stable.stderr +++ /dev/null @@ -1,89 +0,0 @@ -error: trait implementations cannot be const stable yet - --> $DIR/staged-api.rs:21:1 - | -LL | / impl const MyTrait for Foo { -LL | | -LL | | fn func() {} -LL | | } - | |_^ - | - = note: see issue #67792 for more information - -error: function has missing const stability attribute - --> $DIR/staged-api.rs:48:1 - | -LL | / pub const fn const_context_not_const_stable() { -LL | | -LL | | Unstable::func(); -LL | | -... | -LL | | // ^ fails, because the `unstable2` feature is not active -LL | | } - | |_^ - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:34:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable)]` to the crate attributes to enable - -error: `::func` cannot be (indirectly) exposed to stable - --> $DIR/staged-api.rs:37:5 - | -LL | Foo::func(); - | ^^^^^^^^^^^ - | - = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:41:5 - | -LL | Unstable2::func(); - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable2)]` to the crate attributes to enable - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:50:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable)]` to the crate attributes to enable - -error: `::func` cannot be (indirectly) exposed to stable - --> $DIR/staged-api.rs:52:5 - | -LL | Foo::func(); - | ^^^^^^^^^^^ - | - = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:55:5 - | -LL | Unstable2::func(); - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable2)]` to the crate attributes to enable - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:63:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable)]` to the crate attributes to enable - -error: `::func` cannot be (indirectly) exposed to stable - --> $DIR/staged-api.rs:66:5 - | -LL | Foo::func(); - | ^^^^^^^^^^^ - | - = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` - -error: aborting due to 10 previous errors - diff --git a/tests/ui/traits/const-traits/staged-api.stderr b/tests/ui/traits/const-traits/staged-api.stderr new file mode 100644 index 0000000000000..29aafa4e0f32e --- /dev/null +++ b/tests/ui/traits/const-traits/staged-api.stderr @@ -0,0 +1,139 @@ +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:38:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:40:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:42:5 + | +LL | Unstable2::func(); + | ^^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:44:5 + | +LL | conditionally_const::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:60:5 + | +LL | Unstable::func(); + | ^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:62:5 + | +LL | Foo::func(); + | ^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` + --> $DIR/staged-api.rs:64:5 + | +LL | const_context_not_const_stable(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features +help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(local_feature)] +LL | const fn stable_const_context() { + | + +error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]` + --> $DIR/staged-api.rs:66:5 + | +LL | conditionally_const::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) + | +LL + #[rustc_const_unstable(feature = "...", issue = "...")] +LL | const fn stable_const_context() { + | +help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + | +LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] +LL | const fn stable_const_context() { + | + +error: aborting due to 8 previous errors + diff --git a/tests/ui/traits/const-traits/staged-api.unstable.stderr b/tests/ui/traits/const-traits/staged-api.unstable.stderr deleted file mode 100644 index 76275452e90c4..0000000000000 --- a/tests/ui/traits/const-traits/staged-api.unstable.stderr +++ /dev/null @@ -1,108 +0,0 @@ -error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` - --> $DIR/staged-api.rs:34:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) - | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] -LL | const fn const_context() { - | - -error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` - --> $DIR/staged-api.rs:37:5 - | -LL | Foo::func(); - | ^^^^^^^^^^^ - | - = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) - | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local_feature)] -LL | const fn const_context() { - | - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:41:5 - | -LL | Unstable2::func(); - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable2)]` to the crate attributes to enable - -error: `::func` is not yet stable as a const fn - --> $DIR/staged-api.rs:55:5 - | -LL | Unstable2::func(); - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable2)]` to the crate attributes to enable - -error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]` - --> $DIR/staged-api.rs:63:5 - | -LL | Unstable::func(); - | ^^^^^^^^^^^^^^^^ - | - = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) - | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] -LL | const fn stable_const_context() { - | - -error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` - --> $DIR/staged-api.rs:66:5 - | -LL | Foo::func(); - | ^^^^^^^^^^^ - | - = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) - | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local_feature)] -LL | const fn stable_const_context() { - | - -error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]` - --> $DIR/staged-api.rs:70:5 - | -LL | const_context_not_const_stable() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) - | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local_feature)] -LL | const fn stable_const_context() { - | - -error: aborting due to 7 previous errors - From f235b6f9c6788e213b6365103cfa9c6c798fe659 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Nov 2024 23:32:06 +0100 Subject: [PATCH 56/79] give a hint which feature is missing --- .../rustc_const_eval/src/check_consts/ops.rs | 26 ++++++++----------- compiler/rustc_session/src/parse.rs | 1 + compiler/rustc_session/src/session.rs | 1 + .../const-traits/cross-crate.stock.stderr | 7 ++++- .../const-traits/cross-crate.stocknc.stderr | 13 ++++++++-- .../const-traits/staged-api-user-crate.stderr | 7 ++++- 6 files changed, 36 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 5b745e6dffd6c..036ca76328045 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -89,12 +89,15 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> { } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - ccx.dcx().create_err(errors::ConditionallyConstCall { - span, - def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args), - def_descr: ccx.tcx.def_descr(self.callee), - kind: ccx.const_kind(), - }) + ccx.tcx.sess.create_feature_err( + errors::ConditionallyConstCall { + span, + def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args), + def_descr: ccx.tcx.def_descr(self.callee), + kind: ccx.const_kind(), + }, + sym::const_trait_impl, + ) } } @@ -417,15 +420,8 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind()); - if let hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - ) = self.0 - { - ccx.tcx.sess.create_feature_err( - errors::UnallowedOpInConstContext { span, msg }, - sym::const_async_blocks, - ) + if let Status::Unstable { gate, .. } = self.status_in_item(ccx) { + ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate) } else { ccx.dcx().create_err(errors::UnallowedOpInConstContext { span, msg }) } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index f20ae85b8e8a7..21c1165511099 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -155,6 +155,7 @@ pub fn feature_warn_issue( } /// Adds the diagnostics for a feature to an existing error. +/// Must be a language feature! pub fn add_feature_diagnostics( err: &mut Diag<'_, G>, sess: &Session, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 470e372ee48e1..9d9434a77760d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -300,6 +300,7 @@ impl Session { self.opts.test } + /// `feature` must be a language feature. #[track_caller] pub fn create_feature_err<'a>(&'a self, err: impl Diagnostic<'a>, feature: Symbol) -> Diag<'a> { let mut err = self.dcx().create_err(err); diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr index d26228f6958fc..09bf9c023c843 100644 --- a/tests/ui/traits/const-traits/cross-crate.stock.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr @@ -1,8 +1,13 @@ -error: cannot call conditionally-const method `::func` in constant functions +error[E0658]: cannot call conditionally-const method `::func` in constant functions --> $DIR/cross-crate.rs:22:5 | LL | Const.func(); | ^^^^^^^^^^^^ + | + = note: see issue #67792 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr index 9b37286026216..e52e5609b01d4 100644 --- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr +++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr @@ -1,14 +1,23 @@ -error: cannot call conditionally-const method `::func` in constant functions +error[E0658]: cannot call conditionally-const method `::func` in constant functions --> $DIR/cross-crate.rs:19:5 | LL | NonConst.func(); | ^^^^^^^^^^^^^^^ + | + = note: see issue #67792 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: cannot call conditionally-const method `::func` in constant functions +error[E0658]: cannot call conditionally-const method `::func` in constant functions --> $DIR/cross-crate.rs:22:5 | LL | Const.func(); | ^^^^^^^^^^^^ + | + = note: see issue #67792 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr index 2bce230ffdf4f..bf7466b8e1666 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -1,8 +1,13 @@ -error: cannot call conditionally-const associated function `::func` in constant functions +error[E0658]: cannot call conditionally-const associated function `::func` in constant functions --> $DIR/staged-api-user-crate.rs:12:5 | LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ + | + = note: see issue #67792 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0658`. From be30861174202b669f69ad43d4d4545beeb9b800 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 9 Nov 2024 18:12:21 -0500 Subject: [PATCH 57/79] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 0310497822a7a..4a2d8dc636445 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 0310497822a7a673a330a5dd068b7aaa579a265e +Subproject commit 4a2d8dc636445b276288543882e076f254b3ae95 From 7312b41239c83112f57cd495a0d516d2f3547fa5 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 9 Nov 2024 22:55:20 +0100 Subject: [PATCH 58/79] Unify disallowed-positions test files into one file Also make the file have a third mode for where everything is cfg'd out to make sure it's an early error. --- ...sallowed-positions-without-feature-gate.rs | 340 ----- ...rr => disallowed-positions.feature.stderr} | 276 ++-- .../disallowed-positions.no_feature.stderr | 1111 +++++++++++++++++ ... => disallowed-positions.nofeature.stderr} | 410 +++--- .../disallowed-positions.nothing.stderr | 862 +++++++++++++ .../disallowed-positions.rs | 58 +- 6 files changed, 2405 insertions(+), 652 deletions(-) delete mode 100644 tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs rename tests/ui/rfcs/rfc-2497-if-let-chains/{disallowed-positions.stderr => disallowed-positions.feature.stderr} (84%) create mode 100644 tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr rename tests/ui/rfcs/rfc-2497-if-let-chains/{disallowed-positions-without-feature-gate.stderr => disallowed-positions.nofeature.stderr} (70%) create mode 100644 tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs deleted file mode 100644 index 096036bb1333a..0000000000000 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs +++ /dev/null @@ -1,340 +0,0 @@ -// Check that we don't suggest enabling a feature for code that's -// not accepted even with that feature. - -#![allow(irrefutable_let_patterns)] - -use std::ops::Range; - -fn main() {} - -fn _if() { - if (let 0 = 1) {} - //~^ ERROR expected expression, found `let` statement - - if (((let 0 = 1))) {} - //~^ ERROR expected expression, found `let` statement - - if (let 0 = 1) && true {} - //~^ ERROR expected expression, found `let` statement - - if true && (let 0 = 1) {} - //~^ ERROR expected expression, found `let` statement - - if (let 0 = 1) && (let 0 = 1) {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement - - if (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement -} - -fn _while() { - while (let 0 = 1) {} - //~^ ERROR expected expression, found `let` statement - - while (((let 0 = 1))) {} - //~^ ERROR expected expression, found `let` statement - - while (let 0 = 1) && true {} - //~^ ERROR expected expression, found `let` statement - - while true && (let 0 = 1) {} - //~^ ERROR expected expression, found `let` statement - - while (let 0 = 1) && (let 0 = 1) {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement - - while (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement -} - -fn _macros() { - macro_rules! use_expr { - ($e:expr) => { - if $e {} - while $e {} - } - } - use_expr!((let 0 = 1 && 0 == 0)); - //~^ ERROR expected expression, found `let` statement - use_expr!((let 0 = 1)); - //~^ ERROR expected expression, found `let` statement -} - -fn nested_within_if_expr() { - if &let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - - if !let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - if *let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - if -let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - - fn _check_try_binds_tighter() -> Result<(), ()> { - if let 0 = 0? {} - //~^ ERROR the `?` operator can only be applied to values that implement `Try` - Ok(()) - } - if (let 0 = 0)? {} - //~^ ERROR expected expression, found `let` statement - - if true || let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - if (true || let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - if true && (true || let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - if true || (true && let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - - let mut x = true; - if x = let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - - if true..(let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - if ..(let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - if (let 0 = 0).. {} - //~^ ERROR expected expression, found `let` statement - - // Binds as `(let ... = true)..true &&/|| false`. - if let Range { start: _, end: _ } = true..true && false {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - if let Range { start: _, end: _ } = true..true || false {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - - // Binds as `(let Range { start: F, end } = F)..(|| true)`. - const F: fn() -> bool = || true; - if let Range { start: F, end } = F..|| true {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - - // Binds as `(let Range { start: true, end } = t)..(&&false)`. - let t = &&true; - if let Range { start: true, end } = t..&&false {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - - if let true = let true = true {} - //~^ ERROR expected expression, found `let` statement -} - -fn nested_within_while_expr() { - while &let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - - while !let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - while *let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - while -let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - - fn _check_try_binds_tighter() -> Result<(), ()> { - while let 0 = 0? {} - //~^ ERROR the `?` operator can only be applied to values that implement `Try` - Ok(()) - } - while (let 0 = 0)? {} - //~^ ERROR expected expression, found `let` statement - - while true || let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - while (true || let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - while true && (true || let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - while true || (true && let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - - let mut x = true; - while x = let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement - - while true..(let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - while ..(let 0 = 0) {} - //~^ ERROR expected expression, found `let` statement - while (let 0 = 0).. {} - //~^ ERROR expected expression, found `let` statement - - // Binds as `(let ... = true)..true &&/|| false`. - while let Range { start: _, end: _ } = true..true && false {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - while let Range { start: _, end: _ } = true..true || false {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - - // Binds as `(let Range { start: F, end } = F)..(|| true)`. - const F: fn() -> bool = || true; - while let Range { start: F, end } = F..|| true {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - - // Binds as `(let Range { start: true, end } = t)..(&&false)`. - let t = &&true; - while let Range { start: true, end } = t..&&false {} - //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types - - while let true = let true = true {} - //~^ ERROR expected expression, found `let` statement -} - -fn not_error_because_clarified_intent() { - if let Range { start: _, end: _ } = (true..true || false) { } - - if let Range { start: _, end: _ } = (true..true && false) { } - - while let Range { start: _, end: _ } = (true..true || false) { } - - while let Range { start: _, end: _ } = (true..true && false) { } -} - -fn outside_if_and_while_expr() { - &let 0 = 0; - //~^ ERROR expected expression, found `let` statement - - !let 0 = 0; - //~^ ERROR expected expression, found `let` statement - *let 0 = 0; - //~^ ERROR expected expression, found `let` statement - -let 0 = 0; - //~^ ERROR expected expression, found `let` statement - let _ = let _ = 3; - //~^ ERROR expected expression, found `let` statement - - fn _check_try_binds_tighter() -> Result<(), ()> { - let 0 = 0?; - //~^ ERROR the `?` operator can only be applied to values that implement `Try` - Ok(()) - } - (let 0 = 0)?; - //~^ ERROR expected expression, found `let` statement - - true || let 0 = 0; - //~^ ERROR expected expression, found `let` statement - (true || let 0 = 0); - //~^ ERROR expected expression, found `let` statement - true && (true || let 0 = 0); - //~^ ERROR expected expression, found `let` statement - - let mut x = true; - x = let 0 = 0; - //~^ ERROR expected expression, found `let` statement - - true..(let 0 = 0); - //~^ ERROR expected expression, found `let` statement - ..(let 0 = 0); - //~^ ERROR expected expression, found `let` statement - (let 0 = 0)..; - //~^ ERROR expected expression, found `let` statement - - (let Range { start: _, end: _ } = true..true || false); - //~^ ERROR mismatched types - //~| ERROR expected expression, found `let` statement - - (let true = let true = true); - //~^ ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement - - { - #[cfg(FALSE)] - let x = true && let y = 1; - //~^ ERROR expected expression, found `let` statement - } - - #[cfg(FALSE)] - { - [1, 2, 3][let _ = ()] - //~^ ERROR expected expression, found `let` statement - } - - // Check function tail position. - &let 0 = 0 - //~^ ERROR expected expression, found `let` statement -} - -// Let's make sure that `let` inside const generic arguments are considered. -fn inside_const_generic_arguments() { - struct A; - impl A<{B}> { const O: u32 = 5; } - - if let A::<{ - true && let 1 = 1 - //~^ ERROR expected expression, found `let` statement - }>::O = 5 {} - - while let A::<{ - true && let 1 = 1 - //~^ ERROR expected expression, found `let` statement - }>::O = 5 {} - - if A::<{ - true && let 1 = 1 - //~^ ERROR expected expression, found `let` statement - }>::O == 5 {} - - // In the cases above we have `ExprKind::Block` to help us out. - // Below however, we would not have a block and so an implementation might go - // from visiting expressions to types without banning `let` expressions down the tree. - // This tests ensures that we are not caught by surprise should the parser - // admit non-IDENT expressions in const generic arguments. - - if A::< - true && let 1 = 1 - //~^ ERROR expressions must be enclosed in braces - //~| ERROR expected expression, found `let` statement - >::O == 5 {} -} - -fn with_parenthesis() { - let opt = Some(Some(1i32)); - - if (let Some(a) = opt && true) { - //~^ ERROR expected expression, found `let` statement - } - - if (let Some(a) = opt) && true { - //~^ ERROR expected expression, found `let` statement - } - if (let Some(a) = opt) && (let Some(b) = a) { - //~^ ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement - } - - if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { - //~^ ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement - } - if (let Some(a) = opt && (let Some(b) = a)) && true { - //~^ ERROR expected expression, found `let` statement - //~| ERROR expected expression, found `let` statement - } - if (let Some(a) = opt && (true)) && true { - //~^ ERROR expected expression, found `let` statement - } - - #[cfg(FALSE)] - let x = (true && let y = 1); - //~^ ERROR expected expression, found `let` statement - - #[cfg(FALSE)] - { - ([1, 2, 3][let _ = ()]) - //~^ ERROR expected expression, found `let` statement - } -} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr similarity index 84% rename from tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr rename to tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr index ab58abf4d4605..ae3856b7e7595 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr @@ -1,239 +1,239 @@ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:29:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:29:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:32:11 + --> $DIR/disallowed-positions.rs:35:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:32:11 + --> $DIR/disallowed-positions.rs:35:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:35:9 + --> $DIR/disallowed-positions.rs:38:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:35:9 + --> $DIR/disallowed-positions.rs:38:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:38:17 + --> $DIR/disallowed-positions.rs:41:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:38:17 + --> $DIR/disallowed-positions.rs:41:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:41:9 + --> $DIR/disallowed-positions.rs:44:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:41:9 + --> $DIR/disallowed-positions.rs:44:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:41:24 + --> $DIR/disallowed-positions.rs:44:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:41:24 + --> $DIR/disallowed-positions.rs:44:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:48 + --> $DIR/disallowed-positions.rs:48:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:45:61 + --> $DIR/disallowed-positions.rs:48:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:45:35 + --> $DIR/disallowed-positions.rs:48:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:52:12 + --> $DIR/disallowed-positions.rs:58:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:52:12 + --> $DIR/disallowed-positions.rs:58:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:55:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:55:14 + --> $DIR/disallowed-positions.rs:61:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:61:20 + --> $DIR/disallowed-positions.rs:67:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:61:20 + --> $DIR/disallowed-positions.rs:67:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:70:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:70:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:64:27 + --> $DIR/disallowed-positions.rs:70:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:64:27 + --> $DIR/disallowed-positions.rs:70:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:68:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:68:51 + --> $DIR/disallowed-positions.rs:74:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:68:64 + --> $DIR/disallowed-positions.rs:74:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:68:38 + --> $DIR/disallowed-positions.rs:74:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:88:9 + --> $DIR/disallowed-positions.rs:98:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:91:9 + --> $DIR/disallowed-positions.rs:101:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:93:9 + --> $DIR/disallowed-positions.rs:103:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:95:9 + --> $DIR/disallowed-positions.rs:105:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:103:9 + --> $DIR/disallowed-positions.rs:113:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:106:16 + --> $DIR/disallowed-positions.rs:116:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:106:13 + --> $DIR/disallowed-positions.rs:116:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:108:17 + --> $DIR/disallowed-positions.rs:118:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:110:25 + --> $DIR/disallowed-positions.rs:120:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:112:25 + --> $DIR/disallowed-positions.rs:122:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:116:12 + --> $DIR/disallowed-positions.rs:126:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:119:15 + --> $DIR/disallowed-positions.rs:129:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:122:11 + --> $DIR/disallowed-positions.rs:132:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:124:9 + --> $DIR/disallowed-positions.rs:134:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:128:8 + --> $DIR/disallowed-positions.rs:138:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:131:8 + --> $DIR/disallowed-positions.rs:141:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:137:8 + --> $DIR/disallowed-positions.rs:147:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:143:8 + --> $DIR/disallowed-positions.rs:153:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:147:19 + --> $DIR/disallowed-positions.rs:157:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:152:12 + --> $DIR/disallowed-positions.rs:163:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -390,7 +390,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:155:12 + --> $DIR/disallowed-positions.rs:166:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -398,7 +398,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:157:12 + --> $DIR/disallowed-positions.rs:168:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -406,7 +406,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:159:12 + --> $DIR/disallowed-positions.rs:170:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -414,7 +414,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:167:12 + --> $DIR/disallowed-positions.rs:178:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -422,20 +422,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:170:19 + --> $DIR/disallowed-positions.rs:181:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:170:16 + --> $DIR/disallowed-positions.rs:181:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:172:20 + --> $DIR/disallowed-positions.rs:183:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -443,7 +443,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:174:28 + --> $DIR/disallowed-positions.rs:185:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -451,7 +451,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:176:28 + --> $DIR/disallowed-positions.rs:187:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -459,7 +459,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:180:15 + --> $DIR/disallowed-positions.rs:191:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -467,7 +467,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:183:18 + --> $DIR/disallowed-positions.rs:194:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -475,7 +475,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:186:14 + --> $DIR/disallowed-positions.rs:197:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -483,7 +483,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:188:12 + --> $DIR/disallowed-positions.rs:199:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -491,7 +491,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:192:11 + --> $DIR/disallowed-positions.rs:203:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -499,7 +499,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:195:11 + --> $DIR/disallowed-positions.rs:206:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +507,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:201:11 + --> $DIR/disallowed-positions.rs:212:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -515,7 +515,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:207:11 + --> $DIR/disallowed-positions.rs:218:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -523,7 +523,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:211:22 + --> $DIR/disallowed-positions.rs:222:22 | LL | while let true = let true = true {} | ^^^ @@ -531,7 +531,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:226:6 + --> $DIR/disallowed-positions.rs:239:6 | LL | &let 0 = 0; | ^^^ @@ -539,7 +539,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:229:6 + --> $DIR/disallowed-positions.rs:242:6 | LL | !let 0 = 0; | ^^^ @@ -547,7 +547,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:231:6 + --> $DIR/disallowed-positions.rs:244:6 | LL | *let 0 = 0; | ^^^ @@ -555,7 +555,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:233:6 + --> $DIR/disallowed-positions.rs:246:6 | LL | -let 0 = 0; | ^^^ @@ -563,7 +563,15 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:241:6 + --> $DIR/disallowed-positions.rs:248:13 + | +LL | let _ = let _ = 3; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:256:6 | LL | (let 0 = 0)?; | ^^^ @@ -571,7 +579,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:244:13 + --> $DIR/disallowed-positions.rs:259:13 | LL | true || let 0 = 0; | ^^^ @@ -579,7 +587,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:246:14 + --> $DIR/disallowed-positions.rs:261:14 | LL | (true || let 0 = 0); | ^^^ @@ -587,7 +595,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:248:22 + --> $DIR/disallowed-positions.rs:263:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -595,7 +603,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:252:9 + --> $DIR/disallowed-positions.rs:267:9 | LL | x = let 0 = 0; | ^^^ @@ -603,7 +611,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:255:12 + --> $DIR/disallowed-positions.rs:270:12 | LL | true..(let 0 = 0); | ^^^ @@ -611,7 +619,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:257:8 + --> $DIR/disallowed-positions.rs:272:8 | LL | ..(let 0 = 0); | ^^^ @@ -619,7 +627,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:259:6 + --> $DIR/disallowed-positions.rs:274:6 | LL | (let 0 = 0)..; | ^^^ @@ -627,7 +635,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:262:6 + --> $DIR/disallowed-positions.rs:277:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -635,7 +643,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:266:6 + --> $DIR/disallowed-positions.rs:281:6 | LL | (let true = let true = true); | ^^^ @@ -643,7 +651,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:266:17 + --> $DIR/disallowed-positions.rs:281:17 | LL | (let true = let true = true); | ^^^ @@ -651,7 +659,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:25 + --> $DIR/disallowed-positions.rs:287:25 | LL | let x = true && let y = 1; | ^^^ @@ -659,7 +667,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:278:19 + --> $DIR/disallowed-positions.rs:293:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -667,7 +675,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:283:6 + --> $DIR/disallowed-positions.rs:298:6 | LL | &let 0 = 0 | ^^^ @@ -675,7 +683,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:293:17 + --> $DIR/disallowed-positions.rs:309:17 | LL | true && let 1 = 1 | ^^^ @@ -683,7 +691,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:298:17 + --> $DIR/disallowed-positions.rs:314:17 | LL | true && let 1 = 1 | ^^^ @@ -691,7 +699,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:303:17 + --> $DIR/disallowed-positions.rs:319:17 | LL | true && let 1 = 1 | ^^^ @@ -699,7 +707,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:314:17 + --> $DIR/disallowed-positions.rs:330:17 | LL | true && let 1 = 1 | ^^^ @@ -707,7 +715,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:314:9 + --> $DIR/disallowed-positions.rs:330:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -718,124 +726,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:323:9 + --> $DIR/disallowed-positions.rs:340:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:323:9 + --> $DIR/disallowed-positions.rs:340:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:327:9 + --> $DIR/disallowed-positions.rs:344:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:327:9 + --> $DIR/disallowed-positions.rs:344:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:9 + --> $DIR/disallowed-positions.rs:347:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:330:9 + --> $DIR/disallowed-positions.rs:347:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:32 + --> $DIR/disallowed-positions.rs:347:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:330:32 + --> $DIR/disallowed-positions.rs:347:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:337:9 + --> $DIR/disallowed-positions.rs:355:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:337:9 + --> $DIR/disallowed-positions.rs:355:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:337:31 + --> $DIR/disallowed-positions.rs:355:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:337:31 + --> $DIR/disallowed-positions.rs:355:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:341:9 + --> $DIR/disallowed-positions.rs:359:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:341:9 + --> $DIR/disallowed-positions.rs:359:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:341:31 + --> $DIR/disallowed-positions.rs:359:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:341:31 + --> $DIR/disallowed-positions.rs:359:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:345:9 + --> $DIR/disallowed-positions.rs:363:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:345:9 + --> $DIR/disallowed-positions.rs:363:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:361:22 + --> $DIR/disallowed-positions.rs:383:22 | LL | let x = (true && let y = 1); | ^^^ @@ -843,7 +851,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:366:20 + --> $DIR/disallowed-positions.rs:388:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -851,7 +859,7 @@ LL | ([1, 2, 3][let _ = ()]) = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:81:16 + --> $DIR/disallowed-positions.rs:90:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -859,7 +867,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:83:16 + --> $DIR/disallowed-positions.rs:92:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -867,7 +875,7 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if` and `while` expressions error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:119:8 + --> $DIR/disallowed-positions.rs:129:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -876,7 +884,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:128:12 + --> $DIR/disallowed-positions.rs:138:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -887,7 +895,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:131:12 + --> $DIR/disallowed-positions.rs:141:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -898,7 +906,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:137:12 + --> $DIR/disallowed-positions.rs:147:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -909,7 +917,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:143:12 + --> $DIR/disallowed-positions.rs:153:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -920,7 +928,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:99:20 + --> $DIR/disallowed-positions.rs:109:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -928,7 +936,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:183:11 + --> $DIR/disallowed-positions.rs:194:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -937,7 +945,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:192:15 + --> $DIR/disallowed-positions.rs:203:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -948,7 +956,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:195:15 + --> $DIR/disallowed-positions.rs:206:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -959,7 +967,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:201:15 + --> $DIR/disallowed-positions.rs:212:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -970,7 +978,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:207:15 + --> $DIR/disallowed-positions.rs:218:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -981,7 +989,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:163:23 + --> $DIR/disallowed-positions.rs:174:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -989,7 +997,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:262:10 + --> $DIR/disallowed-positions.rs:277:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1000,14 +1008,14 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:237:17 + --> $DIR/disallowed-positions.rs:252:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 104 previous errors +error: aborting due to 105 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr new file mode 100644 index 0000000000000..fd418f4ed7c6c --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr @@ -0,0 +1,1111 @@ +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:32:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:32:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:35:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:35:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:38:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:38:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:41:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:41:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:44:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:44:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:44:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:44:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:48:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:48:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:48:48 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:48:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:48:61 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:48:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:58:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:58:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:61:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:61:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:64:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:64:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:67:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:67:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:70:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:70:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:70:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:70:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:74:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:74:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:74:51 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:74:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:74:64 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:74:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:98:9 + | +LL | if &let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:101:9 + | +LL | if !let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:103:9 + | +LL | if *let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:105:9 + | +LL | if -let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:113:9 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:116:16 + | +LL | if true || let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:116:13 + | +LL | if true || let 0 = 0 {} + | ^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:118:17 + | +LL | if (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:120:25 + | +LL | if true && (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:122:25 + | +LL | if true || (true && let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:126:12 + | +LL | if x = let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:129:15 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:132:11 + | +LL | if ..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:134:9 + | +LL | if (let 0 = 0).. {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:138:8 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:141:8 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:147:8 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:153:8 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:157:19 + | +LL | if let true = let true = true {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:163:12 + | +LL | while &let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:166:12 + | +LL | while !let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:168:12 + | +LL | while *let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:170:12 + | +LL | while -let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:178:12 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:181:19 + | +LL | while true || let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:181:16 + | +LL | while true || let 0 = 0 {} + | ^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:183:20 + | +LL | while (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:185:28 + | +LL | while true && (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:187:28 + | +LL | while true || (true && let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:191:15 + | +LL | while x = let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:194:18 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:197:14 + | +LL | while ..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:199:12 + | +LL | while (let 0 = 0).. {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:203:11 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:206:11 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:212:11 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:218:11 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:222:22 + | +LL | while let true = let true = true {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:239:6 + | +LL | &let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:242:6 + | +LL | !let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:244:6 + | +LL | *let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:246:6 + | +LL | -let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:248:13 + | +LL | let _ = let _ = 3; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:256:6 + | +LL | (let 0 = 0)?; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:259:13 + | +LL | true || let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:261:14 + | +LL | (true || let 0 = 0); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:263:22 + | +LL | true && (true || let 0 = 0); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:267:9 + | +LL | x = let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:270:12 + | +LL | true..(let 0 = 0); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:272:8 + | +LL | ..(let 0 = 0); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:274:6 + | +LL | (let 0 = 0)..; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:277:6 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:281:6 + | +LL | (let true = let true = true); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:281:17 + | +LL | (let true = let true = true); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:287:25 + | +LL | let x = true && let y = 1; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:293:19 + | +LL | [1, 2, 3][let _ = ()] + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:298:6 + | +LL | &let 0 = 0 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:309:17 + | +LL | true && let 1 = 1 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:314:17 + | +LL | true && let 1 = 1 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:319:17 + | +LL | true && let 1 = 1 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:330:17 + | +LL | true && let 1 = 1 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/disallowed-positions.rs:330:9 + | +LL | true && let 1 = 1 + | ^^^^^^^^^^^^^^^^^ + | +help: enclose the `const` expression in braces + | +LL | { true && let 1 = 1 } + | + + + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:340:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:340:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:344:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:344:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:347:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:347:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:347:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:347:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:355:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:355:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:355:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:355:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:359:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:359:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:359:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:359:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:363:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:363:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:383:22 + | +LL | let x = (true && let y = 1); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:388:20 + | +LL | ([1, 2, 3][let _ = ()]) + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:90:16 + | +LL | use_expr!((let 0 = 1 && 0 == 0)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:92:16 + | +LL | use_expr!((let 0 = 1)); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:48:8 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:48:21 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:74:11 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:74:24 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:351:8 + | +LL | if let Some(a) = opt && (true && true) { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:367:28 + | +LL | if (true && (true)) && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:370:18 + | +LL | if (true) && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:373:16 + | +LL | if true && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:378:8 + | +LL | if let true = (true && fun()) && (true) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:129:8 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` + | + = note: expected type `bool` + found struct `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:138:12 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:141:12 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:147:12 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` + | | + | expected fn pointer, found `Range<_>` + | + = note: expected fn pointer `fn() -> bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:153:12 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:109:20 + | +LL | if let 0 = 0? {} + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `Try` is not implemented for `{integer}` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:194:11 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` + | + = note: expected type `bool` + found struct `std::ops::Range` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:203:15 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:206:15 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:212:15 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` + | | + | expected fn pointer, found `Range<_>` + | + = note: expected fn pointer `fn() -> bool` + found struct `std::ops::Range<_>` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:218:15 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:174:23 + | +LL | while let 0 = 0? {} + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `Try` is not implemented for `{integer}` + +error[E0308]: mismatched types + --> $DIR/disallowed-positions.rs:277:10 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` + | | + | expected `bool`, found `Range<_>` + | + = note: expected type `bool` + found struct `std::ops::Range<_>` + +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/disallowed-positions.rs:252:17 + | +LL | let 0 = 0?; + | ^^ the `?` operator cannot be applied to type `{integer}` + | + = help: the trait `Try` is not implemented for `{integer}` + +error: aborting due to 114 previous errors + +Some errors have detailed explanations: E0277, E0308, E0658. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nofeature.stderr similarity index 70% rename from tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr rename to tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nofeature.stderr index 31f389512edb4..f556ecf7f91d3 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nofeature.stderr @@ -1,239 +1,239 @@ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:11:9 + --> $DIR/disallowed-positions.rs:31:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:11:9 + --> $DIR/disallowed-positions.rs:31:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:14:11 + --> $DIR/disallowed-positions.rs:34:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:14:11 + --> $DIR/disallowed-positions.rs:34:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:17:9 + --> $DIR/disallowed-positions.rs:37:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:17:9 + --> $DIR/disallowed-positions.rs:37:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:20:17 + --> $DIR/disallowed-positions.rs:40:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:20:17 + --> $DIR/disallowed-positions.rs:40:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:23:9 + --> $DIR/disallowed-positions.rs:43:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:23:9 + --> $DIR/disallowed-positions.rs:43:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:23:24 + --> $DIR/disallowed-positions.rs:43:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:23:24 + --> $DIR/disallowed-positions.rs:43:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:27:9 + --> $DIR/disallowed-positions.rs:47:35 | -LL | if (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:27:9 + --> $DIR/disallowed-positions.rs:47:35 | -LL | if (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:27:22 + --> $DIR/disallowed-positions.rs:47:48 | -LL | if (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:27:9 + --> $DIR/disallowed-positions.rs:47:35 | -LL | if (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:27:35 + --> $DIR/disallowed-positions.rs:47:61 | -LL | if (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:27:9 + --> $DIR/disallowed-positions.rs:47:35 | -LL | if (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:34:12 + --> $DIR/disallowed-positions.rs:56:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:34:12 + --> $DIR/disallowed-positions.rs:56:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:37:14 + --> $DIR/disallowed-positions.rs:59:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:37:14 + --> $DIR/disallowed-positions.rs:59:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:40:12 + --> $DIR/disallowed-positions.rs:62:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:40:12 + --> $DIR/disallowed-positions.rs:62:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:43:20 + --> $DIR/disallowed-positions.rs:65:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:43:20 + --> $DIR/disallowed-positions.rs:65:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:46:12 + --> $DIR/disallowed-positions.rs:68:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:46:12 + --> $DIR/disallowed-positions.rs:68:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:46:27 + --> $DIR/disallowed-positions.rs:68:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:46:27 + --> $DIR/disallowed-positions.rs:68:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:50:12 + --> $DIR/disallowed-positions.rs:72:38 | -LL | while (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:50:12 + --> $DIR/disallowed-positions.rs:72:38 | -LL | while (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:50:25 + --> $DIR/disallowed-positions.rs:72:51 | -LL | while (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:50:12 + --> $DIR/disallowed-positions.rs:72:38 | -LL | while (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:50:38 + --> $DIR/disallowed-positions.rs:72:64 | -LL | while (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^ +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:50:12 + --> $DIR/disallowed-positions.rs:72:38 | -LL | while (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:70:9 + --> $DIR/disallowed-positions.rs:95:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:73:9 + --> $DIR/disallowed-positions.rs:98:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:75:9 + --> $DIR/disallowed-positions.rs:100:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:77:9 + --> $DIR/disallowed-positions.rs:102:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:85:9 + --> $DIR/disallowed-positions.rs:110:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:88:16 + --> $DIR/disallowed-positions.rs:113:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions-without-feature-gate.rs:88:13 + --> $DIR/disallowed-positions.rs:113:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:90:17 + --> $DIR/disallowed-positions.rs:115:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:92:25 + --> $DIR/disallowed-positions.rs:117:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:94:25 + --> $DIR/disallowed-positions.rs:119:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:98:12 + --> $DIR/disallowed-positions.rs:123:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:101:15 + --> $DIR/disallowed-positions.rs:126:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:104:11 + --> $DIR/disallowed-positions.rs:129:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:106:9 + --> $DIR/disallowed-positions.rs:131:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:110:8 + --> $DIR/disallowed-positions.rs:135:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:113:8 + --> $DIR/disallowed-positions.rs:138:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:119:8 + --> $DIR/disallowed-positions.rs:144:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:125:8 + --> $DIR/disallowed-positions.rs:150:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:129:19 + --> $DIR/disallowed-positions.rs:154:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,7 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:134:12 + --> $DIR/disallowed-positions.rs:160:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -390,7 +390,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:137:12 + --> $DIR/disallowed-positions.rs:163:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -398,7 +398,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:139:12 + --> $DIR/disallowed-positions.rs:165:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -406,7 +406,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:141:12 + --> $DIR/disallowed-positions.rs:167:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -414,7 +414,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:149:12 + --> $DIR/disallowed-positions.rs:175:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -422,20 +422,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:152:19 + --> $DIR/disallowed-positions.rs:178:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions-without-feature-gate.rs:152:16 + --> $DIR/disallowed-positions.rs:178:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:154:20 + --> $DIR/disallowed-positions.rs:180:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -443,7 +443,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:156:28 + --> $DIR/disallowed-positions.rs:182:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -451,7 +451,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:158:28 + --> $DIR/disallowed-positions.rs:184:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -459,7 +459,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:162:15 + --> $DIR/disallowed-positions.rs:188:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -467,7 +467,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:165:18 + --> $DIR/disallowed-positions.rs:191:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -475,7 +475,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:168:14 + --> $DIR/disallowed-positions.rs:194:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -483,7 +483,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:170:12 + --> $DIR/disallowed-positions.rs:196:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -491,7 +491,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:174:11 + --> $DIR/disallowed-positions.rs:200:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -499,7 +499,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:177:11 + --> $DIR/disallowed-positions.rs:203:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +507,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:183:11 + --> $DIR/disallowed-positions.rs:209:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -515,7 +515,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:189:11 + --> $DIR/disallowed-positions.rs:215:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -523,7 +523,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:193:22 + --> $DIR/disallowed-positions.rs:219:22 | LL | while let true = let true = true {} | ^^^ @@ -531,7 +531,7 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:208:6 + --> $DIR/disallowed-positions.rs:236:6 | LL | &let 0 = 0; | ^^^ @@ -539,7 +539,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:211:6 + --> $DIR/disallowed-positions.rs:239:6 | LL | !let 0 = 0; | ^^^ @@ -547,7 +547,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:213:6 + --> $DIR/disallowed-positions.rs:241:6 | LL | *let 0 = 0; | ^^^ @@ -555,7 +555,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:215:6 + --> $DIR/disallowed-positions.rs:243:6 | LL | -let 0 = 0; | ^^^ @@ -563,7 +563,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:217:13 + --> $DIR/disallowed-positions.rs:245:13 | LL | let _ = let _ = 3; | ^^^ @@ -571,7 +571,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:225:6 + --> $DIR/disallowed-positions.rs:253:6 | LL | (let 0 = 0)?; | ^^^ @@ -579,7 +579,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:228:13 + --> $DIR/disallowed-positions.rs:256:13 | LL | true || let 0 = 0; | ^^^ @@ -587,7 +587,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:230:14 + --> $DIR/disallowed-positions.rs:258:14 | LL | (true || let 0 = 0); | ^^^ @@ -595,7 +595,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:232:22 + --> $DIR/disallowed-positions.rs:260:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -603,7 +603,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:236:9 + --> $DIR/disallowed-positions.rs:264:9 | LL | x = let 0 = 0; | ^^^ @@ -611,7 +611,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:239:12 + --> $DIR/disallowed-positions.rs:267:12 | LL | true..(let 0 = 0); | ^^^ @@ -619,7 +619,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:241:8 + --> $DIR/disallowed-positions.rs:269:8 | LL | ..(let 0 = 0); | ^^^ @@ -627,7 +627,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:243:6 + --> $DIR/disallowed-positions.rs:271:6 | LL | (let 0 = 0)..; | ^^^ @@ -635,7 +635,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:246:6 + --> $DIR/disallowed-positions.rs:274:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -643,7 +643,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:250:6 + --> $DIR/disallowed-positions.rs:278:6 | LL | (let true = let true = true); | ^^^ @@ -651,7 +651,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:250:17 + --> $DIR/disallowed-positions.rs:278:17 | LL | (let true = let true = true); | ^^^ @@ -659,7 +659,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:256:25 + --> $DIR/disallowed-positions.rs:284:25 | LL | let x = true && let y = 1; | ^^^ @@ -667,7 +667,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:262:19 + --> $DIR/disallowed-positions.rs:290:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -675,7 +675,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:267:6 + --> $DIR/disallowed-positions.rs:295:6 | LL | &let 0 = 0 | ^^^ @@ -683,7 +683,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:277:17 + --> $DIR/disallowed-positions.rs:306:17 | LL | true && let 1 = 1 | ^^^ @@ -691,7 +691,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:282:17 + --> $DIR/disallowed-positions.rs:311:17 | LL | true && let 1 = 1 | ^^^ @@ -699,7 +699,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:287:17 + --> $DIR/disallowed-positions.rs:316:17 | LL | true && let 1 = 1 | ^^^ @@ -707,7 +707,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:298:17 + --> $DIR/disallowed-positions.rs:327:17 | LL | true && let 1 = 1 | ^^^ @@ -715,7 +715,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions-without-feature-gate.rs:298:9 + --> $DIR/disallowed-positions.rs:327:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -726,124 +726,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:307:9 + --> $DIR/disallowed-positions.rs:337:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:307:9 + --> $DIR/disallowed-positions.rs:337:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:311:9 + --> $DIR/disallowed-positions.rs:341:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:311:9 + --> $DIR/disallowed-positions.rs:341:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:314:9 + --> $DIR/disallowed-positions.rs:344:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:314:9 + --> $DIR/disallowed-positions.rs:344:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:314:32 + --> $DIR/disallowed-positions.rs:344:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:314:32 + --> $DIR/disallowed-positions.rs:344:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:319:9 + --> $DIR/disallowed-positions.rs:351:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:319:9 + --> $DIR/disallowed-positions.rs:351:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:319:31 + --> $DIR/disallowed-positions.rs:351:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:319:31 + --> $DIR/disallowed-positions.rs:351:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:323:9 + --> $DIR/disallowed-positions.rs:355:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:323:9 + --> $DIR/disallowed-positions.rs:355:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:323:31 + --> $DIR/disallowed-positions.rs:355:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:323:31 + --> $DIR/disallowed-positions.rs:355:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:327:9 + --> $DIR/disallowed-positions.rs:359:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions-without-feature-gate.rs:327:9 + --> $DIR/disallowed-positions.rs:359:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:332:22 + --> $DIR/disallowed-positions.rs:375:22 | LL | let x = (true && let y = 1); | ^^^ @@ -851,7 +851,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:337:20 + --> $DIR/disallowed-positions.rs:380:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -859,7 +859,7 @@ LL | ([1, 2, 3][let _ = ()]) = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:63:16 + --> $DIR/disallowed-positions.rs:87:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -867,15 +867,105 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions-without-feature-gate.rs:65:16 + --> $DIR/disallowed-positions.rs:89:16 | LL | use_expr!((let 0 = 1)); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:47:8 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:47:21 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:72:11 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:72:24 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:348:8 + | +LL | if let Some(a) = opt && (true && true) { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:363:28 + | +LL | if (true && (true)) && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:365:18 + | +LL | if (true) && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:367:16 + | +LL | if true && let Some(a) = opt { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `let` expressions in this position are unstable + --> $DIR/disallowed-positions.rs:371:8 + | +LL | if let true = (true && fun()) && (true) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #53667 for more information + = help: add `#![feature(let_chains)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:101:8 + --> $DIR/disallowed-positions.rs:126:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -884,7 +974,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:110:12 + --> $DIR/disallowed-positions.rs:135:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -895,7 +985,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:113:12 + --> $DIR/disallowed-positions.rs:138:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -906,7 +996,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:119:12 + --> $DIR/disallowed-positions.rs:144:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -917,7 +1007,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:125:12 + --> $DIR/disallowed-positions.rs:150:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -928,7 +1018,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions-without-feature-gate.rs:81:20 + --> $DIR/disallowed-positions.rs:106:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -936,7 +1026,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:165:11 + --> $DIR/disallowed-positions.rs:191:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -945,7 +1035,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:174:15 + --> $DIR/disallowed-positions.rs:200:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -956,7 +1046,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:177:15 + --> $DIR/disallowed-positions.rs:203:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -967,7 +1057,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:183:15 + --> $DIR/disallowed-positions.rs:209:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -978,7 +1068,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:189:15 + --> $DIR/disallowed-positions.rs:215:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -989,7 +1079,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions-without-feature-gate.rs:145:23 + --> $DIR/disallowed-positions.rs:171:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -997,7 +1087,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions-without-feature-gate.rs:246:10 + --> $DIR/disallowed-positions.rs:274:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1008,14 +1098,14 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions-without-feature-gate.rs:221:17 + --> $DIR/disallowed-positions.rs:249:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 105 previous errors +error: aborting due to 114 previous errors -Some errors have detailed explanations: E0277, E0308. +Some errors have detailed explanations: E0277, E0308, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr new file mode 100644 index 0000000000000..dbe694b6e946d --- /dev/null +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr @@ -0,0 +1,862 @@ +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:32:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:32:9 + | +LL | if (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:35:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:35:11 + | +LL | if (((let 0 = 1))) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:38:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:38:9 + | +LL | if (let 0 = 1) && true {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:41:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:41:17 + | +LL | if true && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:44:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:44:9 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:44:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:44:24 + | +LL | if (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:48:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:48:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:48:48 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:48:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:48:61 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:48:35 + | +LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:58:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:58:12 + | +LL | while (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:61:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:61:14 + | +LL | while (((let 0 = 1))) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:64:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:64:12 + | +LL | while (let 0 = 1) && true {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:67:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:67:20 + | +LL | while true && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:70:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:70:12 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:70:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:70:27 + | +LL | while (let 0 = 1) && (let 0 = 1) {} + | ^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:74:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:74:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:74:51 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:74:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:74:64 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:74:38 + | +LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:98:9 + | +LL | if &let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:101:9 + | +LL | if !let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:103:9 + | +LL | if *let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:105:9 + | +LL | if -let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:113:9 + | +LL | if (let 0 = 0)? {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:116:16 + | +LL | if true || let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:116:13 + | +LL | if true || let 0 = 0 {} + | ^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:118:17 + | +LL | if (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:120:25 + | +LL | if true && (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:122:25 + | +LL | if true || (true && let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:126:12 + | +LL | if x = let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:129:15 + | +LL | if true..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:132:11 + | +LL | if ..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:134:9 + | +LL | if (let 0 = 0).. {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:138:8 + | +LL | if let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:141:8 + | +LL | if let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:147:8 + | +LL | if let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:153:8 + | +LL | if let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:157:19 + | +LL | if let true = let true = true {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:163:12 + | +LL | while &let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:166:12 + | +LL | while !let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:168:12 + | +LL | while *let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:170:12 + | +LL | while -let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:178:12 + | +LL | while (let 0 = 0)? {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:181:19 + | +LL | while true || let 0 = 0 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `||` operators are not supported in let chain expressions + --> $DIR/disallowed-positions.rs:181:16 + | +LL | while true || let 0 = 0 {} + | ^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:183:20 + | +LL | while (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:185:28 + | +LL | while true && (true || let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:187:28 + | +LL | while true || (true && let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:191:15 + | +LL | while x = let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:194:18 + | +LL | while true..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:197:14 + | +LL | while ..(let 0 = 0) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:199:12 + | +LL | while (let 0 = 0).. {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:203:11 + | +LL | while let Range { start: _, end: _ } = true..true && false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:206:11 + | +LL | while let Range { start: _, end: _ } = true..true || false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:212:11 + | +LL | while let Range { start: F, end } = F..|| true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:218:11 + | +LL | while let Range { start: true, end } = t..&&false {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:222:22 + | +LL | while let true = let true = true {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:239:6 + | +LL | &let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:242:6 + | +LL | !let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:244:6 + | +LL | *let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:246:6 + | +LL | -let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:248:13 + | +LL | let _ = let _ = 3; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:256:6 + | +LL | (let 0 = 0)?; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:259:13 + | +LL | true || let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:261:14 + | +LL | (true || let 0 = 0); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:263:22 + | +LL | true && (true || let 0 = 0); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:267:9 + | +LL | x = let 0 = 0; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:270:12 + | +LL | true..(let 0 = 0); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:272:8 + | +LL | ..(let 0 = 0); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:274:6 + | +LL | (let 0 = 0)..; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:277:6 + | +LL | (let Range { start: _, end: _ } = true..true || false); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:281:6 + | +LL | (let true = let true = true); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:281:17 + | +LL | (let true = let true = true); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:287:25 + | +LL | let x = true && let y = 1; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:293:19 + | +LL | [1, 2, 3][let _ = ()] + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:298:6 + | +LL | &let 0 = 0 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:309:17 + | +LL | true && let 1 = 1 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:314:17 + | +LL | true && let 1 = 1 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:319:17 + | +LL | true && let 1 = 1 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:330:17 + | +LL | true && let 1 = 1 + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/disallowed-positions.rs:330:9 + | +LL | true && let 1 = 1 + | ^^^^^^^^^^^^^^^^^ + | +help: enclose the `const` expression in braces + | +LL | { true && let 1 = 1 } + | + + + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:340:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:340:9 + | +LL | if (let Some(a) = opt && true) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:344:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:344:9 + | +LL | if (let Some(a) = opt) && true { + | ^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:347:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:347:9 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:347:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:347:32 + | +LL | if (let Some(a) = opt) && (let Some(b) = a) { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:355:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:355:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:355:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:355:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:359:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:359:9 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:359:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:359:31 + | +LL | if (let Some(a) = opt && (let Some(b) = a)) && true { + | ^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:363:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +note: `let`s wrapped in parentheses are not supported in a context with let chains + --> $DIR/disallowed-positions.rs:363:9 + | +LL | if (let Some(a) = opt && (true)) && true { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:383:22 + | +LL | let x = (true && let y = 1); + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:388:20 + | +LL | ([1, 2, 3][let _ = ()]) + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: aborting due to 89 previous errors + diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs index 4ac3ea53a08ab..c0f7b03a6e3e7 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -1,3 +1,4 @@ +//@ revisions: no_feature feature nothing // Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions. // // We want to make sure that `let` is banned in situations other than: @@ -17,7 +18,8 @@ // // To that end, we check some positions which is not part of the language above. -#![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. +// Avoid inflating `.stderr` with overzealous gates (or test what happens if you disable the gate) +#![cfg_attr(not(no_feature), feature(let_chains))] #![allow(irrefutable_let_patterns)] @@ -25,6 +27,7 @@ use std::ops::Range; fn main() {} +#[cfg(not(nothing))] fn _if() { if (let 0 = 1) {} //~^ ERROR expected expression, found `let` statement @@ -46,8 +49,11 @@ fn _if() { //~^ ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement + //[no_feature]~| ERROR `let` expressions in this position are unstable + //[no_feature]~| ERROR `let` expressions in this position are unstable } +#[cfg(not(nothing))] fn _while() { while (let 0 = 1) {} //~^ ERROR expected expression, found `let` statement @@ -69,8 +75,11 @@ fn _while() { //~^ ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement //~| ERROR expected expression, found `let` statement + //[no_feature]~| ERROR `let` expressions in this position are unstable + //[no_feature]~| ERROR `let` expressions in this position are unstable } +#[cfg(not(nothing))] fn _macros() { macro_rules! use_expr { ($e:expr) => { @@ -79,11 +88,12 @@ fn _macros() { } } use_expr!((let 0 = 1 && 0 == 0)); - //~^ ERROR expected expression, found `let` statement + //[feature,no_feature]~^ ERROR expected expression, found `let` statement use_expr!((let 0 = 1)); - //~^ ERROR expected expression, found `let` statement + //[feature,no_feature]~^ ERROR expected expression, found `let` statement } +#[cfg(not(nothing))] fn nested_within_if_expr() { if &let 0 = 0 {} //~^ ERROR expected expression, found `let` statement @@ -97,7 +107,7 @@ fn nested_within_if_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { if let 0 = 0? {} - //~^ ERROR the `?` operator can only be applied to values that implement `Try` + //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } if (let 0 = 0)? {} @@ -118,7 +128,7 @@ fn nested_within_if_expr() { if true..(let 0 = 0) {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types if ..(let 0 = 0) {} //~^ ERROR expected expression, found `let` statement if (let 0 = 0).. {} @@ -127,27 +137,28 @@ fn nested_within_if_expr() { // Binds as `(let ... = true)..true &&/|| false`. if let Range { start: _, end: _ } = true..true && false {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types if let Range { start: _, end: _ } = true..true || false {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types // Binds as `(let Range { start: F, end } = F)..(|| true)`. const F: fn() -> bool = || true; if let Range { start: F, end } = F..|| true {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types // Binds as `(let Range { start: true, end } = t)..(&&false)`. let t = &&true; if let Range { start: true, end } = t..&&false {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types if let true = let true = true {} //~^ ERROR expected expression, found `let` statement } +#[cfg(not(nothing))] fn nested_within_while_expr() { while &let 0 = 0 {} //~^ ERROR expected expression, found `let` statement @@ -161,7 +172,7 @@ fn nested_within_while_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { while let 0 = 0? {} - //~^ ERROR the `?` operator can only be applied to values that implement `Try` + //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } while (let 0 = 0)? {} @@ -182,7 +193,7 @@ fn nested_within_while_expr() { while true..(let 0 = 0) {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types while ..(let 0 = 0) {} //~^ ERROR expected expression, found `let` statement while (let 0 = 0).. {} @@ -191,27 +202,28 @@ fn nested_within_while_expr() { // Binds as `(let ... = true)..true &&/|| false`. while let Range { start: _, end: _ } = true..true && false {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types while let Range { start: _, end: _ } = true..true || false {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types // Binds as `(let Range { start: F, end } = F)..(|| true)`. const F: fn() -> bool = || true; while let Range { start: F, end } = F..|| true {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types // Binds as `(let Range { start: true, end } = t)..(&&false)`. let t = &&true; while let Range { start: true, end } = t..&&false {} //~^ ERROR expected expression, found `let` statement - //~| ERROR mismatched types + //[feature,no_feature]~| ERROR mismatched types while let true = let true = true {} //~^ ERROR expected expression, found `let` statement } +#[cfg(not(nothing))] fn not_error_because_clarified_intent() { if let Range { start: _, end: _ } = (true..true || false) { } @@ -222,6 +234,7 @@ fn not_error_because_clarified_intent() { while let Range { start: _, end: _ } = (true..true && false) { } } +#[cfg(not(nothing))] fn outside_if_and_while_expr() { &let 0 = 0; //~^ ERROR expected expression, found `let` statement @@ -232,10 +245,12 @@ fn outside_if_and_while_expr() { //~^ ERROR expected expression, found `let` statement -let 0 = 0; //~^ ERROR expected expression, found `let` statement + let _ = let _ = 3; + //~^ ERROR expected expression, found `let` statement fn _check_try_binds_tighter() -> Result<(), ()> { let 0 = 0?; - //~^ ERROR the `?` operator can only be applied to values that implement `Try` + //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } (let 0 = 0)?; @@ -260,8 +275,8 @@ fn outside_if_and_while_expr() { //~^ ERROR expected expression, found `let` statement (let Range { start: _, end: _ } = true..true || false); - //~^ ERROR mismatched types - //~| ERROR expected expression, found `let` statement + //~^ ERROR expected expression, found `let` statement + //[feature,no_feature]~| ERROR mismatched types (let true = let true = true); //~^ ERROR expected expression, found `let` statement @@ -285,6 +300,7 @@ fn outside_if_and_while_expr() { } // Let's make sure that `let` inside const generic arguments are considered. +#[cfg(not(nothing))] fn inside_const_generic_arguments() { struct A; impl A<{B}> { const O: u32 = 5; } @@ -317,6 +333,7 @@ fn inside_const_generic_arguments() { >::O == 5 {} } +#[cfg(not(nothing))] fn with_parenthesis() { let opt = Some(Some(1i32)); @@ -332,6 +349,7 @@ fn with_parenthesis() { //~| ERROR expected expression, found `let` statement } if let Some(a) = opt && (true && true) { + //[no_feature]~^ ERROR `let` expressions in this position are unstable } if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { @@ -347,14 +365,18 @@ fn with_parenthesis() { } if (true && (true)) && let Some(a) = opt { + //[no_feature]~^ ERROR `let` expressions in this position are unstable } if (true) && let Some(a) = opt { + //[no_feature]~^ ERROR `let` expressions in this position are unstable } if true && let Some(a) = opt { + //[no_feature]~^ ERROR `let` expressions in this position are unstable } let fun = || true; if let true = (true && fun()) && (true) { + //[no_feature]~^ ERROR `let` expressions in this position are unstable } #[cfg(FALSE)] From 935bf6995f7cad774b12168b76d8253285a4101e Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 9 Nov 2024 23:31:11 +0100 Subject: [PATCH 59/79] Add more places where expressions can occur --- .../disallowed-positions.feature.stderr | 398 +++++++++++------ .../disallowed-positions.no_feature.stderr | 416 ++++++++++++------ .../disallowed-positions.nothing.stderr | 366 ++++++++++----- .../disallowed-positions.rs | 53 +++ 4 files changed, 835 insertions(+), 398 deletions(-) diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr index ae3856b7e7595..db32b8c1de4ff 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr @@ -1,239 +1,239 @@ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:32:9 + --> $DIR/disallowed-positions.rs:33:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:32:9 + --> $DIR/disallowed-positions.rs:33:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:35:11 + --> $DIR/disallowed-positions.rs:36:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:35:11 + --> $DIR/disallowed-positions.rs:36:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:38:9 + --> $DIR/disallowed-positions.rs:39:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:38:9 + --> $DIR/disallowed-positions.rs:39:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:41:17 + --> $DIR/disallowed-positions.rs:42:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:41:17 + --> $DIR/disallowed-positions.rs:42:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:44:9 + --> $DIR/disallowed-positions.rs:45:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:44:9 + --> $DIR/disallowed-positions.rs:45:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:44:24 + --> $DIR/disallowed-positions.rs:45:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:44:24 + --> $DIR/disallowed-positions.rs:45:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:48 + --> $DIR/disallowed-positions.rs:49:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:61 + --> $DIR/disallowed-positions.rs:49:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:59:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:59:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:61:14 + --> $DIR/disallowed-positions.rs:62:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:61:14 + --> $DIR/disallowed-positions.rs:62:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:65:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:65:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:67:20 + --> $DIR/disallowed-positions.rs:68:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:67:20 + --> $DIR/disallowed-positions.rs:68:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:70:12 + --> $DIR/disallowed-positions.rs:71:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:70:12 + --> $DIR/disallowed-positions.rs:71:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:70:27 + --> $DIR/disallowed-positions.rs:71:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:70:27 + --> $DIR/disallowed-positions.rs:71:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:51 + --> $DIR/disallowed-positions.rs:75:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:64 + --> $DIR/disallowed-positions.rs:75:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:98:9 + --> $DIR/disallowed-positions.rs:99:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:101:9 + --> $DIR/disallowed-positions.rs:102:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:103:9 + --> $DIR/disallowed-positions.rs:104:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:105:9 + --> $DIR/disallowed-positions.rs:106:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:113:9 + --> $DIR/disallowed-positions.rs:114:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:116:16 + --> $DIR/disallowed-positions.rs:117:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:116:13 + --> $DIR/disallowed-positions.rs:117:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:118:17 + --> $DIR/disallowed-positions.rs:119:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:120:25 + --> $DIR/disallowed-positions.rs:121:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:122:25 + --> $DIR/disallowed-positions.rs:123:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:126:12 + --> $DIR/disallowed-positions.rs:127:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:129:15 + --> $DIR/disallowed-positions.rs:130:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:132:11 + --> $DIR/disallowed-positions.rs:133:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:134:9 + --> $DIR/disallowed-positions.rs:135:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:138:8 + --> $DIR/disallowed-positions.rs:139:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:141:8 + --> $DIR/disallowed-positions.rs:142:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:147:8 + --> $DIR/disallowed-positions.rs:148:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:153:8 + --> $DIR/disallowed-positions.rs:154:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:157:19 + --> $DIR/disallowed-positions.rs:158:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,71 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:163:12 + --> $DIR/disallowed-positions.rs:161:15 + | +LL | if return let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:164:21 + | +LL | loop { if break let 0 = 0 {} } + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:167:15 + | +LL | if (match let 0 = 0 { _ => { false } }) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:170:9 + | +LL | if (let 0 = 0, false).1 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:173:9 + | +LL | if (let 0 = 0,) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:177:13 + | +LL | if (let 0 = 0).await {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:181:12 + | +LL | if (|| let 0 = 0) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:184:9 + | +LL | if (let 0 = 0)() {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:190:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -390,7 +454,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:166:12 + --> $DIR/disallowed-positions.rs:193:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -398,7 +462,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:168:12 + --> $DIR/disallowed-positions.rs:195:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -406,7 +470,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:170:12 + --> $DIR/disallowed-positions.rs:197:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -414,7 +478,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:178:12 + --> $DIR/disallowed-positions.rs:205:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -422,20 +486,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:19 + --> $DIR/disallowed-positions.rs:208:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:181:16 + --> $DIR/disallowed-positions.rs:208:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:183:20 + --> $DIR/disallowed-positions.rs:210:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -443,7 +507,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:185:28 + --> $DIR/disallowed-positions.rs:212:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -451,7 +515,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:187:28 + --> $DIR/disallowed-positions.rs:214:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -459,7 +523,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:191:15 + --> $DIR/disallowed-positions.rs:218:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -467,7 +531,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:194:18 + --> $DIR/disallowed-positions.rs:221:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -475,7 +539,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:14 + --> $DIR/disallowed-positions.rs:224:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -483,7 +547,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:199:12 + --> $DIR/disallowed-positions.rs:226:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -491,7 +555,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:203:11 + --> $DIR/disallowed-positions.rs:230:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -499,7 +563,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:206:11 + --> $DIR/disallowed-positions.rs:233:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +571,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:11 + --> $DIR/disallowed-positions.rs:239:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -515,7 +579,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:11 + --> $DIR/disallowed-positions.rs:245:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -523,7 +587,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:222:22 + --> $DIR/disallowed-positions.rs:249:22 | LL | while let true = let true = true {} | ^^^ @@ -531,7 +595,71 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:239:6 + --> $DIR/disallowed-positions.rs:252:18 + | +LL | while return let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:255:39 + | +LL | 'outer: loop { while break 'outer let 0 = 0 {} } + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:258:18 + | +LL | while (match let 0 = 0 { _ => { false } }) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:261:12 + | +LL | while (let 0 = 0, false).1 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:264:12 + | +LL | while (let 0 = 0,) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:268:16 + | +LL | while (let 0 = 0).await {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:272:15 + | +LL | while (|| let 0 = 0) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:275:12 + | +LL | while (let 0 = 0)() {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:292:6 | LL | &let 0 = 0; | ^^^ @@ -539,7 +667,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:242:6 + --> $DIR/disallowed-positions.rs:295:6 | LL | !let 0 = 0; | ^^^ @@ -547,7 +675,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:244:6 + --> $DIR/disallowed-positions.rs:297:6 | LL | *let 0 = 0; | ^^^ @@ -555,7 +683,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:246:6 + --> $DIR/disallowed-positions.rs:299:6 | LL | -let 0 = 0; | ^^^ @@ -563,7 +691,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:248:13 + --> $DIR/disallowed-positions.rs:301:13 | LL | let _ = let _ = 3; | ^^^ @@ -571,7 +699,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:256:6 + --> $DIR/disallowed-positions.rs:309:6 | LL | (let 0 = 0)?; | ^^^ @@ -579,7 +707,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:259:13 + --> $DIR/disallowed-positions.rs:312:13 | LL | true || let 0 = 0; | ^^^ @@ -587,7 +715,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:261:14 + --> $DIR/disallowed-positions.rs:314:14 | LL | (true || let 0 = 0); | ^^^ @@ -595,7 +723,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:263:22 + --> $DIR/disallowed-positions.rs:316:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -603,7 +731,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:267:9 + --> $DIR/disallowed-positions.rs:320:9 | LL | x = let 0 = 0; | ^^^ @@ -611,7 +739,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:270:12 + --> $DIR/disallowed-positions.rs:323:12 | LL | true..(let 0 = 0); | ^^^ @@ -619,7 +747,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:8 + --> $DIR/disallowed-positions.rs:325:8 | LL | ..(let 0 = 0); | ^^^ @@ -627,7 +755,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:274:6 + --> $DIR/disallowed-positions.rs:327:6 | LL | (let 0 = 0)..; | ^^^ @@ -635,7 +763,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:277:6 + --> $DIR/disallowed-positions.rs:330:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -643,7 +771,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:281:6 + --> $DIR/disallowed-positions.rs:334:6 | LL | (let true = let true = true); | ^^^ @@ -651,7 +779,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:281:17 + --> $DIR/disallowed-positions.rs:334:17 | LL | (let true = let true = true); | ^^^ @@ -659,7 +787,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:287:25 + --> $DIR/disallowed-positions.rs:340:25 | LL | let x = true && let y = 1; | ^^^ @@ -667,7 +795,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:293:19 + --> $DIR/disallowed-positions.rs:346:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -675,7 +803,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:298:6 + --> $DIR/disallowed-positions.rs:351:6 | LL | &let 0 = 0 | ^^^ @@ -683,7 +811,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:309:17 + --> $DIR/disallowed-positions.rs:362:17 | LL | true && let 1 = 1 | ^^^ @@ -691,7 +819,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:314:17 + --> $DIR/disallowed-positions.rs:367:17 | LL | true && let 1 = 1 | ^^^ @@ -699,7 +827,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:319:17 + --> $DIR/disallowed-positions.rs:372:17 | LL | true && let 1 = 1 | ^^^ @@ -707,7 +835,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:17 + --> $DIR/disallowed-positions.rs:383:17 | LL | true && let 1 = 1 | ^^^ @@ -715,7 +843,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:330:9 + --> $DIR/disallowed-positions.rs:383:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -726,124 +854,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:340:9 + --> $DIR/disallowed-positions.rs:393:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:340:9 + --> $DIR/disallowed-positions.rs:393:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:344:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:344:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:347:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:347:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:347:32 + --> $DIR/disallowed-positions.rs:400:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:347:32 + --> $DIR/disallowed-positions.rs:400:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:9 + --> $DIR/disallowed-positions.rs:408:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:355:9 + --> $DIR/disallowed-positions.rs:408:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:31 + --> $DIR/disallowed-positions.rs:408:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:355:31 + --> $DIR/disallowed-positions.rs:408:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:359:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:359:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:359:31 + --> $DIR/disallowed-positions.rs:412:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:359:31 + --> $DIR/disallowed-positions.rs:412:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:363:9 + --> $DIR/disallowed-positions.rs:416:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:363:9 + --> $DIR/disallowed-positions.rs:416:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:383:22 + --> $DIR/disallowed-positions.rs:436:22 | LL | let x = (true && let y = 1); | ^^^ @@ -851,7 +979,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:388:20 + --> $DIR/disallowed-positions.rs:441:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -859,7 +987,7 @@ LL | ([1, 2, 3][let _ = ()]) = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:90:16 + --> $DIR/disallowed-positions.rs:91:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -867,7 +995,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:92:16 + --> $DIR/disallowed-positions.rs:93:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -875,7 +1003,7 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if` and `while` expressions error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:129:8 + --> $DIR/disallowed-positions.rs:130:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -884,7 +1012,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:138:12 + --> $DIR/disallowed-positions.rs:139:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -895,7 +1023,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:141:12 + --> $DIR/disallowed-positions.rs:142:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -906,7 +1034,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:147:12 + --> $DIR/disallowed-positions.rs:148:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -917,7 +1045,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:153:12 + --> $DIR/disallowed-positions.rs:154:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -928,7 +1056,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:109:20 + --> $DIR/disallowed-positions.rs:110:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -936,7 +1064,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:194:11 + --> $DIR/disallowed-positions.rs:221:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -945,7 +1073,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:203:15 + --> $DIR/disallowed-positions.rs:230:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -956,7 +1084,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:206:15 + --> $DIR/disallowed-positions.rs:233:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -967,7 +1095,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:212:15 + --> $DIR/disallowed-positions.rs:239:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -978,7 +1106,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:218:15 + --> $DIR/disallowed-positions.rs:245:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -989,7 +1117,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:174:23 + --> $DIR/disallowed-positions.rs:201:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -997,7 +1125,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:277:10 + --> $DIR/disallowed-positions.rs:330:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1008,14 +1136,14 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:252:17 + --> $DIR/disallowed-positions.rs:305:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 105 previous errors +error: aborting due to 121 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr index fd418f4ed7c6c..ad16a0f8ed812 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr @@ -1,239 +1,239 @@ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:32:9 + --> $DIR/disallowed-positions.rs:33:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:32:9 + --> $DIR/disallowed-positions.rs:33:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:35:11 + --> $DIR/disallowed-positions.rs:36:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:35:11 + --> $DIR/disallowed-positions.rs:36:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:38:9 + --> $DIR/disallowed-positions.rs:39:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:38:9 + --> $DIR/disallowed-positions.rs:39:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:41:17 + --> $DIR/disallowed-positions.rs:42:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:41:17 + --> $DIR/disallowed-positions.rs:42:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:44:9 + --> $DIR/disallowed-positions.rs:45:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:44:9 + --> $DIR/disallowed-positions.rs:45:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:44:24 + --> $DIR/disallowed-positions.rs:45:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:44:24 + --> $DIR/disallowed-positions.rs:45:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:48 + --> $DIR/disallowed-positions.rs:49:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:61 + --> $DIR/disallowed-positions.rs:49:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:59:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:59:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:61:14 + --> $DIR/disallowed-positions.rs:62:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:61:14 + --> $DIR/disallowed-positions.rs:62:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:65:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:65:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:67:20 + --> $DIR/disallowed-positions.rs:68:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:67:20 + --> $DIR/disallowed-positions.rs:68:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:70:12 + --> $DIR/disallowed-positions.rs:71:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:70:12 + --> $DIR/disallowed-positions.rs:71:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:70:27 + --> $DIR/disallowed-positions.rs:71:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:70:27 + --> $DIR/disallowed-positions.rs:71:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:51 + --> $DIR/disallowed-positions.rs:75:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:64 + --> $DIR/disallowed-positions.rs:75:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:98:9 + --> $DIR/disallowed-positions.rs:99:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:101:9 + --> $DIR/disallowed-positions.rs:102:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:103:9 + --> $DIR/disallowed-positions.rs:104:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:105:9 + --> $DIR/disallowed-positions.rs:106:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:113:9 + --> $DIR/disallowed-positions.rs:114:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:116:16 + --> $DIR/disallowed-positions.rs:117:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:116:13 + --> $DIR/disallowed-positions.rs:117:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:118:17 + --> $DIR/disallowed-positions.rs:119:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:120:25 + --> $DIR/disallowed-positions.rs:121:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:122:25 + --> $DIR/disallowed-positions.rs:123:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:126:12 + --> $DIR/disallowed-positions.rs:127:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:129:15 + --> $DIR/disallowed-positions.rs:130:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:132:11 + --> $DIR/disallowed-positions.rs:133:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:134:9 + --> $DIR/disallowed-positions.rs:135:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:138:8 + --> $DIR/disallowed-positions.rs:139:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:141:8 + --> $DIR/disallowed-positions.rs:142:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:147:8 + --> $DIR/disallowed-positions.rs:148:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:153:8 + --> $DIR/disallowed-positions.rs:154:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:157:19 + --> $DIR/disallowed-positions.rs:158:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,71 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:163:12 + --> $DIR/disallowed-positions.rs:161:15 + | +LL | if return let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:164:21 + | +LL | loop { if break let 0 = 0 {} } + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:167:15 + | +LL | if (match let 0 = 0 { _ => { false } }) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:170:9 + | +LL | if (let 0 = 0, false).1 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:173:9 + | +LL | if (let 0 = 0,) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:177:13 + | +LL | if (let 0 = 0).await {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:181:12 + | +LL | if (|| let 0 = 0) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:184:9 + | +LL | if (let 0 = 0)() {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:190:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -390,7 +454,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:166:12 + --> $DIR/disallowed-positions.rs:193:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -398,7 +462,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:168:12 + --> $DIR/disallowed-positions.rs:195:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -406,7 +470,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:170:12 + --> $DIR/disallowed-positions.rs:197:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -414,7 +478,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:178:12 + --> $DIR/disallowed-positions.rs:205:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -422,20 +486,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:19 + --> $DIR/disallowed-positions.rs:208:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:181:16 + --> $DIR/disallowed-positions.rs:208:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:183:20 + --> $DIR/disallowed-positions.rs:210:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -443,7 +507,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:185:28 + --> $DIR/disallowed-positions.rs:212:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -451,7 +515,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:187:28 + --> $DIR/disallowed-positions.rs:214:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -459,7 +523,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:191:15 + --> $DIR/disallowed-positions.rs:218:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -467,7 +531,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:194:18 + --> $DIR/disallowed-positions.rs:221:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -475,7 +539,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:14 + --> $DIR/disallowed-positions.rs:224:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -483,7 +547,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:199:12 + --> $DIR/disallowed-positions.rs:226:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -491,7 +555,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:203:11 + --> $DIR/disallowed-positions.rs:230:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -499,7 +563,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:206:11 + --> $DIR/disallowed-positions.rs:233:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +571,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:11 + --> $DIR/disallowed-positions.rs:239:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -515,7 +579,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:11 + --> $DIR/disallowed-positions.rs:245:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -523,7 +587,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:222:22 + --> $DIR/disallowed-positions.rs:249:22 | LL | while let true = let true = true {} | ^^^ @@ -531,7 +595,71 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:239:6 + --> $DIR/disallowed-positions.rs:252:18 + | +LL | while return let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:255:39 + | +LL | 'outer: loop { while break 'outer let 0 = 0 {} } + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:258:18 + | +LL | while (match let 0 = 0 { _ => { false } }) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:261:12 + | +LL | while (let 0 = 0, false).1 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:264:12 + | +LL | while (let 0 = 0,) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:268:16 + | +LL | while (let 0 = 0).await {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:272:15 + | +LL | while (|| let 0 = 0) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:275:12 + | +LL | while (let 0 = 0)() {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:292:6 | LL | &let 0 = 0; | ^^^ @@ -539,7 +667,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:242:6 + --> $DIR/disallowed-positions.rs:295:6 | LL | !let 0 = 0; | ^^^ @@ -547,7 +675,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:244:6 + --> $DIR/disallowed-positions.rs:297:6 | LL | *let 0 = 0; | ^^^ @@ -555,7 +683,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:246:6 + --> $DIR/disallowed-positions.rs:299:6 | LL | -let 0 = 0; | ^^^ @@ -563,7 +691,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:248:13 + --> $DIR/disallowed-positions.rs:301:13 | LL | let _ = let _ = 3; | ^^^ @@ -571,7 +699,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:256:6 + --> $DIR/disallowed-positions.rs:309:6 | LL | (let 0 = 0)?; | ^^^ @@ -579,7 +707,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:259:13 + --> $DIR/disallowed-positions.rs:312:13 | LL | true || let 0 = 0; | ^^^ @@ -587,7 +715,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:261:14 + --> $DIR/disallowed-positions.rs:314:14 | LL | (true || let 0 = 0); | ^^^ @@ -595,7 +723,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:263:22 + --> $DIR/disallowed-positions.rs:316:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -603,7 +731,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:267:9 + --> $DIR/disallowed-positions.rs:320:9 | LL | x = let 0 = 0; | ^^^ @@ -611,7 +739,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:270:12 + --> $DIR/disallowed-positions.rs:323:12 | LL | true..(let 0 = 0); | ^^^ @@ -619,7 +747,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:8 + --> $DIR/disallowed-positions.rs:325:8 | LL | ..(let 0 = 0); | ^^^ @@ -627,7 +755,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:274:6 + --> $DIR/disallowed-positions.rs:327:6 | LL | (let 0 = 0)..; | ^^^ @@ -635,7 +763,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:277:6 + --> $DIR/disallowed-positions.rs:330:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -643,7 +771,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:281:6 + --> $DIR/disallowed-positions.rs:334:6 | LL | (let true = let true = true); | ^^^ @@ -651,7 +779,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:281:17 + --> $DIR/disallowed-positions.rs:334:17 | LL | (let true = let true = true); | ^^^ @@ -659,7 +787,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:287:25 + --> $DIR/disallowed-positions.rs:340:25 | LL | let x = true && let y = 1; | ^^^ @@ -667,7 +795,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:293:19 + --> $DIR/disallowed-positions.rs:346:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -675,7 +803,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:298:6 + --> $DIR/disallowed-positions.rs:351:6 | LL | &let 0 = 0 | ^^^ @@ -683,7 +811,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:309:17 + --> $DIR/disallowed-positions.rs:362:17 | LL | true && let 1 = 1 | ^^^ @@ -691,7 +819,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:314:17 + --> $DIR/disallowed-positions.rs:367:17 | LL | true && let 1 = 1 | ^^^ @@ -699,7 +827,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:319:17 + --> $DIR/disallowed-positions.rs:372:17 | LL | true && let 1 = 1 | ^^^ @@ -707,7 +835,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:17 + --> $DIR/disallowed-positions.rs:383:17 | LL | true && let 1 = 1 | ^^^ @@ -715,7 +843,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:330:9 + --> $DIR/disallowed-positions.rs:383:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -726,124 +854,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:340:9 + --> $DIR/disallowed-positions.rs:393:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:340:9 + --> $DIR/disallowed-positions.rs:393:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:344:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:344:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:347:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:347:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:347:32 + --> $DIR/disallowed-positions.rs:400:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:347:32 + --> $DIR/disallowed-positions.rs:400:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:9 + --> $DIR/disallowed-positions.rs:408:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:355:9 + --> $DIR/disallowed-positions.rs:408:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:31 + --> $DIR/disallowed-positions.rs:408:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:355:31 + --> $DIR/disallowed-positions.rs:408:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:359:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:359:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:359:31 + --> $DIR/disallowed-positions.rs:412:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:359:31 + --> $DIR/disallowed-positions.rs:412:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:363:9 + --> $DIR/disallowed-positions.rs:416:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:363:9 + --> $DIR/disallowed-positions.rs:416:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:383:22 + --> $DIR/disallowed-positions.rs:436:22 | LL | let x = (true && let y = 1); | ^^^ @@ -851,7 +979,7 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:388:20 + --> $DIR/disallowed-positions.rs:441:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ @@ -859,7 +987,7 @@ LL | ([1, 2, 3][let _ = ()]) = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:90:16 + --> $DIR/disallowed-positions.rs:91:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); | ^^^ @@ -867,7 +995,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:92:16 + --> $DIR/disallowed-positions.rs:93:16 | LL | use_expr!((let 0 = 1)); | ^^^ @@ -875,7 +1003,7 @@ LL | use_expr!((let 0 = 1)); = note: only supported directly in conditions of `if` and `while` expressions error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:48:8 + --> $DIR/disallowed-positions.rs:49:8 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ @@ -885,7 +1013,7 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:48:21 + --> $DIR/disallowed-positions.rs:49:21 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ @@ -895,7 +1023,7 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:74:11 + --> $DIR/disallowed-positions.rs:75:11 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ @@ -905,7 +1033,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:74:24 + --> $DIR/disallowed-positions.rs:75:24 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ @@ -915,7 +1043,7 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:351:8 + --> $DIR/disallowed-positions.rs:404:8 | LL | if let Some(a) = opt && (true && true) { | ^^^^^^^^^^^^^^^^^ @@ -925,7 +1053,7 @@ LL | if let Some(a) = opt && (true && true) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:367:28 + --> $DIR/disallowed-positions.rs:420:28 | LL | if (true && (true)) && let Some(a) = opt { | ^^^^^^^^^^^^^^^^^ @@ -935,7 +1063,7 @@ LL | if (true && (true)) && let Some(a) = opt { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:370:18 + --> $DIR/disallowed-positions.rs:423:18 | LL | if (true) && let Some(a) = opt { | ^^^^^^^^^^^^^^^^^ @@ -945,7 +1073,7 @@ LL | if (true) && let Some(a) = opt { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:373:16 + --> $DIR/disallowed-positions.rs:426:16 | LL | if true && let Some(a) = opt { | ^^^^^^^^^^^^^^^^^ @@ -955,7 +1083,7 @@ LL | if true && let Some(a) = opt { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `let` expressions in this position are unstable - --> $DIR/disallowed-positions.rs:378:8 + --> $DIR/disallowed-positions.rs:431:8 | LL | if let true = (true && fun()) && (true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -965,7 +1093,7 @@ LL | if let true = (true && fun()) && (true) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:129:8 + --> $DIR/disallowed-positions.rs:130:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -974,7 +1102,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:138:12 + --> $DIR/disallowed-positions.rs:139:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -985,7 +1113,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:141:12 + --> $DIR/disallowed-positions.rs:142:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -996,7 +1124,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:147:12 + --> $DIR/disallowed-positions.rs:148:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1007,7 +1135,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:153:12 + --> $DIR/disallowed-positions.rs:154:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1018,7 +1146,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:109:20 + --> $DIR/disallowed-positions.rs:110:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1026,7 +1154,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:194:11 + --> $DIR/disallowed-positions.rs:221:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range` @@ -1035,7 +1163,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:203:15 + --> $DIR/disallowed-positions.rs:230:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1046,7 +1174,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:206:15 + --> $DIR/disallowed-positions.rs:233:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1057,7 +1185,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:212:15 + --> $DIR/disallowed-positions.rs:239:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -1068,7 +1196,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:218:15 + --> $DIR/disallowed-positions.rs:245:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -1079,7 +1207,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:174:23 + --> $DIR/disallowed-positions.rs:201:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -1087,7 +1215,7 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:277:10 + --> $DIR/disallowed-positions.rs:330:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -1098,14 +1226,14 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:252:17 + --> $DIR/disallowed-positions.rs:305:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 114 previous errors +error: aborting due to 130 previous errors Some errors have detailed explanations: E0277, E0308, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr index dbe694b6e946d..2d5fd1144addd 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr @@ -1,239 +1,239 @@ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:32:9 + --> $DIR/disallowed-positions.rs:33:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:32:9 + --> $DIR/disallowed-positions.rs:33:9 | LL | if (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:35:11 + --> $DIR/disallowed-positions.rs:36:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:35:11 + --> $DIR/disallowed-positions.rs:36:11 | LL | if (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:38:9 + --> $DIR/disallowed-positions.rs:39:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:38:9 + --> $DIR/disallowed-positions.rs:39:9 | LL | if (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:41:17 + --> $DIR/disallowed-positions.rs:42:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:41:17 + --> $DIR/disallowed-positions.rs:42:17 | LL | if true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:44:9 + --> $DIR/disallowed-positions.rs:45:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:44:9 + --> $DIR/disallowed-positions.rs:45:9 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:44:24 + --> $DIR/disallowed-positions.rs:45:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:44:24 + --> $DIR/disallowed-positions.rs:45:24 | LL | if (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:48 + --> $DIR/disallowed-positions.rs:49:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:48:61 + --> $DIR/disallowed-positions.rs:49:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:48:35 + --> $DIR/disallowed-positions.rs:49:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:59:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:58:12 + --> $DIR/disallowed-positions.rs:59:12 | LL | while (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:61:14 + --> $DIR/disallowed-positions.rs:62:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:61:14 + --> $DIR/disallowed-positions.rs:62:14 | LL | while (((let 0 = 1))) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:65:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:64:12 + --> $DIR/disallowed-positions.rs:65:12 | LL | while (let 0 = 1) && true {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:67:20 + --> $DIR/disallowed-positions.rs:68:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:67:20 + --> $DIR/disallowed-positions.rs:68:20 | LL | while true && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:70:12 + --> $DIR/disallowed-positions.rs:71:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:70:12 + --> $DIR/disallowed-positions.rs:71:12 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:70:27 + --> $DIR/disallowed-positions.rs:71:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:70:27 + --> $DIR/disallowed-positions.rs:71:27 | LL | while (let 0 = 1) && (let 0 = 1) {} | ^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:51 + --> $DIR/disallowed-positions.rs:75:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:74:64 + --> $DIR/disallowed-positions.rs:75:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:74:38 + --> $DIR/disallowed-positions.rs:75:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:98:9 + --> $DIR/disallowed-positions.rs:99:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -241,7 +241,7 @@ LL | if &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:101:9 + --> $DIR/disallowed-positions.rs:102:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -249,7 +249,7 @@ LL | if !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:103:9 + --> $DIR/disallowed-positions.rs:104:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -257,7 +257,7 @@ LL | if *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:105:9 + --> $DIR/disallowed-positions.rs:106:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -265,7 +265,7 @@ LL | if -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:113:9 + --> $DIR/disallowed-positions.rs:114:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -273,20 +273,20 @@ LL | if (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:116:16 + --> $DIR/disallowed-positions.rs:117:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:116:13 + --> $DIR/disallowed-positions.rs:117:13 | LL | if true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:118:17 + --> $DIR/disallowed-positions.rs:119:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -294,7 +294,7 @@ LL | if (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:120:25 + --> $DIR/disallowed-positions.rs:121:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | if true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:122:25 + --> $DIR/disallowed-positions.rs:123:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -310,7 +310,7 @@ LL | if true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:126:12 + --> $DIR/disallowed-positions.rs:127:12 | LL | if x = let 0 = 0 {} | ^^^ @@ -318,7 +318,7 @@ LL | if x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:129:15 + --> $DIR/disallowed-positions.rs:130:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -326,7 +326,7 @@ LL | if true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:132:11 + --> $DIR/disallowed-positions.rs:133:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -334,7 +334,7 @@ LL | if ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:134:9 + --> $DIR/disallowed-positions.rs:135:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -342,7 +342,7 @@ LL | if (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:138:8 + --> $DIR/disallowed-positions.rs:139:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:141:8 + --> $DIR/disallowed-positions.rs:142:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:147:8 + --> $DIR/disallowed-positions.rs:148:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:153:8 + --> $DIR/disallowed-positions.rs:154:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:157:19 + --> $DIR/disallowed-positions.rs:158:19 | LL | if let true = let true = true {} | ^^^ @@ -382,7 +382,71 @@ LL | if let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:163:12 + --> $DIR/disallowed-positions.rs:161:15 + | +LL | if return let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:164:21 + | +LL | loop { if break let 0 = 0 {} } + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:167:15 + | +LL | if (match let 0 = 0 { _ => { false } }) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:170:9 + | +LL | if (let 0 = 0, false).1 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:173:9 + | +LL | if (let 0 = 0,) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:177:13 + | +LL | if (let 0 = 0).await {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:181:12 + | +LL | if (|| let 0 = 0) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:184:9 + | +LL | if (let 0 = 0)() {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:190:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -390,7 +454,7 @@ LL | while &let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:166:12 + --> $DIR/disallowed-positions.rs:193:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -398,7 +462,7 @@ LL | while !let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:168:12 + --> $DIR/disallowed-positions.rs:195:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -406,7 +470,7 @@ LL | while *let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:170:12 + --> $DIR/disallowed-positions.rs:197:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -414,7 +478,7 @@ LL | while -let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:178:12 + --> $DIR/disallowed-positions.rs:205:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -422,20 +486,20 @@ LL | while (let 0 = 0)? {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:181:19 + --> $DIR/disallowed-positions.rs:208:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `||` operators are not supported in let chain expressions - --> $DIR/disallowed-positions.rs:181:16 + --> $DIR/disallowed-positions.rs:208:16 | LL | while true || let 0 = 0 {} | ^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:183:20 + --> $DIR/disallowed-positions.rs:210:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -443,7 +507,7 @@ LL | while (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:185:28 + --> $DIR/disallowed-positions.rs:212:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -451,7 +515,7 @@ LL | while true && (true || let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:187:28 + --> $DIR/disallowed-positions.rs:214:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -459,7 +523,7 @@ LL | while true || (true && let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:191:15 + --> $DIR/disallowed-positions.rs:218:15 | LL | while x = let 0 = 0 {} | ^^^ @@ -467,7 +531,7 @@ LL | while x = let 0 = 0 {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:194:18 + --> $DIR/disallowed-positions.rs:221:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -475,7 +539,7 @@ LL | while true..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:197:14 + --> $DIR/disallowed-positions.rs:224:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -483,7 +547,7 @@ LL | while ..(let 0 = 0) {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:199:12 + --> $DIR/disallowed-positions.rs:226:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -491,7 +555,7 @@ LL | while (let 0 = 0).. {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:203:11 + --> $DIR/disallowed-positions.rs:230:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -499,7 +563,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:206:11 + --> $DIR/disallowed-positions.rs:233:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +571,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:11 + --> $DIR/disallowed-positions.rs:239:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -515,7 +579,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:218:11 + --> $DIR/disallowed-positions.rs:245:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -523,7 +587,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:222:22 + --> $DIR/disallowed-positions.rs:249:22 | LL | while let true = let true = true {} | ^^^ @@ -531,7 +595,71 @@ LL | while let true = let true = true {} = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:239:6 + --> $DIR/disallowed-positions.rs:252:18 + | +LL | while return let 0 = 0 {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:255:39 + | +LL | 'outer: loop { while break 'outer let 0 = 0 {} } + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:258:18 + | +LL | while (match let 0 = 0 { _ => { false } }) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:261:12 + | +LL | while (let 0 = 0, false).1 {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:264:12 + | +LL | while (let 0 = 0,) {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:268:16 + | +LL | while (let 0 = 0).await {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:272:15 + | +LL | while (|| let 0 = 0) {} + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:275:12 + | +LL | while (let 0 = 0)() {} + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: expected expression, found `let` statement + --> $DIR/disallowed-positions.rs:292:6 | LL | &let 0 = 0; | ^^^ @@ -539,7 +667,7 @@ LL | &let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:242:6 + --> $DIR/disallowed-positions.rs:295:6 | LL | !let 0 = 0; | ^^^ @@ -547,7 +675,7 @@ LL | !let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:244:6 + --> $DIR/disallowed-positions.rs:297:6 | LL | *let 0 = 0; | ^^^ @@ -555,7 +683,7 @@ LL | *let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:246:6 + --> $DIR/disallowed-positions.rs:299:6 | LL | -let 0 = 0; | ^^^ @@ -563,7 +691,7 @@ LL | -let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:248:13 + --> $DIR/disallowed-positions.rs:301:13 | LL | let _ = let _ = 3; | ^^^ @@ -571,7 +699,7 @@ LL | let _ = let _ = 3; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:256:6 + --> $DIR/disallowed-positions.rs:309:6 | LL | (let 0 = 0)?; | ^^^ @@ -579,7 +707,7 @@ LL | (let 0 = 0)?; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:259:13 + --> $DIR/disallowed-positions.rs:312:13 | LL | true || let 0 = 0; | ^^^ @@ -587,7 +715,7 @@ LL | true || let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:261:14 + --> $DIR/disallowed-positions.rs:314:14 | LL | (true || let 0 = 0); | ^^^ @@ -595,7 +723,7 @@ LL | (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:263:22 + --> $DIR/disallowed-positions.rs:316:22 | LL | true && (true || let 0 = 0); | ^^^ @@ -603,7 +731,7 @@ LL | true && (true || let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:267:9 + --> $DIR/disallowed-positions.rs:320:9 | LL | x = let 0 = 0; | ^^^ @@ -611,7 +739,7 @@ LL | x = let 0 = 0; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:270:12 + --> $DIR/disallowed-positions.rs:323:12 | LL | true..(let 0 = 0); | ^^^ @@ -619,7 +747,7 @@ LL | true..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:272:8 + --> $DIR/disallowed-positions.rs:325:8 | LL | ..(let 0 = 0); | ^^^ @@ -627,7 +755,7 @@ LL | ..(let 0 = 0); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:274:6 + --> $DIR/disallowed-positions.rs:327:6 | LL | (let 0 = 0)..; | ^^^ @@ -635,7 +763,7 @@ LL | (let 0 = 0)..; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:277:6 + --> $DIR/disallowed-positions.rs:330:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^ @@ -643,7 +771,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:281:6 + --> $DIR/disallowed-positions.rs:334:6 | LL | (let true = let true = true); | ^^^ @@ -651,7 +779,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:281:17 + --> $DIR/disallowed-positions.rs:334:17 | LL | (let true = let true = true); | ^^^ @@ -659,7 +787,7 @@ LL | (let true = let true = true); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:287:25 + --> $DIR/disallowed-positions.rs:340:25 | LL | let x = true && let y = 1; | ^^^ @@ -667,7 +795,7 @@ LL | let x = true && let y = 1; = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:293:19 + --> $DIR/disallowed-positions.rs:346:19 | LL | [1, 2, 3][let _ = ()] | ^^^ @@ -675,7 +803,7 @@ LL | [1, 2, 3][let _ = ()] = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:298:6 + --> $DIR/disallowed-positions.rs:351:6 | LL | &let 0 = 0 | ^^^ @@ -683,7 +811,7 @@ LL | &let 0 = 0 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:309:17 + --> $DIR/disallowed-positions.rs:362:17 | LL | true && let 1 = 1 | ^^^ @@ -691,7 +819,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:314:17 + --> $DIR/disallowed-positions.rs:367:17 | LL | true && let 1 = 1 | ^^^ @@ -699,7 +827,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:319:17 + --> $DIR/disallowed-positions.rs:372:17 | LL | true && let 1 = 1 | ^^^ @@ -707,7 +835,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:330:17 + --> $DIR/disallowed-positions.rs:383:17 | LL | true && let 1 = 1 | ^^^ @@ -715,7 +843,7 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if` and `while` expressions error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:330:9 + --> $DIR/disallowed-positions.rs:383:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -726,124 +854,124 @@ LL | { true && let 1 = 1 } | + + error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:340:9 + --> $DIR/disallowed-positions.rs:393:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:340:9 + --> $DIR/disallowed-positions.rs:393:9 | LL | if (let Some(a) = opt && true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:344:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:344:9 + --> $DIR/disallowed-positions.rs:397:9 | LL | if (let Some(a) = opt) && true { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:347:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:347:9 + --> $DIR/disallowed-positions.rs:400:9 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:347:32 + --> $DIR/disallowed-positions.rs:400:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:347:32 + --> $DIR/disallowed-positions.rs:400:32 | LL | if (let Some(a) = opt) && (let Some(b) = a) { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:9 + --> $DIR/disallowed-positions.rs:408:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:355:9 + --> $DIR/disallowed-positions.rs:408:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:355:31 + --> $DIR/disallowed-positions.rs:408:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:355:31 + --> $DIR/disallowed-positions.rs:408:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:359:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:359:9 + --> $DIR/disallowed-positions.rs:412:9 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:359:31 + --> $DIR/disallowed-positions.rs:412:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:359:31 + --> $DIR/disallowed-positions.rs:412:31 | LL | if (let Some(a) = opt && (let Some(b) = a)) && true { | ^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:363:9 + --> $DIR/disallowed-positions.rs:416:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions note: `let`s wrapped in parentheses are not supported in a context with let chains - --> $DIR/disallowed-positions.rs:363:9 + --> $DIR/disallowed-positions.rs:416:9 | LL | if (let Some(a) = opt && (true)) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:383:22 + --> $DIR/disallowed-positions.rs:436:22 | LL | let x = (true && let y = 1); | ^^^ @@ -851,12 +979,12 @@ LL | let x = (true && let y = 1); = note: only supported directly in conditions of `if` and `while` expressions error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:388:20 + --> $DIR/disallowed-positions.rs:441:20 | LL | ([1, 2, 3][let _ = ()]) | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions -error: aborting due to 89 previous errors +error: aborting due to 105 previous errors diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs index c0f7b03a6e3e7..8eb8d617d581c 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -1,4 +1,5 @@ //@ revisions: no_feature feature nothing +//@ edition: 2021 // Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions. // // We want to make sure that `let` is banned in situations other than: @@ -156,6 +157,32 @@ fn nested_within_if_expr() { if let true = let true = true {} //~^ ERROR expected expression, found `let` statement + + if return let 0 = 0 {} + //~^ ERROR expected expression, found `let` statement + + loop { if break let 0 = 0 {} } + //~^ ERROR expected expression, found `let` statement + + if (match let 0 = 0 { _ => { false } }) {} + //~^ ERROR expected expression, found `let` statement + + if (let 0 = 0, false).1 {} + //~^ ERROR expected expression, found `let` statement + + if (let 0 = 0,) {} + //~^ ERROR expected expression, found `let` statement + + async fn foo() { + if (let 0 = 0).await {} + //~^ ERROR expected expression, found `let` statement + } + + if (|| let 0 = 0) {} + //~^ ERROR expected expression, found `let` statement + + if (let 0 = 0)() {} + //~^ ERROR expected expression, found `let` statement } #[cfg(not(nothing))] @@ -221,6 +248,32 @@ fn nested_within_while_expr() { while let true = let true = true {} //~^ ERROR expected expression, found `let` statement + + while return let 0 = 0 {} + //~^ ERROR expected expression, found `let` statement + + 'outer: loop { while break 'outer let 0 = 0 {} } + //~^ ERROR expected expression, found `let` statement + + while (match let 0 = 0 { _ => { false } }) {} + //~^ ERROR expected expression, found `let` statement + + while (let 0 = 0, false).1 {} + //~^ ERROR expected expression, found `let` statement + + while (let 0 = 0,) {} + //~^ ERROR expected expression, found `let` statement + + async fn foo() { + while (let 0 = 0).await {} + //~^ ERROR expected expression, found `let` statement + } + + while (|| let 0 = 0) {} + //~^ ERROR expected expression, found `let` statement + + while (let 0 = 0)() {} + //~^ ERROR expected expression, found `let` statement } #[cfg(not(nothing))] From 925dfc8608e1906e0fc51518f9b0cf40f22a5618 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 10 Nov 2024 11:53:04 +1100 Subject: [PATCH 60/79] coverage: Pass a `LocalFileId` to `CoverageSpan::from_source_region` --- compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs | 8 +++++++- compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index a73ee0a3e07cd..a6e07ea2a60ec 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -1,5 +1,7 @@ use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion}; +use crate::coverageinfo::mapgen::LocalFileId; + /// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -137,7 +139,11 @@ pub(crate) struct CoverageSpan { } impl CoverageSpan { - pub(crate) fn from_source_region(file_id: u32, code_region: &SourceRegion) -> Self { + pub(crate) fn from_source_region( + local_file_id: LocalFileId, + code_region: &SourceRegion, + ) -> Self { + let file_id = local_file_id.as_u32(); let &SourceRegion { start_line, start_col, end_line, end_col } = code_region; // Internally, LLVM uses the high bit of `end_col` to distinguish between // code regions and gap regions, so it can't be used by the column number. diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 488ce62074624..e008e2ad450d4 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -210,7 +210,7 @@ rustc_index::newtype_index! { /// An index into a function's list of global file IDs. That underlying list /// of local-to-global mappings will be embedded in the function's record in /// the `__llvm_covfun` linker section. - struct LocalFileId {} + pub(crate) struct LocalFileId {} } /// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU) @@ -280,7 +280,7 @@ fn encode_mappings_for_function( // form suitable for FFI. for (mapping_kind, region) in counter_regions { debug!("Adding counter {mapping_kind:?} to map for {region:?}"); - let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region); + let span = ffi::CoverageSpan::from_source_region(local_file_id, region); match mapping_kind { MappingKind::Code(term) => { code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); From 2ac1c1868f8034dd8a8b8d4c82fd0b9abb66a0f1 Mon Sep 17 00:00:00 2001 From: Kaden Nelson Date: Sat, 9 Nov 2024 15:16:22 -0600 Subject: [PATCH 61/79] Update grammar in wasm-c-abi's compiler flag documentation Co-authored-by: Jubilee --- src/doc/unstable-book/src/compiler-flags/wasm-c-abi.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-flags/wasm-c-abi.md b/src/doc/unstable-book/src/compiler-flags/wasm-c-abi.md index bde4bf58133b3..4dd8d9707d460 100644 --- a/src/doc/unstable-book/src/compiler-flags/wasm-c-abi.md +++ b/src/doc/unstable-book/src/compiler-flags/wasm-c-abi.md @@ -3,8 +3,8 @@ This option controls whether Rust uses the spec-compliant C ABI when compiling for the `wasm32-unknown-unknown` target. -This makes it possible to be ABI-compatible with all other spec-compliant Wasm -like Rusts `wasm32-wasip1`. +This makes it possible to be ABI-compatible with all other spec-compliant Wasm targets +like `wasm32-wasip1`. This compiler flag is perma-unstable, as it will be enabled by default in the future with no option to fall back to the old non-spec-compliant ABI. From 965a2801a09667ba87ae8d419aa04086dc3a5113 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 15 Oct 2024 23:41:51 +0900 Subject: [PATCH 62/79] Stabilize Arm64EC inline assembly --- compiler/rustc_ast_lowering/src/asm.rs | 1 + .../asm-experimental-arch.md | 32 ++----------------- tests/assembly/asm/aarch64-types.rs | 2 +- tests/codegen/asm/arm64ec-clobbers.rs | 2 +- tests/ui/asm/aarch64/arm64ec-sve.rs | 2 +- 5 files changed, 6 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 3acca94a54bdf..215e6d84d0f0a 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -45,6 +45,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | asm::InlineAsmArch::X86_64 | asm::InlineAsmArch::Arm | asm::InlineAsmArch::AArch64 + | asm::InlineAsmArch::Arm64EC | asm::InlineAsmArch::RiscV32 | asm::InlineAsmArch::RiscV64 | asm::InlineAsmArch::LoongArch64 diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index f00a0fe72876e..01de12bb90e98 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -18,7 +18,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - MSP430 - M68k - CSKY -- Arm64EC - SPARC ## Register classes @@ -53,9 +52,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | `f[0-31]` | `f` | | SPARC | `reg` | `r[2-29]` | `r` | | SPARC | `yreg` | `y` | Only clobbers | -| Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` | -| Arm64EC | `vreg` | `v[0-15]` | `w` | -| Arm64EC | `vreg_low16` | `v[0-15]` | `x` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -92,8 +88,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | None | `f32`, | | SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) | | SPARC | `yreg` | N/A | Only clobbers | -| Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | -| Arm64EC | `vreg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
`i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | ## Register aliases @@ -134,12 +128,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | SPARC | `r[8-15]` | `o[0-7]` | | SPARC | `r[16-23]` | `l[0-7]` | | SPARC | `r[24-31]` | `i[0-7]` | -| Arm64EC | `x[0-30]` | `w[0-30]` | -| Arm64EC | `x29` | `fp` | -| Arm64EC | `x30` | `lr` | -| Arm64EC | `sp` | `wsp` | -| Arm64EC | `xzr` | `wzr` | -| Arm64EC | `v[0-15]` | `b[0-15]`, `h[0-15]`, `s[0-15]`, `d[0-15]`, `q[0-15]` | > **Notes**: > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed @@ -150,8 +138,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | -| All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. | +| All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC) | The frame pointer cannot be used as an input or output. | +| All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | @@ -176,9 +164,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | SPARC | `r5`/`g5` | Reserved for system. (SPARC32 only) | | SPARC | `r6`/`g6`, `r7`/`g7` | Reserved for system. | | SPARC | `r31`/`i7` | Return address cannot be used as inputs or outputs. | -| Arm64EC | `xzr` | This is a constant zero register which can't be modified. | -| Arm64EC | `x18` | This is an OS-reserved register. | -| Arm64EC | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. | ## Template modifiers @@ -197,16 +182,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | SPARC | `reg` | None | `%o0` | None | | CSKY | `reg` | None | `r0` | None | | CSKY | `freg` | None | `f0` | None | -| Arm64EC | `reg` | None | `x0` | `x` | -| Arm64EC | `reg` | `w` | `w0` | `w` | -| Arm64EC | `reg` | `x` | `x0` | `x` | -| Arm64EC | `vreg` | None | `v0` | None | -| Arm64EC | `vreg` | `v` | `v0` | None | -| Arm64EC | `vreg` | `b` | `b0` | `b` | -| Arm64EC | `vreg` | `h` | `h0` | `h` | -| Arm64EC | `vreg` | `s` | `s0` | `s` | -| Arm64EC | `vreg` | `d` | `d0` | `d` | -| Arm64EC | `vreg` | `q` | `q0` | `q` | # Flags covered by `preserves_flags` @@ -220,6 +195,3 @@ These flags registers must be restored upon exiting the asm block if the `preser - SPARC - Integer condition codes (`icc` and `xcc`) - Floating-point condition codes (`fcc[0-3]`) -- Arm64EC - - Condition flags (`NZCV` register). - - Floating-point status (`FPSR` register). diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs index 1173ba8a4eb56..22e60cd8159b0 100644 --- a/tests/assembly/asm/aarch64-types.rs +++ b/tests/assembly/asm/aarch64-types.rs @@ -6,7 +6,7 @@ //@ [arm64ec] needs-llvm-components: aarch64 //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch, f16, f128)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd, f16, f128)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] diff --git a/tests/codegen/asm/arm64ec-clobbers.rs b/tests/codegen/asm/arm64ec-clobbers.rs index 2ec61907947cb..80059331642d7 100644 --- a/tests/codegen/asm/arm64ec-clobbers.rs +++ b/tests/codegen/asm/arm64ec-clobbers.rs @@ -3,7 +3,7 @@ //@ needs-llvm-components: aarch64 #![crate_type = "rlib"] -#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] +#![feature(no_core, rustc_attrs, lang_items)] #![no_core] #[lang = "sized"] diff --git a/tests/ui/asm/aarch64/arm64ec-sve.rs b/tests/ui/asm/aarch64/arm64ec-sve.rs index 389b365a75409..d2313f8417dc2 100644 --- a/tests/ui/asm/aarch64/arm64ec-sve.rs +++ b/tests/ui/asm/aarch64/arm64ec-sve.rs @@ -3,7 +3,7 @@ //@ needs-llvm-components: aarch64 #![crate_type = "rlib"] -#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)] +#![feature(no_core, rustc_attrs, lang_items)] #![no_core] // SVE cannot be used for Arm64EC From ce7a56072b78c9924de7c2e58378c6f206333b04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Nov 2024 10:01:05 +0100 Subject: [PATCH 63/79] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 5adbfbfebfb0a..bec28af6257fa 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -328b759142ddeae96da83176f103200009d3e3f1 +668959740f97e7a22ae340742886d330ab63950f From d1a481216487378361a2da130bb4de3c00e2aaad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Oct 2024 16:08:06 +0200 Subject: [PATCH 64/79] store futexes in per-allocation data rather than globally --- src/tools/miri/src/concurrency/sync.rs | 65 ++++++++++++------- src/tools/miri/src/concurrency/thread.rs | 2 +- src/tools/miri/src/shims/unix/linux/sync.rs | 62 ++++++++++++------ src/tools/miri/src/shims/windows/sync.rs | 41 +++++++++--- .../tests/pass-dep/concurrency/linux-futex.rs | 7 +- 5 files changed, 122 insertions(+), 55 deletions(-) diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 78e5ad5deb249..02e8261a6ed90 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -1,6 +1,8 @@ +use std::cell::RefCell; use std::collections::VecDeque; use std::collections::hash_map::Entry; use std::ops::Not; +use std::rc::Rc; use std::time::Duration; use rustc_abi::Size; @@ -121,6 +123,15 @@ struct Futex { clock: VClock, } +#[derive(Default, Clone)] +pub struct FutexRef(Rc>); + +impl VisitProvenance for FutexRef { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // No provenance in `Futex`. + } +} + /// A thread waiting on a futex. #[derive(Debug)] struct FutexWaiter { @@ -137,9 +148,6 @@ pub struct SynchronizationObjects { rwlocks: IndexVec, condvars: IndexVec, pub(super) init_onces: IndexVec, - - /// Futex info for the futex at the given address. - futexes: FxHashMap, } // Private extension trait for local helper methods @@ -184,7 +192,7 @@ impl SynchronizationObjects { } impl<'tcx> AllocExtra<'tcx> { - pub fn get_sync(&self, offset: Size) -> Option<&T> { + fn get_sync(&self, offset: Size) -> Option<&T> { self.sync.get(&offset).and_then(|s| s.downcast_ref::()) } } @@ -273,27 +281,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Get the synchronization primitive associated with the given pointer, /// or initialize a new one. + /// + /// Return `None` if this pointer does not point to at least 1 byte of mutable memory. fn get_sync_or_init<'a, T: 'static>( &'a mut self, ptr: Pointer, - new: impl FnOnce(&'a mut MiriMachine<'tcx>) -> InterpResult<'tcx, T>, - ) -> InterpResult<'tcx, &'a T> + new: impl FnOnce(&'a mut MiriMachine<'tcx>) -> T, + ) -> Option<&'a T> where 'tcx: 'a, { let this = self.eval_context_mut(); - // Ensure there is memory behind this pointer, so that this allocation - // is truly the only place where the data could be stored. - this.check_ptr_access(ptr, Size::from_bytes(1), CheckInAllocMsg::InboundsTest)?; - - let (alloc, offset, _) = this.ptr_get_alloc_id(ptr, 0)?; - let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc)?; + if !this.ptr_try_get_alloc_id(ptr, 0).ok().is_some_and(|(alloc_id, offset, ..)| { + let info = this.get_alloc_info(alloc_id); + info.kind == AllocKind::LiveData && info.mutbl.is_mut() && offset < info.size + }) { + return None; + } + // This cannot fail now. + let (alloc, offset, _) = this.ptr_get_alloc_id(ptr, 0).unwrap(); + let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc).unwrap(); // Due to borrow checker reasons, we have to do the lookup twice. if alloc_extra.get_sync::(offset).is_none() { - let new = new(machine)?; + let new = new(machine); alloc_extra.sync.insert(offset, Box::new(new)); } - interp_ok(alloc_extra.get_sync::(offset).unwrap()) + Some(alloc_extra.get_sync::(offset).unwrap()) } #[inline] @@ -690,7 +703,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// On a timeout, `retval_timeout` is written to `dest` and `errno_timeout` is set as the last error. fn futex_wait( &mut self, - addr: u64, + futex_ref: FutexRef, bitset: u32, timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, retval_succ: Scalar, @@ -700,23 +713,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) { let this = self.eval_context_mut(); let thread = this.active_thread(); - let futex = &mut this.machine.sync.futexes.entry(addr).or_default(); + let mut futex = futex_ref.0.borrow_mut(); let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread, bitset }); + drop(futex); + this.block_thread( - BlockReason::Futex { addr }, + BlockReason::Futex, timeout, callback!( @capture<'tcx> { - addr: u64, + futex_ref: FutexRef, retval_succ: Scalar, retval_timeout: Scalar, dest: MPlaceTy<'tcx>, errno_timeout: IoError, } @unblock = |this| { - let futex = this.machine.sync.futexes.get(&addr).unwrap(); + let futex = futex_ref.0.borrow(); // Acquire the clock of the futex. if let Some(data_race) = &this.machine.data_race { data_race.acquire_clock(&futex.clock, &this.machine.threads); @@ -728,7 +743,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { @timeout = |this| { // Remove the waiter from the futex. let thread = this.active_thread(); - let futex = this.machine.sync.futexes.get_mut(&addr).unwrap(); + let mut futex = futex_ref.0.borrow_mut(); futex.waiters.retain(|waiter| waiter.thread != thread); // Set errno and write return value. this.set_last_error(errno_timeout)?; @@ -739,12 +754,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } + /// Wake up the first thread in the queue that matches any of the bits in the bitset. /// Returns whether anything was woken. - fn futex_wake(&mut self, addr: u64, bitset: u32) -> InterpResult<'tcx, bool> { + fn futex_wake(&mut self, futex_ref: &FutexRef, bitset: u32) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let Some(futex) = this.machine.sync.futexes.get_mut(&addr) else { - return interp_ok(false); - }; + let mut futex = futex_ref.0.borrow_mut(); let data_race = &this.machine.data_race; // Each futex-wake happens-before the end of the futex wait @@ -757,7 +771,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(false); }; let waiter = futex.waiters.remove(i).unwrap(); - this.unblock_thread(waiter.thread, BlockReason::Futex { addr })?; + drop(futex); + this.unblock_thread(waiter.thread, BlockReason::Futex)?; interp_ok(true) } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 7477494281dc9..e6a3ae897c23b 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -147,7 +147,7 @@ pub enum BlockReason { /// Blocked on a reader-writer lock. RwLock(RwLockId), /// Blocked on a Futex variable. - Futex { addr: u64 }, + Futex, /// Blocked on an InitOnce. InitOnce(InitOnceId), /// Blocked on epoll. diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index 6d5747d7c159b..01b011d35046e 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -1,6 +1,11 @@ +use crate::concurrency::sync::FutexRef; use crate::helpers::check_min_arg_count; use crate::*; +struct LinuxFutex { + futex: FutexRef, +} + /// Implementation of the SYS_futex syscall. /// `args` is the arguments *including* the syscall number. pub fn futex<'tcx>( @@ -27,7 +32,6 @@ pub fn futex<'tcx>( // This is a vararg function so we have to bring our own type for this pointer. let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32); - let addr_usize = addr.ptr().addr().bytes(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG"); let futex_wait = this.eval_libc_i32("FUTEX_WAIT"); @@ -63,8 +67,7 @@ pub fn futex<'tcx>( }; if bitset == 0 { - this.set_last_error_and_return(LibcError("EINVAL"), dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } let timeout = this.deref_pointer_as(timeout, this.libc_ty_layout("timespec"))?; @@ -99,19 +102,18 @@ pub fn futex<'tcx>( // effects of this and the other thread are correctly observed, // otherwise we will deadlock. // - // There are two scenarios to consider: - // 1. If we (FUTEX_WAIT) execute first, we'll push ourselves into - // the waiters queue and go to sleep. They (addr write & FUTEX_WAKE) - // will see us in the queue and wake us up. - // 2. If they (addr write & FUTEX_WAKE) execute first, we must observe - // addr's new value. If we see an outdated value that happens to equal - // the expected val, then we'll put ourselves to sleep with no one to wake us - // up, so we end up with a deadlock. This is prevented by having a SeqCst - // fence inside FUTEX_WAKE syscall, and another SeqCst fence - // below, the atomic read on addr after the SeqCst fence is guaranteed - // not to see any value older than the addr write immediately before - // calling FUTEX_WAKE. We'll see futex_val != val and return without - // sleeping. + // There are two scenarios to consider, depending on whether WAIT or WAKE goes first: + // 1. If we (FUTEX_WAIT) execute first, we'll push ourselves into the waiters queue and + // go to sleep. They (FUTEX_WAKE) will see us in the queue and wake us up. It doesn't + // matter how the addr write is ordered. + // 2. If they (FUTEX_WAKE) execute first, that means the addr write is also before us + // (FUTEX_WAIT). It is crucial that we observe addr's new value. If we see an + // outdated value that happens to equal the expected val, then we'll put ourselves to + // sleep with no one to wake us up, so we end up with a deadlock. This is prevented + // by having a SeqCst fence inside FUTEX_WAKE syscall, and another SeqCst fence here + // in FUTEX_WAIT. The atomic read on addr after the SeqCst fence is guaranteed not to + // see any value older than the addr write immediately before calling FUTEX_WAKE. + // We'll see futex_val != val and return without sleeping. // // Note that the fences do not create any happens-before relationship. // The read sees the write immediately before the fence not because @@ -140,11 +142,22 @@ pub fn futex<'tcx>( this.atomic_fence(AtomicFenceOrd::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. - let futex_val = this.read_scalar_atomic(&addr, AtomicReadOrd::Relaxed)?.to_i32()?; + // We do an acquire read -- it only seems reasonable that if we observe a value here, we + // actually establish an ordering with that value. + let futex_val = this.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?; if val == futex_val { // The value still matches, so we block the thread and make it wait for FUTEX_WAKE. + + // This cannot fail since we already did an atomic acquire read on that pointer. + // Acquire reads are only allowed on mutable memory. + let futex_ref = this + .get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() }) + .unwrap() + .futex + .clone(); + this.futex_wait( - addr_usize, + futex_ref, bitset, timeout, Scalar::from_target_isize(0, this), // retval_succ @@ -165,6 +178,17 @@ pub fn futex<'tcx>( // FUTEX_WAKE_BITSET: (int *addr, int op = FUTEX_WAKE, int val, const timespect *_unused, int *_unused, unsigned int bitset) // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. op if op == futex_wake || op == futex_wake_bitset => { + let Some(futex_ref) = + this.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() }) + else { + // No AllocId, or no live allocation at that AllocId. + // Return an error code. (That seems nicer than silently doing something non-intuitive.) + // This means that if an address gets reused by a new allocation, + // we'll use an independent futex queue for this... that seems acceptable. + return this.set_last_error_and_return(LibcError("EFAULT"), dest); + }; + let futex_ref = futex_ref.futex.clone(); + let bitset = if op == futex_wake_bitset { let [_, _, _, _, timeout, uaddr2, bitset] = check_min_arg_count("`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", args)?; @@ -184,7 +208,7 @@ pub fn futex<'tcx>( let mut n = 0; #[expect(clippy::arithmetic_side_effects)] for _ in 0..val { - if this.futex_wake(addr_usize, bitset)? { + if this.futex_wake(&futex_ref, bitset)? { n += 1; } else { break; diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index 7263958411fb0..b03dedea146c4 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -3,6 +3,7 @@ use std::time::Duration; use rustc_abi::Size; use crate::concurrency::init_once::InitOnceStatus; +use crate::concurrency::sync::FutexRef; use crate::*; #[derive(Copy, Clone)] @@ -10,6 +11,10 @@ struct WindowsInitOnce { id: InitOnceId, } +struct WindowsFutex { + futex: FutexRef, +} + impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Windows sync primitives are pointer sized. @@ -168,8 +173,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let size = this.read_target_usize(size_op)?; let timeout_ms = this.read_scalar(timeout_op)?.to_u32()?; - let addr = ptr.addr().bytes(); - if size > 8 || !size.is_power_of_two() { let invalid_param = this.eval_windows("c", "ERROR_INVALID_PARAMETER"); this.set_last_error(invalid_param)?; @@ -190,13 +193,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let layout = this.machine.layouts.uint(size).unwrap(); let futex_val = - this.read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Relaxed)?; + this.read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Acquire)?; let compare_val = this.read_scalar(&this.ptr_to_mplace(compare, layout))?; if futex_val == compare_val { // If the values are the same, we have to block. + + // This cannot fail since we already did an atomic acquire read on that pointer. + let futex_ref = this + .get_sync_or_init(ptr, |_| WindowsFutex { futex: Default::default() }) + .unwrap() + .futex + .clone(); + this.futex_wait( - addr, + futex_ref, u32::MAX, // bitset timeout, Scalar::from_i32(1), // retval_succ @@ -219,8 +230,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // See the Linux futex implementation for why this fence exists. this.atomic_fence(AtomicFenceOrd::SeqCst)?; - let addr = ptr.addr().bytes(); - this.futex_wake(addr, u32::MAX)?; + let Some(futex_ref) = + this.get_sync_or_init(ptr, |_| WindowsFutex { futex: Default::default() }) + else { + // Seems like this cannot return an error, so we just wake nobody. + return interp_ok(()); + }; + let futex_ref = futex_ref.futex.clone(); + + this.futex_wake(&futex_ref, u32::MAX)?; interp_ok(()) } @@ -232,8 +250,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // See the Linux futex implementation for why this fence exists. this.atomic_fence(AtomicFenceOrd::SeqCst)?; - let addr = ptr.addr().bytes(); - while this.futex_wake(addr, u32::MAX)? {} + let Some(futex_ref) = + this.get_sync_or_init(ptr, |_| WindowsFutex { futex: Default::default() }) + else { + // Seems like this cannot return an error, so we just wake nobody. + return interp_ok(()); + }; + let futex_ref = futex_ref.futex.clone(); + + while this.futex_wake(&futex_ref, u32::MAX)? {} interp_ok(()) } diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs index 2a36c10f7d4d7..d1fcf61c4c81f 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs @@ -41,9 +41,12 @@ fn wake_dangling() { let ptr: *const i32 = &*futex; drop(futex); - // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. + // Expect error since this is now "unmapped" memory. + // parking_lot relies on this: + // unsafe { - assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1), 0); + assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1), -1); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EFAULT); } } From e8a3ffee490d5e20502247330fec061f558ea251 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Nov 2024 12:32:23 +0100 Subject: [PATCH 65/79] fix linux-futex test being accidentally disabled --- src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs index d1fcf61c4c81f..3adeb89ecec72 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs @@ -1,5 +1,4 @@ -//@only-target: linux -//@only-target: android +//@only-target: linux android //@compile-flags: -Zmiri-disable-isolation // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint @@ -8,8 +7,8 @@ use std::mem::MaybeUninit; use std::ptr::{self, addr_of}; use std::sync::atomic::{AtomicI32, Ordering}; -use std::thread; use std::time::{Duration, Instant}; +use std::{io, thread}; fn wake_nobody() { let futex = 0; From c0cee4e36b5f0964bdeb2ac12cfd9002addb51cc Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 10 Nov 2024 19:58:10 +0800 Subject: [PATCH 66/79] Revert "Rollup merge of #132772 - onur-ozkan:download-rustc-default, r=jieyouxu" This reverts commit c435fa8c4b55f0f8ef8e2e839ce7de960613267e, reversing changes made to 88acd493f9dbbc8228db2b123c9b4132a995de92. Seems to have unintentionally omitted commit hash leading to . --- src/bootstrap/defaults/config.dist.toml | 1 - src/bootstrap/defaults/config.library.toml | 3 ++ src/bootstrap/defaults/config.tools.toml | 5 ++ src/bootstrap/src/core/config/config.rs | 55 ++++++++++------------ src/bootstrap/src/core/config/tests.rs | 3 -- 5 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/bootstrap/defaults/config.dist.toml b/src/bootstrap/defaults/config.dist.toml index 4346a9c2dd11a..d4feffe02271c 100644 --- a/src/bootstrap/defaults/config.dist.toml +++ b/src/bootstrap/defaults/config.dist.toml @@ -11,7 +11,6 @@ extended = true # Most users installing from source want to build all parts of the project from source. [llvm] download-ci-llvm = false - [rust] # We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`). # Make sure they don't get set when installing from source. diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml index 5447565a4b04c..3d697be815658 100644 --- a/src/bootstrap/defaults/config.library.toml +++ b/src/bootstrap/defaults/config.library.toml @@ -8,6 +8,9 @@ bench-stage = 0 [rust] # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true +# Download rustc from CI instead of building it from source. +# For stage > 1 builds, this cuts compile times significantly when there are no changes on "compiler" tree. +download-rustc = "if-unchanged" # Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown. lto = "off" diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml index 76b47a841b3f2..27c1d1cf26dac 100644 --- a/src/bootstrap/defaults/config.tools.toml +++ b/src/bootstrap/defaults/config.tools.toml @@ -3,6 +3,11 @@ [rust] # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true +# Download rustc from CI instead of building it from source. +# For stage > 1 builds, this cuts compile times significantly when there are no changes on "compiler" tree. +# Using these defaults will download the stage2 compiler (see `download-rustc` +# setting) and the stage2 toolchain should therefore be used for these defaults. +download-rustc = "if-unchanged" [build] # Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index a93038d51d3d0..f977c285a74c1 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1665,26 +1665,10 @@ impl Config { let mut debuginfo_level_tools = None; let mut debuginfo_level_tests = None; let mut optimize = None; + let mut omit_git_hash = None; let mut lld_enabled = None; let mut std_features = None; - let default = config.channel == "dev"; - config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default); - - config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); - config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo")); - config.rust_analyzer_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer")); - config.clippy_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy")); - config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri")); - config.rustfmt_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt")); - config.enzyme_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme")); - config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); - config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); - let mut is_user_configured_rust_channel = false; if let Some(rust) = toml.rust { @@ -1715,7 +1699,7 @@ impl Config { verbose_tests, optimize_tests, codegen_tests, - omit_git_hash: _, // already handled above + omit_git_hash: omit_git_hash_toml, dist_src, save_toolstates, codegen_backends, @@ -1766,6 +1750,7 @@ impl Config { std_features = std_features_toml; optimize = optimize_toml; + omit_git_hash = omit_git_hash_toml; config.rust_new_symbol_mangling = new_symbol_mangling; set(&mut config.rust_optimize_tests, optimize_tests); set(&mut config.codegen_tests, codegen_tests); @@ -1841,6 +1826,24 @@ impl Config { config.reproducible_artifacts = flags.reproducible_artifact; + // rust_info must be set before is_ci_llvm_available() is called. + let default = config.channel == "dev"; + config.omit_git_hash = omit_git_hash.unwrap_or(default); + config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); + + config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo")); + config.rust_analyzer_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer")); + config.clippy_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy")); + config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri")); + config.rustfmt_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt")); + config.enzyme_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme")); + config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); + config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); + // We need to override `rust.channel` if it's manually specified when using the CI rustc. // This is because if the compiler uses a different channel than the one specified in config.toml, // tests may fail due to using a different channel than the one used by the compiler during tests. @@ -2757,19 +2760,9 @@ impl Config { // If `download-rustc` is not set, default to rebuilding. let if_unchanged = match download_rustc { - None => self.rust_info.is_managed_git_subrepository(), - Some(StringOrBool::Bool(false)) => return None, + None | Some(StringOrBool::Bool(false)) => return None, Some(StringOrBool::Bool(true)) => false, - Some(StringOrBool::String(s)) if s == "if-unchanged" => { - if !self.rust_info.is_managed_git_subrepository() { - println!( - "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources." - ); - crate::exit!(1); - } - - true - } + Some(StringOrBool::String(s)) if s == "if-unchanged" => true, Some(StringOrBool::String(other)) => { panic!("unrecognized option for download-rustc: {other}") } @@ -2796,7 +2789,7 @@ impl Config { } println!("ERROR: could not find commit hash for downloading rustc"); println!("HELP: maybe your repository history is too shallow?"); - println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); + println!("HELP: consider disabling `download-rustc`"); println!("HELP: or fetch enough history to include one upstream commit"); crate::exit!(1); } diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index b6523a458e2b2..1f02757682c22 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -135,7 +135,6 @@ change-id = 0 [rust] lto = "off" deny-warnings = true -download-rustc=false [build] gdb = "foo" @@ -201,8 +200,6 @@ runner = "x86_64-runner" .collect(), "setting dictionary value" ); - assert!(!config.llvm_from_ci); - assert!(!config.download_rustc()); } #[test] From c4c6d2b8d5e62b3f7bbaa44a5cc7471ebed37ba4 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 10 Nov 2024 20:30:44 +0800 Subject: [PATCH 67/79] Temporarily disable `version-verbose-commit-hash` to force revert through --- tests/run-make/version-verbose-commit-hash/rmake.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-make/version-verbose-commit-hash/rmake.rs b/tests/run-make/version-verbose-commit-hash/rmake.rs index 733c0e2cdb14f..6e88193280f4c 100644 --- a/tests/run-make/version-verbose-commit-hash/rmake.rs +++ b/tests/run-make/version-verbose-commit-hash/rmake.rs @@ -3,6 +3,9 @@ // test ensures it will not be broken again. // See https://github.com/rust-lang/rust/issues/107094 +// FIXME(#132845): temporarily disabled to get revert through +//@ ignore-test + //@ needs-git-hash use run_make_support::{bare_rustc, bare_rustdoc, regex}; From c8058c81bffcf8dae340d6fdd9f8650227738189 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Nov 2024 15:13:33 +0100 Subject: [PATCH 68/79] query/plumbing: adjust comment to reality --- compiler/rustc_middle/src/query/plumbing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 57da5b39ba781..20ba1b27c0ed9 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -319,7 +319,7 @@ macro_rules! define_callbacks { pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache>; - // Ensure that keys grow no larger than 72 bytes by accident. + // Ensure that keys grow no larger than 80 bytes by accident. // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] const _: () = { From b3c212103b826cde383093fab2f4237bb5736923 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Nov 2024 14:47:16 +0100 Subject: [PATCH 69/79] do not trust download-rustc=if-unchanged on CI for now --- src/ci/run.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index 8e2f525db68fc..9f39ad9c55c54 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -179,7 +179,9 @@ else fi if [ "$NO_DOWNLOAD_CI_RUSTC" = "" ]; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.download-rustc=if-unchanged" + # disabled for now, see https://github.com/rust-lang/rust/issues/131658 + #RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.download-rustc=if-unchanged" + true fi fi From 5c9cc0cfbb11a97d084e5a09bb47cc5566421460 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 10 Nov 2024 20:50:15 +0800 Subject: [PATCH 70/79] Re-enable `version-verbose-commit-hash` run-make test --- tests/run-make/version-verbose-commit-hash/rmake.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-make/version-verbose-commit-hash/rmake.rs b/tests/run-make/version-verbose-commit-hash/rmake.rs index 6e88193280f4c..733c0e2cdb14f 100644 --- a/tests/run-make/version-verbose-commit-hash/rmake.rs +++ b/tests/run-make/version-verbose-commit-hash/rmake.rs @@ -3,9 +3,6 @@ // test ensures it will not be broken again. // See https://github.com/rust-lang/rust/issues/107094 -// FIXME(#132845): temporarily disabled to get revert through -//@ ignore-test - //@ needs-git-hash use run_make_support::{bare_rustc, bare_rustdoc, regex}; From bc1c4be2fd14b8f172a4472a2c4926b91cf97bc1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 10 Nov 2024 16:32:22 +0100 Subject: [PATCH 71/79] Update minifer version to `0.3.2` --- Cargo.lock | 7 ++----- src/librustdoc/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9cca91c25df0a..97d07cd6ca8ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2223,12 +2223,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437" -dependencies = [ - "clap", -] +checksum = "bd559bbf5d350ac7f2c1cf92ed71a869b847a92bce0c1318b47932a5b5f65cdd" [[package]] name = "minimal-lexical" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 57b6de67ee8a9..70749f7cb17a0 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -13,7 +13,7 @@ rinja = { version = "0.3", default-features = false, features = ["config"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" -minifier = "0.3.1" +minifier = { version = "0.3.2", default-features = false } pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } From 3af91a4cd4a61b34e184d3a28e98a553a49d1af6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 30 Sep 2024 17:51:06 -0700 Subject: [PATCH 72/79] Stabilize WebAssembly `multivalue`, `reference-types`, and `tail-call` target features For the `multivalue` and `reference-types` features this commit is similar to #117457 in that it's stabilizing target features specific to WebAssembly targets. The previous PR left out these two features because they weren't expected to change much about compiled code so it was unclear what the rationale was. It has [since been discovered][blog] that `reference-types` can be useful as it changes the binary format of the `call_indirect` instruction. Additionally [on Zulip][zulip] there's a use case of detecting these features at compile time and generating a compile error to better warn users about features not supported on engines. This PR then additionally adds the `tail-call` feature which corresponds to the [tail-call] proposal to WebAssembly. This feature advanced to "phase 4" in the WebAssembly CG awhile back and has been supported in LLVM for quite some time now. Engines are finishing up implementations or have already shipped implementations, so while this is a bit of a late addition to Rust itself it reflects the current status of WebAssembly's state of the feature. A test has been added here not only for these features but other WebAssembly features as well to showcase that they're usable without feature gates in stable Rust. [blog]: https://blog.rust-lang.org/2024/09/24/webassembly-targets-change-in-default-target-features.html [zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/wasm32.20reference-types.20.2F.20multivalue.20in.201.2E82-beta.20not.20enabled/near/473893987 [tail-call]: https://github.com/webassembly/tail-call --- compiler/rustc_target/src/target_features.rs | 5 +- tests/ui/check-cfg/mix.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- tests/ui/wasm/wasm-stable-target-features.rs | 49 ++++++++++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 tests/ui/wasm/wasm-stable-target-features.rs diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index c4f9c742650d7..1dc0e69a45d7f 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -463,13 +463,14 @@ const WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("bulk-memory", Stable, &[]), ("exception-handling", Unstable(sym::wasm_target_feature), &[]), ("extended-const", Stable, &[]), - ("multivalue", Unstable(sym::wasm_target_feature), &[]), + ("multivalue", Stable, &[]), ("mutable-globals", Stable, &[]), ("nontrapping-fptoint", Stable, &[]), - ("reference-types", Unstable(sym::wasm_target_feature), &[]), + ("reference-types", Stable, &[]), ("relaxed-simd", Stable, &["simd128"]), ("sign-ext", Stable, &[]), ("simd128", Stable, &[]), + ("tail-call", Stable, &[]), ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]), // tidy-alphabetical-end ]; diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index ab212dda01527..0a993214f5a1e 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 250 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 251 more = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index f51271dc3def7..ca6a173d6387a 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `leoncasa`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v8plus`, `v9`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `wide-arithmetic`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `leoncasa`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tail-call`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v8plus`, `v9`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `wide-arithmetic`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/wasm/wasm-stable-target-features.rs b/tests/ui/wasm/wasm-stable-target-features.rs new file mode 100644 index 0000000000000..b6d4b67d0703f --- /dev/null +++ b/tests/ui/wasm/wasm-stable-target-features.rs @@ -0,0 +1,49 @@ +//@ only-wasm32 +//@ build-pass + +// Test that a variety of WebAssembly features are all stable and can be used in +// `#[target_feature]`. That should mean they're also available via +// `#[cfg(target_feature)]` as well. + +#[target_feature(enable = "multivalue")] +fn foo1() {} + +#[target_feature(enable = "reference-types")] +fn foo2() {} + +#[target_feature(enable = "bulk-memory")] +fn foo3() {} + +#[target_feature(enable = "extended-const")] +fn foo4() {} + +#[target_feature(enable = "mutable-globals")] +fn foo5() {} + +#[target_feature(enable = "nontrapping-fptoint")] +fn foo6() {} + +#[target_feature(enable = "simd128")] +fn foo7() {} + +#[target_feature(enable = "relaxed-simd")] +fn foo8() {} + +#[target_feature(enable = "sign-ext")] +fn foo9() {} + +#[target_feature(enable = "tail-call")] +fn foo10() {} + +fn main() { + foo1(); + foo2(); + foo3(); + foo4(); + foo5(); + foo6(); + foo7(); + foo8(); + foo9(); + foo10(); +} From e49d9173f866178f73a4df4db2709912e3bad166 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 11 Nov 2024 02:27:09 +0800 Subject: [PATCH 73/79] Break from review rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 95538dd7ee37c..bc7c3b0beebee 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -972,6 +972,7 @@ warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "fmease", + "jieyouxu", "jyn514", "oli-obk", ] From 93ea5bb709b2542b58f9020d95d4c09a8ab640ce Mon Sep 17 00:00:00 2001 From: binarycat Date: Sun, 10 Nov 2024 13:38:41 -0600 Subject: [PATCH 74/79] add regression test for #85763 --- tests/rustdoc/heterogeneous-concat.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/rustdoc/heterogeneous-concat.rs diff --git a/tests/rustdoc/heterogeneous-concat.rs b/tests/rustdoc/heterogeneous-concat.rs new file mode 100644 index 0000000000000..8443ccc559ece --- /dev/null +++ b/tests/rustdoc/heterogeneous-concat.rs @@ -0,0 +1,11 @@ +// regression test for https://github.com/rust-lang/rust/issues/85763 + +#![crate_name = "foo"] + +//@ has foo/index.html '//main' 'Some text that should be concatenated.' +#[doc = " Some text"] +#[doc = r" that should"] +/// be concatenated. +pub fn main() { + println!("Hello, world!"); +} From 7e9c46b8836cef7c63be58ee1aaa2838485ffb06 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Sun, 10 Nov 2024 21:44:28 +0000 Subject: [PATCH 75/79] triagebot: Assign rustdoc tests to T-rustdoc. --- triagebot.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 95538dd7ee37c..f1dc632aea621 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1185,6 +1185,12 @@ project-exploit-mitigations = [ "/src/rustdoc-json-types" = ["rustdoc"] "/src/stage0" = ["bootstrap"] "/tests/run-make" = ["@jieyouxu"] +"/tests/rustdoc" = ["rustdoc"] +"/tests/rustdoc-gui" = ["rustdoc"] +"/tests/rustdoc-js-std" = ["rustdoc"] +"/tests/rustdoc-js" = ["rustdoc"] +"/tests/rustdoc-json" = ["@aDotInTheVoid"] +"/tests/rustdoc-ui" = ["rustdoc"] "/tests/ui" = ["compiler"] "/src/tools/cargo" = ["@ehuss"] "/src/tools/compiletest" = ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors", "@jieyouxu"] From 1d78004575bea3b958b199d50a8491ae3fd65679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 17 Jun 2024 15:14:07 +0000 Subject: [PATCH 76/79] Add Unicode block-drawing compiler output support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add nightly-only theming support to rustc output using Unicode box drawing characters instead of ASCII-art to draw the terminal UI: After: ``` error: foo ╭▸ test.rs:3:3 │ 3 │ X0 Y0 Z0 │ ┌───╿──│──┘ │ ┌│───│──┘ │ ┏││━━━┙ │ ┃││ 4 │ ┃││ X1 Y1 Z1 5 │ ┃││ X2 Y2 Z2 │ ┃│└────╿──│──┘ `Z` label │ ┃└─────│──┤ │ ┗━━━━━━┥ `Y` is a good letter too │ `X` is a good letter ╰╴ note: bar ╭▸ test.rs:4:3 │ 4 │ ┏ X1 Y1 Z1 5 │ ┃ X2 Y2 Z2 6 │ ┃ X3 Y3 Z3 │ ┗━━━━━━━━━━┛ ├ note: bar ╰ note: baz note: qux ╭▸ test.rs:4:3 │ 4 │ X1 Y1 Z1 ╰╴ ━━━━━━━━ ``` Before: ``` error: foo --> test.rs:3:3 | 3 | X0 Y0 Z0 | ___^__-__- | |___|__| | ||___| | ||| 4 | ||| X1 Y1 Z1 5 | ||| X2 Y2 Z2 | |||____^__-__- `Z` label | ||_____|__| | |______| `Y` is a good letter too | `X` is a good letter | note: bar --> test.rs:4:3 | 4 | / X1 Y1 Z1 5 | | X2 Y2 Z2 6 | | X3 Y3 Z3 | |__________^ = note: bar = note: baz note: qux --> test.rs:4:3 | 4 | X1 Y1 Z1 | ^^^^^^^^ ``` --- compiler/rustc_errors/src/emitter.rs | 703 +++++++-- compiler/rustc_errors/src/json.rs | 7 +- compiler/rustc_parse/src/parser/tests.rs | 1401 +++++++++++++++-- compiler/rustc_session/src/config.rs | 9 + compiler/rustc_session/src/session.rs | 14 +- src/librustdoc/core.rs | 9 +- src/librustdoc/doctest.rs | 5 + .../ui/empty_line_after/doc_comments.stderr | 20 +- .../empty_line_after/outer_attribute.stderr | 18 +- .../tests/ui/four_forward_slashes.stderr | 10 +- .../ui/four_forward_slashes_first_line.stderr | 2 +- .../too_long_first_doc_paragraph-fix.stderr | 2 +- .../ui/too_long_first_doc_paragraph.stderr | 4 +- tests/rustdoc-ui/invalid-syntax.stderr | 2 +- ...svg => huge_multispan_highlight.ascii.svg} | 14 +- .../codemap_tests/huge_multispan_highlight.rs | 5 +- .../huge_multispan_highlight.unicode.svg | 116 ++ .../{E0271.stderr => E0271.ascii.stderr} | 4 +- tests/ui/diagnostic-width/E0271.rs | 6 +- .../ui/diagnostic-width/E0271.unicode.stderr | 22 + ...g-human.stderr => flag-human.ascii.stderr} | 2 +- tests/ui/diagnostic-width/flag-human.rs | 6 +- .../flag-human.unicode.stderr | 11 + ...g-E0308.stderr => long-E0308.ascii.stderr} | 16 +- tests/ui/diagnostic-width/long-E0308.rs | 4 +- .../long-E0308.unicode.stderr | 82 + ...idth-unicode-multiline-label.ascii.stderr} | 2 +- .../non-1-width-unicode-multiline-label.rs | 4 +- ...dth-unicode-multiline-label.unicode.stderr | 18 + ...=> non-whitespace-trimming-2.ascii.stderr} | 2 +- .../non-whitespace-trimming-2.rs | 4 +- .../non-whitespace-trimming-2.unicode.stderr | 11 + tests/ui/error-emitter/highlighting.svg | 2 +- .../ui/error-emitter/highlighting.windows.svg | 2 +- tests/ui/error-emitter/unicode-output.rs | 21 + tests/ui/error-emitter/unicode-output.svg | 72 + tests/ui/parser/bad-char-literals.stderr | 2 +- 37 files changed, 2339 insertions(+), 295 deletions(-) rename tests/ui/codemap_tests/{huge_multispan_highlight.svg => huge_multispan_highlight.ascii.svg} (94%) create mode 100644 tests/ui/codemap_tests/huge_multispan_highlight.unicode.svg rename tests/ui/diagnostic-width/{E0271.stderr => E0271.ascii.stderr} (94%) create mode 100644 tests/ui/diagnostic-width/E0271.unicode.stderr rename tests/ui/diagnostic-width/{flag-human.stderr => flag-human.ascii.stderr} (89%) create mode 100644 tests/ui/diagnostic-width/flag-human.unicode.stderr rename tests/ui/diagnostic-width/{long-E0308.stderr => long-E0308.ascii.stderr} (88%) create mode 100644 tests/ui/diagnostic-width/long-E0308.unicode.stderr rename tests/ui/diagnostic-width/{non-1-width-unicode-multiline-label.stderr => non-1-width-unicode-multiline-label.ascii.stderr} (97%) create mode 100644 tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr rename tests/ui/diagnostic-width/{non-whitespace-trimming-2.stderr => non-whitespace-trimming-2.ascii.stderr} (91%) create mode 100644 tests/ui/diagnostic-width/non-whitespace-trimming-2.unicode.stderr create mode 100644 tests/ui/error-emitter/unicode-output.rs create mode 100644 tests/ui/error-emitter/unicode-output.svg diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 0ccc71ae06c45..120f5ba7d4867 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -44,6 +44,7 @@ const DEFAULT_COLUMN_WIDTH: usize = 140; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum HumanReadableErrorType { Default, + Unicode, AnnotateSnippet, Short, } @@ -595,6 +596,12 @@ impl ColorConfig { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum OutputTheme { + Ascii, + Unicode, +} + /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short` #[derive(Setters)] pub struct HumanEmitter { @@ -613,6 +620,7 @@ pub struct HumanEmitter { macro_backtrace: bool, track_diagnostics: bool, terminal_url: TerminalUrl, + theme: OutputTheme, } #[derive(Debug)] @@ -637,6 +645,7 @@ impl HumanEmitter { macro_backtrace: false, track_diagnostics: false, terminal_url: TerminalUrl::No, + theme: OutputTheme::Ascii, } } @@ -680,17 +689,19 @@ impl HumanEmitter { }) .collect(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); + let placeholder = self.margin(); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. - buffer.puts(line_offset, code_offset, "...", Style::LineNumber); + buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber); } if margin.was_cut_right(line_len) { + let padding: usize = placeholder.chars().map(|ch| char_width(ch)).sum(); // We have stripped some code after the rightmost span end, make it clear we did so. - buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber); + buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber); } buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); - draw_col_separator_no_space(buffer, line_offset, width_offset - 2); + self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2); } #[instrument(level = "trace", skip(self), ret)] @@ -702,6 +713,7 @@ impl HumanEmitter { width_offset: usize, code_offset: usize, margin: Margin, + close_window: bool, ) -> Vec<(usize, Style)> { // Draw: // @@ -767,13 +779,10 @@ impl HumanEmitter { for ann in &line.annotations { if let AnnotationType::MultilineStart(depth) = ann.annotation_type { if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) { - let style = if ann.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; - annotations.push((depth, style)); - buffer_ops.push((line_offset, width_offset + depth - 1, '/', style)); + let uline = self.underline(ann.is_primary); + let chr = uline.multiline_whole_line; + annotations.push((depth, uline.style)); + buffer_ops.push((line_offset, width_offset + depth - 1, chr, uline.style)); } else { short_start = false; break; @@ -970,7 +979,7 @@ impl HumanEmitter { // 3 │ X0 Y0 Z0 // │ ┏━━━━━┛ │ │ < We are writing these lines // │ ┃┌───────┘ │ < by reverting the "depth" of - // │ ┃│┌─────────┘ < their multilne spans. + // │ ┃│┌─────────┘ < their multiline spans. // 4 │ ┃││ X1 Y1 Z1 // 5 │ ┃││ X2 Y2 Z2 // │ ┃│└────╿──│──┘ `Z` label @@ -997,7 +1006,10 @@ impl HumanEmitter { // 4 | } // | for pos in 0..=line_len { - draw_col_separator_no_space(buffer, line_offset + pos + 1, width_offset - 2); + self.draw_col_separator_no_space(buffer, line_offset + pos + 1, width_offset - 2); + } + if close_window { + self.draw_col_separator_end(buffer, line_offset + line_len + 1, width_offset - 2); } // Write the horizontal lines for multiline annotations @@ -1013,21 +1025,17 @@ impl HumanEmitter { // 4 | } // | _ for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; + let underline = self.underline(annotation.is_primary); let pos = pos + 1; match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { - draw_range( + self.draw_range( buffer, - '_', + underline.multiline_horizontal, line_offset + pos, width_offset + depth, (code_offset + annotation.start_col.display).saturating_sub(left), - style, + underline.style, ); } _ if self.teach => { @@ -1035,7 +1043,7 @@ impl HumanEmitter { line_offset, (code_offset + annotation.start_col.display).saturating_sub(left), (code_offset + annotation.end_col.display).saturating_sub(left), - style, + underline.style, annotation.is_primary, ); } @@ -1055,33 +1063,78 @@ impl HumanEmitter { // 4 | | } // | |_ for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }; + let underline = self.underline(annotation.is_primary); let pos = pos + 1; if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { + if let AnnotationType::MultilineLine(_) = annotation.annotation_type { + buffer.putc( + p, + (code_offset + annotation.start_col.display).saturating_sub(left), + underline.multiline_vertical, + underline.style, + ); + } else { + buffer.putc( + p, + (code_offset + annotation.start_col.display).saturating_sub(left), + underline.vertical_text_line, + underline.style, + ); + } + } + if let AnnotationType::MultilineStart(_) = annotation.annotation_type { buffer.putc( - p, + line_offset + pos, (code_offset + annotation.start_col.display).saturating_sub(left), - '|', - style, + underline.bottom_right, + underline.style, + ); + } + if let AnnotationType::MultilineEnd(_) = annotation.annotation_type + && annotation.has_label() + { + buffer.putc( + line_offset + pos, + (code_offset + annotation.start_col.display).saturating_sub(left), + underline.multiline_bottom_right_with_text, + underline.style, ); } } match annotation.annotation_type { AnnotationType::MultilineStart(depth) => { + buffer.putc( + line_offset + pos, + width_offset + depth - 1, + underline.top_left, + underline.style, + ); for p in line_offset + pos + 1..line_offset + line_len + 2 { - buffer.putc(p, width_offset + depth - 1, '|', style); + buffer.putc( + p, + width_offset + depth - 1, + underline.multiline_vertical, + underline.style, + ); } } AnnotationType::MultilineEnd(depth) => { - for p in line_offset..=line_offset + pos { - buffer.putc(p, width_offset + depth - 1, '|', style); + for p in line_offset..line_offset + pos { + buffer.putc( + p, + width_offset + depth - 1, + underline.multiline_vertical, + underline.style, + ); } + buffer.putc( + line_offset + pos, + width_offset + depth - 1, + underline.bottom_left, + underline.style, + ); } _ => (), } @@ -1102,7 +1155,11 @@ impl HumanEmitter { let style = if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) + if annotation.end_col.display == 0 { + (pos + 1, (annotation.end_col.display + 2).saturating_sub(left)) + } else { + (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) + } } else { (pos + 2, annotation.start_col.display.saturating_sub(left)) }; @@ -1135,18 +1192,60 @@ impl HumanEmitter { // 3 | // 4 | } // | _^ test - for &(_, annotation) in &annotations_position { - let (underline, style) = if annotation.is_primary { - ('^', Style::UnderlinePrimary) - } else { - ('-', Style::UnderlineSecondary) - }; + for &(pos, annotation) in &annotations_position { + let uline = self.underline(annotation.is_primary); for p in annotation.start_col.display..annotation.end_col.display { + // The default span label underline. buffer.putc( line_offset + 1, (code_offset + p).saturating_sub(left), - underline, - style, + uline.underline, + uline.style, + ); + } + + if pos == 0 + && matches!( + annotation.annotation_type, + AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_) + ) + { + // The beginning of a multiline span with its leftward moving line on the same line. + buffer.putc( + line_offset + 1, + (code_offset + annotation.start_col.display).saturating_sub(left), + match annotation.annotation_type { + AnnotationType::MultilineStart(_) => uline.top_right_flat, + AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line, + _ => panic!("unexpected annotation type: {annotation:?}"), + }, + uline.style, + ); + } else if pos != 0 + && matches!( + annotation.annotation_type, + AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_) + ) + { + // The beginning of a multiline span with its leftward moving line on another line, + // so we start going down first. + buffer.putc( + line_offset + 1, + (code_offset + annotation.start_col.display).saturating_sub(left), + match annotation.annotation_type { + AnnotationType::MultilineStart(_) => uline.multiline_start_down, + AnnotationType::MultilineEnd(_) => uline.multiline_end_up, + _ => panic!("unexpected annotation type: {annotation:?}"), + }, + uline.style, + ); + } else if pos != 0 && annotation.has_label() { + // The beginning of a span label with an actual label, we'll point down. + buffer.putc( + line_offset + 1, + (code_offset + annotation.start_col.display).saturating_sub(left), + uline.label_start, + uline.style, ); } } @@ -1217,7 +1316,7 @@ impl HumanEmitter { padding: usize, label: &str, override_style: Option + + + + + error[E0308]: `match` arms have incompatible types + + ╭▸ $DIR/huge_multispan_highlight.rs:99:18 + + + + LL let _ = match true { + + ────────── `match` arms have incompatible types + + LL true => ( + + ┌─────────────────┘ + + LL // last line shown in multispan header + + + + LL + + LL ), + + └─────────┘ this is found to be of type `()` + + LL false => " + + ┏━━━━━━━━━━━━━━━━━━┛ + + + + LL + + LL ", + + ╰╴┗━━━━━━━━━┛ expected `()`, found `&str` + + + + error[E0308]: `match` arms have incompatible types + + ╭▸ $DIR/huge_multispan_highlight.rs:216:18 + + + + LL let _ = match true { + + ────────── `match` arms have incompatible types + + LL true => ( + + ┌─────────────────┘ + + LL + + LL 1 // last line shown in multispan header + + + + LL + + LL ), + + └─────────┘ this is found to be of type `{integer}` + + LL false => " + + ┏━━━━━━━━━━━━━━━━━━┛ + + LL + + LL + + LL 1 last line shown in multispan + + + + LL + + LL ", + + ╰╴┗━━━━━━━━━┛ expected integer, found `&str` + + + + error: aborting due to 2 previous errors + + + + For more information about this error, try `rustc --explain E0308`. + + + + + + diff --git a/tests/ui/diagnostic-width/E0271.stderr b/tests/ui/diagnostic-width/E0271.ascii.stderr similarity index 94% rename from tests/ui/diagnostic-width/E0271.stderr rename to tests/ui/diagnostic-width/E0271.ascii.stderr index 31ec3fe366f4b..e276299e9e8ef 100644 --- a/tests/ui/diagnostic-width/E0271.stderr +++ b/tests/ui/diagnostic-width/E0271.ascii.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo` - --> $DIR/E0271.rs:18:5 + --> $DIR/E0271.rs:20:5 | LL | / Box::new( LL | | Ok::<_, ()>( @@ -11,7 +11,7 @@ LL | | ) | |_____^ type mismatch resolving `, ...>>, ...> as Future>::Error == Foo` | note: expected this to be `Foo` - --> $DIR/E0271.rs:8:18 + --> $DIR/E0271.rs:10:18 | LL | type Error = E; | ^ diff --git a/tests/ui/diagnostic-width/E0271.rs b/tests/ui/diagnostic-width/E0271.rs index d8cb24898ac30..ce41ad2952bc9 100644 --- a/tests/ui/diagnostic-width/E0271.rs +++ b/tests/ui/diagnostic-width/E0271.rs @@ -1,4 +1,6 @@ -//@ compile-flags: --diagnostic-width=40 +//@ revisions: ascii unicode +//@[ascii] compile-flags: --diagnostic-width=40 +//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode --diagnostic-width=40 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" trait Future { type Error; @@ -15,7 +17,7 @@ impl Future for Option { struct Foo; fn foo() -> Box> { - Box::new( //~ ERROR E0271 + Box::new( //[ascii]~ ERROR E0271 Ok::<_, ()>( Err::<(), _>( Ok::<_, ()>( diff --git a/tests/ui/diagnostic-width/E0271.unicode.stderr b/tests/ui/diagnostic-width/E0271.unicode.stderr new file mode 100644 index 0000000000000..4a96ca36cd78d --- /dev/null +++ b/tests/ui/diagnostic-width/E0271.unicode.stderr @@ -0,0 +1,22 @@ +error[E0271]: type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo` + ╭▸ $DIR/E0271.rs:20:5 + │ +LL │ ┏ Box::new( +LL │ ┃ Ok::<_, ()>( +LL │ ┃ Err::<(), _>( +LL │ ┃ Ok::<_, ()>( + ‡ ┃ +LL │ ┃ ) +LL │ ┃ ) + │ ┗━━━━━┛ type mismatch resolving `, ...>>, ...> as Future>::Error == Foo` + ╰╴ +note: expected this to be `Foo` + ╭▸ $DIR/E0271.rs:10:18 + │ +LL │ type Error = E; + │ ━ + ╰ note: required for the cast from `Box>, ()>>, ()>>, ()>>` to `Box<(dyn Future + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/diagnostic-width/flag-human.stderr b/tests/ui/diagnostic-width/flag-human.ascii.stderr similarity index 89% rename from tests/ui/diagnostic-width/flag-human.stderr rename to tests/ui/diagnostic-width/flag-human.ascii.stderr index eaa9684108069..4593304e087d2 100644 --- a/tests/ui/diagnostic-width/flag-human.stderr +++ b/tests/ui/diagnostic-width/flag-human.ascii.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/flag-human.rs:7:17 + --> $DIR/flag-human.rs:9:17 | LL | ..._: () = 42; | -- ^^ expected `()`, found integer diff --git a/tests/ui/diagnostic-width/flag-human.rs b/tests/ui/diagnostic-width/flag-human.rs index a46122ed78350..1af4165914164 100644 --- a/tests/ui/diagnostic-width/flag-human.rs +++ b/tests/ui/diagnostic-width/flag-human.rs @@ -1,9 +1,11 @@ -//@ compile-flags: --diagnostic-width=20 +//@ revisions: ascii unicode +//@[ascii] compile-flags: --diagnostic-width=20 +//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode --diagnostic-width=20 // This test checks that `-Z output-width` effects the human error output by restricting it to an // arbitrarily low value so that the effect is visible. fn main() { let _: () = 42; - //~^ ERROR mismatched types + //[ascii]~^ ERROR mismatched types } diff --git a/tests/ui/diagnostic-width/flag-human.unicode.stderr b/tests/ui/diagnostic-width/flag-human.unicode.stderr new file mode 100644 index 0000000000000..50176564786b1 --- /dev/null +++ b/tests/ui/diagnostic-width/flag-human.unicode.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + ╭▸ $DIR/flag-human.rs:9:17 + │ +LL │ …t _: () = 42; + │ ┬─ ━━ expected `()`, found integer + │ │ + ╰╴ expected due to this + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/long-E0308.stderr b/tests/ui/diagnostic-width/long-E0308.ascii.stderr similarity index 88% rename from tests/ui/diagnostic-width/long-E0308.stderr rename to tests/ui/diagnostic-width/long-E0308.ascii.stderr index eb37da037e9d7..d45d6bf329bd3 100644 --- a/tests/ui/diagnostic-width/long-E0308.stderr +++ b/tests/ui/diagnostic-width/long-E0308.ascii.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/long-E0308.rs:44:9 + --> $DIR/long-E0308.rs:46:9 | LL | let x: Atype< | _____________- @@ -20,11 +20,11 @@ LL | | )))))))))))))))))))))))))))))); | = note: expected struct `Atype, ...>` found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:57:26 + --> $DIR/long-E0308.rs:59:26 | LL | ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O... | __________________________^ @@ -36,11 +36,11 @@ LL | | )))))))))))))))))))))))); | = note: expected enum `Option>` found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:88:9 + --> $DIR/long-E0308.rs:90:9 | LL | let x: Atype< | ____________- @@ -56,11 +56,11 @@ LL | | > = (); | = note: expected struct `Atype, ...>` found unit type `()` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:91:17 + --> $DIR/long-E0308.rs:93:17 | LL | let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O... | ____________--___^ @@ -74,7 +74,7 @@ LL | | )))))))))))))))))))))))); | = note: expected unit type `()` found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error: aborting due to 4 previous errors diff --git a/tests/ui/diagnostic-width/long-E0308.rs b/tests/ui/diagnostic-width/long-E0308.rs index 150164ba21b4d..73f81f5872a64 100644 --- a/tests/ui/diagnostic-width/long-E0308.rs +++ b/tests/ui/diagnostic-width/long-E0308.rs @@ -1,4 +1,6 @@ -//@ compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes +//@ revisions: ascii unicode +//@[ascii] compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes +//@[unicode] compile-flags: -Zunstable-options=yes --json=diagnostic-unicode --diagnostic-width=60 -Zwrite-long-types-to-disk=yes //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" mod a { diff --git a/tests/ui/diagnostic-width/long-E0308.unicode.stderr b/tests/ui/diagnostic-width/long-E0308.unicode.stderr new file mode 100644 index 0000000000000..3e8d881d7a6b1 --- /dev/null +++ b/tests/ui/diagnostic-width/long-E0308.unicode.stderr @@ -0,0 +1,82 @@ +error[E0308]: mismatched types + ╭▸ $DIR/long-E0308.rs:46:9 + │ +LL │ let x: Atype< + │ ┌─────────────┘ +LL │ │ Btype< +LL │ │ Ctype< +LL │ │ Atype< + ‡ │ +LL │ │ i32 +LL │ │ > = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O… + │ │┏━━━━━│━━━┛ + │ └┃─────┤ + │ ┃ expected due to this +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O… +LL │ ┃ Ok("") +LL │ ┃ )))))))))))))))))))))))))))))) +LL │ ┃ )))))))))))))))))))))))))))))); + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype, ...>`, found `Result, ...>` + │ + ├ note: expected struct `Atype, ...>` + │ found enum `Result, ...>` + ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console + +error[E0308]: mismatched types + ╭▸ $DIR/long-E0308.rs:59:26 + │ +LL │ ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(… + │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┛ +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok… +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) +LL │ ┃ )))))))))))))))))))))))))))))) +LL │ ┃ )))))))))))))))))))))))); + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option>`, found `Result, ...>` + │ + ├ note: expected enum `Option>` + │ found enum `Result, ...>` + ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console + +error[E0308]: mismatched types + ╭▸ $DIR/long-E0308.rs:90:9 + │ +LL │ let x: Atype< + │ ┌────────────┘ +LL │ │ Btype< +LL │ │ Ctype< +LL │ │ Atype< + ‡ │ +LL │ │ i32 +LL │ │ > = (); + │ │ │ ━━ expected `Atype, ...>`, found `()` + │ └─────┤ + │ expected due to this + │ + ├ note: expected struct `Atype, ...>` + │ found unit type `()` + ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console + +error[E0308]: mismatched types + ╭▸ $DIR/long-E0308.rs:93:17 + │ +LL │ let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(… + │ ┏━━━━━━━━━━━━┬─━━━┛ + │ ┃ │ + │ ┃ expected due to this +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok… +LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) +LL │ ┃ )))))))))))))))))))))))))))))) +LL │ ┃ )))))))))))))))))))))))); + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result, ...>` + │ + ├ note: expected unit type `()` + │ found enum `Result, ...>` + ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr similarity index 97% rename from tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr rename to tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr index 8f200e15c64d8..4d8afb6f3ad9b 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.ascii.stderr @@ -1,5 +1,5 @@ error[E0369]: cannot add `&str` to `&str` - --> $DIR/non-1-width-unicode-multiline-label.rs:5:260 + --> $DIR/non-1-width-unicode-multiline-label.rs:7:260 | LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇...࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; | -------------- ^ -------------- &str diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs index 1989ea8863592..61c4b31e03a62 100644 --- a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs @@ -1,7 +1,9 @@ +//@ revisions: ascii unicode +//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode // ignore-tidy-linelength fn main() { let unicode_is_fun = "؁‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥"; let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; - //~^ ERROR cannot add `&str` to `&str` + //[ascii]~^ ERROR cannot add `&str` to `&str` } diff --git a/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr new file mode 100644 index 0000000000000..ed8ce770bb7ea --- /dev/null +++ b/tests/ui/diagnostic-width/non-1-width-unicode-multiline-label.unicode.stderr @@ -0,0 +1,18 @@ +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260 + │ +LL │ …ཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉…࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-2.stderr b/tests/ui/diagnostic-width/non-whitespace-trimming-2.ascii.stderr similarity index 91% rename from tests/ui/diagnostic-width/non-whitespace-trimming-2.stderr rename to tests/ui/diagnostic-width/non-whitespace-trimming-2.ascii.stderr index a7d5c0bfb9415..70bd149545cfe 100644 --- a/tests/ui/diagnostic-width/non-whitespace-trimming-2.stderr +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-2.ascii.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/non-whitespace-trimming-2.rs:4:311 + --> $DIR/non-whitespace-trimming-2.rs:6:311 | LL | ...13; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let ... | -- ^^ expected `()`, found integer diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs b/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs index abd9e189a7537..283506bd6c90d 100644 --- a/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-2.rs @@ -1,6 +1,8 @@ +//@ revisions: ascii unicode +//@[unicode] compile-flags: -Zunstable-options=yes --error-format=human-unicode // ignore-tidy-linelength fn main() { let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _: usize = 4; let _: usize = 5; let _: usize = 6; let _: usize = 7; let _: usize = 8; let _: usize = 9; let _: usize = 10; let _: usize = 11; let _: usize = 12; let _: usize = 13; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _: usize = 4; let _: usize = 5; let _: usize = 6; let _: usize = 7; let _: usize = 8; let _: usize = 9; let _: usize = 10; let _: usize = 11; let _: usize = 12; let _: usize = 13; let _: usize = 14; let _: usize = 15; -//~^ ERROR mismatched types +//[ascii]~^ ERROR mismatched types } diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-2.unicode.stderr b/tests/ui/diagnostic-width/non-whitespace-trimming-2.unicode.stderr new file mode 100644 index 0000000000000..600d196de1673 --- /dev/null +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-2.unicode.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + ╭▸ $DIR/non-whitespace-trimming-2.rs:6:311 + │ +LL │ …= 13; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _:… + │ ┬─ ━━ expected `()`, found integer + │ │ + ╰╴ expected due to this + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/error-emitter/highlighting.svg b/tests/ui/error-emitter/highlighting.svg index be92c00c19bdc..a4019c78f4841 100644 --- a/tests/ui/error-emitter/highlighting.svg +++ b/tests/ui/error-emitter/highlighting.svg @@ -49,7 +49,7 @@ LL | fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( - | ____^^^^^_- + | ____^^^^^_- LL | | dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static diff --git a/tests/ui/error-emitter/highlighting.windows.svg b/tests/ui/error-emitter/highlighting.windows.svg index 152245da9ddc1..c2378113b86f5 100644 --- a/tests/ui/error-emitter/highlighting.windows.svg +++ b/tests/ui/error-emitter/highlighting.windows.svg @@ -50,7 +50,7 @@ LL | fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( - | ____^^^^^_- + | ____^^^^^_- LL | | dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static diff --git a/tests/ui/error-emitter/unicode-output.rs b/tests/ui/error-emitter/unicode-output.rs new file mode 100644 index 0000000000000..ba6db37b66c22 --- /dev/null +++ b/tests/ui/error-emitter/unicode-output.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Zunstable-options=yes --error-format=human-unicode --color=always +//@ edition:2018 +//@ only-linux + +use core::pin::Pin; +use core::future::Future; +use core::any::Any; + +fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin, String>> + Send + 'static +)>>) {} + +fn wrapped_fn<'a>(_: Box<(dyn Any + Send)>) -> Pin, String>> + Send + 'static +)>> { + Box::pin(async { Err("nope".into()) }) +} + +fn main() { + query(wrapped_fn); +} diff --git a/tests/ui/error-emitter/unicode-output.svg b/tests/ui/error-emitter/unicode-output.svg new file mode 100644 index 0000000000000..f98fd8b74032b --- /dev/null +++ b/tests/ui/error-emitter/unicode-output.svg @@ -0,0 +1,72 @@ + + + + + + + error[E0308]: mismatched types + + ╭▸ $DIR/unicode-output.rs:20:11 + + + + LL query(wrapped_fn); + + ┬──── ━━━━━━━━━━ one type is more general than the other + + + + arguments to this function are incorrect + + + + note: expected fn pointer `for<'a> fn(Box<(dyn Any + Send + 'a)>) -> Pin<_>` + + found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}` + + note: function defined here + + ╭▸ $DIR/unicode-output.rs:9:4 + + + + LL fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( + + ┌────━━━━━─┘ + + LL dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static + + LL )>>) {} + + ╰╴└───┘ + + + + error: aborting due to 1 previous error + + + + For more information about this error, try `rustc --explain E0308`. + + + + + + diff --git a/tests/ui/parser/bad-char-literals.stderr b/tests/ui/parser/bad-char-literals.stderr index 1fb324a1b7e84..5a81ede0336ff 100644 --- a/tests/ui/parser/bad-char-literals.stderr +++ b/tests/ui/parser/bad-char-literals.stderr @@ -15,7 +15,7 @@ error: character constant must be escaped: `\n` LL | ' | ______^ LL | | '; - | |_ + | |_^ | help: escape the character | From acf6344b42b86bf63c73632620438fc4836b0d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 10 Nov 2024 17:51:37 +0100 Subject: [PATCH 77/79] Address review comments --- compiler/rustc_errors/src/emitter.rs | 51 ++++++++++++++-------------- compiler/rustc_session/src/config.rs | 32 ++++++++--------- compiler/rustc_span/src/lib.rs | 4 +++ 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 120f5ba7d4867..06c961c33042d 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -22,7 +22,7 @@ use rustc_error_messages::{FluentArgs, SpanLabel}; use rustc_lint_defs::pluralize; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; -use rustc_span::{FileLines, FileName, SourceFile, Span, char_width}; +use rustc_span::{FileLines, FileName, SourceFile, Span, char_width, str_width}; use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use tracing::{debug, instrument, trace, warn}; @@ -113,8 +113,12 @@ impl Margin { fn was_cut_right(&self, line_len: usize) -> bool { let right = if self.computed_right == self.span_right || self.computed_right == self.label_right { + // FIXME: This comment refers to the only callsite of this method. + // Rephrase it or refactor it, so it can stand on its own. // Account for the "..." padding given above. Otherwise we end up with code lines // that do fit but end in "..." as if they were trimmed. + // FIXME: Don't hard-code this offset. Is this meant to represent + // `2 * str_width(self.margin())`? self.computed_right - 6 } else { self.computed_right @@ -673,6 +677,7 @@ impl HumanEmitter { // Create the source line we will highlight. let left = margin.left(line_len); let right = margin.right(line_len); + // FIXME: The following code looks fishy. See #132860. // On long lines, we strip the source line, accounting for unicode. let mut taken = 0; let code: String = source_string @@ -695,7 +700,7 @@ impl HumanEmitter { buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber); } if margin.was_cut_right(line_len) { - let padding: usize = placeholder.chars().map(|ch| char_width(ch)).sum(); + let padding = str_width(placeholder); // We have stripped some code after the rightmost span end, make it clear we did so. buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber); } @@ -744,6 +749,7 @@ impl HumanEmitter { // Left trim let left = margin.left(source_string.len()); + // FIXME: This looks fishy. See #132860. // Account for unicode characters of width !=0 that were removed. let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum(); @@ -1068,21 +1074,15 @@ impl HumanEmitter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { - if let AnnotationType::MultilineLine(_) = annotation.annotation_type { - buffer.putc( - p, - (code_offset + annotation.start_col.display).saturating_sub(left), - underline.multiline_vertical, - underline.style, - ); - } else { - buffer.putc( - p, - (code_offset + annotation.start_col.display).saturating_sub(left), - underline.vertical_text_line, - underline.style, - ); - } + buffer.putc( + p, + (code_offset + annotation.start_col.display).saturating_sub(left), + match annotation.annotation_type { + AnnotationType::MultilineLine(_) => underline.multiline_vertical, + _ => underline.vertical_text_line, + }, + underline.style, + ); } if let AnnotationType::MultilineStart(_) = annotation.annotation_type { buffer.putc( @@ -2134,7 +2134,7 @@ impl HumanEmitter { } let placeholder = self.margin(); - let padding: usize = placeholder.chars().map(|ch| char_width(ch)).sum(); + let padding = str_width(placeholder); buffer.puts( row_num, max_line_num_len.saturating_sub(padding), @@ -2224,11 +2224,11 @@ impl HumanEmitter { }; // ...or trailing spaces. Account for substitutions containing unicode // characters. - let sub_len: usize = - if is_whitespace_addition { &part.snippet } else { part.snippet.trim() } - .chars() - .map(|ch| char_width(ch)) - .sum(); + let sub_len: usize = str_width(if is_whitespace_addition { + &part.snippet + } else { + part.snippet.trim() + }); let offset: isize = offsets .iter() @@ -2266,8 +2266,7 @@ impl HumanEmitter { } // length of the code after substitution - let full_sub_len = - part.snippet.chars().map(|ch| char_width(ch)).sum::() as isize; + let full_sub_len = str_width(&part.snippet) as isize; // length of the code to be substituted let snippet_len = span_end_pos as isize - span_start_pos as isize; @@ -2282,7 +2281,7 @@ impl HumanEmitter { // if we elided some lines, add an ellipsis if lines.next().is_some() { let placeholder = self.margin(); - let padding: usize = placeholder.chars().map(|ch| char_width(ch)).sum(); + let padding = str_width(placeholder); buffer.puts( row_num, max_line_num_len.saturating_sub(padding), diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 352152a1bd42c..114ee7ac9ded1 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1772,8 +1772,8 @@ pub fn parse_error_format( color, )); early_dcx.early_fatal(format!( - "argument for `--error-format` must be `human`, `json` or \ - `short` (instead was `{arg}`)" + "argument for `--error-format` must be `human`, `human-annotate-rs`, \ + `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)" )) } } @@ -1826,21 +1826,21 @@ pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches fn check_error_format_stability( early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions, - error_format: ErrorOutputType, + format: ErrorOutputType, ) { - if !unstable_opts.unstable_options { - if let ErrorOutputType::Json { pretty: true, .. } = error_format { - early_dcx.early_fatal("`--error-format=pretty-json` is unstable"); - } - if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, _) = - error_format - { - early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable"); - } - if let ErrorOutputType::HumanReadable(HumanReadableErrorType::Unicode, _) = error_format { - early_dcx.early_fatal("`--error-format=human-unicode` is unstable"); - } - } + if unstable_opts.unstable_options { + return; + } + let format = match format { + ErrorOutputType::Json { pretty: true, .. } => "pretty-json", + ErrorOutputType::HumanReadable(format, _) => match format { + HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs", + HumanReadableErrorType::Unicode => "human-unicode", + _ => return, + }, + _ => return, + }; + early_dcx.early_fatal(format!("`--error-format={format}` is unstable")) } fn parse_output_types( diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 5b1be5bca0593..ef775068515ef 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2223,6 +2223,10 @@ pub fn char_width(ch: char) -> usize { } } +pub fn str_width(s: &str) -> usize { + s.chars().map(char_width).sum() +} + /// Normalizes the source code and records the normalizations. fn normalize_src(src: &mut String) -> Vec { let mut normalized_pos = vec![]; From 2c7f3badcf631d2b11459bb23590b776c0076a61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Nov 2024 22:51:38 +0100 Subject: [PATCH 78/79] target_features: explain what exacty 'implied' means here --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 14 +++++++++++--- compiler/rustc_target/src/target_features.rs | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index c382242d8d074..db2b03d9aeda8 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -344,15 +344,23 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { }) { if enabled { + // Also add all transitively implied features. features.extend(sess.target.implied_target_features(std::iter::once(feature))); } else { + // Remove transitively reverse-implied features. + // We don't care about the order in `features` since the only thing we use it for is the // `features.contains` below. #[allow(rustc::potential_query_instability)] features.retain(|f| { - // Keep a feature if it does not imply `feature`. Or, equivalently, - // remove the reverse-dependencies of `feature`. - !sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) + if sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) { + // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to + // remove `f`. (This is the standard logical contraposition principle.) + false + } else { + // We can keep `f`. + true + } }); } } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index c4f9c742650d7..e8a6de98b7e5c 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -92,6 +92,11 @@ impl Stability { // // Stabilizing a target feature requires t-lang approval. +// If feature A "implies" feature B, then: +// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B +// - when B gets disabled (via `-Ctarget-feature`), we also disable A +// +// Both of these are also applied transitively. type ImpliedFeatures = &'static [&'static str]; const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ From 8e068b989bdbbf6eeeeee8ca2ba7db50c3e49dfc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 9 Nov 2024 18:21:03 +0000 Subject: [PATCH 79/79] Recurse into APITs in impl_trait_overcaptures --- .../rustc_lint/src/impl_trait_overcaptures.rs | 6 ++- .../precise-capturing/overcaptures-2024.fixed | 5 ++ .../precise-capturing/overcaptures-2024.rs | 5 ++ .../overcaptures-2024.stderr | 51 +++++++++++++------ 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 036e0381a067c..beab4d4e6a929 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -262,7 +262,11 @@ where // If it's owned by this function && let opaque = self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty() - && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin + // We want to recurse into RPITs and async fns, even though the latter + // doesn't overcapture on its own, it may mention additional RPITs + // in its bounds. + && let hir::OpaqueTyOrigin::FnReturn { parent, .. } + | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = opaque.origin && parent == self.parent_def_id { let opaque_span = self.tcx.def_span(opaque_def_id); diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed index 6a9d72d028c85..1eb88c71d54f6 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed @@ -1,4 +1,5 @@ //@ run-rustfix +//@ edition: 2018 #![allow(unused)] #![deny(impl_trait_overcaptures)] @@ -37,4 +38,8 @@ fn apit2(_: &T, _: U) -> impl Sized + use {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs index 3a4f5ebb7fb1a..6f1ef6a472feb 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs @@ -1,4 +1,5 @@ //@ run-rustfix +//@ edition: 2018 #![allow(unused)] #![deny(impl_trait_overcaptures)] @@ -37,4 +38,8 @@ fn apit2(_: &impl Sized, _: U) -> impl Sized {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +async fn async_fn<'a>(x: &'a ()) -> impl Sized {} +//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index c101b980c71ae..63c87cd46c84f 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -1,5 +1,5 @@ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:6:29 + --> $DIR/overcaptures-2024.rs:7:29 | LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } = warning: this changes meaning in Rust 2024 = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:6:10 + --> $DIR/overcaptures-2024.rs:7:10 | LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 note: the lint level is defined here - --> $DIR/overcaptures-2024.rs:4:9 + --> $DIR/overcaptures-2024.rs:5:9 | LL | #![deny(impl_trait_overcaptures)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } | +++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:10:25 + --> $DIR/overcaptures-2024.rs:11:25 | LL | fn implicit(x: &i32) -> impl Sized { *x } | ^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | fn implicit(x: &i32) -> impl Sized { *x } = warning: this changes meaning in Rust 2024 = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:10:16 + --> $DIR/overcaptures-2024.rs:11:16 | LL | fn implicit(x: &i32) -> impl Sized { *x } | ^ @@ -42,7 +42,7 @@ LL | fn implicit(x: &i32) -> impl Sized + use<> { *x } | +++++++ error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:16:33 + --> $DIR/overcaptures-2024.rs:17:33 | LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } | ^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } = warning: this changes meaning in Rust 2024 = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:16:24 + --> $DIR/overcaptures-2024.rs:17:24 | LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } | ^ @@ -61,7 +61,7 @@ LL | fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self } | +++++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:28:47 + --> $DIR/overcaptures-2024.rs:29:47 | LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} | ^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} = warning: this changes meaning in Rust 2024 = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:28:23 + --> $DIR/overcaptures-2024.rs:29:23 | LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} | ^^ @@ -80,7 +80,7 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} | +++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:32:28 + --> $DIR/overcaptures-2024.rs:33:28 | LL | fn apit(_: &impl Sized) -> impl Sized {} | ^^^^^^^^^^ @@ -88,13 +88,13 @@ LL | fn apit(_: &impl Sized) -> impl Sized {} = warning: this changes meaning in Rust 2024 = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:32:12 + --> $DIR/overcaptures-2024.rs:33:12 | LL | fn apit(_: &impl Sized) -> impl Sized {} | ^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable - --> $DIR/overcaptures-2024.rs:32:13 + --> $DIR/overcaptures-2024.rs:33:13 | LL | fn apit(_: &impl Sized) -> impl Sized {} | ^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | fn apit(_: &T) -> impl Sized + use {} | ++++++++++ ~ ++++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:36:38 + --> $DIR/overcaptures-2024.rs:37:38 | LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} | ^^^^^^^^^^ @@ -112,13 +112,13 @@ LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} = warning: this changes meaning in Rust 2024 = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:36:16 + --> $DIR/overcaptures-2024.rs:37:16 | LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} | ^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 note: you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable - --> $DIR/overcaptures-2024.rs:36:17 + --> $DIR/overcaptures-2024.rs:37:17 | LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} | ^^^^^^^^^^ @@ -127,5 +127,24 @@ help: use the precise capturing `use<...>` syntax to make the captures explicit LL | fn apit2(_: &T, _: U) -> impl Sized + use {} | ++++++++++ ~ +++++++++++ -error: aborting due to 6 previous errors +error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 + --> $DIR/overcaptures-2024.rs:41:37 + | +LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized {} + | ^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: specifically, this lifetime is in scope but not mentioned in the type's bounds + --> $DIR/overcaptures-2024.rs:41:19 + | +LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized {} + | ^^ + = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 +help: use the precise capturing `use<...>` syntax to make the captures explicit + | +LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} + | +++++++ + +error: aborting due to 7 previous errors