From 817b0932fa66ee8fd6e695f9ec74804a6c360269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Wed, 19 Feb 2025 10:36:21 +0100 Subject: [PATCH 001/356] Implement 'PartialEq<{&Self, CString, Cow}>' for 'CStr'; Implement 'PartialEq<{CStr, &CStr, Cow}>' for 'CString'; Implement 'PartialEq<{CStr, &CStr, CString}>' for 'Cow'; --- library/alloc/src/ffi/c_str.rs | 109 +++++++++++++++++++++++++++++++++ library/core/src/ffi/c_str.rs | 14 +++++ 2 files changed, 123 insertions(+) diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index fd93045a5ac4..91cfb50c5e07 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -1095,6 +1095,46 @@ impl From<&CStr> for CString { } } +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq for CString { + #[inline] + fn eq(&self, other: &CStr) -> bool { + **self == *other + } + + #[inline] + fn ne(&self, other: &CStr) -> bool { + **self != *other + } +} + +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<&CStr> for CString { + #[inline] + fn eq(&self, other: &&CStr) -> bool { + **self == **other + } + + #[inline] + fn ne(&self, other: &&CStr) -> bool { + **self != **other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq> for CString { + #[inline] + fn eq(&self, other: &Cow<'_, CStr>) -> bool { + **self == **other + } + + #[inline] + fn ne(&self, other: &Cow<'_, CStr>) -> bool { + **self != **other + } +} + #[stable(feature = "cstring_asref", since = "1.7.0")] impl ops::Index for CString { type Output = CStr; @@ -1178,6 +1218,75 @@ impl CStr { } } +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq for CStr { + #[inline] + fn eq(&self, other: &CString) -> bool { + *self == **other + } + + #[inline] + fn ne(&self, other: &CString) -> bool { + *self != **other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq> for CStr { + #[inline] + fn eq(&self, other: &Cow<'_, Self>) -> bool { + *self == **other + } + + #[inline] + fn ne(&self, other: &Cow<'_, Self>) -> bool { + *self != **other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq for Cow<'_, CStr> { + #[inline] + fn eq(&self, other: &CStr) -> bool { + **self == *other + } + + #[inline] + fn ne(&self, other: &CStr) -> bool { + **self != *other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<&CStr> for Cow<'_, CStr> { + #[inline] + fn eq(&self, other: &&CStr) -> bool { + **self == **other + } + + #[inline] + fn ne(&self, other: &&CStr) -> bool { + **self != **other + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq for Cow<'_, CStr> { + #[inline] + fn eq(&self, other: &CString) -> bool { + **self == **other + } + + #[inline] + fn ne(&self, other: &CString) -> bool { + **self != **other + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl core::error::Error for NulError { #[allow(deprecated)] diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 75338e492ee0..227799a352a3 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -660,6 +660,19 @@ impl CStr { } } +#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")] +impl PartialEq<&Self> for CStr { + #[inline] + fn eq(&self, other: &&Self) -> bool { + *self == **other + } + + #[inline] + fn ne(&self, other: &&Self) -> bool { + *self != **other + } +} + // `.to_bytes()` representations are compared instead of the inner `[c_char]`s, // because `c_char` is `i8` (not `u8`) on some platforms. // That is why this is implemented manually and not derived. @@ -670,6 +683,7 @@ impl PartialOrd for CStr { self.to_bytes().partial_cmp(&other.to_bytes()) } } + #[stable(feature = "rust1", since = "1.0.0")] impl Ord for CStr { #[inline] From 4f24d142d960350f9cb585795c5cd58857782045 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 25 May 2025 18:51:16 +0000 Subject: [PATCH 002/356] Merge commit '979dcf8e2f213e4f4b645cb62e7fe9f4f2c0c785' into sync_cg_clif-2025-05-25 --- .github/workflows/main.yml | 6 +- Cargo.lock | 80 ++--- Cargo.toml | 24 +- Readme.md | 4 +- build_system/build_backend.rs | 2 +- build_system/build_sysroot.rs | 5 +- docs/usage.md | 2 +- example/mini_core.rs | 20 +- example/std_example.rs | 3 + ...0027-stdlib-128bit-atomic-operations.patch | 9 + rust-toolchain | 2 +- scripts/setup_rust_fork.sh | 2 +- scripts/test_rustc_tests.sh | 17 +- src/abi/mod.rs | 68 +++-- src/abi/pass_mode.rs | 2 + src/abi/returning.rs | 12 +- src/base.rs | 69 +++-- src/cast.rs | 21 +- src/codegen_f16_f128.rs | 284 ++++++++++++++++++ src/common.rs | 8 +- src/compiler_builtins.rs | 88 +++++- src/debuginfo/emit.rs | 39 ++- src/debuginfo/unwind.rs | 20 +- src/driver/jit.rs | 7 +- src/intrinsics/llvm.rs | 7 +- src/intrinsics/llvm_aarch64.rs | 9 +- src/intrinsics/llvm_x86.rs | 13 +- src/intrinsics/mod.rs | 181 ++++++++++- src/intrinsics/simd.rs | 36 ++- src/lib.rs | 43 ++- src/num.rs | 76 ++++- src/pretty_clif.rs | 73 +++-- src/trap.rs | 38 --- src/unwind_module.rs | 24 +- src/value_and_place.rs | 76 +++-- triagebot.toml | 7 + 36 files changed, 1111 insertions(+), 266 deletions(-) create mode 100644 src/codegen_f16_f128.rs delete mode 100644 src/trap.rs create mode 100644 triagebot.toml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6fd288d195c0..d92e0fdce99a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,9 +34,9 @@ jobs: - name: Rustfmt run: | cargo fmt --check - rustfmt --check build_system/main.rs - rustfmt --check example/* - rustfmt --check scripts/*.rs + rustfmt --check --edition 2024 build_system/main.rs + rustfmt --check --edition 2024 example/* + rustfmt --check --edition 2024 scripts/*.rs test: diff --git a/Cargo.lock b/Cargo.lock index e5f1896b9230..a906bec8b7e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,39 +43,42 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-assembler-x64" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4b56ebe316895d3fa37775d0a87b0c889cc933f5c8b253dbcc7c7bcb7fe7e4" +checksum = "9ff8e35182c7372df00447cb90a04e584e032c42b9b9b6e8c50ddaaf0d7900d5" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95cabbc01dfbd7dcd6c329ca44f0212910309c221797ac736a67a5bc8857fe1b" +checksum = "14220f9c2698015c3b94dc6b84ae045c1c45509ddc406e43c6139252757fdb7a" +dependencies = [ + "cranelift-srcgen", +] [[package]] name = "cranelift-bforest" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ffe46df300a45f1dc6f609dc808ce963f0e3a2e971682c479a2d13e3b9b8ef" +checksum = "d372ef2777ceefd75829e1390211ac240e9196bc60699218f7ea2419038288ee" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b265bed7c51e1921fdae6419791d31af77d33662ee56d7b0fa0704dc8d231cab" +checksum = "56323783e423818fa89ce8078e90a3913d2a6e0810399bfce8ebd7ee87baa81f" [[package]] name = "cranelift-codegen" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e606230a7e3a6897d603761baee0d19f88d077f17b996bb5089488a29ae96e41" +checksum = "74ffb780aab6186c6e9ba26519654b1ac55a09c0a866f6088a4efbbd84da68ed" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -98,43 +101,44 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a63bffafc23bc60969ad528e138788495999d935f0adcfd6543cb151ca8637d" +checksum = "c23ef13814d3b39c869650d5961128cbbecad83fbdff4e6836a03ecf6862d7ed" dependencies = [ - "cranelift-assembler-x64", + "cranelift-assembler-x64-meta", "cranelift-codegen-shared", + "cranelift-srcgen", ] [[package]] name = "cranelift-codegen-shared" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af50281b67324b58e843170a6a5943cf6d387c06f7eeacc9f5696e4ab7ae7d7e" +checksum = "b9f623300657679f847803ce80811454bfff89cea4f6bf684be5c468d4a73631" [[package]] name = "cranelift-control" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c20c1b38d1abfbcebb0032e497e71156c0e3b8dcb3f0a92b9863b7bcaec290c" +checksum = "31f4168af69989aa6b91fab46799ed4df6096f3209f4a6c8fb4358f49c60188f" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2c67d95507c51b4a1ff3f3555fe4bfec36b9e13c1b684ccc602736f5d5f4a2" +checksum = "ca6fa9bae1c8de26d71ac2162f069447610fd91e7780cb480ee0d76ac81eabb8" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e002691cc69c38b54fc7ec93e5be5b744f627d027031d991cc845d1d512d0ce" +checksum = "b8219205608aa0b0e6769b580284a7e055c7e0c323c1041cde7ca078add3e412" dependencies = [ "cranelift-codegen", "log", @@ -144,15 +148,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93588ed1796cbcb0e2ad160403509e2c5d330d80dd6e0014ac6774c7ebac496" +checksum = "588d0c5964f10860b04043e55aab26d7f7a206b0fd4f10c5260e8aa5773832bd" [[package]] name = "cranelift-jit" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6682f0b193d6b7873cc8e7ed67e8776a8a26f50eeabf88534e9be618b9a03" +checksum = "56bd917ddc524f84f4066f954062875bdfc0dffea068ee94e906d98de5ac7c33" dependencies = [ "anyhow", "cranelift-codegen", @@ -170,9 +174,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff19784c6de05116e63e6a34791012bd927b2a4eac56233039c46f1b6a4edac8" +checksum = "68a03c057d8a992e06596c871341e446af43ff9224f941e5b8adea39137a5391" dependencies = [ "anyhow", "cranelift-codegen", @@ -181,9 +185,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5b09bdd6407bf5d89661b80cf926ce731c9e8cc184bf49102267a2369a8358e" +checksum = "19ed3c94cb97b14f92b6a94a1d45ef8c851f6a2ad9114e5d91d233f7da638fed" dependencies = [ "cranelift-codegen", "libc", @@ -192,9 +196,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.118.0" +version = "0.120.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685e8661a30d1cb69509f589ac643adeee79c5f63c0da316431b9fad29e6d3b4" +checksum = "a64dacef362a69375a604f6636e5e9a174fb96dba3b273646fcd9fa85c1d0997" dependencies = [ "anyhow", "cranelift-codegen", @@ -205,6 +209,12 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cranelift-srcgen" +version = "0.120.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85256fac1519a7d25a040c1d850fba67478f3f021ad5fdf738ba4425ee862dbf" + [[package]] name = "crc32fast" version = "1.4.2" @@ -331,9 +341,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.11.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3" +checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" dependencies = [ "allocator-api2", "bumpalo", @@ -436,9 +446,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" -version = "31.0.0" +version = "33.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a54f6c6c7e9d7eeee32dfcc10db7f29d505ee7dd28d00593ea241d5f70698e64" +checksum = "175e924dbc944c185808466d1e90b5a7feb610f3b9abdfe26f8ee25fd1086d1c" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index 08b60de14c1f..94fcbd0a5023 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.118.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.118.0" } -cranelift-module = { version = "0.118.0" } -cranelift-native = { version = "0.118.0" } -cranelift-jit = { version = "0.118.0", optional = true } -cranelift-object = { version = "0.118.0" } +cranelift-codegen = { version = "0.120.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.120.0" } +cranelift-module = { version = "0.120.0" } +cranelift-native = { version = "0.120.0" } +cranelift-jit = { version = "0.120.0", optional = true } +cranelift-object = { version = "0.120.0" } target-lexicon = "0.13" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-31.0.0", version = "0.118.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/Readme.md b/Readme.md index 28edb5795ce3..4d1e4d843ffe 100644 --- a/Readme.md +++ b/Readme.md @@ -7,7 +7,7 @@ If not please open an issue. ## Download using Rustup -The Cranelift codegen backend is distributed in nightly builds on Linux and x86_64 macOS. If you want to +The Cranelift codegen backend is distributed in nightly builds on Linux, macOS and x86_64 Windows. If you want to install it using Rustup, you can do that by running: ```bash @@ -79,7 +79,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system Not all targets are available as rustup component for nightly. See notes in the platform support matrix. [^xcoff]: XCOFF object file format is not supported. -[^no-rustup]: Not available as rustup component for nightly. You can build it yourself. +[^no-rustup]: Not available as [rustup component for nightly](https://rust-lang.github.io/rustup-components-history/). You can build it yourself. ## Usage diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index 72bc422523d5..bf7cf1c0a346 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -18,7 +18,7 @@ pub(crate) fn build_backend( let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs); let mut rustflags = rustflags_from_env("RUSTFLAGS"); - rustflags.push("-Zallow-features=rustc_private".to_owned()); + rustflags.push("-Zallow-features=rustc_private,f16,f128".to_owned()); rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); if env::var("CG_CLIF_EXPENSIVE_CHECKS").is_ok() { diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index a73e3c87d43d..00955998e703 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -168,7 +168,8 @@ fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { let file_name_str = file.file_name().unwrap().to_str().unwrap(); if (file_name_str.contains("rustc_") && !file_name_str.contains("rustc_std_workspace_") - && !file_name_str.contains("rustc_demangle")) + && !file_name_str.contains("rustc_demangle") + && !file_name_str.contains("rustc_literal_escaper")) || file_name_str.contains("chalk") || file_name_str.contains("tracing") || file_name_str.contains("regex") @@ -234,7 +235,7 @@ fn build_clif_sysroot_for_triple( compiler.rustflags.extend(rustflags); let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); build_cmd.arg("--release"); - build_cmd.arg("--features").arg("backtrace panic-unwind compiler-builtins-no-f16-f128"); + build_cmd.arg("--features").arg("backtrace panic-unwind"); build_cmd.arg(format!("-Zroot-dir={}", STDLIB_SRC.to_path(dirs).display())); build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true"); build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif"); diff --git a/docs/usage.md b/docs/usage.md index dbe36109f83e..9dcfee4f535a 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -47,7 +47,7 @@ These are a few functions that allow you to easily run rust code from the shell ```bash function jit_naked() { - echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode-Cprefer-dynamic + echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode -Cprefer-dynamic } function jit() { diff --git a/example/mini_core.rs b/example/mini_core.rs index 6e345b2a6fdf..1dc799c0aeea 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -521,10 +521,28 @@ fn panic_cannot_unwind() -> ! { } #[lang = "eh_personality"] -fn eh_personality() -> ! { +// FIXME personality signature depends on target +fn eh_personality( + _version: i32, + _actions: i32, + _exception_class: u64, + _exception_object: *mut (), + _context: *mut (), +) -> i32 { loop {} } +#[lang = "panic_in_cleanup"] +fn panic_in_cleanup() -> ! { + loop {} +} + +#[cfg(all(unix, not(target_vendor = "apple")))] +#[link(name = "gcc_s")] +extern "C" { + fn _Unwind_Resume(exc: *mut ()) -> !; +} + #[lang = "drop_in_place"] #[allow(unconditional_recursion)] pub unsafe fn drop_in_place(to_drop: *mut T) { diff --git a/example/std_example.rs b/example/std_example.rs index 2d9de2a5b8d6..5d83066cffb8 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -166,6 +166,7 @@ fn main() { enum Never {} } + #[cfg(not(target_arch = "s390x"))] // s390x doesn't have vector instructions enabled by default foo(I64X2([0, 0])); transmute_wide_pointer(); @@ -203,9 +204,11 @@ fn rust_call_abi() { rust_call_abi_callee((1, 2)); } +#[cfg_attr(target_arch = "s390x", allow(dead_code))] #[repr(simd)] struct I64X2([i64; 2]); +#[cfg_attr(target_arch = "s390x", allow(dead_code))] #[allow(improper_ctypes_definitions)] extern "C" fn foo(_a: I64X2) {} diff --git a/patches/0027-stdlib-128bit-atomic-operations.patch b/patches/0027-stdlib-128bit-atomic-operations.patch index d7e3b11127c4..38bb43f8204b 100644 --- a/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/patches/0027-stdlib-128bit-atomic-operations.patch @@ -37,6 +37,15 @@ diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index bf2b6d59f88..d5ccce03bbf 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs +@@ -300,8 +300,6 @@ impl_atomic_primitive!(AtomicI32(i32), size("32"), align(4)); + impl_atomic_primitive!(AtomicU32(u32), size("32"), align(4)); + impl_atomic_primitive!(AtomicI64(i64), size("64"), align(8)); + impl_atomic_primitive!(AtomicU64(u64), size("64"), align(8)); +-impl_atomic_primitive!(AtomicI128(i128), size("128"), align(16)); +-impl_atomic_primitive!(AtomicU128(u128), size("128"), align(16)); + + #[cfg(target_pointer_width = "16")] + impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(2)); @@ -3585,44 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type { 8, u64 AtomicU64 diff --git a/rust-toolchain b/rust-toolchain index ceff15b1180a..af4bd6dc6b85 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-03-30" +channel = "nightly-2025-05-25" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index ca6426f2ba9d..532702bb1a46 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -43,7 +43,7 @@ verbose-tests = false # disabled bootstrap will crash trying to copy llvm tools for the bootstrap # compiler. llvm-tools = false -std-features = ["panic-unwind", "compiler-builtins-no-f16-f128"] +std-features = ["panic-unwind"] EOF diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 95a4302b5e47..32c71f433b0f 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -53,6 +53,8 @@ rm -r tests/run-make/split-debuginfo # same rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly +rm tests/ui/asm/global-asm-mono-sym-fn.rs # same +rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes rm -r tests/run-make/embed-source-dwarf # embedding sources in debuginfo @@ -70,19 +72,13 @@ rm tests/ui/consts/precise-drop-with-coverage.rs rm tests/ui/issues/issue-85461.rs rm -r tests/ui/instrument-coverage/ -# missing f16/f128 support -rm tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs -rm tests/ui/asm/aarch64/type-f16.rs -rm tests/ui/float/conv-bits-runtime-const.rs -rm tests/ui/consts/const-eval/float_methods.rs -rm tests/ui/match/match-float.rs - # optimization tests # ================== rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations rm tests/ui/codegen/init-large-type.rs # same rm -r tests/run-make/fmt-write-bloat/ # tests an optimization rm tests/ui/statics/const_generics.rs # same +rm tests/ui/linking/executable-no-mangle-strip.rs # requires --gc-sections to work for statics # backend specific tests # ====================== @@ -96,6 +92,7 @@ rm -r tests/run-make/llvm-location-discriminator-limit-dummy-span # same rm tests/ui/abi/stack-protector.rs # requires stack protector support rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific +rm -r tests/ui/optimization-remark.rs # same rm -r tests/run-make/print-to-output # requires --print relocation-models # requires asm, llvm-ir and/or llvm-bc emit support @@ -118,7 +115,6 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift -rm tests/ui/abi/simd-abi-checks-avx.rs # attempts to declare function with two different signatures # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended @@ -129,7 +125,11 @@ rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contain rm -r tests/run-make/translation # same rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features rm -r tests/run-make/const-trait-stable-toolchain # same +rm -r tests/run-make/print-request-help-stable-unstable # same rm -r tests/run-make/incr-add-rust-src-component +rm tests/ui/errors/remap-path-prefix-sysroot.rs # different sysroot source path +rm -r tests/run-make/export/extern-opt # something about rustc version mismatches +rm -r tests/run-make/export # same # genuine bugs # ============ @@ -141,6 +141,7 @@ rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue rm tests/ui/backtrace/synchronized-panic-handler.rs # missing needs-unwind annotation rm tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs # same +rm tests/ui/async-await/async-drop/async-drop-initial.rs # same (rust-lang/rust#140493) rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 5f631405a9a4..5f7bf3821d77 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_target::callconv::{Conv, FnAbi, PassMode}; +use smallvec::SmallVec; use self::pass_mode::*; pub(crate) use self::returning::codegen_return; @@ -153,10 +154,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { let ret = self.lib_call_unadjusted(name, params, returns, &args)[0]; - // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128 - let ret_ptr = self.create_stack_slot(16, 16); - ret_ptr.store(self, ret, MemFlags::trusted()); - Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]) + Cow::Owned(vec![codegen_bitcast(self, types::I128, ret)]) } else if ret_single_i128 && self.tcx.sess.target.arch == "s390x" { // Return i128 using a return area pointer on s390x. let mut params = params; @@ -184,11 +182,9 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv }; let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap(); let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func); - if self.clif_comments.enabled() { - self.add_comment(func_ref, format!("{:?}", name)); - } let call_inst = self.bcx.ins().call(func_ref, args); if self.clif_comments.enabled() { + self.add_comment(func_ref, format!("{:?}", name)); self.add_comment(call_inst, format!("lib_call {}", name)); } let results = self.bcx.inst_results(call_inst); @@ -384,6 +380,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( args: &[Spanned>], destination: Place<'tcx>, target: Option, + _unwind: UnwindAction, ) { let func = codegen_operand(fx, func); let fn_sig = func.layout().ty.fn_sig(fx.tcx); @@ -529,7 +526,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( Some(Instance { def: InstanceKind::Virtual(_, idx), .. }) => { if fx.clif_comments.enabled() { let nop_inst = fx.bcx.ins().nop(); - fx.add_comment( + fx.add_post_comment( nop_inst, with_no_trimmed_paths!(format!( "virtual call; self arg pass mode: {:?}", @@ -555,7 +552,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( None => { if fx.clif_comments.enabled() { let nop_inst = fx.bcx.ins().nop(); - fx.add_comment(nop_inst, "indirect call"); + fx.add_post_comment(nop_inst, "indirect call"); } let func = func.load_scalar(fx); @@ -585,17 +582,18 @@ pub(crate) fn codegen_terminator_call<'tcx>( adjust_call_for_c_variadic(fx, &fn_abi, source_info, func_ref, &mut call_args); } - if fx.clif_comments.enabled() { - let nop_inst = fx.bcx.ins().nop(); - with_no_trimmed_paths!(fx.add_comment(nop_inst, format!("abi: {:?}", fn_abi))); - } - - match func_ref { + let call_inst = match func_ref { CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args), CallTarget::Indirect(sig, func_ptr) => { fx.bcx.ins().call_indirect(sig, func_ptr, &call_args) } + }; + + if fx.clif_comments.enabled() { + with_no_trimmed_paths!(fx.add_comment(call_inst, format!("abi: {:?}", fn_abi))); } + + fx.bcx.func.dfg.inst_results(call_inst).iter().copied().collect::>() }); if let Some(dest) = target { @@ -705,13 +703,16 @@ pub(crate) fn codegen_drop<'tcx>( source_info: mir::SourceInfo, drop_place: CPlace<'tcx>, target: BasicBlock, + _unwind: UnwindAction, ) { let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty); + let ret_block = fx.get_block(target); // AsyncDropGlueCtorShim can't be here if let ty::InstanceKind::DropGlue(_, None) = drop_instance.def { // we don't actually need to drop anything + fx.bcx.ins().jump(ret_block, &[]); } else { match ty.kind() { ty::Dynamic(_, _, ty::Dyn) => { @@ -748,7 +749,9 @@ pub(crate) fn codegen_drop<'tcx>( let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); let sig = fx.bcx.import_signature(sig); + // FIXME implement cleanup on exceptions fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]); + fx.bcx.ins().jump(ret_block, &[]); } ty::Dynamic(_, _, ty::DynStar) => { // IN THIS ARM, WE HAVE: @@ -792,6 +795,8 @@ pub(crate) fn codegen_drop<'tcx>( let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); let sig = fx.bcx.import_signature(sig); fx.bcx.ins().call_indirect(sig, drop_fn, &[data]); + // FIXME implement cleanup on exceptions + fx.bcx.ins().jump(ret_block, &[]); } _ => { assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _))); @@ -817,10 +822,37 @@ pub(crate) fn codegen_drop<'tcx>( let func_ref = fx.get_function_ref(drop_instance); fx.bcx.ins().call(func_ref, &call_args); + // FIXME implement cleanup on exceptions + fx.bcx.ins().jump(ret_block, &[]); } } } - - let target_block = fx.get_block(target); - fx.bcx.ins().jump(target_block, &[]); +} + +pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam { + let param = AbiParam::new(ty); + if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size.bits() { + match (&*tcx.sess.target.arch, &*tcx.sess.target.vendor) { + ("x86_64", _) | ("aarch64", "apple") => match (ty, is_signed) { + (types::I8 | types::I16, true) => param.sext(), + (types::I8 | types::I16, false) => param.uext(), + _ => param, + }, + ("aarch64", _) => param, + ("riscv64", _) => match (ty, is_signed) { + (types::I32, _) | (_, true) => param.sext(), + _ => param.uext(), + }, + ("s390x", _) => { + if is_signed { + param.sext() + } else { + param.uext() + } + } + _ => unimplemented!("{:?}", tcx.sess.target.arch), + } + } else { + param + } } diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 06d89bc9ea7d..6d8614aca693 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -22,8 +22,10 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam { (RegKind::Integer, 3..=4) => types::I32, (RegKind::Integer, 5..=8) => types::I64, (RegKind::Integer, 9..=16) => types::I128, + (RegKind::Float, 2) => types::F16, (RegKind::Float, 4) => types::F32, (RegKind::Float, 8) => types::F64, + (RegKind::Float, 16) => types::F128, (RegKind::Vector, size) => types::I8.by(u32::try_from(size).unwrap()).unwrap(), _ => unreachable!("{:?}", reg), }; diff --git a/src/abi/returning.rs b/src/abi/returning.rs index 9e048c7badb8..36087f96dd77 100644 --- a/src/abi/returning.rs +++ b/src/abi/returning.rs @@ -46,7 +46,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, ret_place: CPlace<'tcx>, - f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option) -> Inst, + f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option) -> SmallVec<[Value; 2]>, ) { let (ret_temp_place, return_ptr) = match ret_arg_abi.mode { PassMode::Ignore => (None, None), @@ -67,23 +67,21 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None), }; - let call_inst = f(fx, return_ptr); + let results = f(fx, return_ptr); match ret_arg_abi.mode { PassMode::Ignore => {} PassMode::Direct(_) => { - let ret_val = fx.bcx.inst_results(call_inst)[0]; + let ret_val = results[0]; ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout)); } PassMode::Pair(_, _) => { - let ret_val_a = fx.bcx.inst_results(call_inst)[0]; - let ret_val_b = fx.bcx.inst_results(call_inst)[1]; + let ret_val_a = results[0]; + let ret_val_b = results[1]; ret_place .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout)); } PassMode::Cast { ref cast, .. } => { - let results = - fx.bcx.inst_results(call_inst).iter().copied().collect::>(); let result = super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); ret_place.write_cvalue(fx, result); diff --git a/src/base.rs b/src/base.rs index 524e0d9fe35e..4617304105a5 100644 --- a/src/base.rs +++ b/src/base.rs @@ -15,9 +15,9 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; -use crate::enable_verifier; use crate::prelude::*; use crate::pretty_clif::CommentWriter; +use crate::{codegen_f16_f128, enable_verifier}; pub(crate) struct CodegenedFunction { symbol_name: String, @@ -193,6 +193,18 @@ pub(crate) fn compile_fn( name = codegened_func.symbol_name )); } + Err(ModuleError::Compilation(CodegenError::Verifier(err))) => { + let early_dcx = rustc_session::EarlyDiagCtxt::new( + rustc_session::config::ErrorOutputType::default(), + ); + let _ = early_dcx.early_err(format!("{:?}", err)); + let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error( + &context.func, + Some(Box::new(&clif_comments)), + err, + ); + early_dcx.early_fatal(format!("cranelift verify error:\n{}", pretty_error)); + } Err(err) => { panic!("Error while defining {name}: {err:?}", name = codegened_func.symbol_name); } @@ -303,7 +315,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { bb_data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); }); let inst = fx.bcx.func.layout.last_inst(block).unwrap(); - fx.add_comment(inst, terminator_head); + fx.add_post_comment(inst, terminator_head); } let source_info = bb_data.terminator().source_info; @@ -337,7 +349,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { TerminatorKind::Return => { crate::abi::codegen_return(fx); } - TerminatorKind::Assert { cond, expected, msg, target, unwind: _ } => { + TerminatorKind::Assert { cond, expected, msg, target, unwind } => { if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() { let target = fx.get_block(*target); fx.bcx.ins().jump(target, &[]); @@ -367,6 +379,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, rustc_hir::LangItem::PanicBoundsCheck, &[index, len, location], + *unwind, Some(source_info.span), ); } @@ -379,6 +392,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, rustc_hir::LangItem::PanicMisalignedPointerDereference, &[required, found, location], + *unwind, Some(source_info.span), ); } @@ -389,6 +403,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, rustc_hir::LangItem::PanicNullPointerDereference, &[location], + *unwind, Some(source_info.span), ) } @@ -399,6 +414,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fx, msg.panic_function(), &[location], + *unwind, Some(source_info.span), ); } @@ -457,7 +473,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { destination, target, fn_span, - unwind: _, + unwind, call_source: _, } => { fx.tcx.prof.generic_activity("codegen call").run(|| { @@ -468,6 +484,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { args, *destination, *target, + *unwind, ) }); } @@ -514,7 +531,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ); } TerminatorKind::UnwindTerminate(reason) => { - codegen_unwind_terminate(fx, source_info, *reason); + codegen_unwind_terminate(fx, Some(source_info.span), *reason); } TerminatorKind::UnwindResume => { // FIXME implement unwinding @@ -530,23 +547,19 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { | TerminatorKind::CoroutineDrop => { bug!("shouldn't exist at codegen {:?}", bb_data.terminator()); } - TerminatorKind::Drop { place, target, unwind: _, replace: _, drop, async_fut } => { + TerminatorKind::Drop { place, target, unwind, replace: _, drop, async_fut } => { assert!( async_fut.is_none() && drop.is_none(), "Async Drop must be expanded or reset to sync before codegen" ); let drop_place = codegen_place(fx, *place); - crate::abi::codegen_drop(fx, source_info, drop_place, *target); + crate::abi::codegen_drop(fx, source_info, drop_place, *target, *unwind); } }; } } -fn codegen_stmt<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - #[allow(unused_variables)] cur_block: Block, - stmt: &Statement<'tcx>, -) { +fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: &Statement<'tcx>) { let _print_guard = crate::PrintOnPanic(|| format!("stmt {:?}", stmt)); fx.set_debug_loc(stmt.source_info); @@ -557,7 +570,7 @@ fn codegen_stmt<'tcx>( if fx.clif_comments.enabled() { let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap(); with_no_trimmed_paths!({ - fx.add_comment(inst, format!("{:?}", stmt)); + fx.add_post_comment(inst, format!("{:?}", stmt)); }); } } @@ -622,6 +635,15 @@ fn codegen_stmt<'tcx>( let val = operand.load_scalar(fx); match layout.ty.kind() { ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), + // FIXME(bytecodealliance/wasmtime#8312): Remove + // once backend lowerings have been added to + // Cranelift. + ty::Float(FloatTy::F16) => { + CValue::by_val(codegen_f16_f128::neg_f16(fx, val), layout) + } + ty::Float(FloatTy::F128) => { + CValue::by_val(codegen_f16_f128::neg_f128(fx, val), layout) + } ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout), _ => unreachable!("un op Neg for {:?}", layout.ty), } @@ -793,7 +815,7 @@ fn codegen_stmt<'tcx>( let done_block = fx.bcx.create_block(); let index = fx.bcx.append_block_param(loop_block, fx.pointer_type); let zero = fx.bcx.ins().iconst(fx.pointer_type, 0); - fx.bcx.ins().jump(loop_block, &[zero]); + fx.bcx.ins().jump(loop_block, &[zero.into()]); fx.bcx.switch_to_block(loop_block); let done = fx.bcx.ins().icmp_imm(IntCC::Equal, index, times as i64); @@ -803,7 +825,7 @@ fn codegen_stmt<'tcx>( let to = lval.place_index(fx, index); to.write_cvalue(fx, operand); let index = fx.bcx.ins().iadd_imm(index, 1); - fx.bcx.ins().jump(loop_block, &[index]); + fx.bcx.ins().jump(loop_block, &[index.into()]); fx.bcx.switch_to_block(done_block); fx.bcx.ins().nop(); @@ -1058,23 +1080,28 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); let args = [msg_ptr, msg_len]; - codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, span); + codegen_panic_inner( + fx, + rustc_hir::LangItem::PanicNounwind, + &args, + UnwindAction::Terminate(UnwindTerminateReason::Abi), + span, + ); } pub(crate) fn codegen_unwind_terminate<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - source_info: mir::SourceInfo, + span: Option, reason: UnwindTerminateReason, ) { - let args = []; - - codegen_panic_inner(fx, reason.lang_item(), &args, Some(source_info.span)); + codegen_panic_inner(fx, reason.lang_item(), &[], UnwindAction::Unreachable, span); } fn codegen_panic_inner<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, lang_item: rustc_hir::LangItem, args: &[Value], + _unwind: UnwindAction, span: Option, ) { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); @@ -1090,6 +1117,8 @@ fn codegen_panic_inner<'tcx>( let symbol_name = fx.tcx.symbol_name(instance).name; + // FIXME implement cleanup on exceptions + fx.lib_call( symbol_name, args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(), diff --git a/src/cast.rs b/src/cast.rs index e2346324232f..8a725680e705 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -1,5 +1,6 @@ //! Various number casting functions +use crate::codegen_f16_f128; use crate::prelude::*; pub(crate) fn clif_intcast( @@ -36,6 +37,14 @@ pub(crate) fn clif_int_or_float_cast( ) -> Value { let from_ty = fx.bcx.func.dfg.value_type(from); + // FIXME(bytecodealliance/wasmtime#8312): Remove in favour of native + // Cranelift operations once Cranelift backends have lowerings for them. + if matches!(from_ty, types::F16 | types::F128) + || matches!(to_ty, types::F16 | types::F128) && from_ty != to_ty + { + return codegen_f16_f128::codegen_cast(fx, from, from_signed, to_ty, to_signed); + } + if from_ty.is_int() && to_ty.is_int() { // int-like -> int-like clif_intcast( @@ -58,8 +67,10 @@ pub(crate) fn clif_int_or_float_cast( "__float{sign}ti{flt}f", sign = if from_signed { "" } else { "un" }, flt = match to_ty { + types::F16 => "h", types::F32 => "s", types::F64 => "d", + types::F128 => "t", _ => unreachable!("{:?}", to_ty), }, ); @@ -90,8 +101,10 @@ pub(crate) fn clif_int_or_float_cast( "__fix{sign}{flt}fti", sign = if to_signed { "" } else { "uns" }, flt = match from_ty { + types::F16 => "h", types::F32 => "s", types::F64 => "d", + types::F128 => "t", _ => unreachable!("{:?}", to_ty), }, ); @@ -145,8 +158,12 @@ pub(crate) fn clif_int_or_float_cast( } else if from_ty.is_float() && to_ty.is_float() { // float -> float match (from_ty, to_ty) { - (types::F32, types::F64) => fx.bcx.ins().fpromote(types::F64, from), - (types::F64, types::F32) => fx.bcx.ins().fdemote(types::F32, from), + (types::F16, types::F32 | types::F64 | types::F128) + | (types::F32, types::F64 | types::F128) + | (types::F64, types::F128) => fx.bcx.ins().fpromote(to_ty, from), + (types::F128, types::F64 | types::F32 | types::F16) + | (types::F64, types::F32 | types::F16) + | (types::F32, types::F16) => fx.bcx.ins().fdemote(to_ty, from), _ => from, } } else { diff --git a/src/codegen_f16_f128.rs b/src/codegen_f16_f128.rs new file mode 100644 index 000000000000..1e202be1f185 --- /dev/null +++ b/src/codegen_f16_f128.rs @@ -0,0 +1,284 @@ +use crate::prelude::*; + +pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let (value, arg_ty) = + if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == "x86_64" { + ( + fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value), + lib_call_arg_param(fx.tcx, types::I16, false), + ) + } else { + (value, AbiParam::new(types::F16)) + }; + fx.lib_call("__extendhfsf2", vec![arg_ty], vec![AbiParam::new(types::F32)], &[value])[0] +} + +fn f16_to_f64(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let ret = f16_to_f32(fx, value); + fx.bcx.ins().fpromote(types::F64, ret) +} + +pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == "x86_64" { + types::I16 + } else { + types::F16 + }; + let ret = fx.lib_call( + "__truncsfhf2", + vec![AbiParam::new(types::F32)], + vec![AbiParam::new(ret_ty)], + &[value], + )[0]; + if ret_ty == types::I16 { fx.bcx.ins().bitcast(types::F16, MemFlags::new(), ret) } else { ret } +} + +fn f64_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == "x86_64" { + types::I16 + } else { + types::F16 + }; + let ret = fx.lib_call( + "__truncdfhf2", + vec![AbiParam::new(types::F64)], + vec![AbiParam::new(ret_ty)], + &[value], + )[0]; + if ret_ty == types::I16 { fx.bcx.ins().bitcast(types::F16, MemFlags::new(), ret) } else { ret } +} + +pub(crate) fn fcmp(fx: &mut FunctionCx<'_, '_, '_>, cc: FloatCC, lhs: Value, rhs: Value) -> Value { + let ty = fx.bcx.func.dfg.value_type(lhs); + match ty { + types::F32 | types::F64 => fx.bcx.ins().fcmp(cc, lhs, rhs), + types::F16 => { + let lhs = f16_to_f32(fx, lhs); + let rhs = f16_to_f32(fx, rhs); + fx.bcx.ins().fcmp(cc, lhs, rhs) + } + types::F128 => { + let (name, int_cc) = match cc { + FloatCC::Equal => ("__eqtf2", IntCC::Equal), + FloatCC::NotEqual => ("__netf2", IntCC::NotEqual), + FloatCC::LessThan => ("__lttf2", IntCC::SignedLessThan), + FloatCC::LessThanOrEqual => ("__letf2", IntCC::SignedLessThanOrEqual), + FloatCC::GreaterThan => ("__gttf2", IntCC::SignedGreaterThan), + FloatCC::GreaterThanOrEqual => ("__getf2", IntCC::SignedGreaterThanOrEqual), + _ => unreachable!("not currently used in rustc_codegen_cranelift: {cc:?}"), + }; + let res = fx.lib_call( + name, + vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], + // FIXME(rust-lang/compiler-builtins#919): This should be `I64` on non-AArch64 + // architectures, but switching it before compiler-builtins is fixed causes test + // failures. + vec![AbiParam::new(types::I32)], + &[lhs, rhs], + )[0]; + let zero = fx.bcx.ins().iconst(types::I32, 0); + let res = fx.bcx.ins().icmp(int_cc, res, zero); + res + } + _ => unreachable!("{ty:?}"), + } +} + +pub(crate) fn codegen_f128_binop( + fx: &mut FunctionCx<'_, '_, '_>, + bin_op: BinOp, + lhs: Value, + rhs: Value, +) -> Value { + let name = match bin_op { + BinOp::Add => "__addtf3", + BinOp::Sub => "__subtf3", + BinOp::Mul => "__multf3", + BinOp::Div => "__divtf3", + _ => unreachable!("handled in `codegen_float_binop`"), + }; + fx.lib_call( + name, + vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], + vec![AbiParam::new(types::F128)], + &[lhs, rhs], + )[0] +} + +pub(crate) fn neg_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let bits = fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value); + let bits = fx.bcx.ins().bxor_imm(bits, 0x8000); + fx.bcx.ins().bitcast(types::F16, MemFlags::new(), bits) +} + +pub(crate) fn neg_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let bits = fx.bcx.ins().bitcast(types::I128, MemFlags::new(), value); + let (low, high) = fx.bcx.ins().isplit(bits); + let high = fx.bcx.ins().bxor_imm(high, 0x8000_0000_0000_0000_u64 as i64); + let bits = fx.bcx.ins().iconcat(low, high); + fx.bcx.ins().bitcast(types::F128, MemFlags::new(), bits) +} + +pub(crate) fn abs_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let bits = fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value); + let bits = fx.bcx.ins().band_imm(bits, 0x7fff); + fx.bcx.ins().bitcast(types::F16, MemFlags::new(), bits) +} + +pub(crate) fn abs_f128(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { + let bits = fx.bcx.ins().bitcast(types::I128, MemFlags::new(), value); + let (low, high) = fx.bcx.ins().isplit(bits); + let high = fx.bcx.ins().band_imm(high, 0x7fff_ffff_ffff_ffff_u64 as i64); + let bits = fx.bcx.ins().iconcat(low, high); + fx.bcx.ins().bitcast(types::F128, MemFlags::new(), bits) +} + +pub(crate) fn copysign_f16(fx: &mut FunctionCx<'_, '_, '_>, lhs: Value, rhs: Value) -> Value { + let lhs = fx.bcx.ins().bitcast(types::I16, MemFlags::new(), lhs); + let rhs = fx.bcx.ins().bitcast(types::I16, MemFlags::new(), rhs); + let res = fx.bcx.ins().band_imm(lhs, 0x7fff); + let sign = fx.bcx.ins().band_imm(rhs, 0x8000); + let res = fx.bcx.ins().bor(res, sign); + fx.bcx.ins().bitcast(types::F16, MemFlags::new(), res) +} + +pub(crate) fn copysign_f128(fx: &mut FunctionCx<'_, '_, '_>, lhs: Value, rhs: Value) -> Value { + let lhs = fx.bcx.ins().bitcast(types::I128, MemFlags::new(), lhs); + let rhs = fx.bcx.ins().bitcast(types::I128, MemFlags::new(), rhs); + let (low, lhs_high) = fx.bcx.ins().isplit(lhs); + let (_, rhs_high) = fx.bcx.ins().isplit(rhs); + let high = fx.bcx.ins().band_imm(lhs_high, 0x7fff_ffff_ffff_ffff_u64 as i64); + let sign = fx.bcx.ins().band_imm(rhs_high, 0x8000_0000_0000_0000_u64 as i64); + let high = fx.bcx.ins().bor(high, sign); + let res = fx.bcx.ins().iconcat(low, high); + fx.bcx.ins().bitcast(types::F128, MemFlags::new(), res) +} + +pub(crate) fn codegen_cast( + fx: &mut FunctionCx<'_, '_, '_>, + from: Value, + from_signed: bool, + to_ty: Type, + to_signed: bool, +) -> Value { + let from_ty = fx.bcx.func.dfg.value_type(from); + if from_ty.is_float() && to_ty.is_float() { + let name = match (from_ty, to_ty) { + (types::F16, types::F32) => return f16_to_f32(fx, from), + (types::F16, types::F64) => return f16_to_f64(fx, from), + (types::F16, types::F128) => "__extendhftf2", + (types::F32, types::F128) => "__extendsftf2", + (types::F64, types::F128) => "__extenddftf2", + (types::F128, types::F64) => "__trunctfdf2", + (types::F128, types::F32) => "__trunctfsf2", + (types::F128, types::F16) => "__trunctfhf2", + (types::F64, types::F16) => return f64_to_f16(fx, from), + (types::F32, types::F16) => return f32_to_f16(fx, from), + _ => unreachable!("{from_ty:?} -> {to_ty:?}"), + }; + fx.lib_call(name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(to_ty)], &[from])[0] + } else if from_ty.is_int() && to_ty == types::F16 { + let res = clif_int_or_float_cast(fx, from, from_signed, types::F32, false); + f32_to_f16(fx, res) + } else if from_ty == types::F16 && to_ty.is_int() { + let from = f16_to_f32(fx, from); + clif_int_or_float_cast(fx, from, false, to_ty, to_signed) + } else if from_ty.is_int() && to_ty == types::F128 { + let (from, from_ty) = if from_ty.bits() < 32 { + (clif_int_or_float_cast(fx, from, from_signed, types::I32, from_signed), types::I32) + } else { + (from, from_ty) + }; + let name = format!( + "__float{sign}{size}itf", + sign = if from_signed { "" } else { "un" }, + size = match from_ty { + types::I32 => 's', + types::I64 => 'd', + types::I128 => 't', + _ => unreachable!("{from_ty:?}"), + }, + ); + fx.lib_call( + &name, + vec![lib_call_arg_param(fx.tcx, from_ty, from_signed)], + vec![AbiParam::new(to_ty)], + &[from], + )[0] + } else if from_ty == types::F128 && to_ty.is_int() { + let ret_ty = if to_ty.bits() < 32 { types::I32 } else { to_ty }; + let name = format!( + "__fix{sign}tf{size}i", + sign = if from_signed { "" } else { "un" }, + size = match ret_ty { + types::I32 => 's', + types::I64 => 'd', + types::I128 => 't', + _ => unreachable!("{from_ty:?}"), + }, + ); + let ret = + fx.lib_call(&name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(to_ty)], &[from]) + [0]; + let val = if ret_ty == to_ty { + ret + } else { + let (min, max) = match (to_ty, to_signed) { + (types::I8, false) => (0, i64::from(u8::MAX)), + (types::I16, false) => (0, i64::from(u16::MAX)), + (types::I8, true) => (i64::from(i8::MIN as u32), i64::from(i8::MAX as u32)), + (types::I16, true) => (i64::from(i16::MIN as u32), i64::from(i16::MAX as u32)), + _ => unreachable!("{to_ty:?}"), + }; + let min_val = fx.bcx.ins().iconst(types::I32, min); + let max_val = fx.bcx.ins().iconst(types::I32, max); + + let val = if to_signed { + let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, ret, min); + let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, ret, max); + let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, ret); + fx.bcx.ins().select(has_overflow, max_val, bottom_capped) + } else { + let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, ret, max); + fx.bcx.ins().select(has_overflow, max_val, ret) + }; + fx.bcx.ins().ireduce(to_ty, val) + }; + + if let Some(false) = fx.tcx.sess.opts.unstable_opts.saturating_float_casts { + return val; + } + + let is_not_nan = fcmp(fx, FloatCC::Equal, from, from); + let zero = type_zero_value(&mut fx.bcx, to_ty); + fx.bcx.ins().select(is_not_nan, val, zero) + } else { + unreachable!("{from_ty:?} -> {to_ty:?}"); + } +} + +pub(crate) fn fma_f16(fx: &mut FunctionCx<'_, '_, '_>, x: Value, y: Value, z: Value) -> Value { + let x = f16_to_f64(fx, x); + let y = f16_to_f64(fx, y); + let z = f16_to_f64(fx, z); + let res = fx.bcx.ins().fma(x, y, z); + f64_to_f16(fx, res) +} + +pub(crate) fn fmin_f128(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { + fx.lib_call( + "fminimumf128", + vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], + vec![AbiParam::new(types::F128)], + &[a, b], + )[0] +} + +pub(crate) fn fmax_f128(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { + fx.lib_call( + "fmaximumf128", + vec![AbiParam::new(types::F128), AbiParam::new(types::F128)], + vec![AbiParam::new(types::F128)], + &[a, b], + )[0] +} diff --git a/src/common.rs b/src/common.rs index abe2972ba0cb..2f11b2d2dcc1 100644 --- a/src/common.rs +++ b/src/common.rs @@ -33,10 +33,10 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type { Integer::I128 => types::I128, }, Primitive::Float(float) => match float { - Float::F16 => unimplemented!("f16_f128"), + Float::F16 => types::F16, Float::F32 => types::F32, Float::F64 => types::F64, - Float::F128 => unimplemented!("f16_f128"), + Float::F128 => types::F128, }, // FIXME(erikdesjardins): handle non-default addrspace ptr sizes Primitive::Pointer(_) => pointer_ty(tcx), @@ -64,10 +64,10 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option types::I32, ty::Float(size) => match size { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => types::F16, FloatTy::F32 => types::F32, FloatTy::F64 => types::F64, - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => types::F128, }, ty::FnPtr(..) => pointer_ty(tcx), ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => { diff --git a/src/compiler_builtins.rs b/src/compiler_builtins.rs index bf16e81a06f9..6eea19211fa1 100644 --- a/src/compiler_builtins.rs +++ b/src/compiler_builtins.rs @@ -46,15 +46,100 @@ builtin_functions! { fn __rust_u128_mulo(a: u128, b: u128, oflow: &mut i32) -> u128; fn __rust_i128_mulo(a: i128, b: i128, oflow: &mut i32) -> i128; - // floats + // integer -> float fn __floattisf(i: i128) -> f32; fn __floattidf(i: i128) -> f64; + fn __floatsitf(i: i32) -> f128; + fn __floatditf(i: i64) -> f128; + fn __floattitf(i: i128) -> f128; fn __floatuntisf(i: u128) -> f32; fn __floatuntidf(i: u128) -> f64; + fn __floatunsitf(i: u32) -> f128; + fn __floatunditf(i: u64) -> f128; + fn __floatuntitf(i: u128) -> f128; + // float -> integer fn __fixsfti(f: f32) -> i128; fn __fixdfti(f: f64) -> i128; + fn __fixtfsi(f: f128) -> i32; + fn __fixtfdi(f: f128) -> i64; + fn __fixtfti(f: f128) -> i128; fn __fixunssfti(f: f32) -> u128; fn __fixunsdfti(f: f64) -> u128; + fn __fixunstfsi(f: f128) -> u32; + fn __fixunstfdi(f: f128) -> u64; + fn __fixunstfti(f: f128) -> u128; + // float -> float + fn __extendhfsf2(f: f16) -> f32; + fn __extendhftf2(f: f16) -> f128; + fn __extendsftf2(f: f32) -> f128; + fn __extenddftf2(f: f64) -> f128; + fn __trunctfdf2(f: f128) -> f64; + fn __trunctfsf2(f: f128) -> f32; + fn __trunctfhf2(f: f128) -> f16; + fn __truncdfhf2(f: f64) -> f16; + fn __truncsfhf2(f: f32) -> f16; + // float binops + fn __addtf3(a: f128, b: f128) -> f128; + fn __subtf3(a: f128, b: f128) -> f128; + fn __multf3(a: f128, b: f128) -> f128; + fn __divtf3(a: f128, b: f128) -> f128; + fn fmodf(a: f32, b: f32) -> f32; + fn fmod(a: f64, b: f64) -> f64; + fn fmodf128(a: f128, b: f128) -> f128; + // float comparison + fn __eqtf2(a: f128, b: f128) -> i32; + fn __netf2(a: f128, b: f128) -> i32; + fn __lttf2(a: f128, b: f128) -> i32; + fn __letf2(a: f128, b: f128) -> i32; + fn __gttf2(a: f128, b: f128) -> i32; + fn __getf2(a: f128, b: f128) -> i32; + fn fminimumf128(a: f128, b: f128) -> f128; + fn fmaximumf128(a: f128, b: f128) -> f128; + // Cranelift float libcalls + fn fmaf(a: f32, b: f32, c: f32) -> f32; + fn fma(a: f64, b: f64, c: f64) -> f64; + fn floorf(f: f32) -> f32; + fn floor(f: f64) -> f64; + fn ceilf(f: f32) -> f32; + fn ceil(f: f64) -> f64; + fn truncf(f: f32) -> f32; + fn trunc(f: f64) -> f64; + fn nearbyintf(f: f32) -> f32; + fn nearbyint(f: f64) -> f64; + // float intrinsics + fn __powisf2(a: f32, b: i32) -> f32; + fn __powidf2(a: f64, b: i32) -> f64; + // FIXME(f16_f128): `compiler-builtins` doesn't currently support `__powitf2` on MSVC. + // fn __powitf2(a: f128, b: i32) -> f128; + fn powf(a: f32, b: f32) -> f32; + fn pow(a: f64, b: f64) -> f64; + fn expf(f: f32) -> f32; + fn exp(f: f64) -> f64; + fn exp2f(f: f32) -> f32; + fn exp2(f: f64) -> f64; + fn logf(f: f32) -> f32; + fn log(f: f64) -> f64; + fn log2f(f: f32) -> f32; + fn log2(f: f64) -> f64; + fn log10f(f: f32) -> f32; + fn log10(f: f64) -> f64; + fn sinf(f: f32) -> f32; + fn sin(f: f64) -> f64; + fn cosf(f: f32) -> f32; + fn cos(f: f64) -> f64; + fn fmaf128(a: f128, b: f128, c: f128) -> f128; + fn floorf16(f: f16) -> f16; + fn floorf128(f: f128) -> f128; + fn ceilf16(f: f16) -> f16; + fn ceilf128(f: f128) -> f128; + fn truncf16(f: f16) -> f16; + fn truncf128(f: f128) -> f128; + fn rintf16(f: f16) -> f16; + fn rintf128(f: f128) -> f128; + fn sqrtf16(f: f16) -> f16; + fn sqrtf128(f: f128) -> f128; + // FIXME(f16_f128): Add other float intrinsics as compiler-builtins gains support (meaning they + // are available on all targets). // allocator // NOTE: These need to be mentioned here despite not being part of compiler_builtins because @@ -67,5 +152,4 @@ builtin_functions! { fn malloc(size: size_t) -> *mut c_void; fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; fn free(p: *mut c_void) -> (); - } diff --git a/src/debuginfo/emit.rs b/src/debuginfo/emit.rs index ccdc347af660..0f4696b9337e 100644 --- a/src/debuginfo/emit.rs +++ b/src/debuginfo/emit.rs @@ -81,13 +81,36 @@ impl WriterRelocate { /// Perform the collected relocations to be usable for JIT usage. #[cfg(all(feature = "jit", not(windows)))] pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec { + use cranelift_module::Module; + for reloc in self.relocs.drain(..) { match reloc.name { super::DebugRelocName::Section(_) => unreachable!(), super::DebugRelocName::Symbol(sym) => { - let addr = jit_module.get_finalized_function( - cranelift_module::FuncId::from_u32(sym.try_into().unwrap()), - ); + let addr = if sym & 1 << 31 == 0 { + let func_id = FuncId::from_u32(sym.try_into().unwrap()); + // FIXME make JITModule::get_address public and use it here instead. + // HACK rust_eh_personality is likely not defined in the same crate, + // so get_finalized_function won't work. Use the rust_eh_personality + // of cg_clif itself, which is likely ABI compatible. + if jit_module.declarations().get_function_decl(func_id).name.as_deref() + == Some("rust_eh_personality") + { + extern "C" { + fn rust_eh_personality() -> !; + } + rust_eh_personality as *const u8 + } else { + jit_module.get_finalized_function(func_id) + } + } else { + jit_module + .get_finalized_data(DataId::from_u32( + u32::try_from(sym).unwrap() & !(1 << 31), + )) + .0 + }; + let val = (addr as u64 as i64 + reloc.addend) as u64; self.writer.write_udata_at(reloc.offset as usize, val, reloc.size).unwrap(); } @@ -196,6 +219,16 @@ impl Writer for WriterRelocate { }); self.write_udata(0, size) } + gimli::DW_EH_PE_absptr => { + self.relocs.push(DebugReloc { + offset: self.len() as u32, + size: size.into(), + name: DebugRelocName::Symbol(symbol), + addend, + kind: object::RelocationKind::Absolute, + }); + self.write_udata(0, size.into()) + } _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), }, } diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index 362333d35a41..74b82a7139ab 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -1,7 +1,6 @@ //! Unwind info generation (`.eh_frame`) use cranelift_codegen::ir::Endianness; -use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::isa::unwind::UnwindInfo; use cranelift_object::ObjectProduct; use gimli::RunTimeEndian; @@ -18,14 +17,14 @@ pub(crate) struct UnwindContext { } impl UnwindContext { - pub(crate) fn new(isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { - let endian = match isa.endianness() { + pub(crate) fn new(module: &mut dyn Module, pic_eh_frame: bool) -> Self { + let endian = match module.isa().endianness() { Endianness::Little => RunTimeEndian::Little, Endianness::Big => RunTimeEndian::Big, }; let mut frame_table = FrameTable::default(); - let cie_id = if let Some(mut cie) = isa.create_systemv_cie() { + let cie_id = if let Some(mut cie) = module.isa().create_systemv_cie() { if pic_eh_frame { cie.fde_address_encoding = gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0); @@ -38,8 +37,15 @@ impl UnwindContext { UnwindContext { endian, frame_table, cie_id } } - pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) { - if let target_lexicon::OperatingSystem::MacOSX { .. } = isa.triple().operating_system { + pub(crate) fn add_function( + &mut self, + module: &mut dyn Module, + func_id: FuncId, + context: &Context, + ) { + if let target_lexicon::OperatingSystem::MacOSX { .. } = + module.isa().triple().operating_system + { // The object crate doesn't currently support DW_GNU_EH_PE_absptr, which macOS // requires for unwinding tables. In addition on arm64 it currently doesn't // support 32bit relocations as we currently use for the unwinding table. @@ -48,7 +54,7 @@ impl UnwindContext { } let unwind_info = if let Some(unwind_info) = - context.compiled_code().unwrap().create_unwind_info(isa).unwrap() + context.compiled_code().unwrap().create_unwind_info(module.isa()).unwrap() { unwind_info } else { diff --git a/src/driver/jit.rs b/src/driver/jit.rs index e368cf4386d0..b1f185b551c3 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -6,6 +6,7 @@ use std::os::raw::{c_char, c_int}; use cranelift_jit::{JITBuilder, JITModule}; use rustc_codegen_ssa::CrateInfo; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::MonoItem; use rustc_session::Session; use rustc_span::sym; @@ -84,7 +85,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { tcx.dcx().abort_if_errors(); - jit_module.finalize_definitions(); + let mut jit_module = jit_module.finalize_definitions(); println!( "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed" @@ -104,7 +105,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { call_conv: jit_module.target_config().default_call_conv, }; let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap(); - let finalized_start: *const u8 = jit_module.module.get_finalized_function(start_func_id); + let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); let f: extern "C" fn(c_int, *const *const c_char) -> c_int = unsafe { ::std::mem::transmute(finalized_start) }; @@ -119,7 +120,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { std::process::exit(ret); } -pub(crate) fn codegen_and_compile_fn<'tcx>( +fn codegen_and_compile_fn<'tcx>( tcx: TyCtxt<'tcx>, cx: &mut crate::CodegenCx, cached_context: &mut Context, diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index eb0dfbb69c3b..2e02e85a997d 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -66,7 +66,12 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( fx.tcx .dcx() .warn(format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic)); - crate::trap::trap_unimplemented(fx, intrinsic); + let msg = format!( + "{intrinsic} is not yet supported.\n\ + See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ + Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" + ); + crate::base::codegen_panic_nounwind(fx, &msg, None); return; } } diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index 387c87d123a3..d22483cf1776 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -7,7 +7,7 @@ use crate::inline_asm::{CInlineAsmOperand, codegen_inline_asm_inner}; use crate::intrinsics::*; use crate::prelude::*; -pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( +pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, args: &[Spanned>], @@ -507,7 +507,12 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( "unsupported AArch64 llvm intrinsic {}; replacing with trap", intrinsic )); - crate::trap::trap_unimplemented(fx, intrinsic); + let msg = format!( + "{intrinsic} is not yet supported.\n\ + See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ + Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" + ); + crate::base::codegen_panic_nounwind(fx, &msg, None); return; } } diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index c02d31844e03..3d67913a8fff 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -7,7 +7,7 @@ use crate::inline_asm::{CInlineAsmOperand, codegen_inline_asm_inner}; use crate::intrinsics::*; use crate::prelude::*; -pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( +pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, intrinsic: &str, args: &[Spanned>], @@ -147,10 +147,10 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( let offset = fx.bcx.ins().imul(index_lane, scale); let lane_ptr = fx.bcx.ins().iadd(ptr, offset); let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), lane_ptr, 0); - fx.bcx.ins().jump(next, &[res]); + fx.bcx.ins().jump(next, &[res.into()]); fx.bcx.switch_to_block(if_disabled); - fx.bcx.ins().jump(next, &[src_lane]); + fx.bcx.ins().jump(next, &[src_lane.into()]); fx.bcx.seal_block(next); fx.bcx.switch_to_block(next); @@ -1316,7 +1316,12 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( fx.tcx .dcx() .warn(format!("unsupported x86 llvm intrinsic {}; replacing with trap", intrinsic)); - crate::trap::trap_unimplemented(fx, intrinsic); + let msg = format!( + "{intrinsic} is not yet supported.\n\ + See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ + Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" + ); + crate::base::codegen_panic_nounwind(fx, &msg, None); return; } } diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 9018d78b00ae..b21ca32c9a2e 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -27,6 +27,7 @@ use rustc_span::{Symbol, sym}; pub(crate) use self::llvm::codegen_llvm_intrinsic_call; use crate::cast::clif_intcast; +use crate::codegen_f16_f128; use crate::prelude::*; fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! { @@ -248,8 +249,10 @@ fn bool_to_zero_or_max_uint<'tcx>( let ty = fx.clif_type(ty).unwrap(); let int_ty = match ty { + types::F16 => types::I16, types::F32 => types::I32, types::F64 => types::I64, + types::F128 => types::I128, ty => ty, }; @@ -308,45 +311,83 @@ fn codegen_float_intrinsic_call<'tcx>( ret: CPlace<'tcx>, ) -> bool { let (name, arg_count, ty, clif_ty) = match intrinsic { + sym::expf16 => ("expf16", 1, fx.tcx.types.f16, types::F16), sym::expf32 => ("expf", 1, fx.tcx.types.f32, types::F32), sym::expf64 => ("exp", 1, fx.tcx.types.f64, types::F64), + sym::expf128 => ("expf128", 1, fx.tcx.types.f128, types::F128), + sym::exp2f16 => ("exp2f16", 1, fx.tcx.types.f16, types::F16), sym::exp2f32 => ("exp2f", 1, fx.tcx.types.f32, types::F32), sym::exp2f64 => ("exp2", 1, fx.tcx.types.f64, types::F64), + sym::exp2f128 => ("exp2f128", 1, fx.tcx.types.f128, types::F128), + sym::sqrtf16 => ("sqrtf16", 1, fx.tcx.types.f16, types::F16), sym::sqrtf32 => ("sqrtf", 1, fx.tcx.types.f32, types::F32), sym::sqrtf64 => ("sqrt", 1, fx.tcx.types.f64, types::F64), + sym::sqrtf128 => ("sqrtf128", 1, fx.tcx.types.f128, types::F128), + sym::powif16 => ("__powisf2", 2, fx.tcx.types.f16, types::F16), // compiler-builtins sym::powif32 => ("__powisf2", 2, fx.tcx.types.f32, types::F32), // compiler-builtins sym::powif64 => ("__powidf2", 2, fx.tcx.types.f64, types::F64), // compiler-builtins + sym::powif128 => ("__powitf2", 2, fx.tcx.types.f128, types::F128), // compiler-builtins + sym::powf16 => ("powf16", 2, fx.tcx.types.f16, types::F16), sym::powf32 => ("powf", 2, fx.tcx.types.f32, types::F32), sym::powf64 => ("pow", 2, fx.tcx.types.f64, types::F64), + sym::powf128 => ("powf128", 2, fx.tcx.types.f128, types::F128), + sym::logf16 => ("logf16", 1, fx.tcx.types.f16, types::F16), sym::logf32 => ("logf", 1, fx.tcx.types.f32, types::F32), sym::logf64 => ("log", 1, fx.tcx.types.f64, types::F64), + sym::logf128 => ("logf128", 1, fx.tcx.types.f128, types::F128), + sym::log2f16 => ("log2f16", 1, fx.tcx.types.f16, types::F16), sym::log2f32 => ("log2f", 1, fx.tcx.types.f32, types::F32), sym::log2f64 => ("log2", 1, fx.tcx.types.f64, types::F64), + sym::log2f128 => ("log2f128", 1, fx.tcx.types.f128, types::F128), + sym::log10f16 => ("log10f16", 1, fx.tcx.types.f16, types::F16), sym::log10f32 => ("log10f", 1, fx.tcx.types.f32, types::F32), sym::log10f64 => ("log10", 1, fx.tcx.types.f64, types::F64), + sym::log10f128 => ("log10f128", 1, fx.tcx.types.f128, types::F128), + sym::fabsf16 => ("fabsf16", 1, fx.tcx.types.f16, types::F16), sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32, types::F32), sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64), + sym::fabsf128 => ("fabsf128", 1, fx.tcx.types.f128, types::F128), + sym::fmaf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16), sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64), + sym::fmaf128 => ("fmaf128", 3, fx.tcx.types.f128, types::F128), // FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation + sym::fmuladdf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f16 sym::fmuladdf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f32 sym::fmuladdf64 => ("fma", 3, fx.tcx.types.f64, types::F64), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f64 + sym::fmuladdf128 => ("fmaf128", 3, fx.tcx.types.f128, types::F128), // TODO: use cranelift intrinsic analogous to llvm.fmuladd.f128 + sym::copysignf16 => ("copysignf16", 2, fx.tcx.types.f16, types::F16), sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32), sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64), + sym::copysignf128 => ("copysignf128", 2, fx.tcx.types.f128, types::F128), + sym::floorf16 => ("floorf16", 1, fx.tcx.types.f16, types::F16), sym::floorf32 => ("floorf", 1, fx.tcx.types.f32, types::F32), sym::floorf64 => ("floor", 1, fx.tcx.types.f64, types::F64), + sym::floorf128 => ("floorf128", 1, fx.tcx.types.f128, types::F128), + sym::ceilf16 => ("ceilf16", 1, fx.tcx.types.f16, types::F16), sym::ceilf32 => ("ceilf", 1, fx.tcx.types.f32, types::F32), sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64, types::F64), + sym::ceilf128 => ("ceilf128", 1, fx.tcx.types.f128, types::F128), + sym::truncf16 => ("truncf16", 1, fx.tcx.types.f16, types::F16), sym::truncf32 => ("truncf", 1, fx.tcx.types.f32, types::F32), sym::truncf64 => ("trunc", 1, fx.tcx.types.f64, types::F64), + sym::truncf128 => ("truncf128", 1, fx.tcx.types.f128, types::F128), + sym::round_ties_even_f16 => ("rintf16", 1, fx.tcx.types.f16, types::F16), sym::round_ties_even_f32 => ("rintf", 1, fx.tcx.types.f32, types::F32), sym::round_ties_even_f64 => ("rint", 1, fx.tcx.types.f64, types::F64), + sym::round_ties_even_f128 => ("rintf128", 1, fx.tcx.types.f128, types::F128), + sym::roundf16 => ("roundf16", 1, fx.tcx.types.f16, types::F16), sym::roundf32 => ("roundf", 1, fx.tcx.types.f32, types::F32), sym::roundf64 => ("round", 1, fx.tcx.types.f64, types::F64), + sym::roundf128 => ("roundf128", 1, fx.tcx.types.f128, types::F128), + sym::sinf16 => ("sinf16", 1, fx.tcx.types.f16, types::F16), sym::sinf32 => ("sinf", 1, fx.tcx.types.f32, types::F32), sym::sinf64 => ("sin", 1, fx.tcx.types.f64, types::F64), + sym::sinf128 => ("sinf128", 1, fx.tcx.types.f128, types::F128), + sym::cosf16 => ("cosf16", 1, fx.tcx.types.f16, types::F16), sym::cosf32 => ("cosf", 1, fx.tcx.types.f32, types::F32), sym::cosf64 => ("cos", 1, fx.tcx.types.f64, types::F64), + sym::cosf128 => ("cosf128", 1, fx.tcx.types.f128, types::F128), _ => return false, }; @@ -379,13 +420,26 @@ fn codegen_float_intrinsic_call<'tcx>( }; let layout = fx.layout_of(ty); + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift operations + // for `f16` and `f128` once the lowerings have been implemented in Cranelift. let res = match intrinsic { + sym::fmaf16 | sym::fmuladdf16 => { + CValue::by_val(codegen_f16_f128::fma_f16(fx, args[0], args[1], args[2]), layout) + } sym::fmaf32 | sym::fmaf64 | sym::fmuladdf32 | sym::fmuladdf64 => { CValue::by_val(fx.bcx.ins().fma(args[0], args[1], args[2]), layout) } + sym::copysignf16 => { + CValue::by_val(codegen_f16_f128::copysign_f16(fx, args[0], args[1]), layout) + } + sym::copysignf128 => { + CValue::by_val(codegen_f16_f128::copysign_f128(fx, args[0], args[1]), layout) + } sym::copysignf32 | sym::copysignf64 => { CValue::by_val(fx.bcx.ins().fcopysign(args[0], args[1]), layout) } + sym::fabsf16 => CValue::by_val(codegen_f16_f128::abs_f16(fx, args[0]), layout), + sym::fabsf128 => CValue::by_val(codegen_f16_f128::abs_f128(fx, args[0]), layout), sym::fabsf32 | sym::fabsf64 | sym::floorf32 @@ -415,11 +469,36 @@ fn codegen_float_intrinsic_call<'tcx>( // These intrinsics aren't supported natively by Cranelift. // Lower them to a libcall. - sym::powif32 | sym::powif64 => { - let input_tys: Vec<_> = vec![AbiParam::new(clif_ty), AbiParam::new(types::I32)]; + sym::powif16 | sym::powif32 | sym::powif64 | sym::powif128 => { + let temp; + let (clif_ty, args) = if intrinsic == sym::powif16 { + temp = [codegen_f16_f128::f16_to_f32(fx, args[0]), args[1]]; + (types::F32, temp.as_slice()) + } else { + (clif_ty, args) + }; + let input_tys: Vec<_> = + vec![AbiParam::new(clif_ty), lib_call_arg_param(fx.tcx, types::I32, true)]; let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0]; + let ret_val = if intrinsic == sym::powif16 { + codegen_f16_f128::f32_to_f16(fx, ret_val) + } else { + ret_val + }; CValue::by_val(ret_val, fx.layout_of(ty)) } + sym::powf16 => { + // FIXME(f16_f128): Rust `compiler-builtins` doesn't export `powf16` yet. + let x = codegen_f16_f128::f16_to_f32(fx, args[0]); + let y = codegen_f16_f128::f16_to_f32(fx, args[1]); + let ret_val = fx.lib_call( + "powf", + vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], + vec![AbiParam::new(types::F32)], + &[x, y], + )[0]; + CValue::by_val(codegen_f16_f128::f32_to_f16(fx, ret_val), fx.layout_of(ty)) + } _ => { let input_tys: Vec<_> = args.iter().map(|_| AbiParam::new(clif_ty)).collect(); let ret_val = fx.lib_call(name, input_tys, vec![AbiParam::new(clif_ty)], &args)[0]; @@ -801,7 +880,11 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME implement 128bit atomics if fx.tcx.is_compiler_builtins(LOCAL_CRATE) { // special case for compiler-builtins to avoid having to patch it - crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported"); + crate::base::codegen_panic_nounwind( + fx, + "128bit atomics not yet supported", + None, + ); return Ok(()); } else { fx.tcx @@ -832,7 +915,11 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME implement 128bit atomics if fx.tcx.is_compiler_builtins(LOCAL_CRATE) { // special case for compiler-builtins to avoid having to patch it - crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported"); + crate::base::codegen_panic_nounwind( + fx, + "128bit atomics not yet supported", + None, + ); return Ok(()); } else { fx.tcx @@ -1109,6 +1196,20 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, old); } + sym::minimumf16 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + // FIXME(bytecodealliance/wasmtime#8312): Use `fmin` directly once + // Cranelift backend lowerings are implemented. + let a = codegen_f16_f128::f16_to_f32(fx, a); + let b = codegen_f16_f128::f16_to_f32(fx, b); + let val = fx.bcx.ins().fmin(a, b); + let val = codegen_f16_f128::f32_to_f16(fx, val); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); + ret.write_cvalue(fx, val); + } sym::minimumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1127,6 +1228,31 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } + sym::minimumf128 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + // FIXME(bytecodealliance/wasmtime#8312): Use `fmin` once Cranelift + // backend lowerings are implemented. + let val = codegen_f16_f128::fmin_f128(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); + ret.write_cvalue(fx, val); + } + sym::maximumf16 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + // FIXME(bytecodealliance/wasmtime#8312): Use `fmax` directly once + // Cranelift backend lowerings are implemented. + let a = codegen_f16_f128::f16_to_f32(fx, a); + let b = codegen_f16_f128::f16_to_f32(fx, b); + let val = fx.bcx.ins().fmax(a, b); + let val = codegen_f16_f128::f32_to_f16(fx, val); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); + ret.write_cvalue(fx, val); + } sym::maximumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1145,7 +1271,27 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } + sym::maximumf128 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + // FIXME(bytecodealliance/wasmtime#8312): Use `fmax` once Cranelift + // backend lowerings are implemented. + let val = codegen_f16_f128::fmax_f128(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); + ret.write_cvalue(fx, val); + } + + sym::minnumf16 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = crate::num::codegen_float_min(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); + ret.write_cvalue(fx, val); + } sym::minnumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1164,6 +1310,24 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } + sym::minnumf128 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = crate::num::codegen_float_min(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); + ret.write_cvalue(fx, val); + } + sym::maxnumf16 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = crate::num::codegen_float_max(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f16)); + ret.write_cvalue(fx, val); + } sym::maxnumf32 => { intrinsic_args!(fx, args => (a, b); intrinsic); let a = a.load_scalar(fx); @@ -1182,6 +1346,15 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64)); ret.write_cvalue(fx, val); } + sym::maxnumf128 => { + intrinsic_args!(fx, args => (a, b); intrinsic); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + let val = crate::num::codegen_float_max(fx, a, b); + let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f128)); + ret.write_cvalue(fx, val); + } sym::catch_unwind => { intrinsic_args!(fx, args => (f, data, catch_fn); intrinsic); diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index dd6d8dbb6f5e..46a441488fa6 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -283,6 +283,20 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ret_lane.write_cvalue(fx, val); } + sym::simd_insert_dyn => { + intrinsic_args!(fx, args => (base, idx, val); intrinsic); + + if !base.layout().ty.is_simd() { + report_simd_type_validation_error(fx, intrinsic, span, base.layout().ty); + return; + } + + let idx = idx.load_scalar(fx); + + ret.write_cvalue(fx, base); + ret.write_lane_dyn(fx, idx, val); + } + sym::simd_extract => { let (v, idx) = match args { [v, idx] => (v, idx), @@ -318,6 +332,20 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ret.write_cvalue(fx, ret_lane); } + sym::simd_extract_dyn => { + intrinsic_args!(fx, args => (v, idx); intrinsic); + + if !v.layout().ty.is_simd() { + report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); + return; + } + + let idx = idx.load_scalar(fx); + + let ret_lane = v.value_lane_dyn(fx, idx); + ret.write_cvalue(fx, ret_lane); + } + sym::simd_neg | sym::simd_bswap | sym::simd_bitreverse @@ -980,10 +1008,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.switch_to_block(if_enabled); let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), ptr_lane, 0); - fx.bcx.ins().jump(next, &[res]); + fx.bcx.ins().jump(next, &[res.into()]); fx.bcx.switch_to_block(if_disabled); - fx.bcx.ins().jump(next, &[val_lane]); + fx.bcx.ins().jump(next, &[val_lane.into()]); fx.bcx.seal_block(next); fx.bcx.switch_to_block(next); @@ -1029,10 +1057,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( ptr_val, Offset32::new(offset), ); - fx.bcx.ins().jump(next, &[res]); + fx.bcx.ins().jump(next, &[res.into()]); fx.bcx.switch_to_block(if_disabled); - fx.bcx.ins().jump(next, &[val_lane]); + fx.bcx.ins().jump(next, &[val_lane.into()]); fx.bcx.seal_block(next); fx.bcx.switch_to_block(next); diff --git a/src/lib.rs b/src/lib.rs index ab09a6f8b38e..8ef623cde005 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,9 @@ #![cfg_attr(doc, feature(rustdoc_internals))] // Note: please avoid adding other feature gates where possible #![feature(rustc_private)] +// Only used to define intrinsics in `compiler_builtins.rs`. +#![feature(f16)] +#![feature(f128)] // Note: please avoid adding other feature gates where possible #![warn(rust_2018_idioms)] #![warn(unreachable_pub)] @@ -57,6 +60,7 @@ mod allocator; mod analyze; mod base; mod cast; +mod codegen_f16_f128; mod codegen_i128; mod common; mod compiler_builtins; @@ -76,7 +80,6 @@ mod optimize; mod pointer; mod pretty_clif; mod toolchain; -mod trap; mod unsize; mod unwind_module; mod value_and_place; @@ -198,14 +201,36 @@ impl CodegenBackend for CraneliftCodegenBackend { // FIXME do `unstable_target_features` properly let unstable_target_features = target_features.clone(); + // FIXME(f16_f128): LLVM 20 (currently used by `rustc`) passes `f128` in XMM registers on + // Windows, whereas LLVM 21+ and Cranelift pass it indirectly. This means that `f128` won't + // work when linking against a LLVM-built sysroot. + let has_reliable_f128 = !sess.target.is_like_windows; + let has_reliable_f16 = match &*sess.target.arch { + // FIXME(f16_f128): LLVM 20 does not support `f16` on s390x, meaning the required + // builtins are not available in `compiler-builtins`. + "s390x" => false, + // FIXME(f16_f128): `rustc_codegen_llvm` currently disables support on Windows GNU + // targets due to GCC using a different ABI than LLVM. Therefore `f16` won't be + // available when using a LLVM-built sysroot. + "x86_64" + if sess.target.os == "windows" + && sess.target.env == "gnu" + && sess.target.abi != "llvm" => + { + false + } + _ => true, + }; + TargetConfig { target_features, unstable_target_features, - // Cranelift does not yet support f16 or f128 - has_reliable_f16: false, - has_reliable_f16_math: false, - has_reliable_f128: false, - has_reliable_f128_math: false, + // `rustc_codegen_cranelift` polyfills functionality not yet + // available in Cranelift. + has_reliable_f16, + has_reliable_f16_math: has_reliable_f16, + has_reliable_f128, + has_reliable_f128_math: has_reliable_f128, } } @@ -290,6 +315,12 @@ fn build_isa(sess: &Session, jit: bool) -> Arc { flags_builder.set("enable_llvm_abi_extensions", "true").unwrap(); + if let Some(align) = sess.opts.unstable_opts.min_function_alignment { + flags_builder + .set("log2_min_function_alignment", &align.bytes().ilog2().to_string()) + .unwrap(); + } + use rustc_session::config::OptLevel; match sess.opts.optimize { OptLevel::No => { diff --git a/src/num.rs b/src/num.rs index 2a4d1e3ae571..f53045df6e79 100644 --- a/src/num.rs +++ b/src/num.rs @@ -1,8 +1,9 @@ //! Various operations on integer and floating-point numbers +use crate::codegen_f16_f128; use crate::prelude::*; -pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> IntCC { +fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> IntCC { use BinOp::*; use IntCC::*; match bin_op { @@ -109,7 +110,7 @@ pub(crate) fn codegen_binop<'tcx>( } } -pub(crate) fn codegen_bool_binop<'tcx>( +fn codegen_bool_binop<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, bin_op: BinOp, in_lhs: CValue<'tcx>, @@ -350,25 +351,60 @@ pub(crate) fn codegen_float_binop<'tcx>( let lhs = in_lhs.load_scalar(fx); let rhs = in_rhs.load_scalar(fx); + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let (lhs, rhs) = if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F16) { + (codegen_f16_f128::f16_to_f32(fx, lhs), codegen_f16_f128::f16_to_f32(fx, rhs)) + } else { + (lhs, rhs) + }; let b = fx.bcx.ins(); let res = match bin_op { + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings + // have been added to Cranelift. + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div + if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F128) => + { + codegen_f16_f128::codegen_f128_binop(fx, bin_op, lhs, rhs) + } BinOp::Add => b.fadd(lhs, rhs), BinOp::Sub => b.fsub(lhs, rhs), BinOp::Mul => b.fmul(lhs, rhs), BinOp::Div => b.fdiv(lhs, rhs), BinOp::Rem => { - let (name, ty) = match in_lhs.layout().ty.kind() { - ty::Float(FloatTy::F32) => ("fmodf", types::F32), - ty::Float(FloatTy::F64) => ("fmod", types::F64), + let (name, ty, lhs, rhs) = match in_lhs.layout().ty.kind() { + ty::Float(FloatTy::F16) => ( + "fmodf", + types::F32, + // FIXME(bytecodealliance/wasmtime#8312): Already converted + // by the FIXME above. + // fx.bcx.ins().fpromote(types::F32, lhs), + // fx.bcx.ins().fpromote(types::F32, rhs), + lhs, + rhs, + ), + ty::Float(FloatTy::F32) => ("fmodf", types::F32, lhs, rhs), + ty::Float(FloatTy::F64) => ("fmod", types::F64, lhs, rhs), + ty::Float(FloatTy::F128) => ("fmodf128", types::F128, lhs, rhs), _ => bug!(), }; - fx.lib_call( + let ret_val = fx.lib_call( name, vec![AbiParam::new(ty), AbiParam::new(ty)], vec![AbiParam::new(ty)], &[lhs, rhs], - )[0] + )[0]; + + let ret_val = if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F16) { + // FIXME(bytecodealliance/wasmtime#8312): Use native Cranelift + // operation once Cranelift backend lowerings have been + // implemented. + codegen_f16_f128::f32_to_f16(fx, ret_val) + } else { + ret_val + }; + return CValue::by_val(ret_val, in_lhs.layout()); } BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { let fltcc = match bin_op { @@ -380,16 +416,26 @@ pub(crate) fn codegen_float_binop<'tcx>( BinOp::Gt => FloatCC::GreaterThan, _ => unreachable!(), }; - let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs); + // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift + // `fcmp` once `f16`/`f128` backend lowerings have been added to + // Cranelift. + let val = codegen_f16_f128::fcmp(fx, fltcc, lhs, rhs); return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool)); } _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs), }; + // FIXME(bytecodealliance/wasmtime#8312): Remove once backend lowerings have + // been added to Cranelift. + let res = if *in_lhs.layout().ty.kind() == ty::Float(FloatTy::F16) { + codegen_f16_f128::f32_to_f16(fx, res) + } else { + res + }; CValue::by_val(res, in_lhs.layout()) } -pub(crate) fn codegen_ptr_binop<'tcx>( +fn codegen_ptr_binop<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, bin_op: BinOp, in_lhs: CValue<'tcx>, @@ -457,15 +503,19 @@ pub(crate) fn codegen_ptr_binop<'tcx>( // and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing // a float against itself. Only in case of NaN is it not equal to itself. pub(crate) fn codegen_float_min(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { - let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a); - let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b); + // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift `fcmp` once + // `f16`/`f128` backend lowerings have been added to Cranelift. + let a_is_nan = codegen_f16_f128::fcmp(fx, FloatCC::NotEqual, a, a); + let a_ge_b = codegen_f16_f128::fcmp(fx, FloatCC::GreaterThanOrEqual, a, b); let temp = fx.bcx.ins().select(a_ge_b, b, a); fx.bcx.ins().select(a_is_nan, b, temp) } pub(crate) fn codegen_float_max(fx: &mut FunctionCx<'_, '_, '_>, a: Value, b: Value) -> Value { - let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a); - let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b); + // FIXME(bytecodealliance/wasmtime#8312): Replace with Cranelift `fcmp` once + // `f16`/`f128` backend lowerings have been added to Cranelift. + let a_is_nan = codegen_f16_f128::fcmp(fx, FloatCC::NotEqual, a, a); + let a_le_b = codegen_f16_f128::fcmp(fx, FloatCC::LessThanOrEqual, a, b); let temp = fx.bcx.ins().select(a_le_b, b, a); fx.bcx.ins().select(a_is_nan, b, temp) } diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index cd254b04ed9e..9400ae9fcff0 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -8,40 +8,41 @@ //! target x86_64 //! //! function u0:22(i64) -> i8, i8 system_v { -//! ; symbol _ZN97_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$RF$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17hd517c453d67c0915E -//! ; instance Instance { def: Item(WithOptConstParam { did: DefId(0:42 ~ example[4e51]::{impl#0}::call_once), const_param_did: None }), args: [ReErased, ReErased] } -//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, abi: Aggregate { sized: true }, fields: Arbitrary { offsets: [], memory_index: [] }, largest_niche: None, variants: Single { index: 0 } } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), variants: Single { index: 0 } } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, variants: Single { index: 0 } } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } +//! ; symbol _ZN97_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$RF$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17hd361e9f5c3d1c4deE +//! ; instance Instance { def: Item(DefId(0:42 ~ example[3895]::{impl#0}::call_once)), args: ['{erased}, '{erased}] } +//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: Memory { sized: true }, fields: Arbitrary { offsets: [], memory_index: [] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 12266848898570219025 } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } //! //! ; kind loc.idx param pass mode ty -//! ; ssa _0 (u8, u8) 2b 1, 8 var=(0, 1) +//! ; ssa _0 (u8, u8) 2b 1 var=(0, 1) //! ; ret _0 - Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) (u8, u8) //! ; arg _1 - Ignore IsNotEmpty -//! ; arg _2.0 = v0 Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) &&[u16] +//! ; arg _2.0 = v0 Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) &'{erased} &'{erased} [u16] //! -//! ; kind local ty size align (abi,pref) -//! ; zst _1 IsNotEmpty 0b 1, 8 align=8,offset= -//! ; stack _2 (&&[u16],) 8b 8, 8 storage=ss0 -//! ; ssa _3 &mut IsNotEmpty 8b 8, 8 var=2 +//! ; kind local ty size align (abi) +//! ; zst _1 IsNotEmpty 0b 1 align=1,offset= +//! ; stack _2 (&'{erased} &'{erased} [u16],) 8b 8 storage=ss0 +//! ; ssa _3 &'{erased} mut IsNotEmpty 8b 8 var=2 //! -//! ss0 = explicit_slot 16 +//! ss0 = explicit_slot 16, align = 16 //! sig0 = (i64, i64) -> i8, i8 system_v -//! fn0 = colocated u0:23 sig0 ; Instance { def: Item(WithOptConstParam { did: DefId(0:46 ~ example[4e51]::{impl#1}::call_mut), const_param_did: None }), args: [ReErased, ReErased] } +//! fn0 = colocated u0:23 sig0 ; Instance { def: Item(DefId(0:46 ~ example[3895]::{impl#1}::call_mut)), args: ['{erased}, '{erased}] } //! //! block0(v0: i64): //! nop -//! ; write_cvalue: Addr(Pointer { base: Stack(ss0), offset: Offset32(0) }, None): &&[u16] <- ByVal(v0): &&[u16] +//! ; write_cvalue: Addr(Pointer { base: Stack(ss0), offset: Offset32(0) }, None): &'{erased} &'{erased} [u16] <- ByVal(v0): &'{erased} &'{erased} [u16] //! stack_store v0, ss0 //! jump block1 //! //! block1: //! nop //! ; _3 = &mut _1 -//! v1 = iconst.i64 8 -//! ; write_cvalue: Var(_3, var2): &mut IsNotEmpty <- ByVal(v1): &mut IsNotEmpty +//! v1 = iconst.i64 1 +//! ; write_cvalue: Var(_3, var2): &'{erased} mut IsNotEmpty <- ByVal(v1): &'{erased} mut IsNotEmpty //! ; -//! ; _0 = >::call_mut(move _3, _2) +//! ; _0 = >::call_mut(move _3, copy _2) //! v2 = stack_load.i64 ss0 -//! v3, v4 = call fn0(v1, v2) ; v1 = 8 +//! ; abi: FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: &mut IsNotEmpty, layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(1 bytes)) }) }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } +//! v3, v4 = call fn0(v1, v2) ; v1 = 1 //! v5 -> v3 //! v6 -> v4 //! ; write_cvalue: VarPair(_0, var0, var1): (u8, u8) <- ByValPair(v3, v4): (u8, u8) @@ -73,6 +74,7 @@ pub(crate) struct CommentWriter { enabled: bool, global_comments: Vec, entity_comments: FxHashMap, + inst_post_comments: FxHashMap, } impl CommentWriter { @@ -95,7 +97,12 @@ impl CommentWriter { vec![] }; - CommentWriter { enabled, global_comments, entity_comments: FxHashMap::default() } + CommentWriter { + enabled, + global_comments, + entity_comments: FxHashMap::default(), + inst_post_comments: FxHashMap::default(), + } } } @@ -127,6 +134,25 @@ impl CommentWriter { } } } + + pub(crate) fn add_post_comment + AsRef>( + &mut self, + entity: Inst, + comment: S, + ) { + debug_assert!(self.enabled); + + use std::collections::hash_map::Entry; + match self.inst_post_comments.entry(entity) { + Entry::Occupied(mut occ) => { + occ.get_mut().push('\n'); + occ.get_mut().push_str(comment.as_ref()); + } + Entry::Vacant(vac) => { + vac.insert(comment.into()); + } + } + } } impl FuncWriter for &'_ CommentWriter { @@ -188,10 +214,13 @@ impl FuncWriter for &'_ CommentWriter { inst: Inst, indent: usize, ) -> fmt::Result { - PlainWriter.write_instruction(w, func, aliases, inst, indent)?; if let Some(comment) = self.entity_comments.get(&inst.into()) { writeln!(w, "; {}", comment.replace('\n', "\n; "))?; } + PlainWriter.write_instruction(w, func, aliases, inst, indent)?; + if let Some(comment) = self.inst_post_comments.get(&inst) { + writeln!(w, "; {}", comment.replace('\n', "\n; "))?; + } Ok(()) } } @@ -208,6 +237,14 @@ impl FunctionCx<'_, '_, '_> { ) { self.clif_comments.add_comment(entity, comment); } + + pub(crate) fn add_post_comment + AsRef>( + &mut self, + entity: Inst, + comment: S, + ) { + self.clif_comments.add_post_comment(entity, comment); + } } pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool { diff --git a/src/trap.rs b/src/trap.rs deleted file mode 100644 index ac3f58ee1ee6..000000000000 --- a/src/trap.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Helpers used to print a message and abort in case of certain panics and some detected UB. - -use crate::prelude::*; - -fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { - let puts = fx - .module - .declare_function( - "puts", - Linkage::Import, - &Signature { - call_conv: fx.target_config.default_call_conv, - params: vec![AbiParam::new(fx.pointer_type)], - returns: vec![AbiParam::new(types::I32)], - }, - ) - .unwrap(); - let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func); - if fx.clif_comments.enabled() { - fx.add_comment(puts, "puts"); - } - - let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg); - let msg_ptr = fx.anonymous_str(&real_msg); - fx.bcx.ins().call(puts, &[msg_ptr]); -} - -/// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen. -/// -/// Trap code: user65535 -pub(crate) fn trap_unimplemented(fx: &mut FunctionCx<'_, '_, '_>, msg: impl AsRef) { - codegen_print(fx, msg.as_ref()); - - let one = fx.bcx.ins().iconst(types::I32, 1); - fx.lib_call("exit", vec![AbiParam::new(types::I32)], vec![], &[one]); - - fx.bcx.ins().trap(TrapCode::user(3).unwrap()); -} diff --git a/src/unwind_module.rs b/src/unwind_module.rs index b950aaa29ce0..b4eb939cf256 100644 --- a/src/unwind_module.rs +++ b/src/unwind_module.rs @@ -1,10 +1,10 @@ +use cranelift_codegen::Context; use cranelift_codegen::control::ControlPlane; -use cranelift_codegen::ir::{Function, Signature}; +use cranelift_codegen::ir::Signature; use cranelift_codegen::isa::{TargetFrontendConfig, TargetIsa}; -use cranelift_codegen::{Context, FinalizedMachReloc}; use cranelift_module::{ DataDescription, DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleDeclarations, - ModuleResult, + ModuleReloc, ModuleResult, }; use cranelift_object::{ObjectModule, ObjectProduct}; @@ -17,8 +17,8 @@ pub(crate) struct UnwindModule { } impl UnwindModule { - pub(crate) fn new(module: T, pic_eh_frame: bool) -> Self { - let unwind_context = UnwindContext::new(module.isa(), pic_eh_frame); + pub(crate) fn new(mut module: T, pic_eh_frame: bool) -> Self { + let unwind_context = UnwindContext::new(&mut module, pic_eh_frame); UnwindModule { module, unwind_context } } } @@ -33,13 +33,10 @@ impl UnwindModule { #[cfg(feature = "jit")] impl UnwindModule { - pub(crate) fn finalize_definitions(&mut self) { + pub(crate) fn finalize_definitions(mut self) -> cranelift_jit::JITModule { self.module.finalize_definitions().unwrap(); - let prev_unwind_context = std::mem::replace( - &mut self.unwind_context, - UnwindContext::new(self.module.isa(), false), - ); - unsafe { prev_unwind_context.register_jit(&self.module) }; + unsafe { self.unwind_context.register_jit(&self.module) }; + self.module } } @@ -94,17 +91,16 @@ impl Module for UnwindModule { ctrl_plane: &mut ControlPlane, ) -> ModuleResult<()> { self.module.define_function_with_control_plane(func, ctx, ctrl_plane)?; - self.unwind_context.add_function(func, ctx, self.module.isa()); + self.unwind_context.add_function(&mut self.module, func, ctx); Ok(()) } fn define_function_bytes( &mut self, _func_id: FuncId, - _func: &Function, _alignment: u64, _bytes: &[u8], - _relocs: &[FinalizedMachReloc], + _relocs: &[ModuleReloc], ) -> ModuleResult<()> { unimplemented!() } diff --git a/src/value_and_place.rs b/src/value_and_place.rs index f8a19589fdd7..cbfb215a892a 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -309,6 +309,7 @@ impl<'tcx> CValue<'tcx> { match self.0 { CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => unreachable!(), CValueInner::ByRef(ptr, None) => { + let lane_idx = clif_intcast(fx, lane_idx, fx.pointer_type, false); let field_offset = fx.bcx.ins().imul_imm(lane_idx, lane_layout.size.bytes() as i64); let field_ptr = ptr.offset_value(fx, field_offset); CValue::by_ref(field_ptr, lane_layout) @@ -324,7 +325,7 @@ impl<'tcx> CValue<'tcx> { const_val: ty::ScalarInt, ) -> CValue<'tcx> { assert_eq!(const_val.size(), layout.size, "{:#?}: {:?}", const_val, layout); - use cranelift_codegen::ir::immediates::{Ieee32, Ieee64}; + use cranelift_codegen::ir::immediates::{Ieee16, Ieee32, Ieee64, Ieee128}; let clif_ty = fx.clif_type(layout.ty).unwrap(); @@ -345,12 +346,24 @@ impl<'tcx> CValue<'tcx> { let raw_val = const_val.size().truncate(const_val.to_bits(layout.size)); fx.bcx.ins().iconst(clif_ty, raw_val as i64) } + ty::Float(FloatTy::F16) => { + fx.bcx.ins().f16const(Ieee16::with_bits(u16::try_from(const_val).unwrap())) + } ty::Float(FloatTy::F32) => { fx.bcx.ins().f32const(Ieee32::with_bits(u32::try_from(const_val).unwrap())) } ty::Float(FloatTy::F64) => { fx.bcx.ins().f64const(Ieee64::with_bits(u64::try_from(const_val).unwrap())) } + ty::Float(FloatTy::F128) => { + let value = fx + .bcx + .func + .dfg + .constants + .insert(Ieee128::with_bits(u128::try_from(const_val).unwrap()).into()); + fx.bcx.ins().f128const(value) + } _ => panic!( "CValue::const_val for non bool/char/float/integer/pointer type {:?} is not allowed", layout.ty @@ -563,27 +576,7 @@ impl<'tcx> CPlace<'tcx> { src_ty, dst_ty, ); - let data = match (src_ty, dst_ty) { - (_, _) if src_ty == dst_ty => data, - - // This is a `write_cvalue_transmute`. - (types::I32, types::F32) - | (types::F32, types::I32) - | (types::I64, types::F64) - | (types::F64, types::I64) => codegen_bitcast(fx, dst_ty, data), - _ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data), - _ if src_ty.is_vector() || dst_ty.is_vector() => { - // FIXME(bytecodealliance/wasmtime#6104) do something more efficient for transmutes between vectors and integers. - let ptr = fx.create_stack_slot(src_ty.bytes(), src_ty.bytes()); - ptr.store(fx, data, MemFlags::trusted()); - ptr.load(fx, dst_ty, MemFlags::trusted()) - } - - // `CValue`s should never contain SSA-only types, so if you ended - // up here having seen an error like `B1 -> I8`, then before - // calling `write_cvalue` you need to add a `bint` instruction. - _ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty), - }; + let data = if src_ty == dst_ty { data } else { codegen_bitcast(fx, dst_ty, data) }; //fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index())); fx.bcx.def_var(var, data); } @@ -591,13 +584,9 @@ impl<'tcx> CPlace<'tcx> { assert_eq!(self.layout().size, from.layout().size); if fx.clif_comments.enabled() { - use cranelift_codegen::cursor::{Cursor, CursorPosition}; - let cur_block = match fx.bcx.cursor().position() { - CursorPosition::After(block) => block, - _ => unreachable!(), - }; - fx.add_comment( - fx.bcx.func.layout.last_inst(cur_block).unwrap(), + let inst = fx.bcx.func.layout.last_inst(fx.bcx.current_block().unwrap()).unwrap(); + fx.add_post_comment( + inst, format!( "{}: {:?}: {:?} <- {:?}: {:?}", method, @@ -806,6 +795,35 @@ impl<'tcx> CPlace<'tcx> { } } + /// Write a value to an individual lane in a SIMD vector. + pub(crate) fn write_lane_dyn( + self, + fx: &mut FunctionCx<'_, '_, 'tcx>, + lane_idx: Value, + value: CValue<'tcx>, + ) { + let layout = self.layout(); + assert!(layout.ty.is_simd()); + let (_lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let lane_layout = fx.layout_of(lane_ty); + assert_eq!(lane_layout, value.layout()); + + match self.inner { + CPlaceInner::Var(_, _) => unreachable!(), + CPlaceInner::VarPair(_, _, _) => unreachable!(), + CPlaceInner::Addr(ptr, None) => { + let lane_idx = clif_intcast(fx, lane_idx, fx.pointer_type, false); + let field_offset = fx + .bcx + .ins() + .imul_imm(lane_idx, i64::try_from(lane_layout.size.bytes()).unwrap()); + let field_ptr = ptr.offset_value(fx, field_offset); + CPlace::for_ptr(field_ptr, lane_layout).write_cvalue(fx, value); + } + CPlaceInner::Addr(_, Some(_)) => unreachable!(), + } + } + pub(crate) fn place_index( self, fx: &mut FunctionCx<'_, '_, 'tcx>, diff --git a/triagebot.toml b/triagebot.toml new file mode 100644 index 000000000000..13da0a87def3 --- /dev/null +++ b/triagebot.toml @@ -0,0 +1,7 @@ +# Documentation at https://forge.rust-lang.org/triagebot/index.html + +# Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust) +[issue-links] + +# Prevents mentions in commits to avoid users being spammed +[no-mentions] From ea26272c94c7a66ed018930c13c63551cb2f1390 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 18 May 2025 17:12:13 +0000 Subject: [PATCH 003/356] clif: Provide better output messages for failed copies --- build_system/utils.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build_system/utils.rs b/build_system/utils.rs index f23997684596..d9807155a3d5 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -213,11 +213,13 @@ pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) { if filename == "." || filename == ".." { continue; } + let src = from.join(&filename); + let dst = to.join(&filename); if entry.metadata().unwrap().is_dir() { - fs::create_dir(to.join(&filename)).unwrap(); - copy_dir_recursively(&from.join(&filename), &to.join(&filename)); + fs::create_dir(&dst).unwrap_or_else(|e| panic!("failed to create {dst:?}: {e}")); + copy_dir_recursively(&src, &dst); } else { - fs::copy(from.join(&filename), to.join(&filename)).unwrap(); + fs::copy(&src, &dst).unwrap_or_else(|e| panic!("failed to copy {src:?}->{dst:?}: {e}")); } } } From 99e783d4e9bdcc44e2071973631a7d5e689b0787 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 May 2025 16:35:20 +0200 Subject: [PATCH 004/356] atomic_load intrinsic: use const generic parameter for ordering --- src/intrinsics/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index b21ca32c9a2e..0de23e55e817 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -870,11 +870,12 @@ fn codegen_regular_intrinsic_call<'tcx>( // FIXME use a compiler fence once Cranelift supports it fx.bcx.ins().fence(); } - _ if intrinsic.as_str().starts_with("atomic_load") => { + sym::atomic_load => { intrinsic_args!(fx, args => (ptr); intrinsic); let ptr = ptr.load_scalar(fx); let ty = generic_args.type_at(0); + let _ord = generic_args.const_at(1).to_value(); // FIXME: forward this to cranelift once they support that match ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { // FIXME implement 128bit atomics From bc74556fa4dd083eeb0fd7177edf5e64b89763a0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 31 May 2025 13:43:30 +0000 Subject: [PATCH 005/356] Rustup to rustc 1.89.0-nightly (70b3f4666 2025-05-30) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index af4bd6dc6b85..bc7da7c12a05 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-05-25" +channel = "nightly-2025-05-31" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 814ef9f080907942dd3884a536c0a71212c8c3be Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 3 Jun 2025 08:51:18 +0000 Subject: [PATCH 006/356] Rustup to rustc 1.89.0-nightly (5d707b07e 2025-06-02) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index bc7da7c12a05..f20b6b82a53a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-05-31" +channel = "nightly-2025-06-03" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From ad43500e96c4dd6a90e66cc7fdc018f1a0317a0c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 30 May 2025 11:55:06 +0000 Subject: [PATCH 007/356] Only borrow EncodedMetadata in codegen_crate And move passing it to the linker to the driver code. --- src/driver/aot.rs | 13 ++----------- src/lib.rs | 9 ++------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 5d07c94859f3..58a0a3809452 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -62,7 +62,6 @@ pub(crate) struct OngoingCodegen { modules: Vec, allocator_module: Option, metadata_module: Option, - metadata: EncodedMetadata, crate_info: CrateInfo, concurrency_limiter: ConcurrencyLimiter, } @@ -135,7 +134,6 @@ impl OngoingCodegen { modules, allocator_module: self.allocator_module, metadata_module: self.metadata_module, - metadata: self.metadata, crate_info: self.crate_info, }; @@ -706,11 +704,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { } } -pub(crate) fn run_aot( - tcx: TyCtxt<'_>, - metadata: EncodedMetadata, - need_metadata_module: bool, -) -> Box { +pub(crate) fn run_aot(tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Box { // FIXME handle `-Ctarget-cpu=native` let target_cpu = match tcx.sess.opts.cg.target_cpu { Some(ref name) => name, @@ -727,7 +721,6 @@ pub(crate) fn run_aot( modules: vec![], allocator_module: None, metadata_module: None, - metadata, crate_info: CrateInfo::new(tcx, target_cpu), concurrency_limiter: ConcurrencyLimiter::new(0), }); @@ -787,14 +780,12 @@ pub(crate) fn run_aot( let allocator_module = emit_allocator_module(tcx); - let metadata_module = - if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None }; + let metadata_module = metadata.map(|metadata| emit_metadata_module(tcx, metadata)); Box::new(OngoingCodegen { modules, allocator_module, metadata_module, - metadata, crate_info: CrateInfo::new(tcx, target_cpu), concurrency_limiter: concurrency_limiter.0, }) diff --git a/src/lib.rs b/src/lib.rs index 8ef623cde005..277d4f16f194 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,12 +238,7 @@ impl CodegenBackend for CraneliftCodegenBackend { println!("Cranelift version: {}", cranelift_codegen::VERSION); } - fn codegen_crate( - &self, - tcx: TyCtxt<'_>, - metadata: EncodedMetadata, - need_metadata_module: bool, - ) -> Box { + fn codegen_crate(&self, tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Box { info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); let config = self.config.clone().unwrap_or_else(|| { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) @@ -256,7 +251,7 @@ impl CodegenBackend for CraneliftCodegenBackend { #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); } else { - driver::aot::run_aot(tcx, metadata, need_metadata_module) + driver::aot::run_aot(tcx, metadata) } } From 2974c99566b343afc4834db7af525c4f82224b68 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 30 May 2025 12:51:15 +0000 Subject: [PATCH 008/356] Move metadata object generation for dylibs to the linker code This deduplicates some code between codegen backends and may in the future allow adding extra metadata that is only known at link time. --- src/driver/aot.rs | 46 +--------------------------------------------- src/lib.rs | 5 ++--- 2 files changed, 3 insertions(+), 48 deletions(-) diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 58a0a3809452..442151fe32de 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -11,7 +11,6 @@ use std::thread::JoinHandle; use cranelift_object::{ObjectBuilder, ObjectModule}; use rustc_codegen_ssa::assert_module_sources::CguReuse; use rustc_codegen_ssa::back::link::ensure_removed; -use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{ CodegenResults, CompiledModule, CrateInfo, ModuleKind, errors as ssa_errors, @@ -19,7 +18,6 @@ use rustc_codegen_ssa::{ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; -use rustc_metadata::EncodedMetadata; use rustc_metadata::fs::copy_to_stdout; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -61,7 +59,6 @@ impl HashStable for OngoingModuleCodegen { pub(crate) struct OngoingCodegen { modules: Vec, allocator_module: Option, - metadata_module: Option, crate_info: CrateInfo, concurrency_limiter: ConcurrencyLimiter, } @@ -133,7 +130,6 @@ impl OngoingCodegen { let codegen_results = CodegenResults { modules, allocator_module: self.allocator_module, - metadata_module: self.metadata_module, crate_info: self.crate_info, }; @@ -644,42 +640,6 @@ fn module_codegen( })) } -fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> CompiledModule { - use rustc_middle::mir::mono::CodegenUnitNameBuilder; - - let _timer = tcx.sess.timer("write compressed metadata"); - - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); - let metadata_cgu_name = cgu_name_builder - .build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata")) - .as_str() - .to_string(); - - let tmp_file = tcx.output_filenames(()).temp_path_for_cgu( - OutputType::Metadata, - &metadata_cgu_name, - tcx.sess.invocation_temp.as_deref(), - ); - - let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx); - let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name); - - if let Err(err) = std::fs::write(&tmp_file, obj) { - tcx.dcx().fatal(format!("error writing metadata object file: {}", err)); - } - - CompiledModule { - name: metadata_cgu_name, - kind: ModuleKind::Metadata, - object: Some(tmp_file), - dwarf_object: None, - bytecode: None, - assembly: None, - llvm_ir: None, - links_from_incr_cache: Vec::new(), - } -} - fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { let mut allocator_module = make_module(tcx.sess, "allocator_shim".to_string()); let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module); @@ -704,7 +664,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { } } -pub(crate) fn run_aot(tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Box { +pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box { // FIXME handle `-Ctarget-cpu=native` let target_cpu = match tcx.sess.opts.cg.target_cpu { Some(ref name) => name, @@ -720,7 +680,6 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Bo return Box::new(OngoingCodegen { modules: vec![], allocator_module: None, - metadata_module: None, crate_info: CrateInfo::new(tcx, target_cpu), concurrency_limiter: ConcurrencyLimiter::new(0), }); @@ -780,12 +739,9 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Bo let allocator_module = emit_allocator_module(tcx); - let metadata_module = metadata.map(|metadata| emit_metadata_module(tcx, metadata)); - Box::new(OngoingCodegen { modules, allocator_module, - metadata_module, crate_info: CrateInfo::new(tcx, target_cpu), concurrency_limiter: concurrency_limiter.0, }) diff --git a/src/lib.rs b/src/lib.rs index 277d4f16f194..07ea29f3024e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,6 @@ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::{self, Configurable}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenResults, TargetConfig}; -use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; use rustc_session::config::OutputFilenames; @@ -238,7 +237,7 @@ impl CodegenBackend for CraneliftCodegenBackend { println!("Cranelift version: {}", cranelift_codegen::VERSION); } - fn codegen_crate(&self, tcx: TyCtxt<'_>, metadata: Option<&EncodedMetadata>) -> Box { + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE)); let config = self.config.clone().unwrap_or_else(|| { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) @@ -251,7 +250,7 @@ impl CodegenBackend for CraneliftCodegenBackend { #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); } else { - driver::aot::run_aot(tcx, metadata) + driver::aot::run_aot(tcx) } } From b97136c817c989f37baca1191a07828346251a64 Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 3 Jun 2025 20:37:10 +0530 Subject: [PATCH 009/356] Add impl for `llvm.roundeven` in cg_clif - remove unused `llvm.aarch64.neon.frintn` from cg_clif --- example/neon.rs | 2 +- src/intrinsics/llvm.rs | 8 ++++++++ src/intrinsics/llvm_aarch64.rs | 8 -------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/example/neon.rs b/example/neon.rs index 69ce17d3d752..704f866e2c4f 100644 --- a/example/neon.rs +++ b/example/neon.rs @@ -233,7 +233,7 @@ unsafe fn test_vaddvq_f32() { #[cfg(target_arch = "aarch64")] unsafe fn test_vrndnq_f32() { - // AArch64 llvm intrinsic: llvm.aarch64.neon.frintn.v4f32 + // llvm intrinsic: llvm.roundeven.v4f32 let a = f32x4::from([0.1, -1.9, 4.5, 5.5]); let e = f32x4::from([0., -2., 4., 6.]); let r: f32x4 = transmute(vrndnq_f32(transmute(a))); diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index 2e02e85a997d..81dc038a5516 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -62,6 +62,14 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( }); } + _ if intrinsic.starts_with("llvm.roundeven.v") => { + intrinsic_args!(fx, args => (v); intrinsic); + + simd_for_each_lane(fx, v, ret, &|fx, _lane_ty, _res_lane_ty, lane| { + fx.bcx.ins().nearest(lane) + }); + } + _ => { fx.tcx .dcx() diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index d22483cf1776..5448f1b1e909 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -264,14 +264,6 @@ pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().fadd(a, b)); } - _ if intrinsic.starts_with("llvm.aarch64.neon.frintn.v") => { - intrinsic_args!(fx, args => (v); intrinsic); - - simd_for_each_lane(fx, v, ret, &|fx, _lane_ty, _res_lane_ty, lane| { - fx.bcx.ins().nearest(lane) - }); - } - _ if intrinsic.starts_with("llvm.aarch64.neon.smaxv.i") => { intrinsic_args!(fx, args => (v); intrinsic); From 12be26f9280b2a72918be0e7a642a1267ea28896 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 21 May 2025 23:29:37 +0200 Subject: [PATCH 010/356] cg_clif: convert to CanonAbi --- src/abi/mod.rs | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 5f7bf3821d77..fe5b220117f3 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -10,7 +10,7 @@ use std::mem; use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; -use rustc_abi::ExternAbi; +use rustc_abi::{CanonAbi, ExternAbi, X86Call}; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_target::callconv::{Conv, FnAbi, PassMode}; +use rustc_target::callconv::{FnAbi, PassMode}; use smallvec::SmallVec; use self::pass_mode::*; @@ -42,32 +42,27 @@ fn clif_sig_from_fn_abi<'tcx>( Signature { params, returns, call_conv } } -pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { +pub(crate) fn conv_to_call_conv( + sess: &Session, + c: CanonAbi, + default_call_conv: CallConv, +) -> CallConv { match c { - Conv::Rust | Conv::C => default_call_conv, - Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold, - Conv::X86_64SysV => CallConv::SystemV, - Conv::X86_64Win64 => CallConv::WindowsFastcall, + CanonAbi::Rust | CanonAbi::C => default_call_conv, + CanonAbi::RustCold => CallConv::Cold, - // Should already get a back compat warning - Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => { - default_call_conv - } + CanonAbi::X86(x86_call) => match x86_call { + X86Call::SysV64 => CallConv::SystemV, + X86Call::Win64 => CallConv::WindowsFastcall, + // Should already get a back compat warning + _ => default_call_conv, + }, - Conv::X86Intr | Conv::RiscvInterrupt { .. } => { - sess.dcx().fatal(format!("interrupt call conv {c:?} not yet implemented")) + CanonAbi::Interrupt(_) | CanonAbi::Arm(_) => { + sess.dcx().fatal("call conv {c:?} is not yet implemented") } - - Conv::ArmAapcs => sess.dcx().fatal("aapcs call conv not yet implemented"), - Conv::CCmseNonSecureCall => { - sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented"); - } - Conv::CCmseNonSecureEntry => { - sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented"); - } - - Conv::Msp430Intr | Conv::GpuKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { - unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); + CanonAbi::GpuKernel => { + unreachable!("tried to use {c:?} call conv which only exists on an unsupported target") } } } @@ -610,7 +605,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( target: CallTarget, call_args: &mut Vec, ) { - if fn_abi.conv != Conv::C { + if fn_abi.conv != CanonAbi::C { fx.tcx.dcx().span_fatal( source_info.span, format!("Variadic call for non-C abi {:?}", fn_abi.conv), From 57d0559160081a1db2163b06e3fe622bf129f5c5 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 3 Jun 2025 23:42:21 -0700 Subject: [PATCH 011/356] Change `tag_field` to `FieldIdx` in `Variants::Multiple` It was already available as a generic parameter anyway, and it's not like we'll ever put a tag in the 5-billionth field. --- src/discriminant.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/discriminant.rs b/src/discriminant.rs index 4d0d5dc60eba..a08b0e0cbfc5 100644 --- a/src/discriminant.rs +++ b/src/discriminant.rs @@ -28,7 +28,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( tag_encoding: TagEncoding::Direct, variants: _, } => { - let ptr = place.place_field(fx, FieldIdx::new(tag_field)); + let ptr = place.place_field(fx, tag_field); let to = layout.ty.discriminant_for_variant(fx.tcx, variant_index).unwrap().val; let to = match ptr.layout().ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { @@ -53,7 +53,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( variants: _, } => { if variant_index != untagged_variant { - let niche = place.place_field(fx, FieldIdx::new(tag_field)); + let niche = place.place_field(fx, tag_field); let niche_type = fx.clif_type(niche.layout().ty).unwrap(); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = (niche_value as u128).wrapping_add(niche_start); @@ -118,7 +118,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>( let cast_to = fx.clif_type(dest_layout.ty).unwrap(); // Read the tag/niche-encoded discriminant from memory. - let tag = value.value_field(fx, FieldIdx::new(tag_field)); + let tag = value.value_field(fx, tag_field); let tag = tag.load_scalar(fx); // Decode the discriminant (specifically if it's niche-encoded). From bcac194b240879545379def996dd9123dfc829ee Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 5 Jun 2025 09:35:09 +0000 Subject: [PATCH 012/356] Rustup to rustc 1.89.0-nightly (4b27a04cc 2025-06-04) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index f20b6b82a53a..a9a6c7bdf434 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-03" +channel = "nightly-2025-06-05" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 59549af369892581543afc0b48c73a24dbf87e7a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 4 Jun 2025 06:26:56 +0000 Subject: [PATCH 013/356] Replace some `Option` with `Span` and use DUMMY_SP instead of None --- src/base.rs | 16 ++++++++-------- src/intrinsics/llvm.rs | 2 +- src/intrinsics/llvm_aarch64.rs | 2 +- src/intrinsics/llvm_x86.rs | 2 +- src/intrinsics/mod.rs | 6 +++--- src/main_shim.rs | 4 ++-- src/num.rs | 2 +- src/unsize.rs | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/base.rs b/src/base.rs index 4617304105a5..0b641ba64b7a 100644 --- a/src/base.rs +++ b/src/base.rs @@ -380,7 +380,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicBoundsCheck, &[index, len, location], *unwind, - Some(source_info.span), + source_info.span, ); } AssertKind::MisalignedPointerDereference { ref required, ref found } => { @@ -393,7 +393,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicMisalignedPointerDereference, &[required, found, location], *unwind, - Some(source_info.span), + source_info.span, ); } AssertKind::NullPointerDereference => { @@ -404,7 +404,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicNullPointerDereference, &[location], *unwind, - Some(source_info.span), + source_info.span, ) } _ => { @@ -415,7 +415,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { msg.panic_function(), &[location], *unwind, - Some(source_info.span), + source_info.span, ); } } @@ -531,7 +531,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ); } TerminatorKind::UnwindTerminate(reason) => { - codegen_unwind_terminate(fx, Some(source_info.span), *reason); + codegen_unwind_terminate(fx, source_info.span, *reason); } TerminatorKind::UnwindResume => { // FIXME implement unwinding @@ -1074,7 +1074,7 @@ pub(crate) fn codegen_operand<'tcx>( pub(crate) fn codegen_panic_nounwind<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, - span: Option, + span: Span, ) { let msg_ptr = fx.anonymous_str(msg_str); let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); @@ -1091,7 +1091,7 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( pub(crate) fn codegen_unwind_terminate<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - span: Option, + span: Span, reason: UnwindTerminateReason, ) { codegen_panic_inner(fx, reason.lang_item(), &[], UnwindAction::Unreachable, span); @@ -1102,7 +1102,7 @@ fn codegen_panic_inner<'tcx>( lang_item: rustc_hir::LangItem, args: &[Value], _unwind: UnwindAction, - span: Option, + span: Span, ) { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index 2e02e85a997d..99a5518d0b68 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -71,7 +71,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, span); return; } } diff --git a/src/intrinsics/llvm_aarch64.rs b/src/intrinsics/llvm_aarch64.rs index d22483cf1776..c22f2a7b8734 100644 --- a/src/intrinsics/llvm_aarch64.rs +++ b/src/intrinsics/llvm_aarch64.rs @@ -512,7 +512,7 @@ pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, fx.mir.span); return; } } diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 3d67913a8fff..615f6c47d902 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -1321,7 +1321,7 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, span); return; } } diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 0de23e55e817..27a5df8b1520 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -785,7 +785,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } }) }); - crate::base::codegen_panic_nounwind(fx, &msg_str, Some(source_info.span)); + crate::base::codegen_panic_nounwind(fx, &msg_str, source_info.span); return Ok(()); } } @@ -884,7 +884,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic_nounwind( fx, "128bit atomics not yet supported", - None, + source_info.span, ); return Ok(()); } else { @@ -919,7 +919,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic_nounwind( fx, "128bit atomics not yet supported", - None, + source_info.span, ); return Ok(()); } else { diff --git a/src/main_shim.rs b/src/main_shim.rs index 6eef97c14dd2..bf756860b649 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -101,7 +101,7 @@ pub(crate) fn maybe_create_entry_wrapper( let call_inst = bcx.ins().call(main_func_ref, &[]); let call_results = bcx.func.dfg.inst_results(call_inst).to_owned(); - let termination_trait = tcx.require_lang_item(LangItem::Termination, None); + let termination_trait = tcx.require_lang_item(LangItem::Termination, DUMMY_SP); let report = tcx .associated_items(termination_trait) .find_by_ident_and_kind( @@ -136,7 +136,7 @@ pub(crate) fn maybe_create_entry_wrapper( } } else { // Regular main fn invoked via start lang item. - let start_def_id = tcx.require_lang_item(LangItem::Start, None); + let start_def_id = tcx.require_lang_item(LangItem::Start, DUMMY_SP); let start_instance = Instance::expect_resolve( tcx, ty::TypingEnv::fully_monomorphized(), diff --git a/src/num.rs b/src/num.rs index f53045df6e79..95d44dfb6d95 100644 --- a/src/num.rs +++ b/src/num.rs @@ -54,7 +54,7 @@ fn codegen_three_way_compare<'tcx>( let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs); let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs); let val = fx.bcx.ins().isub(gt, lt); - CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span)))) + CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(fx.mir.span))) } fn codegen_compare_bin_op<'tcx>( diff --git a/src/unsize.rs b/src/unsize.rs index f8bbb2149201..662546e49998 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -240,7 +240,7 @@ pub(crate) fn size_and_align_of<'tcx>( }) }); - codegen_panic_nounwind(fx, &msg_str, None); + codegen_panic_nounwind(fx, &msg_str, fx.mir.span); fx.bcx.switch_to_block(next_block); From 2192d869d0624a2013e45183db1cf3595aa7d989 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 4 Jun 2025 01:44:40 -0700 Subject: [PATCH 014/356] Update `InterpCx::project_field` to take `FieldIdx` As suggested by Ralf in 142005. --- src/inline_asm.rs | 2 +- src/vtable.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index afee50955497..120d6ff9e38e 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -850,7 +850,7 @@ fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option { let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args); + let ty = fields[FieldIdx::ONE].ty(fx.tcx, args); let ty::Adt(ty, args) = ty.kind() else { unreachable!("expected first field of `MaybeUninit` to be an ADT") }; diff --git a/src/vtable.rs b/src/vtable.rs index 9d9e0462a9b7..05a8e3c33421 100644 --- a/src/vtable.rs +++ b/src/vtable.rs @@ -53,7 +53,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( .layout() .non_1zst_field(fx) .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type"); - arg = arg.value_field(fx, FieldIdx::new(idx)); + arg = arg.value_field(fx, idx); } } @@ -62,8 +62,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap()); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); - let vtable = - dyn_star.place_field(fx, FieldIdx::new(1)).to_cvalue(fx).load_scalar(fx); + let vtable = dyn_star.place_field(fx, FieldIdx::ONE).to_cvalue(fx).load_scalar(fx); break 'block (ptr, vtable); } } From 669564d0281999a5568159c9d82dea7e51429c59 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 21 May 2025 12:45:17 +0530 Subject: [PATCH 015/356] std: sys: random: uefi: Provide rdrand based fallback Some UEFI systems based on American Megatrends Inc. v3.3 do not provide RNG support [1]. So fallback to rdrand in such cases. [1]: https://github.com/rust-lang/rust/issues/138252#issuecomment-2891270323 Signed-off-by: Ayush Singh --- library/std/src/sys/random/uefi.rs | 175 +++++++++++++++++++++++++---- 1 file changed, 153 insertions(+), 22 deletions(-) diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs index a4d29e66f387..5f001f0f532a 100644 --- a/library/std/src/sys/random/uefi.rs +++ b/library/std/src/sys/random/uefi.rs @@ -1,27 +1,158 @@ -use r_efi::protocols::rng; - -use crate::sys::pal::helpers; - pub fn fill_bytes(bytes: &mut [u8]) { - let handles = - helpers::locate_handles(rng::PROTOCOL_GUID).expect("failed to generate random data"); - for handle in handles { - if let Ok(protocol) = helpers::open_protocol::(handle, rng::PROTOCOL_GUID) { - let r = unsafe { - ((*protocol.as_ptr()).get_rng)( - protocol.as_ptr(), - crate::ptr::null_mut(), - bytes.len(), - bytes.as_mut_ptr(), - ) - }; - if r.is_error() { - continue; - } else { - return; - } - } + // Handle zero-byte request + if bytes.is_empty() { + return; + } + + // Try EFI_RNG_PROTOCOL + if rng_protocol::fill_bytes(bytes) { + return; + } + + // Fallback to rdrand if rng protocol missing. + // + // For real-world example, see [issue-13825](https://github.com/rust-lang/rust/issues/138252#issuecomment-2891270323) + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] + if rdrand::fill_bytes(bytes) { + return; } panic!("failed to generate random data"); } + +mod rng_protocol { + use r_efi::protocols::rng; + + use crate::sys::pal::helpers; + + pub(crate) fn fill_bytes(bytes: &mut [u8]) -> bool { + if let Ok(handles) = helpers::locate_handles(rng::PROTOCOL_GUID) { + for handle in handles { + if let Ok(protocol) = + helpers::open_protocol::(handle, rng::PROTOCOL_GUID) + { + let r = unsafe { + ((*protocol.as_ptr()).get_rng)( + protocol.as_ptr(), + crate::ptr::null_mut(), + bytes.len(), + bytes.as_mut_ptr(), + ) + }; + if r.is_error() { + continue; + } else { + return true; + } + } + } + } + + false + } +} + +/// Port from [getrandom](https://github.com/rust-random/getrandom/blob/master/src/backends/rdrand.rs) +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +mod rdrand { + cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + use crate::arch::x86_64 as arch; + use arch::_rdrand64_step as rdrand_step; + type Word = u64; + } else if #[cfg(target_arch = "x86")] { + use crate::arch::x86 as arch; + use arch::_rdrand32_step as rdrand_step; + type Word = u32; + } + } + + static RDRAND_GOOD: crate::sync::LazyLock = crate::sync::LazyLock::new(is_rdrand_good); + + // Recommendation from "Intel® Digital Random Number Generator (DRNG) Software + // Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures + // Software Developer’s Manual" - Volume 1 - Section 7.3.17.1. + const RETRY_LIMIT: usize = 10; + + unsafe fn rdrand() -> Option { + for _ in 0..RETRY_LIMIT { + let mut val = 0; + if unsafe { rdrand_step(&mut val) } == 1 { + return Some(val); + } + } + None + } + + // Run a small self-test to make sure we aren't repeating values + // Adapted from Linux's test in arch/x86/kernel/cpu/rdrand.c + // Fails with probability < 2^(-90) on 32-bit systems + unsafe fn self_test() -> bool { + // On AMD, RDRAND returns 0xFF...FF on failure, count it as a collision. + let mut prev = Word::MAX; + let mut fails = 0; + for _ in 0..8 { + match unsafe { rdrand() } { + Some(val) if val == prev => fails += 1, + Some(val) => prev = val, + None => return false, + }; + } + fails <= 2 + } + + fn is_rdrand_good() -> bool { + #[cfg(not(target_feature = "rdrand"))] + { + // SAFETY: All Rust x86 targets are new enough to have CPUID, and we + // check that leaf 1 is supported before using it. + let cpuid0 = unsafe { arch::__cpuid(0) }; + if cpuid0.eax < 1 { + return false; + } + let cpuid1 = unsafe { arch::__cpuid(1) }; + + let vendor_id = + [cpuid0.ebx.to_le_bytes(), cpuid0.edx.to_le_bytes(), cpuid0.ecx.to_le_bytes()]; + if vendor_id == [*b"Auth", *b"enti", *b"cAMD"] { + let mut family = (cpuid1.eax >> 8) & 0xF; + if family == 0xF { + family += (cpuid1.eax >> 20) & 0xFF; + } + // AMD CPUs families before 17h (Zen) sometimes fail to set CF when + // RDRAND fails after suspend. Don't use RDRAND on those families. + // See https://bugzilla.redhat.com/show_bug.cgi?id=1150286 + if family < 0x17 { + return false; + } + } + + const RDRAND_FLAG: u32 = 1 << 30; + if cpuid1.ecx & RDRAND_FLAG == 0 { + return false; + } + } + + // SAFETY: We have already checked that rdrand is available. + unsafe { self_test() } + } + + unsafe fn rdrand_exact(dest: &mut [u8]) -> Option<()> { + let mut chunks = dest.array_chunks_mut(); + for chunk in &mut chunks { + *chunk = unsafe { rdrand() }?.to_ne_bytes(); + } + + let tail = chunks.into_remainder(); + let n = tail.len(); + if n > 0 { + let src = unsafe { rdrand() }?.to_ne_bytes(); + tail.copy_from_slice(&src[..n]); + } + Some(()) + } + + pub(crate) fn fill_bytes(bytes: &mut [u8]) -> bool { + if *RDRAND_GOOD { unsafe { rdrand_exact(bytes).is_some() } } else { false } + } +} From 2a473e5aa6c8869dfef3891e32c77085338e4f46 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 6 Jun 2025 16:34:53 +0300 Subject: [PATCH 016/356] In "Fill match arms", allow users to prefer `Self` to the enum name when possible But default to not to. I chose to have a more generic config name because maybe other assists could also use the same approach. --- .../crates/ide-assists/src/assist_config.rs | 1 + .../src/handlers/add_missing_match_arms.rs | 207 +++++++++++++++--- .../crates/ide-assists/src/tests.rs | 21 ++ .../crates/rust-analyzer/src/config.rs | 3 + .../crates/syntax/src/ast/make.rs | 7 + .../docs/book/src/configuration_generated.md | 7 + .../rust-analyzer/editors/code/package.json | 10 + 7 files changed, 227 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs index fb569f8cdae0..57ced8d8534b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs @@ -22,6 +22,7 @@ pub struct AssistConfig { pub term_search_borrowck: bool, pub code_action_grouping: bool, pub expr_fill_default: ExprFillDefaultMode, + pub prefer_self_ty: bool, } impl AssistConfig { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 858d4369914a..682a8e6c78d3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -1,12 +1,13 @@ use std::iter::{self, Peekable}; use either::Either; -use hir::{Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym}; +use hir::{Adt, AsAssocItem, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym}; use ide_db::RootDatabase; use ide_db::assists::ExprFillDefaultMode; use ide_db::syntax_helpers::suggest_name; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; +use syntax::ToSmolStr; use syntax::ast::edit::IndentLevel; use syntax::ast::edit_in_place::Indent; use syntax::ast::syntax_factory::SyntaxFactory; @@ -79,12 +80,20 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let make = SyntaxFactory::with_mappings(); - let module = ctx.sema.scope(expr.syntax())?.module(); + let scope = ctx.sema.scope(expr.syntax())?; + let module = scope.module(); + let self_ty = if ctx.config.prefer_self_ty { + scope + .containing_function() + .and_then(|function| function.as_assoc_item(ctx.db())?.implementing_ty(ctx.db())) + } else { + None + }; let (mut missing_pats, is_non_exhaustive, has_hidden_variants): ( Peekable>>, bool, bool, - ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { + ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr, self_ty.as_ref()) { let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate()); let variants = enum_def.variants(ctx.db()); @@ -102,8 +111,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) }) .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat)); - let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option().map(lift_enum); - let missing_pats: Box> = if Some(enum_def) == option_enum { + let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option(); + let missing_pats: Box> = if matches!(enum_def, ExtendedEnum::Enum { enum_: e, .. } if Some(e) == option_enum) + { // Match `Some` variant first. cov_mark::hit!(option_order); Box::new(missing_pats.rev()) @@ -111,7 +121,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) Box::new(missing_pats) }; (missing_pats.peekable(), is_non_exhaustive, has_hidden_variants) - } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { + } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) { let is_non_exhaustive = enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate())); @@ -159,7 +169,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) is_non_exhaustive, has_hidden_variants, ) - } else if let Some((enum_def, len)) = resolve_array_of_enum_def(&ctx.sema, &expr) { + } else if let Some((enum_def, len)) = + resolve_array_of_enum_def(&ctx.sema, &expr, self_ty.as_ref()) + { let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate()); let variants = enum_def.variants(ctx.db()); @@ -373,23 +385,23 @@ fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { } } -#[derive(Eq, PartialEq, Clone, Copy)] +#[derive(Eq, PartialEq, Clone)] enum ExtendedEnum { Bool, - Enum(hir::Enum), + Enum { enum_: hir::Enum, use_self: bool }, } #[derive(Eq, PartialEq, Clone, Copy, Debug)] enum ExtendedVariant { True, False, - Variant(hir::Variant), + Variant { variant: hir::Variant, use_self: bool }, } impl ExtendedVariant { fn should_be_hidden(self, db: &RootDatabase, krate: Crate) -> bool { match self { - ExtendedVariant::Variant(var) => { + ExtendedVariant::Variant { variant: var, .. } => { var.attrs(db).has_doc_hidden() && var.module(db).krate() != krate } _ => false, @@ -397,25 +409,35 @@ impl ExtendedVariant { } } -fn lift_enum(e: hir::Enum) -> ExtendedEnum { - ExtendedEnum::Enum(e) -} - impl ExtendedEnum { - fn is_non_exhaustive(self, db: &RootDatabase, krate: Crate) -> bool { + fn enum_( + db: &RootDatabase, + enum_: hir::Enum, + enum_ty: &hir::Type, + self_ty: Option<&hir::Type>, + ) -> Self { + ExtendedEnum::Enum { + enum_, + use_self: self_ty.is_some_and(|self_ty| self_ty.could_unify_with_deeply(db, enum_ty)), + } + } + + fn is_non_exhaustive(&self, db: &RootDatabase, krate: Crate) -> bool { match self { - ExtendedEnum::Enum(e) => { + ExtendedEnum::Enum { enum_: e, .. } => { e.attrs(db).by_key(sym::non_exhaustive).exists() && e.module(db).krate() != krate } _ => false, } } - fn variants(self, db: &RootDatabase) -> Vec { - match self { - ExtendedEnum::Enum(e) => { - e.variants(db).into_iter().map(ExtendedVariant::Variant).collect::>() - } + fn variants(&self, db: &RootDatabase) -> Vec { + match *self { + ExtendedEnum::Enum { enum_: e, use_self } => e + .variants(db) + .into_iter() + .map(|variant| ExtendedVariant::Variant { variant, use_self }) + .collect::>(), ExtendedEnum::Bool => { Vec::::from([ExtendedVariant::True, ExtendedVariant::False]) } @@ -423,9 +445,13 @@ impl ExtendedEnum { } } -fn resolve_enum_def(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> Option { +fn resolve_enum_def( + sema: &Semantics<'_, RootDatabase>, + expr: &ast::Expr, + self_ty: Option<&hir::Type>, +) -> Option { sema.type_of_expr(expr)?.adjusted().autoderef(sema.db).find_map(|ty| match ty.as_adt() { - Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)), + Some(Adt::Enum(e)) => Some(ExtendedEnum::enum_(sema.db, e, &ty, self_ty)), _ => ty.is_bool().then_some(ExtendedEnum::Bool), }) } @@ -433,6 +459,7 @@ fn resolve_enum_def(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> Opt fn resolve_tuple_of_enum_def( sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr, + self_ty: Option<&hir::Type>, ) -> Option> { sema.type_of_expr(expr)? .adjusted() @@ -441,7 +468,7 @@ fn resolve_tuple_of_enum_def( .map(|ty| { ty.autoderef(sema.db).find_map(|ty| { match ty.as_adt() { - Some(Adt::Enum(e)) => Some(lift_enum(e)), + Some(Adt::Enum(e)) => Some(ExtendedEnum::enum_(sema.db, e, &ty, self_ty)), // For now we only handle expansion for a tuple of enums. Here // we map non-enum items to None and rely on `collect` to // convert Vec> into Option>. @@ -456,10 +483,11 @@ fn resolve_tuple_of_enum_def( fn resolve_array_of_enum_def( sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr, + self_ty: Option<&hir::Type>, ) -> Option<(ExtendedEnum, usize)> { sema.type_of_expr(expr)?.adjusted().as_array(sema.db).and_then(|(ty, len)| { ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() { - Some(Adt::Enum(e)) => Some((lift_enum(e), len)), + Some(Adt::Enum(e)) => Some((ExtendedEnum::enum_(sema.db, e, &ty, self_ty), len)), _ => ty.is_bool().then_some((ExtendedEnum::Bool, len)), }) }) @@ -474,9 +502,21 @@ fn build_pat( ) -> Option { let db = ctx.db(); match var { - ExtendedVariant::Variant(var) => { + ExtendedVariant::Variant { variant: var, use_self } => { let edition = module.krate().edition(db); - let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition); + let path = if use_self { + make::path_from_segments( + [ + make::path_segment(make::name_ref_self_ty()), + make::path_segment(make::name_ref( + &var.name(db).display(db, edition).to_smolstr(), + )), + ], + false, + ) + } else { + mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition) + }; let fields = var.fields(db); let pat: ast::Pat = match var.kind(db) { hir::StructKind::Tuple => { @@ -509,8 +549,10 @@ fn build_pat( #[cfg(test)] mod tests { + use crate::AssistConfig; use crate::tests::{ - check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved, + TEST_CONFIG, check_assist, check_assist_not_applicable, check_assist_target, + check_assist_unresolved, check_assist_with_config, }; use super::add_missing_match_arms; @@ -2095,4 +2137,111 @@ fn f() { "#, ); } + + #[test] + fn prefer_self() { + check_assist_with_config( + add_missing_match_arms, + AssistConfig { prefer_self_ty: true, ..TEST_CONFIG }, + r#" +enum Foo { + Bar, + Baz, +} + +impl Foo { + fn qux(&self) { + match self { + $0_ => {} + } + } +} + "#, + r#" +enum Foo { + Bar, + Baz, +} + +impl Foo { + fn qux(&self) { + match self { + Self::Bar => ${1:todo!()}, + Self::Baz => ${2:todo!()},$0 + } + } +} + "#, + ); + } + + #[test] + fn prefer_self_with_generics() { + check_assist_with_config( + add_missing_match_arms, + AssistConfig { prefer_self_ty: true, ..TEST_CONFIG }, + r#" +enum Foo { + Bar(T), + Baz, +} + +impl Foo { + fn qux(&self) { + match self { + $0_ => {} + } + } +} + "#, + r#" +enum Foo { + Bar(T), + Baz, +} + +impl Foo { + fn qux(&self) { + match self { + Self::Bar(${1:_}) => ${2:todo!()}, + Self::Baz => ${3:todo!()},$0 + } + } +} + "#, + ); + check_assist_with_config( + add_missing_match_arms, + AssistConfig { prefer_self_ty: true, ..TEST_CONFIG }, + r#" +enum Foo { + Bar(T), + Baz, +} + +impl Foo { + fn qux(v: Foo) { + match v { + $0_ => {} + } + } +} + "#, + r#" +enum Foo { + Bar(T), + Baz, +} + +impl Foo { + fn qux(v: Foo) { + match v { + Foo::Bar(${1:_}) => ${2:todo!()}, + Foo::Baz => ${3:todo!()},$0 + } + } +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 5e6889792db6..cda2ad43278a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -37,6 +37,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { term_search_borrowck: true, code_action_grouping: true, expr_fill_default: ExprFillDefaultMode::Todo, + prefer_self_ty: false, }; pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig { @@ -57,6 +58,7 @@ pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig { term_search_borrowck: true, code_action_grouping: false, expr_fill_default: ExprFillDefaultMode::Todo, + prefer_self_ty: false, }; pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { @@ -77,6 +79,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { term_search_borrowck: true, code_action_grouping: true, expr_fill_default: ExprFillDefaultMode::Todo, + prefer_self_ty: false, }; pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { @@ -97,6 +100,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { term_search_borrowck: true, code_action_grouping: true, expr_fill_default: ExprFillDefaultMode::Todo, + prefer_self_ty: false, }; pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) { @@ -113,6 +117,23 @@ pub(crate) fn check_assist( check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None); } +#[track_caller] +pub(crate) fn check_assist_with_config( + assist: Handler, + config: AssistConfig, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { + let ra_fixture_after = trim_indent(ra_fixture_after); + check_with_config( + config, + assist, + ra_fixture_before, + ExpectedResult::After(&ra_fixture_after), + None, + ); +} + #[track_caller] pub(crate) fn check_assist_no_snippet_cap( assist: Handler, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 5cbea9c2b3d9..ba5142845d09 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -452,6 +452,8 @@ config_data! { assist_emitMustUse: bool = false, /// Placeholder expression to use for missing expressions in assists. assist_expressionFillDefault: ExprFillDefaultDef = ExprFillDefaultDef::Todo, + /// When inserting a type (e.g. in "fill match arms" assist), prefer to use `Self` over the type name where possible. + assist_preferSelf: bool = false, /// Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check. assist_termSearch_borrowcheck: bool = true, /// Term search fuel in "units of work" for assists (Defaults to 1800). @@ -1501,6 +1503,7 @@ impl Config { ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore, }, + prefer_self_ty: *self.assist_preferSelf(source_root), } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index fab4cb287c3d..955aadaa25d3 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -134,6 +134,13 @@ pub fn name_ref(name_ref: &str) -> ast::NameRef { } } } +pub fn name_ref_self_ty() -> ast::NameRef { + quote! { + NameRef { + [Self] + } + } +} fn raw_ident_esc(ident: &str) -> &'static str { if is_raw_identifier(ident, Edition::CURRENT) { "r#" } else { "" } } diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 0e07dadfb7c9..7c1aafcdfa9c 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -13,6 +13,13 @@ Default: `"todo"` Placeholder expression to use for missing expressions in assists. +## rust-analyzer.assist.preferSelf {#assist.preferSelf} + +Default: `false` + +When inserting a type (e.g. in "fill match arms" assist), prefer to use `Self` over the type name where possible. + + ## rust-analyzer.assist.termSearch.borrowcheck {#assist.termSearch.borrowcheck} Default: `true` diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index c8c36cd85c8e..398d0c51e9ad 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -680,6 +680,16 @@ } } }, + { + "title": "assist", + "properties": { + "rust-analyzer.assist.preferSelf": { + "markdownDescription": "When inserting a type (e.g. in \"fill match arms\" assist), prefer to use `Self` over the type name where possible.", + "default": false, + "type": "boolean" + } + } + }, { "title": "assist", "properties": { From 4e3bf2da2f2ec55f16b5e141bc01ce10f38ee054 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 7 Jun 2025 14:18:29 +0000 Subject: [PATCH 017/356] Rustup to rustc 1.89.0-nightly (44f415c1d 2025-06-06) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index a9a6c7bdf434..9bc06fcc838a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-05" +channel = "nightly-2025-06-07" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 18b12218a4ae486b3c699efa159ab07277624982 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 May 2025 18:37:58 +0200 Subject: [PATCH 018/356] intrinsics: use const generic to set atomic ordering --- src/intrinsics/mod.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 27a5df8b1520..a0f96d85dc3c 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -875,7 +875,6 @@ fn codegen_regular_intrinsic_call<'tcx>( let ptr = ptr.load_scalar(fx); let ty = generic_args.type_at(0); - let _ord = generic_args.const_at(1).to_value(); // FIXME: forward this to cranelift once they support that match ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { // FIXME implement 128bit atomics @@ -906,7 +905,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = CValue::by_val(val, fx.layout_of(ty)); ret.write_cvalue(fx, val); } - _ if intrinsic.as_str().starts_with("atomic_store") => { + sym::atomic_store => { intrinsic_args!(fx, args => (ptr, val); intrinsic); let ptr = ptr.load_scalar(fx); @@ -939,7 +938,7 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr); } - _ if intrinsic.as_str().starts_with("atomic_xchg") => { + sym::atomic_xchg => { intrinsic_args!(fx, args => (ptr, new); intrinsic); let ptr = ptr.load_scalar(fx); @@ -960,8 +959,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_cxchg") => { - // both atomic_cxchg_* and atomic_cxchgweak_* + sym::atomic_cxchg | sym::atomic_cxchgweak => { intrinsic_args!(fx, args => (ptr, test_old, new); intrinsic); let ptr = ptr.load_scalar(fx); @@ -984,7 +982,7 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, ret_val) } - _ if intrinsic.as_str().starts_with("atomic_xadd") => { + sym::atomic_xadd => { intrinsic_args!(fx, args => (ptr, amount); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1006,7 +1004,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_xsub") => { + sym::atomic_xsub => { intrinsic_args!(fx, args => (ptr, amount); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1028,7 +1026,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_and") => { + sym::atomic_and => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1049,7 +1047,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_or") => { + sym::atomic_or => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1070,7 +1068,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_xor") => { + sym::atomic_xor => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1091,7 +1089,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_nand") => { + sym::atomic_nand => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1112,7 +1110,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_max") => { + sym::atomic_max => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1133,7 +1131,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_umax") => { + sym::atomic_umax => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1154,7 +1152,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_min") => { + sym::atomic_min => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); @@ -1175,7 +1173,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let old = CValue::by_val(old, layout); ret.write_cvalue(fx, old); } - _ if intrinsic.as_str().starts_with("atomic_umin") => { + sym::atomic_umin => { intrinsic_args!(fx, args => (ptr, src); intrinsic); let ptr = ptr.load_scalar(fx); From 7988b8c0b3cec24f1c827c885f418fa9ae3aa6a6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 8 Jun 2025 11:42:13 +0000 Subject: [PATCH 019/356] Rustup to rustc 1.89.0-nightly (cdd545be1 2025-06-07) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 9bc06fcc838a..1e867bd76580 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-07" +channel = "nightly-2025-06-08" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 5b1ac613834326ea935c52a95089d610f66cd636 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 8 Jun 2025 15:17:34 +0300 Subject: [PATCH 020/356] Add the quickfix for increasing visibility of a private field to the private-field diagnostic (previously it was only on no-such-field) The difference between the diagnostics is that no-such-field is for record struct construction, while private-field is for dot syntax. I tried to unify them, but there is a bit of uniqueness in each. This is possible but maybe not worth it. Also, fix the quickfix when there is already a visibility to the field (replace it instead of appending to it). --- .../src/handlers/no_such_field.rs | 33 +---- .../src/handlers/private_field.rs | 124 +++++++++++++++++- 2 files changed, 125 insertions(+), 32 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index ef42f2dc7448..0edab5e0b3b1 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,5 +1,4 @@ use either::Either; -use hir::{Field, HasCrate}; use hir::{HasSource, HirDisplay, Semantics, VariantId, db::ExpandDatabase}; use ide_db::text_edit::TextEdit; use ide_db::{EditionedFileId, RootDatabase, source_change::SourceChange}; @@ -8,7 +7,10 @@ use syntax::{ ast::{self, edit::IndentLevel, make}, }; -use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix}; +use crate::{ + Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix, + handlers::private_field::field_is_private_fixes, +}; // Diagnostic: no-such-field // @@ -37,8 +39,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option, d: &hir::NoSuchField) -> Option, - usage_file_id: EditionedFileId, - record_expr_field: &ast::RecordExprField, - private_field: Field, -) -> Option> { - let def_crate = private_field.krate(sema.db); - let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate(); - let visibility = if usage_crate == def_crate { "pub(crate) " } else { "pub " }; - - let source = private_field.source(sema.db)?; - let (range, _) = source.syntax().original_file_range_opt(sema.db)?; - let source_change = SourceChange::from_text_edit( - range.file_id.file_id(sema.db), - TextEdit::insert(range.range.start(), visibility.into()), - ); - - Some(vec![fix( - "increase_field_visibility", - "Increase field visibility", - source_change, - sema.original_range(record_expr_field.syntax()).range, - )]) -} - fn missing_record_expr_field_fixes( sema: &Semantics<'_, RootDatabase>, usage_file_id: EditionedFileId, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs index 5b4273a5a627..69cd0d27cb06 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs @@ -1,4 +1,8 @@ -use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; +use hir::{EditionedFileId, FileRange, HasCrate, HasSource, Semantics}; +use ide_db::{RootDatabase, assists::Assist, source_change::SourceChange, text_edit::TextEdit}; +use syntax::{AstNode, TextRange, TextSize, ast::HasVisibility}; + +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix}; // Diagnostic: private-field // @@ -16,11 +20,59 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField) d.expr.map(|it| it.into()), ) .stable() + .with_fixes(field_is_private_fixes( + &ctx.sema, + d.expr.file_id.original_file(ctx.sema.db), + d.field, + ctx.sema.original_range(d.expr.to_node(ctx.sema.db).syntax()).range, + )) +} + +pub(crate) fn field_is_private_fixes( + sema: &Semantics<'_, RootDatabase>, + usage_file_id: EditionedFileId, + private_field: hir::Field, + fix_range: TextRange, +) -> Option> { + let def_crate = private_field.krate(sema.db); + let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate(); + let mut visibility_text = if usage_crate == def_crate { "pub(crate) " } else { "pub " }; + + let source = private_field.source(sema.db)?; + let existing_visibility = match &source.value { + hir::FieldSource::Named(it) => it.visibility(), + hir::FieldSource::Pos(it) => it.visibility(), + }; + let range = match existing_visibility { + Some(visibility) => { + // If there is an existing visibility, don't insert whitespace after. + visibility_text = visibility_text.trim_end(); + source.with_value(visibility.syntax()).original_file_range_opt(sema.db)?.0 + } + None => { + let (range, _) = source.syntax().original_file_range_opt(sema.db)?; + FileRange { + file_id: range.file_id, + range: TextRange::at(range.range.start(), TextSize::new(0)), + } + } + }; + let source_change = SourceChange::from_text_edit( + range.file_id.file_id(sema.db), + TextEdit::replace(range.range, visibility_text.into()), + ); + + Some(vec![fix( + "increase_field_visibility", + "Increase field visibility", + source_change, + fix_range, + )]) } #[cfg(test)] mod tests { - use crate::tests::check_diagnostics; + use crate::tests::{check_diagnostics, check_fix}; #[test] fn private_field() { @@ -29,7 +81,7 @@ mod tests { mod module { pub struct Struct { field: u32 } } fn main(s: module::Struct) { s.field; - //^^^^^^^ error: field `field` of `Struct` is private + //^^^^^^^ 💡 error: field `field` of `Struct` is private } "#, ); @@ -42,7 +94,7 @@ fn main(s: module::Struct) { mod module { pub struct Struct(u32); } fn main(s: module::Struct) { s.0; - //^^^ error: field `0` of `Struct` is private + //^^^ 💡 error: field `0` of `Struct` is private } "#, ); @@ -113,4 +165,68 @@ fn main() { "#, ); } + + #[test] + fn change_visibility_fix() { + check_fix( + r#" +pub mod foo { + pub mod bar { + pub struct Struct { + field: i32, + } + } +} + +fn foo(v: foo::bar::Struct) { + v.field$0; +} + "#, + r#" +pub mod foo { + pub mod bar { + pub struct Struct { + pub(crate) field: i32, + } + } +} + +fn foo(v: foo::bar::Struct) { + v.field; +} + "#, + ); + } + + #[test] + fn change_visibility_with_existing_visibility() { + check_fix( + r#" +pub mod foo { + pub mod bar { + pub struct Struct { + pub(super) field: i32, + } + } +} + +fn foo(v: foo::bar::Struct) { + v.field$0; +} + "#, + r#" +pub mod foo { + pub mod bar { + pub struct Struct { + pub(crate) field: i32, + } + } +} + +fn foo(v: foo::bar::Struct) { + v.field; +} + "#, + ); + } } From d5e9833af388c9f3122877fe355ff7b244c50516 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 11 Feb 2025 22:09:16 -0800 Subject: [PATCH 021/356] Remove rustc's notion of "preferred" alignment AKA `__alignof` In PR 90877 T-lang decided not to remove `intrinsics::pref_align_of`. However, the intrinsic and its supporting code 1. is a nightly feature, so can be removed at compiler/libs discretion 2. requires considerable effort in the compiler to support, as it necessarily complicates every single site reasoning about alignment 3. has been justified based on relevance to codegen, but it is only a requirement for C++ (not C, not Rust) stack frame layout for AIX, in ways Rust would not consider even with increased C++ interop 4. is only used by rustc to overalign some globals, not correctness 5. can be adequately replaced by other rules for globals, as it mostly affects alignments for a few types under 16 bytes of alignment 6. has only one clear benefactor: automating C -> Rust translation for GNU extensions like `__alignof` 7. such code was likely intended to be `alignof` or `_Alignof`, because the GNU extension is a "false friend" of the C keyword, which makes the choice to support such a mapping very questionable 8. makes it easy to do incorrect codegen in the compiler by its mere presence as usual Rust rules of alignment (e.g. `size == align * N`) do not hold with preferred alignment The implementation is clearly damaging the code quality of the compiler. Thus it is within the compiler team's purview to simply rip it out. If T-lang wishes to have this intrinsic restored for c2rust's benefit, it would have to use a radically different implementation that somehow does not cause internal incorrectness. Until then, remove the intrinsic and its supporting code, as one tool and an ill-considered GCC extension cannot justify risking correctness. Because we touch a fair amount of the compiler to change this at all, and unfortunately the duplication of AbiAndPrefAlign is deep-rooted, we keep an "AbiAlign" type which we can wean code off later. --- src/intrinsics/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index a0f96d85dc3c..1d1cf884e48b 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -812,11 +812,7 @@ fn codegen_regular_intrinsic_call<'tcx>( dest.write_cvalue(fx, val); } - sym::pref_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { + sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { intrinsic_args!(fx, args => (); intrinsic); let const_val = fx From f30e9c943ccd1eacb6a75d5b0a64d7091e1a8e83 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:30:06 +0200 Subject: [PATCH 022/356] ci: split x86_64-gnu-tools job --- .../host-x86_64/x86_64-gnu-miri/Dockerfile | 57 +++++++++++++++++ .../host-x86_64/x86_64-gnu-miri/check-miri.sh | 62 +++++++++++++++++++ .../x86_64-gnu-tools/checktools.sh | 55 ---------------- src/ci/github-actions/jobs.yml | 7 ++- 4 files changed, 125 insertions(+), 56 deletions(-) create mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile create mode 100755 src/ci/docker/host-x86_64/x86_64-gnu-miri/check-miri.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile new file mode 100644 index 000000000000..b937bc3e678d --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile @@ -0,0 +1,57 @@ +FROM ghcr.io/rust-lang/ubuntu:22.04 + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + libssl-dev \ + sudo \ + xz-utils \ + tidy \ + \ + libc6 \ + wget \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# Fix rustc_codegen_gcc lto issues. +ENV GCC_EXEC_PREFIX="/usr/lib/gcc/" + +COPY host-x86_64/x86_64-gnu-miri/check-miri.sh /tmp/ + +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --enable-new-symbol-mangling + +ENV HOST_TARGET x86_64-unknown-linux-gnu + +# FIXME(#133381): currently rustc alt builds do *not* have rustc debug +# assertions enabled! Therefore, we cannot force download CI rustc. +#ENV FORCE_CI_RUSTC 1 + +COPY scripts/shared.sh /scripts/ + +# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries +# to create a new folder. For reference: +# https://github.com/puppeteer/puppeteer/issues/375 +# +# We also specify the version in case we need to update it to go around cache limitations. +# +# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case +# the local version of the package is different than the one used by the CI. +ENV SCRIPT /tmp/check-miri.sh ../x.py diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/check-miri.sh b/src/ci/docker/host-x86_64/x86_64-gnu-miri/check-miri.sh new file mode 100755 index 000000000000..c2a5b308b328 --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/check-miri.sh @@ -0,0 +1,62 @@ +#!/bin/sh +# ignore-tidy-linelength + +set -eu +set -x # so one can see where we are in the script + +X_PY="$1" + +# Testing Miri is a bit complicated. +# We set the GC interval to the shortest possible value (0 would be off) to increase the chance +# that bugs which only surface when the GC runs at a specific time are more likely to cause CI to fail. +# This significantly increases the runtime of our test suite, or we'd do this in PR CI too. +if [ -z "${PR_CI_JOB:-}" ]; then + MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri +else + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri +fi +# We re-run the test suite for a chance to find bugs in the intrinsic fallback bodies and in MIR +# optimizations. This can miss UB, so we only run the "pass" tests. We need to enable debug +# assertions as `-O` disables them but some tests rely on them. We also set a cfg flag so tests can +# adjust their expectations if needed. This can change the output of the tests so we ignore that, +# we only ensure that all assertions still pass. +MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \ + MIRI_SKIP_UI_CHECKS=1 \ + python3 "$X_PY" test --stage 2 src/tools/miri -- tests/pass tests/panic +# We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. +# Also cover some other targets via cross-testing, in particular all tier 1 targets. +case $HOST_TARGET in + x86_64-unknown-linux-gnu) + # Only this branch runs in PR CI. + # Fully test all main OSes, and all main architectures. + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target aarch64-apple-darwin + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target i686-pc-windows-msvc + # Only run "pass" tests for the remaining targets, which is quite a bit faster. + python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass + python3 "$X_PY" test --stage 2 src/tools/miri --target i686-unknown-linux-gnu --test-args pass + python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-unknown-linux-gnu --test-args pass + python3 "$X_PY" test --stage 2 src/tools/miri --target s390x-unknown-linux-gnu --test-args pass + ;; + x86_64-pc-windows-msvc) + # Strangely, Linux targets do not work here. cargo always says + # "error: cannot produce cdylib for ... as the target ... does not support these crate types". + # Only run "pass" tests, which is quite a bit faster. + #FIXME: Re-enable this once CI issues are fixed + # See + # For now, these tests are moved to `x86_64-msvc-ext2` in `src/ci/github-actions/jobs.yml`. + #python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-apple-darwin --test-args pass + ;; + *) + echo "FATAL: unexpected host $HOST_TARGET" + exit 1 + ;; +esac +# Also smoke-test `x.py miri`. This doesn't run any actual tests (that would take too long), +# but it ensures that the crates build properly when tested with Miri. + +#FIXME: Re-enable this for msvc once CI issues are fixed +if [ "$HOST_TARGET" != "x86_64-pc-windows-msvc" ]; then + python3 "$X_PY" miri --stage 2 library/core --test-args notest + python3 "$X_PY" miri --stage 2 library/alloc --test-args notest + python3 "$X_PY" miri --stage 2 library/std --test-args notest +fi diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 62e0451814b3..ff9fedad6567 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -30,58 +30,3 @@ cat /tmp/toolstate/toolstates.json python3 "$X_PY" test --stage 2 check-tools python3 "$X_PY" test --stage 2 src/tools/clippy python3 "$X_PY" test --stage 2 src/tools/rustfmt - -# Testing Miri is a bit more complicated. -# We set the GC interval to the shortest possible value (0 would be off) to increase the chance -# that bugs which only surface when the GC runs at a specific time are more likely to cause CI to fail. -# This significantly increases the runtime of our test suite, or we'd do this in PR CI too. -if [ -z "${PR_CI_JOB:-}" ]; then - MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri -else - python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri -fi -# We re-run the test suite for a chance to find bugs in the intrinsic fallback bodies and in MIR -# optimizations. This can miss UB, so we only run the "pass" tests. We need to enable debug -# assertions as `-O` disables them but some tests rely on them. We also set a cfg flag so tests can -# adjust their expectations if needed. This can change the output of the tests so we ignore that, -# we only ensure that all assertions still pass. -MIRIFLAGS="-Zmiri-force-intrinsic-fallback --cfg force_intrinsic_fallback -O -Zmir-opt-level=4 -Cdebug-assertions=yes" \ - MIRI_SKIP_UI_CHECKS=1 \ - python3 "$X_PY" test --stage 2 src/tools/miri -- tests/pass tests/panic -# We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. -# Also cover some other targets via cross-testing, in particular all tier 1 targets. -case $HOST_TARGET in - x86_64-unknown-linux-gnu) - # Only this branch runs in PR CI. - # Fully test all main OSes, and all main architectures. - python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target aarch64-apple-darwin - python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target i686-pc-windows-msvc - # Only run "pass" tests for the remaining targets, which is quite a bit faster. - python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass - python3 "$X_PY" test --stage 2 src/tools/miri --target i686-unknown-linux-gnu --test-args pass - python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-unknown-linux-gnu --test-args pass - python3 "$X_PY" test --stage 2 src/tools/miri --target s390x-unknown-linux-gnu --test-args pass - ;; - x86_64-pc-windows-msvc) - # Strangely, Linux targets do not work here. cargo always says - # "error: cannot produce cdylib for ... as the target ... does not support these crate types". - # Only run "pass" tests, which is quite a bit faster. - #FIXME: Re-enable this once CI issues are fixed - # See - # For now, these tests are moved to `x86_64-msvc-ext2` in `src/ci/github-actions/jobs.yml`. - #python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-apple-darwin --test-args pass - ;; - *) - echo "FATAL: unexpected host $HOST_TARGET" - exit 1 - ;; -esac -# Also smoke-test `x.py miri`. This doesn't run any actual tests (that would take too long), -# but it ensures that the crates build properly when tested with Miri. - -#FIXME: Re-enable this for msvc once CI issues are fixed -if [ "$HOST_TARGET" != "x86_64-pc-windows-msvc" ]; then - python3 "$X_PY" miri --stage 2 library/core --test-args notest - python3 "$X_PY" miri --stage 2 library/alloc --test-args notest - python3 "$X_PY" miri --stage 2 library/std --test-args notest -fi diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 43c77d1ddf7f..cb7d9c0f86f8 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -150,7 +150,9 @@ pr: DOCKER_SCRIPT: stage_2_test_set2.sh <<: *job-aarch64-linux - name: x86_64-gnu-tools - <<: *job-linux-36c-codebuild + <<: *job-linux-4c + - name: x86_64-gnu-miri + <<: *job-linux-4c # Jobs that run when you perform a try build (@bors try) # These jobs automatically inherit envs.try, to avoid repeating @@ -419,6 +421,9 @@ auto: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json <<: *job-linux-4c + - name: x86_64-gnu-miri + <<: *job-linux-4c + #################### # macOS Builders # #################### From 3d9c46e13ceaecbc5c24a6bf1c4b6a3513dbe663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 10 Jun 2025 11:09:54 +0200 Subject: [PATCH 023/356] Add jemalloc feature to Clippy --- src/tools/clippy/Cargo.toml | 1 + src/tools/clippy/src/driver.rs | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 3a76c61489e2..13cf82a062b5 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -58,6 +58,7 @@ rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } [features] integration = ["dep:tempfile"] internal = ["dep:clippy_lints_internal", "dep:tempfile"] +jemalloc = [] [package.metadata.rust-analyzer] # This package uses #[feature(rustc_private)] diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 37adb14169a3..426ba870f5f6 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -13,6 +13,11 @@ extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; +// See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs +// about jemalloc. +#[cfg(feature = "jemalloc")] +extern crate tikv_jemalloc_sys as jemalloc_sys; + use clippy_utils::sym; use rustc_interface::interface; use rustc_session::EarlyDiagCtxt; @@ -181,6 +186,36 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne #[allow(clippy::too_many_lines)] #[allow(clippy::ignored_unit_patterns)] pub fn main() { + // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs + // about jemalloc. + #[cfg(feature = "jemalloc")] + { + use std::os::raw::{c_int, c_void}; + + #[used] + static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc; + #[used] + static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int = jemalloc_sys::posix_memalign; + #[used] + static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc; + #[used] + static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc; + #[used] + static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc; + #[used] + static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free; + + #[cfg(target_os = "macos")] + { + unsafe extern "C" { + fn _rjem_je_zone_register(); + } + + #[used] + static _F7: unsafe extern "C" fn() = _rjem_je_zone_register; + } + } + let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); rustc_driver::init_rustc_env_logger(&early_dcx); From 723dae84c18f512bfc4bbc65c51465d2dea14c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 10 Jun 2025 11:19:46 +0200 Subject: [PATCH 024/356] Pass `jemalloc` feature to Clippy in bootstrap --- src/bootstrap/src/core/build_steps/tool.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 9861637d8c82..e0604135eca4 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1117,6 +1117,7 @@ macro_rules! tool_extended { tool_name: $tool_name:expr, stable: $stable:expr $( , add_bins_to_sysroot: $add_bins_to_sysroot:expr )? + $( , add_features: $add_features:expr )? $( , )? } ) => { @@ -1156,6 +1157,7 @@ macro_rules! tool_extended { $tool_name, $path, None $( .or(Some(&$add_bins_to_sysroot)) )?, + None $( .or(Some($add_features)) )?, ) } } @@ -1193,7 +1195,13 @@ fn run_tool_build_step( tool_name: &'static str, path: &'static str, add_bins_to_sysroot: Option<&[&str]>, + add_features: Option, TargetSelection, &mut Vec)>, ) -> ToolBuildResult { + let mut extra_features = Vec::new(); + if let Some(func) = add_features { + func(builder, target, &mut extra_features); + } + let ToolBuildResult { tool_path, build_compiler, target_compiler } = builder.ensure(ToolBuild { compiler, @@ -1201,7 +1209,7 @@ fn run_tool_build_step( tool: tool_name, mode: Mode::ToolRustc, path, - extra_features: vec![], + extra_features, source_type: SourceType::InTree, allow_features: "", cargo_args: vec![], @@ -1244,7 +1252,12 @@ tool_extended!(Clippy { path: "src/tools/clippy", tool_name: "clippy-driver", stable: true, - add_bins_to_sysroot: ["clippy-driver"] + add_bins_to_sysroot: ["clippy-driver"], + add_features: |builder, target, features| { + if builder.config.jemalloc(target) { + features.push("jemalloc".to_string()); + } + } }); tool_extended!(Miri { path: "src/tools/miri", From 30c48bcb55e10518e4e59a78dcab439a0b327725 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 10 Jun 2025 09:39:50 +0000 Subject: [PATCH 025/356] Use Operand::constant() in a couple of places Also reduce visibility of a function --- src/constant.rs | 2 +- src/intrinsics/llvm_x86.rs | 7 ++++--- src/intrinsics/simd.rs | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/constant.rs b/src/constant.rs index c8527c3a57df..3a62cd52a9d9 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -228,7 +228,7 @@ fn pointer_for_allocation<'tcx>( crate::pointer::Pointer::new(global_ptr) } -pub(crate) fn data_id_for_alloc_id( +fn data_id_for_alloc_id( cx: &mut ConstantCx, module: &mut dyn Module, alloc_id: AllocId, diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 615f6c47d902..37fbe4be1b0f 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -202,9 +202,10 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( }; let x = codegen_operand(fx, &x.node); let y = codegen_operand(fx, &y.node); - let kind = match &kind.node { - Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0, - Operand::Copy(_) | Operand::Move(_) => unreachable!("{kind:?}"), + let kind = if let Some(const_) = kind.node.constant() { + crate::constant::eval_mir_constant(fx, const_).0 + } else { + unreachable!("{kind:?}") }; let flt_cc = match kind diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 46a441488fa6..68ff0b622c8f 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -205,9 +205,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( // Find a way to reuse `immediate_const_vector` from `codegen_ssa` instead. let indexes = { use rustc_middle::mir::interpret::*; - let idx_const = match &idx.node { - Operand::Constant(const_) => crate::constant::eval_mir_constant(fx, const_).0, - Operand::Copy(_) | Operand::Move(_) => unreachable!("{idx:?}"), + let idx_const = if let Some(const_) = idx.node.constant() { + crate::constant::eval_mir_constant(fx, const_).0 + } else { + unreachable!("{idx:?}") }; let idx_bytes = match idx_const { From 32cb8f1537a3c0948e01cb90c850d9f60e3139ed Mon Sep 17 00:00:00 2001 From: "Deven T. Corzine" Date: Tue, 10 Jun 2025 23:50:48 -0400 Subject: [PATCH 026/356] Add trim_prefix and trim_suffix for slice and str. Implements `trim_prefix` and `trim_suffix` methods for both `slice` and `str` types which remove at most one occurrence of a prefix/suffix while always returning a string/slice (rather than Option), enabling easy method chaining. --- library/core/src/slice/mod.rs | 83 +++++++++++++++++++++++++++++++++++ library/core/src/str/mod.rs | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 4f7e14408804..bdd83a2bd33c 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2763,6 +2763,89 @@ impl [T] { None } + /// Returns a subslice with the optional prefix removed. + /// + /// If the slice starts with `prefix`, returns the subslice after the prefix. If `prefix` + /// is empty or the slice does not start with `prefix`, simply returns the original slice. + /// If `prefix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(trim_prefix_suffix)] + /// + /// let v = &[10, 40, 30]; + /// + /// // Prefix present - removes it + /// assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]); + /// assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]); + /// + /// // Prefix absent - returns original slice + /// assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]); + /// + /// let prefix : &str = "he"; + /// assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref()); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[unstable(feature = "trim_prefix_suffix", issue = "142312")] + pub fn trim_prefix + ?Sized>(&self, prefix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let prefix = prefix.as_slice(); + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return tail; + } + } + self + } + + /// Returns a subslice with the optional suffix removed. + /// + /// If the slice ends with `suffix`, returns the subslice before the suffix. If `suffix` + /// is empty or the slice does not end with `suffix`, simply returns the original slice. + /// If `suffix` is equal to the original slice, returns an empty slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(trim_prefix_suffix)] + /// + /// let v = &[10, 40, 30]; + /// + /// // Suffix present - removes it + /// assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]); + /// assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]); + /// assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]); + /// + /// // Suffix absent - returns original slice + /// assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]); + /// assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[unstable(feature = "trim_prefix_suffix", issue = "142312")] + pub fn trim_suffix + ?Sized>(&self, suffix: &P) -> &[T] + where + T: PartialEq, + { + // This function will need rewriting if and when SlicePattern becomes more sophisticated. + let suffix = suffix.as_slice(); + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return head; + } + } + self + } + /// Binary searches this slice for a given element. /// If the slice is not sorted, the returned result is unspecified and /// meaningless. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 41834793d22a..5051b2288fd2 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2426,6 +2426,83 @@ impl str { suffix.strip_suffix_of(self) } + /// Returns a string slice with the optional prefix removed. + /// + /// If the string starts with the pattern `prefix`, returns the substring after the prefix. + /// Unlike [`strip_prefix`], this method always returns `&str` for easy method chaining, + /// instead of returning [`Option<&str>`]. + /// + /// If the string does not start with `prefix`, returns the original string unchanged. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// [`strip_prefix`]: Self::strip_prefix + /// + /// # Examples + /// + /// ``` + /// #![feature(trim_prefix_suffix)] + /// + /// // Prefix present - removes it + /// assert_eq!("foo:bar".trim_prefix("foo:"), "bar"); + /// assert_eq!("foofoo".trim_prefix("foo"), "foo"); + /// + /// // Prefix absent - returns original string + /// assert_eq!("foo:bar".trim_prefix("bar"), "foo:bar"); + /// + /// // Method chaining example + /// assert_eq!("".trim_prefix('<').trim_suffix('>'), "https://example.com/"); + /// ``` + #[must_use = "this returns the remaining substring as a new slice, \ + without modifying the original"] + #[unstable(feature = "trim_prefix_suffix", issue = "142312")] + pub fn trim_prefix(&self, prefix: P) -> &str { + prefix.strip_prefix_of(self).unwrap_or(self) + } + + /// Returns a string slice with the optional suffix removed. + /// + /// If the string ends with the pattern `suffix`, returns the substring before the suffix. + /// Unlike [`strip_suffix`], this method always returns `&str` for easy method chaining, + /// instead of returning [`Option<&str>`]. + /// + /// If the string does not end with `suffix`, returns the original string unchanged. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// [`strip_suffix`]: Self::strip_suffix + /// + /// # Examples + /// + /// ``` + /// #![feature(trim_prefix_suffix)] + /// + /// // Suffix present - removes it + /// assert_eq!("bar:foo".trim_suffix(":foo"), "bar"); + /// assert_eq!("foofoo".trim_suffix("foo"), "foo"); + /// + /// // Suffix absent - returns original string + /// assert_eq!("bar:foo".trim_suffix("bar"), "bar:foo"); + /// + /// // Method chaining example + /// assert_eq!("".trim_prefix('<').trim_suffix('>'), "https://example.com/"); + /// ``` + #[must_use = "this returns the remaining substring as a new slice, \ + without modifying the original"] + #[unstable(feature = "trim_prefix_suffix", issue = "142312")] + pub fn trim_suffix(&self, suffix: P) -> &str + where + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, + { + suffix.strip_suffix_of(self).unwrap_or(self) + } + /// Returns a string slice with all suffixes that match a pattern /// repeatedly removed. /// From 35c5144394c1b93784867d330f694fa7c8f480e3 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 11 Jun 2025 10:43:59 -0700 Subject: [PATCH 027/356] Move rayon-core to rustc_thread_pool files as is This commit literally copied the directory rayon-core from revision `5fadf44`. Link: https://github.com/rust-lang/rustc-rayon/tree/5fadf44/rayon-core --- compiler/rustc_thread_pool/Cargo.toml | 56 + compiler/rustc_thread_pool/LICENSE-APACHE | 201 ++++ compiler/rustc_thread_pool/LICENSE-MIT | 25 + compiler/rustc_thread_pool/README.md | 13 + .../rustc_thread_pool/src/broadcast/mod.rs | 151 +++ .../rustc_thread_pool/src/broadcast/test.rs | 263 +++++ .../rustc_thread_pool/src/compile_fail/mod.rs | 7 + .../src/compile_fail/quicksort_race1.rs | 28 + .../src/compile_fail/quicksort_race2.rs | 28 + .../src/compile_fail/quicksort_race3.rs | 28 + .../src/compile_fail/rc_return.rs | 17 + .../src/compile_fail/rc_upvar.rs | 9 + .../src/compile_fail/scope_join_bad.rs | 24 + compiler/rustc_thread_pool/src/job.rs | 277 +++++ compiler/rustc_thread_pool/src/join/mod.rs | 202 ++++ compiler/rustc_thread_pool/src/join/test.rs | 150 +++ compiler/rustc_thread_pool/src/latch.rs | 459 ++++++++ compiler/rustc_thread_pool/src/lib.rs | 922 +++++++++++++++ compiler/rustc_thread_pool/src/private.rs | 26 + compiler/rustc_thread_pool/src/registry.rs | 1048 +++++++++++++++++ compiler/rustc_thread_pool/src/scope/mod.rs | 783 ++++++++++++ compiler/rustc_thread_pool/src/scope/test.rs | 622 ++++++++++ .../rustc_thread_pool/src/sleep/README.md | 252 ++++ .../rustc_thread_pool/src/sleep/counters.rs | 277 +++++ compiler/rustc_thread_pool/src/sleep/mod.rs | 392 ++++++ compiler/rustc_thread_pool/src/spawn/mod.rs | 164 +++ compiler/rustc_thread_pool/src/spawn/test.rs | 255 ++++ compiler/rustc_thread_pool/src/test.rs | 200 ++++ .../rustc_thread_pool/src/thread_pool/mod.rs | 514 ++++++++ .../rustc_thread_pool/src/thread_pool/test.rs | 418 +++++++ compiler/rustc_thread_pool/src/tlv.rs | 31 + compiler/rustc_thread_pool/src/unwind.rs | 31 + .../rustc_thread_pool/src/worker_local.rs | 78 ++ .../tests/double_init_fail.rs | 15 + .../tests/init_zero_threads.rs | 10 + .../rustc_thread_pool/tests/scope_join.rs | 45 + .../tests/scoped_threadpool.rs | 99 ++ .../rustc_thread_pool/tests/simple_panic.rs | 7 + .../tests/stack_overflow_crash.rs | 98 ++ 39 files changed, 8225 insertions(+) create mode 100644 compiler/rustc_thread_pool/Cargo.toml create mode 100644 compiler/rustc_thread_pool/LICENSE-APACHE create mode 100644 compiler/rustc_thread_pool/LICENSE-MIT create mode 100644 compiler/rustc_thread_pool/README.md create mode 100644 compiler/rustc_thread_pool/src/broadcast/mod.rs create mode 100644 compiler/rustc_thread_pool/src/broadcast/test.rs create mode 100644 compiler/rustc_thread_pool/src/compile_fail/mod.rs create mode 100644 compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs create mode 100644 compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs create mode 100644 compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs create mode 100644 compiler/rustc_thread_pool/src/compile_fail/rc_return.rs create mode 100644 compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs create mode 100644 compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs create mode 100644 compiler/rustc_thread_pool/src/job.rs create mode 100644 compiler/rustc_thread_pool/src/join/mod.rs create mode 100644 compiler/rustc_thread_pool/src/join/test.rs create mode 100644 compiler/rustc_thread_pool/src/latch.rs create mode 100644 compiler/rustc_thread_pool/src/lib.rs create mode 100644 compiler/rustc_thread_pool/src/private.rs create mode 100644 compiler/rustc_thread_pool/src/registry.rs create mode 100644 compiler/rustc_thread_pool/src/scope/mod.rs create mode 100644 compiler/rustc_thread_pool/src/scope/test.rs create mode 100644 compiler/rustc_thread_pool/src/sleep/README.md create mode 100644 compiler/rustc_thread_pool/src/sleep/counters.rs create mode 100644 compiler/rustc_thread_pool/src/sleep/mod.rs create mode 100644 compiler/rustc_thread_pool/src/spawn/mod.rs create mode 100644 compiler/rustc_thread_pool/src/spawn/test.rs create mode 100644 compiler/rustc_thread_pool/src/test.rs create mode 100644 compiler/rustc_thread_pool/src/thread_pool/mod.rs create mode 100644 compiler/rustc_thread_pool/src/thread_pool/test.rs create mode 100644 compiler/rustc_thread_pool/src/tlv.rs create mode 100644 compiler/rustc_thread_pool/src/unwind.rs create mode 100644 compiler/rustc_thread_pool/src/worker_local.rs create mode 100644 compiler/rustc_thread_pool/tests/double_init_fail.rs create mode 100644 compiler/rustc_thread_pool/tests/init_zero_threads.rs create mode 100644 compiler/rustc_thread_pool/tests/scope_join.rs create mode 100644 compiler/rustc_thread_pool/tests/scoped_threadpool.rs create mode 100644 compiler/rustc_thread_pool/tests/simple_panic.rs create mode 100644 compiler/rustc_thread_pool/tests/stack_overflow_crash.rs diff --git a/compiler/rustc_thread_pool/Cargo.toml b/compiler/rustc_thread_pool/Cargo.toml new file mode 100644 index 000000000000..f7a3d1306b43 --- /dev/null +++ b/compiler/rustc_thread_pool/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "rustc-rayon-core" +version = "0.5.1" +authors = ["Niko Matsakis ", + "Josh Stone "] +description = "Core APIs for Rayon - fork for rustc" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rustc-rayon" +documentation = "https://docs.rs/rustc-rayon-core/" +rust-version = "1.63" +edition = "2021" +readme = "README.md" +keywords = ["parallel", "thread", "concurrency", "join", "performance"] +categories = ["concurrency"] + +[lib] +name = "rayon_core" + +# Some dependencies may not be their latest version, in order to support older rustc. +[dependencies] +crossbeam-deque = "0.8.1" +crossbeam-utils = "0.8.0" + +[dev-dependencies] +rand = "0.9" +rand_xorshift = "0.4" +scoped-tls = "1.0" + +[target.'cfg(unix)'.dev-dependencies] +libc = "0.2" + +[[test]] +name = "stack_overflow_crash" +path = "tests/stack_overflow_crash.rs" + +# NB: having one [[test]] manually defined means we need to declare them all + +[[test]] +name = "double_init_fail" +path = "tests/double_init_fail.rs" + +[[test]] +name = "init_zero_threads" +path = "tests/init_zero_threads.rs" + +[[test]] +name = "scope_join" +path = "tests/scope_join.rs" + +[[test]] +name = "simple_panic" +path = "tests/simple_panic.rs" + +[[test]] +name = "scoped_threadpool" +path = "tests/scoped_threadpool.rs" diff --git a/compiler/rustc_thread_pool/LICENSE-APACHE b/compiler/rustc_thread_pool/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/compiler/rustc_thread_pool/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/compiler/rustc_thread_pool/LICENSE-MIT b/compiler/rustc_thread_pool/LICENSE-MIT new file mode 100644 index 000000000000..25597d5838fa --- /dev/null +++ b/compiler/rustc_thread_pool/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2010 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/compiler/rustc_thread_pool/README.md b/compiler/rustc_thread_pool/README.md new file mode 100644 index 000000000000..5b8714f5df48 --- /dev/null +++ b/compiler/rustc_thread_pool/README.md @@ -0,0 +1,13 @@ +Note: This is an unstable fork made for use in rustc + +Rayon-core represents the "core, stable" APIs of Rayon: join, scope, and so forth, as well as the ability to create custom thread-pools with ThreadPool. + +Maybe worth mentioning: users are not necessarily intended to directly access rayon-core; all its APIs are mirrored in the rayon crate. To that end, the examples in the docs use rayon::join and so forth rather than rayon_core::join. + +rayon-core aims to never, or almost never, have a breaking change to its API, because each revision of rayon-core also houses the global thread-pool (and hence if you have two simultaneous versions of rayon-core, you have two thread-pools). + +Please see [Rayon Docs] for details about using Rayon. + +[Rayon Docs]: https://docs.rs/rayon/ + +Rayon-core currently requires `rustc 1.63.0` or greater. diff --git a/compiler/rustc_thread_pool/src/broadcast/mod.rs b/compiler/rustc_thread_pool/src/broadcast/mod.rs new file mode 100644 index 000000000000..442891f2d287 --- /dev/null +++ b/compiler/rustc_thread_pool/src/broadcast/mod.rs @@ -0,0 +1,151 @@ +use crate::job::{ArcJob, StackJob}; +use crate::latch::{CountLatch, LatchRef}; +use crate::registry::{Registry, WorkerThread}; +use std::fmt; +use std::marker::PhantomData; +use std::sync::Arc; + +mod test; + +/// Executes `op` within every thread in the current threadpool. If this is +/// called from a non-Rayon thread, it will execute in the global threadpool. +/// Any attempts to use `join`, `scope`, or parallel iterators will then operate +/// within that threadpool. When the call has completed on each thread, returns +/// a vector containing all of their return values. +/// +/// For more information, see the [`ThreadPool::broadcast()`][m] method. +/// +/// [m]: struct.ThreadPool.html#method.broadcast +pub fn broadcast(op: OP) -> Vec +where + OP: Fn(BroadcastContext<'_>) -> R + Sync, + R: Send, +{ + // We assert that current registry has not terminated. + unsafe { broadcast_in(op, &Registry::current()) } +} + +/// Spawns an asynchronous task on every thread in this thread-pool. This task +/// will run in the implicit, global scope, which means that it may outlast the +/// current stack frame -- therefore, it cannot capture any references onto the +/// stack (you will likely need a `move` closure). +/// +/// For more information, see the [`ThreadPool::spawn_broadcast()`][m] method. +/// +/// [m]: struct.ThreadPool.html#method.spawn_broadcast +pub fn spawn_broadcast(op: OP) +where + OP: Fn(BroadcastContext<'_>) + Send + Sync + 'static, +{ + // We assert that current registry has not terminated. + unsafe { spawn_broadcast_in(op, &Registry::current()) } +} + +/// Provides context to a closure called by `broadcast`. +pub struct BroadcastContext<'a> { + worker: &'a WorkerThread, + + /// Make sure to prevent auto-traits like `Send` and `Sync`. + _marker: PhantomData<&'a mut dyn Fn()>, +} + +impl<'a> BroadcastContext<'a> { + pub(super) fn with(f: impl FnOnce(BroadcastContext<'_>) -> R) -> R { + let worker_thread = WorkerThread::current(); + assert!(!worker_thread.is_null()); + f(BroadcastContext { + worker: unsafe { &*worker_thread }, + _marker: PhantomData, + }) + } + + /// Our index amongst the broadcast threads (ranges from `0..self.num_threads()`). + #[inline] + pub fn index(&self) -> usize { + self.worker.index() + } + + /// The number of threads receiving the broadcast in the thread pool. + /// + /// # Future compatibility note + /// + /// Future versions of Rayon might vary the number of threads over time, but + /// this method will always return the number of threads which are actually + /// receiving your particular `broadcast` call. + #[inline] + pub fn num_threads(&self) -> usize { + self.worker.registry().num_threads() + } +} + +impl<'a> fmt::Debug for BroadcastContext<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("BroadcastContext") + .field("index", &self.index()) + .field("num_threads", &self.num_threads()) + .field("pool_id", &self.worker.registry().id()) + .finish() + } +} + +/// Execute `op` on every thread in the pool. It will be executed on each +/// thread when they have nothing else to do locally, before they try to +/// steal work from other threads. This function will not return until all +/// threads have completed the `op`. +/// +/// Unsafe because `registry` must not yet have terminated. +pub(super) unsafe fn broadcast_in(op: OP, registry: &Arc) -> Vec +where + OP: Fn(BroadcastContext<'_>) -> R + Sync, + R: Send, +{ + let f = move |injected: bool| { + debug_assert!(injected); + BroadcastContext::with(&op) + }; + + let n_threads = registry.num_threads(); + let current_thread = WorkerThread::current().as_ref(); + let tlv = crate::tlv::get(); + let latch = CountLatch::with_count(n_threads, current_thread); + let jobs: Vec<_> = (0..n_threads) + .map(|_| StackJob::new(tlv, &f, LatchRef::new(&latch))) + .collect(); + let job_refs = jobs.iter().map(|job| job.as_job_ref()); + + registry.inject_broadcast(job_refs); + + // Wait for all jobs to complete, then collect the results, maybe propagating a panic. + latch.wait(current_thread); + jobs.into_iter().map(|job| job.into_result()).collect() +} + +/// Execute `op` on every thread in the pool. It will be executed on each +/// thread when they have nothing else to do locally, before they try to +/// steal work from other threads. This function returns immediately after +/// injecting the jobs. +/// +/// Unsafe because `registry` must not yet have terminated. +pub(super) unsafe fn spawn_broadcast_in(op: OP, registry: &Arc) +where + OP: Fn(BroadcastContext<'_>) + Send + Sync + 'static, +{ + let job = ArcJob::new({ + let registry = Arc::clone(registry); + move || { + registry.catch_unwind(|| BroadcastContext::with(&op)); + registry.terminate(); // (*) permit registry to terminate now + } + }); + + let n_threads = registry.num_threads(); + let job_refs = (0..n_threads).map(|_| { + // Ensure that registry cannot terminate until this job has executed + // on each thread. This ref is decremented at the (*) above. + registry.increment_terminate_count(); + + ArcJob::as_static_job_ref(&job) + }); + + registry.inject_broadcast(job_refs); +} diff --git a/compiler/rustc_thread_pool/src/broadcast/test.rs b/compiler/rustc_thread_pool/src/broadcast/test.rs new file mode 100644 index 000000000000..00ab4ad7fe41 --- /dev/null +++ b/compiler/rustc_thread_pool/src/broadcast/test.rs @@ -0,0 +1,263 @@ +#![cfg(test)] + +use crate::ThreadPoolBuilder; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::mpsc::channel; +use std::sync::Arc; +use std::{thread, time}; + +#[test] +fn broadcast_global() { + let v = crate::broadcast(|ctx| ctx.index()); + assert!(v.into_iter().eq(0..crate::current_num_threads())); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_broadcast_global() { + let (tx, rx) = channel(); + crate::spawn_broadcast(move |ctx| tx.send(ctx.index()).unwrap()); + + let mut v: Vec<_> = rx.into_iter().collect(); + v.sort_unstable(); + assert!(v.into_iter().eq(0..crate::current_num_threads())); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn broadcast_pool() { + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + let v = pool.broadcast(|ctx| ctx.index()); + assert!(v.into_iter().eq(0..7)); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_broadcast_pool() { + let (tx, rx) = channel(); + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + pool.spawn_broadcast(move |ctx| tx.send(ctx.index()).unwrap()); + + let mut v: Vec<_> = rx.into_iter().collect(); + v.sort_unstable(); + assert!(v.into_iter().eq(0..7)); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn broadcast_self() { + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + let v = pool.install(|| crate::broadcast(|ctx| ctx.index())); + assert!(v.into_iter().eq(0..7)); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_broadcast_self() { + let (tx, rx) = channel(); + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + pool.spawn(|| crate::spawn_broadcast(move |ctx| tx.send(ctx.index()).unwrap())); + + let mut v: Vec<_> = rx.into_iter().collect(); + v.sort_unstable(); + assert!(v.into_iter().eq(0..7)); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn broadcast_mutual() { + let count = AtomicUsize::new(0); + let pool1 = ThreadPoolBuilder::new().num_threads(3).build().unwrap(); + let pool2 = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + pool1.install(|| { + pool2.broadcast(|_| { + pool1.broadcast(|_| { + count.fetch_add(1, Ordering::Relaxed); + }) + }) + }); + assert_eq!(count.into_inner(), 3 * 7); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_broadcast_mutual() { + let (tx, rx) = channel(); + let pool1 = Arc::new(ThreadPoolBuilder::new().num_threads(3).build().unwrap()); + let pool2 = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + pool1.spawn({ + let pool1 = Arc::clone(&pool1); + move || { + pool2.spawn_broadcast(move |_| { + let tx = tx.clone(); + pool1.spawn_broadcast(move |_| tx.send(()).unwrap()) + }) + } + }); + assert_eq!(rx.into_iter().count(), 3 * 7); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn broadcast_mutual_sleepy() { + let count = AtomicUsize::new(0); + let pool1 = ThreadPoolBuilder::new().num_threads(3).build().unwrap(); + let pool2 = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + pool1.install(|| { + thread::sleep(time::Duration::from_secs(1)); + pool2.broadcast(|_| { + thread::sleep(time::Duration::from_secs(1)); + pool1.broadcast(|_| { + thread::sleep(time::Duration::from_millis(100)); + count.fetch_add(1, Ordering::Relaxed); + }) + }) + }); + assert_eq!(count.into_inner(), 3 * 7); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_broadcast_mutual_sleepy() { + let (tx, rx) = channel(); + let pool1 = Arc::new(ThreadPoolBuilder::new().num_threads(3).build().unwrap()); + let pool2 = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + pool1.spawn({ + let pool1 = Arc::clone(&pool1); + move || { + thread::sleep(time::Duration::from_secs(1)); + pool2.spawn_broadcast(move |_| { + let tx = tx.clone(); + thread::sleep(time::Duration::from_secs(1)); + pool1.spawn_broadcast(move |_| { + thread::sleep(time::Duration::from_millis(100)); + tx.send(()).unwrap(); + }) + }) + } + }); + assert_eq!(rx.into_iter().count(), 3 * 7); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn broadcast_panic_one() { + let count = AtomicUsize::new(0); + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + let result = crate::unwind::halt_unwinding(|| { + pool.broadcast(|ctx| { + count.fetch_add(1, Ordering::Relaxed); + if ctx.index() == 3 { + panic!("Hello, world!"); + } + }) + }); + assert_eq!(count.into_inner(), 7); + assert!(result.is_err(), "broadcast panic should propagate!"); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn spawn_broadcast_panic_one() { + let (tx, rx) = channel(); + let (panic_tx, panic_rx) = channel(); + let pool = ThreadPoolBuilder::new() + .num_threads(7) + .panic_handler(move |e| panic_tx.send(e).unwrap()) + .build() + .unwrap(); + pool.spawn_broadcast(move |ctx| { + tx.send(()).unwrap(); + if ctx.index() == 3 { + panic!("Hello, world!"); + } + }); + drop(pool); // including panic_tx + assert_eq!(rx.into_iter().count(), 7); + assert_eq!(panic_rx.into_iter().count(), 1); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn broadcast_panic_many() { + let count = AtomicUsize::new(0); + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + let result = crate::unwind::halt_unwinding(|| { + pool.broadcast(|ctx| { + count.fetch_add(1, Ordering::Relaxed); + if ctx.index() % 2 == 0 { + panic!("Hello, world!"); + } + }) + }); + assert_eq!(count.into_inner(), 7); + assert!(result.is_err(), "broadcast panic should propagate!"); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn spawn_broadcast_panic_many() { + let (tx, rx) = channel(); + let (panic_tx, panic_rx) = channel(); + let pool = ThreadPoolBuilder::new() + .num_threads(7) + .panic_handler(move |e| panic_tx.send(e).unwrap()) + .build() + .unwrap(); + pool.spawn_broadcast(move |ctx| { + tx.send(()).unwrap(); + if ctx.index() % 2 == 0 { + panic!("Hello, world!"); + } + }); + drop(pool); // including panic_tx + assert_eq!(rx.into_iter().count(), 7); + assert_eq!(panic_rx.into_iter().count(), 4); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn broadcast_sleep_race() { + let test_duration = time::Duration::from_secs(1); + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + let start = time::Instant::now(); + while start.elapsed() < test_duration { + pool.broadcast(|ctx| { + // A slight spread of sleep duration increases the chance that one + // of the threads will race in the pool's idle sleep afterward. + thread::sleep(time::Duration::from_micros(ctx.index() as u64)); + }); + } +} + +#[test] +fn broadcast_after_spawn_broadcast() { + let (tx, rx) = channel(); + + // Queue a non-blocking spawn_broadcast. + crate::spawn_broadcast(move |ctx| tx.send(ctx.index()).unwrap()); + + // This blocking broadcast runs after all prior broadcasts. + crate::broadcast(|_| {}); + + // The spawn_broadcast **must** have run by now on all threads. + let mut v: Vec<_> = rx.try_iter().collect(); + v.sort_unstable(); + assert!(v.into_iter().eq(0..crate::current_num_threads())); +} + +#[test] +fn broadcast_after_spawn() { + let (tx, rx) = channel(); + + // Queue a regular spawn on a thread-local deque. + crate::registry::in_worker(move |_, _| { + crate::spawn(move || tx.send(22).unwrap()); + }); + + // Broadcast runs after the local deque is empty. + crate::broadcast(|_| {}); + + // The spawn **must** have run by now. + assert_eq!(22, rx.try_recv().unwrap()); +} diff --git a/compiler/rustc_thread_pool/src/compile_fail/mod.rs b/compiler/rustc_thread_pool/src/compile_fail/mod.rs new file mode 100644 index 000000000000..f2ec646a4d3d --- /dev/null +++ b/compiler/rustc_thread_pool/src/compile_fail/mod.rs @@ -0,0 +1,7 @@ +// These modules contain `compile_fail` doc tests. +mod quicksort_race1; +mod quicksort_race2; +mod quicksort_race3; +mod rc_return; +mod rc_upvar; +mod scope_join_bad; diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs new file mode 100644 index 000000000000..5615033895a0 --- /dev/null +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs @@ -0,0 +1,28 @@ +/*! ```compile_fail,E0524 + +fn quick_sort(v: &mut [T]) { + if v.len() <= 1 { + return; + } + + let mid = partition(v); + let (lo, _hi) = v.split_at_mut(mid); + rayon_core::join(|| quick_sort(lo), || quick_sort(lo)); //~ ERROR +} + +fn partition(v: &mut [T]) -> usize { + let pivot = v.len() - 1; + let mut i = 0; + for j in 0..pivot { + if v[j] <= v[pivot] { + v.swap(i, j); + i += 1; + } + } + v.swap(i, pivot); + i +} + +fn main() { } + +``` */ diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs new file mode 100644 index 000000000000..020589c29a84 --- /dev/null +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs @@ -0,0 +1,28 @@ +/*! ```compile_fail,E0500 + +fn quick_sort(v: &mut [T]) { + if v.len() <= 1 { + return; + } + + let mid = partition(v); + let (lo, _hi) = v.split_at_mut(mid); + rayon_core::join(|| quick_sort(lo), || quick_sort(v)); //~ ERROR +} + +fn partition(v: &mut [T]) -> usize { + let pivot = v.len() - 1; + let mut i = 0; + for j in 0..pivot { + if v[j] <= v[pivot] { + v.swap(i, j); + i += 1; + } + } + v.swap(i, pivot); + i +} + +fn main() { } + +``` */ diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs new file mode 100644 index 000000000000..16fbf3b824d3 --- /dev/null +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs @@ -0,0 +1,28 @@ +/*! ```compile_fail,E0524 + +fn quick_sort(v: &mut [T]) { + if v.len() <= 1 { + return; + } + + let mid = partition(v); + let (_lo, hi) = v.split_at_mut(mid); + rayon_core::join(|| quick_sort(hi), || quick_sort(hi)); //~ ERROR +} + +fn partition(v: &mut [T]) -> usize { + let pivot = v.len() - 1; + let mut i = 0; + for j in 0..pivot { + if v[j] <= v[pivot] { + v.swap(i, j); + i += 1; + } + } + v.swap(i, pivot); + i +} + +fn main() { } + +``` */ diff --git a/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs b/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs new file mode 100644 index 000000000000..93e3a603849a --- /dev/null +++ b/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs @@ -0,0 +1,17 @@ +/** ```compile_fail,E0277 + +use std::rc::Rc; + +rayon_core::join(|| Rc::new(22), || ()); //~ ERROR + +``` */ +mod left {} + +/** ```compile_fail,E0277 + +use std::rc::Rc; + +rayon_core::join(|| (), || Rc::new(23)); //~ ERROR + +``` */ +mod right {} diff --git a/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs b/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs new file mode 100644 index 000000000000..d8aebcfcbf24 --- /dev/null +++ b/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs @@ -0,0 +1,9 @@ +/*! ```compile_fail,E0277 + +use std::rc::Rc; + +let r = Rc::new(22); +rayon_core::join(|| r.clone(), || r.clone()); +//~^ ERROR + +``` */ diff --git a/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs b/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs new file mode 100644 index 000000000000..75e4c5ca6c0d --- /dev/null +++ b/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs @@ -0,0 +1,24 @@ +/*! ```compile_fail,E0373 + +fn bad_scope(f: F) + where F: FnOnce(&i32) + Send, +{ + rayon_core::scope(|s| { + let x = 22; + s.spawn(|_| f(&x)); //~ ERROR `x` does not live long enough + }); +} + +fn good_scope(f: F) + where F: FnOnce(&i32) + Send, +{ + let x = 22; + rayon_core::scope(|s| { + s.spawn(|_| f(&x)); + }); +} + +fn main() { +} + +``` */ diff --git a/compiler/rustc_thread_pool/src/job.rs b/compiler/rustc_thread_pool/src/job.rs new file mode 100644 index 000000000000..394c7576b2cb --- /dev/null +++ b/compiler/rustc_thread_pool/src/job.rs @@ -0,0 +1,277 @@ +use crate::latch::Latch; +use crate::tlv; +use crate::tlv::Tlv; +use crate::unwind; +use crossbeam_deque::{Injector, Steal}; +use std::any::Any; +use std::cell::UnsafeCell; +use std::mem; +use std::sync::Arc; + +pub(super) enum JobResult { + None, + Ok(T), + Panic(Box), +} + +/// A `Job` is used to advertise work for other threads that they may +/// want to steal. In accordance with time honored tradition, jobs are +/// arranged in a deque, so that thieves can take from the top of the +/// deque while the main worker manages the bottom of the deque. This +/// deque is managed by the `thread_pool` module. +pub(super) trait Job { + /// Unsafe: this may be called from a different thread than the one + /// which scheduled the job, so the implementer must ensure the + /// appropriate traits are met, whether `Send`, `Sync`, or both. + unsafe fn execute(this: *const ()); +} + +/// Effectively a Job trait object. Each JobRef **must** be executed +/// exactly once, or else data may leak. +/// +/// Internally, we store the job's data in a `*const ()` pointer. The +/// true type is something like `*const StackJob<...>`, but we hide +/// it. We also carry the "execute fn" from the `Job` trait. +pub(super) struct JobRef { + pointer: *const (), + execute_fn: unsafe fn(*const ()), +} + +unsafe impl Send for JobRef {} +unsafe impl Sync for JobRef {} + +impl JobRef { + /// Unsafe: caller asserts that `data` will remain valid until the + /// job is executed. + pub(super) unsafe fn new(data: *const T) -> JobRef + where + T: Job, + { + // erase types: + JobRef { + pointer: data as *const (), + execute_fn: ::execute, + } + } + + /// Returns an opaque handle that can be saved and compared, + /// without making `JobRef` itself `Copy + Eq`. + #[inline] + pub(super) fn id(&self) -> impl Eq { + (self.pointer, self.execute_fn) + } + + #[inline] + pub(super) unsafe fn execute(self) { + (self.execute_fn)(self.pointer) + } +} + +/// A job that will be owned by a stack slot. This means that when it +/// executes it need not free any heap data, the cleanup occurs when +/// the stack frame is later popped. The function parameter indicates +/// `true` if the job was stolen -- executed on a different thread. +pub(super) struct StackJob +where + L: Latch + Sync, + F: FnOnce(bool) -> R + Send, + R: Send, +{ + pub(super) latch: L, + func: UnsafeCell>, + result: UnsafeCell>, + tlv: Tlv, +} + +impl StackJob +where + L: Latch + Sync, + F: FnOnce(bool) -> R + Send, + R: Send, +{ + pub(super) fn new(tlv: Tlv, func: F, latch: L) -> StackJob { + StackJob { + latch, + func: UnsafeCell::new(Some(func)), + result: UnsafeCell::new(JobResult::None), + tlv, + } + } + + pub(super) unsafe fn as_job_ref(&self) -> JobRef { + JobRef::new(self) + } + + pub(super) unsafe fn run_inline(self, stolen: bool) -> R { + self.func.into_inner().unwrap()(stolen) + } + + pub(super) unsafe fn into_result(self) -> R { + self.result.into_inner().into_return_value() + } +} + +impl Job for StackJob +where + L: Latch + Sync, + F: FnOnce(bool) -> R + Send, + R: Send, +{ + unsafe fn execute(this: *const ()) { + let this = &*(this as *const Self); + tlv::set(this.tlv); + let abort = unwind::AbortIfPanic; + let func = (*this.func.get()).take().unwrap(); + (*this.result.get()) = JobResult::call(func); + Latch::set(&this.latch); + mem::forget(abort); + } +} + +/// Represents a job stored in the heap. Used to implement +/// `scope`. Unlike `StackJob`, when executed, `HeapJob` simply +/// invokes a closure, which then triggers the appropriate logic to +/// signal that the job executed. +/// +/// (Probably `StackJob` should be refactored in a similar fashion.) +pub(super) struct HeapJob +where + BODY: FnOnce() + Send, +{ + job: BODY, + tlv: Tlv, +} + +impl HeapJob +where + BODY: FnOnce() + Send, +{ + pub(super) fn new(tlv: Tlv, job: BODY) -> Box { + Box::new(HeapJob { job, tlv }) + } + + /// Creates a `JobRef` from this job -- note that this hides all + /// lifetimes, so it is up to you to ensure that this JobRef + /// doesn't outlive any data that it closes over. + pub(super) unsafe fn into_job_ref(self: Box) -> JobRef { + JobRef::new(Box::into_raw(self)) + } + + /// Creates a static `JobRef` from this job. + pub(super) fn into_static_job_ref(self: Box) -> JobRef + where + BODY: 'static, + { + unsafe { self.into_job_ref() } + } +} + +impl Job for HeapJob +where + BODY: FnOnce() + Send, +{ + unsafe fn execute(this: *const ()) { + let this = Box::from_raw(this as *mut Self); + tlv::set(this.tlv); + (this.job)(); + } +} + +/// Represents a job stored in an `Arc` -- like `HeapJob`, but may +/// be turned into multiple `JobRef`s and called multiple times. +pub(super) struct ArcJob +where + BODY: Fn() + Send + Sync, +{ + job: BODY, +} + +impl ArcJob +where + BODY: Fn() + Send + Sync, +{ + pub(super) fn new(job: BODY) -> Arc { + Arc::new(ArcJob { job }) + } + + /// Creates a `JobRef` from this job -- note that this hides all + /// lifetimes, so it is up to you to ensure that this JobRef + /// doesn't outlive any data that it closes over. + pub(super) unsafe fn as_job_ref(this: &Arc) -> JobRef { + JobRef::new(Arc::into_raw(Arc::clone(this))) + } + + /// Creates a static `JobRef` from this job. + pub(super) fn as_static_job_ref(this: &Arc) -> JobRef + where + BODY: 'static, + { + unsafe { Self::as_job_ref(this) } + } +} + +impl Job for ArcJob +where + BODY: Fn() + Send + Sync, +{ + unsafe fn execute(this: *const ()) { + let this = Arc::from_raw(this as *mut Self); + (this.job)(); + } +} + +impl JobResult { + fn call(func: impl FnOnce(bool) -> T) -> Self { + match unwind::halt_unwinding(|| func(true)) { + Ok(x) => JobResult::Ok(x), + Err(x) => JobResult::Panic(x), + } + } + + /// Convert the `JobResult` for a job that has finished (and hence + /// its JobResult is populated) into its return value. + /// + /// NB. This will panic if the job panicked. + pub(super) fn into_return_value(self) -> T { + match self { + JobResult::None => unreachable!(), + JobResult::Ok(x) => x, + JobResult::Panic(x) => unwind::resume_unwinding(x), + } + } +} + +/// Indirect queue to provide FIFO job priority. +pub(super) struct JobFifo { + inner: Injector, +} + +impl JobFifo { + pub(super) fn new() -> Self { + JobFifo { + inner: Injector::new(), + } + } + + pub(super) unsafe fn push(&self, job_ref: JobRef) -> JobRef { + // A little indirection ensures that spawns are always prioritized in FIFO order. The + // jobs in a thread's deque may be popped from the back (LIFO) or stolen from the front + // (FIFO), but either way they will end up popping from the front of this queue. + self.inner.push(job_ref); + JobRef::new(self) + } +} + +impl Job for JobFifo { + unsafe fn execute(this: *const ()) { + // We "execute" a queue by executing its first job, FIFO. + let this = &*(this as *const Self); + loop { + match this.inner.steal() { + Steal::Success(job_ref) => break job_ref.execute(), + Steal::Empty => panic!("FIFO is empty"), + Steal::Retry => {} + } + } + } +} diff --git a/compiler/rustc_thread_pool/src/join/mod.rs b/compiler/rustc_thread_pool/src/join/mod.rs new file mode 100644 index 000000000000..032eec9c4c84 --- /dev/null +++ b/compiler/rustc_thread_pool/src/join/mod.rs @@ -0,0 +1,202 @@ +use crate::job::StackJob; +use crate::latch::SpinLatch; +use crate::registry::{self, WorkerThread}; +use crate::tlv::{self, Tlv}; +use crate::unwind; +use std::any::Any; + +use crate::FnContext; + +#[cfg(test)] +mod test; + +/// Takes two closures and *potentially* runs them in parallel. It +/// returns a pair of the results from those closures. +/// +/// Conceptually, calling `join()` is similar to spawning two threads, +/// one executing each of the two closures. However, the +/// implementation is quite different and incurs very low +/// overhead. The underlying technique is called "work stealing": the +/// Rayon runtime uses a fixed pool of worker threads and attempts to +/// only execute code in parallel when there are idle CPUs to handle +/// it. +/// +/// When `join` is called from outside the thread pool, the calling +/// thread will block while the closures execute in the pool. When +/// `join` is called within the pool, the calling thread still actively +/// participates in the thread pool. It will begin by executing closure +/// A (on the current thread). While it is doing that, it will advertise +/// closure B as being available for other threads to execute. Once closure A +/// has completed, the current thread will try to execute closure B; +/// if however closure B has been stolen, then it will look for other work +/// while waiting for the thief to fully execute closure B. (This is the +/// typical work-stealing strategy). +/// +/// # Examples +/// +/// This example uses join to perform a quick-sort (note this is not a +/// particularly optimized implementation: if you **actually** want to +/// sort for real, you should prefer [the `par_sort` method] offered +/// by Rayon). +/// +/// [the `par_sort` method]: ../rayon/slice/trait.ParallelSliceMut.html#method.par_sort +/// +/// ```rust +/// # use rayon_core as rayon; +/// let mut v = vec![5, 1, 8, 22, 0, 44]; +/// quick_sort(&mut v); +/// assert_eq!(v, vec![0, 1, 5, 8, 22, 44]); +/// +/// fn quick_sort(v: &mut [T]) { +/// if v.len() > 1 { +/// let mid = partition(v); +/// let (lo, hi) = v.split_at_mut(mid); +/// rayon::join(|| quick_sort(lo), +/// || quick_sort(hi)); +/// } +/// } +/// +/// // Partition rearranges all items `<=` to the pivot +/// // item (arbitrary selected to be the last item in the slice) +/// // to the first half of the slice. It then returns the +/// // "dividing point" where the pivot is placed. +/// fn partition(v: &mut [T]) -> usize { +/// let pivot = v.len() - 1; +/// let mut i = 0; +/// for j in 0..pivot { +/// if v[j] <= v[pivot] { +/// v.swap(i, j); +/// i += 1; +/// } +/// } +/// v.swap(i, pivot); +/// i +/// } +/// ``` +/// +/// # Warning about blocking I/O +/// +/// The assumption is that the closures given to `join()` are +/// CPU-bound tasks that do not perform I/O or other blocking +/// operations. If you do perform I/O, and that I/O should block +/// (e.g., waiting for a network request), the overall performance may +/// be poor. Moreover, if you cause one closure to be blocked waiting +/// on another (for example, using a channel), that could lead to a +/// deadlock. +/// +/// # Panics +/// +/// No matter what happens, both closures will always be executed. If +/// a single closure panics, whether it be the first or second +/// closure, that panic will be propagated and hence `join()` will +/// panic with the same panic value. If both closures panic, `join()` +/// will panic with the panic value from the first closure. +pub fn join(oper_a: A, oper_b: B) -> (RA, RB) +where + A: FnOnce() -> RA + Send, + B: FnOnce() -> RB + Send, + RA: Send, + RB: Send, +{ + #[inline] + fn call(f: impl FnOnce() -> R) -> impl FnOnce(FnContext) -> R { + move |_| f() + } + + join_context(call(oper_a), call(oper_b)) +} + +/// Identical to `join`, except that the closures have a parameter +/// that provides context for the way the closure has been called, +/// especially indicating whether they're executing on a different +/// thread than where `join_context` was called. This will occur if +/// the second job is stolen by a different thread, or if +/// `join_context` was called from outside the thread pool to begin +/// with. +pub fn join_context(oper_a: A, oper_b: B) -> (RA, RB) +where + A: FnOnce(FnContext) -> RA + Send, + B: FnOnce(FnContext) -> RB + Send, + RA: Send, + RB: Send, +{ + #[inline] + fn call_a(f: impl FnOnce(FnContext) -> R, injected: bool) -> impl FnOnce() -> R { + move || f(FnContext::new(injected)) + } + + #[inline] + fn call_b(f: impl FnOnce(FnContext) -> R) -> impl FnOnce(bool) -> R { + move |migrated| f(FnContext::new(migrated)) + } + + registry::in_worker(|worker_thread, injected| unsafe { + let tlv = tlv::get(); + // Create virtual wrapper for task b; this all has to be + // done here so that the stack frame can keep it all live + // long enough. + let job_b = StackJob::new(tlv, call_b(oper_b), SpinLatch::new(worker_thread)); + let job_b_ref = job_b.as_job_ref(); + let job_b_id = job_b_ref.id(); + worker_thread.push(job_b_ref); + + // Execute task a; hopefully b gets stolen in the meantime. + let status_a = unwind::halt_unwinding(call_a(oper_a, injected)); + let result_a = match status_a { + Ok(v) => v, + Err(err) => join_recover_from_panic(worker_thread, &job_b.latch, err, tlv), + }; + + // Now that task A has finished, try to pop job B from the + // local stack. It may already have been popped by job A; it + // may also have been stolen. There may also be some tasks + // pushed on top of it in the stack, and we will have to pop + // those off to get to it. + while !job_b.latch.probe() { + if let Some(job) = worker_thread.take_local_job() { + if job_b_id == job.id() { + // Found it! Let's run it. + // + // Note that this could panic, but it's ok if we unwind here. + + // Restore the TLV since we might have run some jobs overwriting it when waiting for job b. + tlv::set(tlv); + + let result_b = job_b.run_inline(injected); + return (result_a, result_b); + } else { + worker_thread.execute(job); + } + } else { + // Local deque is empty. Time to steal from other + // threads. + worker_thread.wait_until(&job_b.latch); + debug_assert!(job_b.latch.probe()); + break; + } + } + + // Restore the TLV since we might have run some jobs overwriting it when waiting for job b. + tlv::set(tlv); + + (result_a, job_b.into_result()) + }) +} + +/// If job A panics, we still cannot return until we are sure that job +/// B is complete. This is because it may contain references into the +/// enclosing stack frame(s). +#[cold] // cold path +unsafe fn join_recover_from_panic( + worker_thread: &WorkerThread, + job_b_latch: &SpinLatch<'_>, + err: Box, + tlv: Tlv, +) -> ! { + worker_thread.wait_until(job_b_latch); + + // Restore the TLV since we might have run some jobs overwriting it when waiting for job b. + tlv::set(tlv); + + unwind::resume_unwinding(err) +} diff --git a/compiler/rustc_thread_pool/src/join/test.rs b/compiler/rustc_thread_pool/src/join/test.rs new file mode 100644 index 000000000000..03f4ab4478d4 --- /dev/null +++ b/compiler/rustc_thread_pool/src/join/test.rs @@ -0,0 +1,150 @@ +//! Tests for the join code. + +use super::*; +use crate::ThreadPoolBuilder; +use rand::distr::StandardUniform; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; + +fn quick_sort(v: &mut [T]) { + if v.len() <= 1 { + return; + } + + let mid = partition(v); + let (lo, hi) = v.split_at_mut(mid); + join(|| quick_sort(lo), || quick_sort(hi)); +} + +fn partition(v: &mut [T]) -> usize { + let pivot = v.len() - 1; + let mut i = 0; + for j in 0..pivot { + if v[j] <= v[pivot] { + v.swap(i, j); + i += 1; + } + } + v.swap(i, pivot); + i +} + +fn seeded_rng() -> XorShiftRng { + let mut seed = ::Seed::default(); + (0..).zip(seed.as_mut()).for_each(|(i, x)| *x = i); + XorShiftRng::from_seed(seed) +} + +#[test] +fn sort() { + let rng = seeded_rng(); + let mut data: Vec = rng.sample_iter(&StandardUniform).take(6 * 1024).collect(); + let mut sorted_data = data.clone(); + sorted_data.sort(); + quick_sort(&mut data); + assert_eq!(data, sorted_data); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn sort_in_pool() { + let rng = seeded_rng(); + let mut data: Vec = rng.sample_iter(&StandardUniform).take(12 * 1024).collect(); + + let pool = ThreadPoolBuilder::new().build().unwrap(); + let mut sorted_data = data.clone(); + sorted_data.sort(); + pool.install(|| quick_sort(&mut data)); + assert_eq!(data, sorted_data); +} + +#[test] +#[should_panic(expected = "Hello, world!")] +fn panic_propagate_a() { + join(|| panic!("Hello, world!"), || ()); +} + +#[test] +#[should_panic(expected = "Hello, world!")] +fn panic_propagate_b() { + join(|| (), || panic!("Hello, world!")); +} + +#[test] +#[should_panic(expected = "Hello, world!")] +fn panic_propagate_both() { + join(|| panic!("Hello, world!"), || panic!("Goodbye, world!")); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn panic_b_still_executes() { + let mut x = false; + match unwind::halt_unwinding(|| join(|| panic!("Hello, world!"), || x = true)) { + Ok(_) => panic!("failed to propagate panic from closure A,"), + Err(_) => assert!(x, "closure b failed to execute"), + } +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn join_context_both() { + // If we're not in a pool, both should be marked stolen as they're injected. + let (a_migrated, b_migrated) = join_context(|a| a.migrated(), |b| b.migrated()); + assert!(a_migrated); + assert!(b_migrated); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn join_context_neither() { + // If we're already in a 1-thread pool, neither job should be stolen. + let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); + let (a_migrated, b_migrated) = + pool.install(|| join_context(|a| a.migrated(), |b| b.migrated())); + assert!(!a_migrated); + assert!(!b_migrated); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn join_context_second() { + use std::sync::Barrier; + + // If we're already in a 2-thread pool, the second job should be stolen. + let barrier = Barrier::new(2); + let pool = ThreadPoolBuilder::new().num_threads(2).build().unwrap(); + let (a_migrated, b_migrated) = pool.install(|| { + join_context( + |a| { + barrier.wait(); + a.migrated() + }, + |b| { + barrier.wait(); + b.migrated() + }, + ) + }); + assert!(!a_migrated); + assert!(b_migrated); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn join_counter_overflow() { + const MAX: u32 = 500_000; + + let mut i = 0; + let mut j = 0; + let pool = ThreadPoolBuilder::new().num_threads(2).build().unwrap(); + + // Hammer on join a bunch of times -- used to hit overflow debug-assertions + // in JEC on 32-bit targets: https://github.com/rayon-rs/rayon/issues/797 + for _ in 0..MAX { + pool.join(|| i += 1, || j += 1); + } + + assert_eq!(i, MAX); + assert_eq!(j, MAX); +} diff --git a/compiler/rustc_thread_pool/src/latch.rs b/compiler/rustc_thread_pool/src/latch.rs new file mode 100644 index 000000000000..8903942a8ce3 --- /dev/null +++ b/compiler/rustc_thread_pool/src/latch.rs @@ -0,0 +1,459 @@ +use std::marker::PhantomData; +use std::ops::Deref; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Condvar, Mutex}; + +use crate::registry::{Registry, WorkerThread}; + +/// We define various kinds of latches, which are all a primitive signaling +/// mechanism. A latch starts as false. Eventually someone calls `set()` and +/// it becomes true. You can test if it has been set by calling `probe()`. +/// +/// Some kinds of latches, but not all, support a `wait()` operation +/// that will wait until the latch is set, blocking efficiently. That +/// is not part of the trait since it is not possibly to do with all +/// latches. +/// +/// The intention is that `set()` is called once, but `probe()` may be +/// called any number of times. Once `probe()` returns true, the memory +/// effects that occurred before `set()` become visible. +/// +/// It'd probably be better to refactor the API into two paired types, +/// but that's a bit of work, and this is not a public API. +/// +/// ## Memory ordering +/// +/// Latches need to guarantee two things: +/// +/// - Once `probe()` returns true, all memory effects from the `set()` +/// are visible (in other words, the set should synchronize-with +/// the probe). +/// - Once `set()` occurs, the next `probe()` *will* observe it. This +/// typically requires a seq-cst ordering. See [the "tickle-then-get-sleepy" scenario in the sleep +/// README](/src/sleep/README.md#tickle-then-get-sleepy) for details. +pub(super) trait Latch { + /// Set the latch, signalling others. + /// + /// # WARNING + /// + /// Setting a latch triggers other threads to wake up and (in some + /// cases) complete. This may, in turn, cause memory to be + /// deallocated and so forth. One must be very careful about this, + /// and it's typically better to read all the fields you will need + /// to access *before* a latch is set! + /// + /// This function operates on `*const Self` instead of `&self` to allow it + /// to become dangling during this call. The caller must ensure that the + /// pointer is valid upon entry, and not invalidated during the call by any + /// actions other than `set` itself. + unsafe fn set(this: *const Self); +} + +pub(super) trait AsCoreLatch { + fn as_core_latch(&self) -> &CoreLatch; +} + +/// Latch is not set, owning thread is awake +const UNSET: usize = 0; + +/// Latch is not set, owning thread is going to sleep on this latch +/// (but has not yet fallen asleep). +const SLEEPY: usize = 1; + +/// Latch is not set, owning thread is asleep on this latch and +/// must be awoken. +const SLEEPING: usize = 2; + +/// Latch is set. +const SET: usize = 3; + +/// Spin latches are the simplest, most efficient kind, but they do +/// not support a `wait()` operation. They just have a boolean flag +/// that becomes true when `set()` is called. +#[derive(Debug)] +pub(super) struct CoreLatch { + state: AtomicUsize, +} + +impl CoreLatch { + #[inline] + fn new() -> Self { + Self { + state: AtomicUsize::new(0), + } + } + + /// Invoked by owning thread as it prepares to sleep. Returns true + /// if the owning thread may proceed to fall asleep, false if the + /// latch was set in the meantime. + #[inline] + pub(super) fn get_sleepy(&self) -> bool { + self.state + .compare_exchange(UNSET, SLEEPY, Ordering::SeqCst, Ordering::Relaxed) + .is_ok() + } + + /// Invoked by owning thread as it falls asleep sleep. Returns + /// true if the owning thread should block, or false if the latch + /// was set in the meantime. + #[inline] + pub(super) fn fall_asleep(&self) -> bool { + self.state + .compare_exchange(SLEEPY, SLEEPING, Ordering::SeqCst, Ordering::Relaxed) + .is_ok() + } + + /// Invoked by owning thread as it falls asleep sleep. Returns + /// true if the owning thread should block, or false if the latch + /// was set in the meantime. + #[inline] + pub(super) fn wake_up(&self) { + if !self.probe() { + let _ = + self.state + .compare_exchange(SLEEPING, UNSET, Ordering::SeqCst, Ordering::Relaxed); + } + } + + /// Set the latch. If this returns true, the owning thread was sleeping + /// and must be awoken. + /// + /// This is private because, typically, setting a latch involves + /// doing some wakeups; those are encapsulated in the surrounding + /// latch code. + #[inline] + unsafe fn set(this: *const Self) -> bool { + let old_state = (*this).state.swap(SET, Ordering::AcqRel); + old_state == SLEEPING + } + + /// Test if this latch has been set. + #[inline] + pub(super) fn probe(&self) -> bool { + self.state.load(Ordering::Acquire) == SET + } +} + +impl AsCoreLatch for CoreLatch { + #[inline] + fn as_core_latch(&self) -> &CoreLatch { + self + } +} + +/// Spin latches are the simplest, most efficient kind, but they do +/// not support a `wait()` operation. They just have a boolean flag +/// that becomes true when `set()` is called. +pub(super) struct SpinLatch<'r> { + core_latch: CoreLatch, + registry: &'r Arc, + target_worker_index: usize, + cross: bool, +} + +impl<'r> SpinLatch<'r> { + /// Creates a new spin latch that is owned by `thread`. This means + /// that `thread` is the only thread that should be blocking on + /// this latch -- it also means that when the latch is set, we + /// will wake `thread` if it is sleeping. + #[inline] + pub(super) fn new(thread: &'r WorkerThread) -> SpinLatch<'r> { + SpinLatch { + core_latch: CoreLatch::new(), + registry: thread.registry(), + target_worker_index: thread.index(), + cross: false, + } + } + + /// Creates a new spin latch for cross-threadpool blocking. Notably, we + /// need to make sure the registry is kept alive after setting, so we can + /// safely call the notification. + #[inline] + pub(super) fn cross(thread: &'r WorkerThread) -> SpinLatch<'r> { + SpinLatch { + cross: true, + ..SpinLatch::new(thread) + } + } + + #[inline] + pub(super) fn probe(&self) -> bool { + self.core_latch.probe() + } +} + +impl<'r> AsCoreLatch for SpinLatch<'r> { + #[inline] + fn as_core_latch(&self) -> &CoreLatch { + &self.core_latch + } +} + +impl<'r> Latch for SpinLatch<'r> { + #[inline] + unsafe fn set(this: *const Self) { + let cross_registry; + + let registry: &Registry = if (*this).cross { + // Ensure the registry stays alive while we notify it. + // Otherwise, it would be possible that we set the spin + // latch and the other thread sees it and exits, causing + // the registry to be deallocated, all before we get a + // chance to invoke `registry.notify_worker_latch_is_set`. + cross_registry = Arc::clone((*this).registry); + &cross_registry + } else { + // If this is not a "cross-registry" spin-latch, then the + // thread which is performing `set` is itself ensuring + // that the registry stays alive. However, that doesn't + // include this *particular* `Arc` handle if the waiting + // thread then exits, so we must completely dereference it. + (*this).registry + }; + let target_worker_index = (*this).target_worker_index; + + // NOTE: Once we `set`, the target may proceed and invalidate `this`! + if CoreLatch::set(&(*this).core_latch) { + // Subtle: at this point, we can no longer read from + // `self`, because the thread owning this spin latch may + // have awoken and deallocated the latch. Therefore, we + // only use fields whose values we already read. + registry.notify_worker_latch_is_set(target_worker_index); + } + } +} + +/// A Latch starts as false and eventually becomes true. You can block +/// until it becomes true. +#[derive(Debug)] +pub(super) struct LockLatch { + m: Mutex, + v: Condvar, +} + +impl LockLatch { + #[inline] + pub(super) fn new() -> LockLatch { + LockLatch { + m: Mutex::new(false), + v: Condvar::new(), + } + } + + /// Block until latch is set, then resets this lock latch so it can be reused again. + pub(super) fn wait_and_reset(&self) { + let mut guard = self.m.lock().unwrap(); + while !*guard { + guard = self.v.wait(guard).unwrap(); + } + *guard = false; + } + + /// Block until latch is set. + pub(super) fn wait(&self) { + let mut guard = self.m.lock().unwrap(); + while !*guard { + guard = self.v.wait(guard).unwrap(); + } + } +} + +impl Latch for LockLatch { + #[inline] + unsafe fn set(this: *const Self) { + let mut guard = (*this).m.lock().unwrap(); + *guard = true; + (*this).v.notify_all(); + } +} + +/// Once latches are used to implement one-time blocking, primarily +/// for the termination flag of the threads in the pool. +/// +/// Note: like a `SpinLatch`, once-latches are always associated with +/// some registry that is probing them, which must be tickled when +/// they are set. *Unlike* a `SpinLatch`, they don't themselves hold a +/// reference to that registry. This is because in some cases the +/// registry owns the once-latch, and that would create a cycle. So a +/// `OnceLatch` must be given a reference to its owning registry when +/// it is set. For this reason, it does not implement the `Latch` +/// trait (but it doesn't have to, as it is not used in those generic +/// contexts). +#[derive(Debug)] +pub(super) struct OnceLatch { + core_latch: CoreLatch, +} + +impl OnceLatch { + #[inline] + pub(super) fn new() -> OnceLatch { + Self { + core_latch: CoreLatch::new(), + } + } + + /// Set the latch, then tickle the specific worker thread, + /// which should be the one that owns this latch. + #[inline] + pub(super) unsafe fn set_and_tickle_one( + this: *const Self, + registry: &Registry, + target_worker_index: usize, + ) { + if CoreLatch::set(&(*this).core_latch) { + registry.notify_worker_latch_is_set(target_worker_index); + } + } +} + +impl AsCoreLatch for OnceLatch { + #[inline] + fn as_core_latch(&self) -> &CoreLatch { + &self.core_latch + } +} + +/// Counting latches are used to implement scopes. They track a +/// counter. Unlike other latches, calling `set()` does not +/// necessarily make the latch be considered `set()`; instead, it just +/// decrements the counter. The latch is only "set" (in the sense that +/// `probe()` returns true) once the counter reaches zero. +#[derive(Debug)] +pub(super) struct CountLatch { + counter: AtomicUsize, + kind: CountLatchKind, +} + +enum CountLatchKind { + /// A latch for scopes created on a rayon thread which will participate in work- + /// stealing while it waits for completion. This thread is not necessarily part + /// of the same registry as the scope itself! + Stealing { + latch: CoreLatch, + /// If a worker thread in registry A calls `in_place_scope` on a ThreadPool + /// with registry B, when a job completes in a thread of registry B, we may + /// need to call `notify_worker_latch_is_set()` to wake the thread in registry A. + /// That means we need a reference to registry A (since at that point we will + /// only have a reference to registry B), so we stash it here. + registry: Arc, + /// The index of the worker to wake in `registry` + worker_index: usize, + }, + + /// A latch for scopes created on a non-rayon thread which will block to wait. + Blocking { latch: LockLatch }, +} + +impl std::fmt::Debug for CountLatchKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + CountLatchKind::Stealing { latch, .. } => { + f.debug_tuple("Stealing").field(latch).finish() + } + CountLatchKind::Blocking { latch, .. } => { + f.debug_tuple("Blocking").field(latch).finish() + } + } + } +} + +impl CountLatch { + pub(super) fn new(owner: Option<&WorkerThread>) -> Self { + Self::with_count(1, owner) + } + + pub(super) fn with_count(count: usize, owner: Option<&WorkerThread>) -> Self { + Self { + counter: AtomicUsize::new(count), + kind: match owner { + Some(owner) => CountLatchKind::Stealing { + latch: CoreLatch::new(), + registry: Arc::clone(owner.registry()), + worker_index: owner.index(), + }, + None => CountLatchKind::Blocking { + latch: LockLatch::new(), + }, + }, + } + } + + #[inline] + pub(super) fn increment(&self) { + let old_counter = self.counter.fetch_add(1, Ordering::Relaxed); + debug_assert!(old_counter != 0); + } + + pub(super) fn wait(&self, owner: Option<&WorkerThread>) { + match &self.kind { + CountLatchKind::Stealing { + latch, + registry, + worker_index, + } => unsafe { + let owner = owner.expect("owner thread"); + debug_assert_eq!(registry.id(), owner.registry().id()); + debug_assert_eq!(*worker_index, owner.index()); + owner.wait_until(latch); + }, + CountLatchKind::Blocking { latch } => latch.wait(), + } + } +} + +impl Latch for CountLatch { + #[inline] + unsafe fn set(this: *const Self) { + if (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 { + // NOTE: Once we call `set` on the internal `latch`, + // the target may proceed and invalidate `this`! + match (*this).kind { + CountLatchKind::Stealing { + ref latch, + ref registry, + worker_index, + } => { + let registry = Arc::clone(registry); + if CoreLatch::set(latch) { + registry.notify_worker_latch_is_set(worker_index); + } + } + CountLatchKind::Blocking { ref latch } => LockLatch::set(latch), + } + } + } +} + +/// `&L` without any implication of `dereferenceable` for `Latch::set` +pub(super) struct LatchRef<'a, L> { + inner: *const L, + marker: PhantomData<&'a L>, +} + +impl LatchRef<'_, L> { + pub(super) fn new(inner: &L) -> LatchRef<'_, L> { + LatchRef { + inner, + marker: PhantomData, + } + } +} + +unsafe impl Sync for LatchRef<'_, L> {} + +impl Deref for LatchRef<'_, L> { + type Target = L; + + fn deref(&self) -> &L { + // SAFETY: if we have &self, the inner latch is still alive + unsafe { &*self.inner } + } +} + +impl Latch for LatchRef<'_, L> { + #[inline] + unsafe fn set(this: *const Self) { + L::set((*this).inner); + } +} diff --git a/compiler/rustc_thread_pool/src/lib.rs b/compiler/rustc_thread_pool/src/lib.rs new file mode 100644 index 000000000000..72064547e526 --- /dev/null +++ b/compiler/rustc_thread_pool/src/lib.rs @@ -0,0 +1,922 @@ +//! Rayon-core houses the core stable APIs of Rayon. +//! +//! These APIs have been mirrored in the Rayon crate and it is recommended to use these from there. +//! +//! [`join`] is used to take two closures and potentially run them in parallel. +//! - It will run in parallel if task B gets stolen before task A can finish. +//! - It will run sequentially if task A finishes before task B is stolen and can continue on task B. +//! +//! [`scope`] creates a scope in which you can run any number of parallel tasks. +//! These tasks can spawn nested tasks and scopes, but given the nature of work stealing, the order of execution can not be guaranteed. +//! The scope will exist until all tasks spawned within the scope have been completed. +//! +//! [`spawn`] add a task into the 'static' or 'global' scope, or a local scope created by the [`scope()`] function. +//! +//! [`ThreadPool`] can be used to create your own thread pools (using [`ThreadPoolBuilder`]) or to customize the global one. +//! Tasks spawned within the pool (using [`install()`], [`join()`], etc.) will be added to a deque, +//! where it becomes available for work stealing from other threads in the local threadpool. +//! +//! [`join`]: fn.join.html +//! [`scope`]: fn.scope.html +//! [`scope()`]: fn.scope.html +//! [`spawn`]: fn.spawn.html +//! [`ThreadPool`]: struct.threadpool.html +//! [`install()`]: struct.ThreadPool.html#method.install +//! [`spawn()`]: struct.ThreadPool.html#method.spawn +//! [`join()`]: struct.ThreadPool.html#method.join +//! [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html +//! +//! # Global fallback when threading is unsupported +//! +//! Rayon uses `std` APIs for threading, but some targets have incomplete implementations that +//! always return `Unsupported` errors. The WebAssembly `wasm32-unknown-unknown` and `wasm32-wasi` +//! targets are notable examples of this. Rather than panicking on the unsupported error when +//! creating the implicit global threadpool, Rayon configures a fallback mode instead. +//! +//! This fallback mode mostly functions as if it were using a single-threaded "pool", like setting +//! `RAYON_NUM_THREADS=1`. For example, `join` will execute its two closures sequentially, since +//! there is no other thread to share the work. However, since the pool is not running independent +//! of the main thread, non-blocking calls like `spawn` may not execute at all, unless a lower- +//! priority call like `broadcast` gives them an opening. The fallback mode does not try to emulate +//! anything like thread preemption or `async` task switching, but `yield_now` or `yield_local` +//! can also volunteer execution time. +//! +//! Explicit `ThreadPoolBuilder` methods always report their error without any fallback. +//! +//! # Restricting multiple versions +//! +//! In order to ensure proper coordination between threadpools, and especially +//! to make sure there's only one global threadpool, `rayon-core` is actively +//! restricted from building multiple versions of itself into a single target. +//! You may see a build error like this in violation: +//! +//! ```text +//! error: native library `rayon-core` is being linked to by more +//! than one package, and can only be linked to by one package +//! ``` +//! +//! While we strive to keep `rayon-core` semver-compatible, it's still +//! possible to arrive at this situation if different crates have overly +//! restrictive tilde or inequality requirements for `rayon-core`. The +//! conflicting requirements will need to be resolved before the build will +//! succeed. + +#![warn(rust_2018_idioms)] + +use std::any::Any; +use std::env; +use std::error::Error; +use std::fmt; +use std::io; +use std::marker::PhantomData; +use std::str::FromStr; +use std::thread; + +#[macro_use] +mod private; + +mod broadcast; +mod job; +mod join; +mod latch; +mod registry; +mod scope; +mod sleep; +mod spawn; +mod thread_pool; +mod unwind; +mod worker_local; + +mod compile_fail; +mod test; + +pub mod tlv; + +pub use self::broadcast::{broadcast, spawn_broadcast, BroadcastContext}; +pub use self::join::{join, join_context}; +pub use self::registry::ThreadBuilder; +pub use self::registry::{mark_blocked, mark_unblocked, Registry}; +pub use self::scope::{in_place_scope, scope, Scope}; +pub use self::scope::{in_place_scope_fifo, scope_fifo, ScopeFifo}; +pub use self::spawn::{spawn, spawn_fifo}; +pub use self::thread_pool::current_thread_has_pending_tasks; +pub use self::thread_pool::current_thread_index; +pub use self::thread_pool::ThreadPool; +pub use self::thread_pool::{yield_local, yield_now, Yield}; +pub use worker_local::WorkerLocal; + +use self::registry::{CustomSpawn, DefaultSpawn, ThreadSpawn}; + +/// Returns the maximum number of threads that Rayon supports in a single thread-pool. +/// +/// If a higher thread count is requested by calling `ThreadPoolBuilder::num_threads` or by setting +/// the `RAYON_NUM_THREADS` environment variable, then it will be reduced to this maximum. +/// +/// The value may vary between different targets, and is subject to change in new Rayon versions. +pub fn max_num_threads() -> usize { + // We are limited by the bits available in the sleep counter's `AtomicUsize`. + crate::sleep::THREADS_MAX +} + +/// Returns the number of threads in the current registry. If this +/// code is executing within a Rayon thread-pool, then this will be +/// the number of threads for the thread-pool of the current +/// thread. Otherwise, it will be the number of threads for the global +/// thread-pool. +/// +/// This can be useful when trying to judge how many times to split +/// parallel work (the parallel iterator traits use this value +/// internally for this purpose). +/// +/// # Future compatibility note +/// +/// Note that unless this thread-pool was created with a +/// builder that specifies the number of threads, then this +/// number may vary over time in future versions (see [the +/// `num_threads()` method for details][snt]). +/// +/// [snt]: struct.ThreadPoolBuilder.html#method.num_threads +pub fn current_num_threads() -> usize { + crate::registry::Registry::current_num_threads() +} + +/// Error when initializing a thread pool. +#[derive(Debug)] +pub struct ThreadPoolBuildError { + kind: ErrorKind, +} + +#[derive(Debug)] +enum ErrorKind { + GlobalPoolAlreadyInitialized, + IOError(io::Error), +} + +/// Used to create a new [`ThreadPool`] or to configure the global rayon thread pool. +/// ## Creating a ThreadPool +/// The following creates a thread pool with 22 threads. +/// +/// ```rust +/// # use rayon_core as rayon; +/// let pool = rayon::ThreadPoolBuilder::new().num_threads(22).build().unwrap(); +/// ``` +/// +/// To instead configure the global thread pool, use [`build_global()`]: +/// +/// ```rust +/// # use rayon_core as rayon; +/// rayon::ThreadPoolBuilder::new().num_threads(22).build_global().unwrap(); +/// ``` +/// +/// [`ThreadPool`]: struct.ThreadPool.html +/// [`build_global()`]: struct.ThreadPoolBuilder.html#method.build_global +pub struct ThreadPoolBuilder { + /// The number of threads in the rayon thread pool. + /// If zero will use the RAYON_NUM_THREADS environment variable. + /// If RAYON_NUM_THREADS is invalid or zero will use the default. + num_threads: usize, + + /// Custom closure, if any, to handle a panic that we cannot propagate + /// anywhere else. + panic_handler: Option>, + + /// Closure to compute the name of a thread. + get_thread_name: Option String>>, + + /// The stack size for the created worker threads + stack_size: Option, + + /// Closure invoked on deadlock. + deadlock_handler: Option>, + + /// Closure invoked on worker thread start. + start_handler: Option>, + + /// Closure invoked on worker thread exit. + exit_handler: Option>, + + /// Closure invoked to spawn threads. + spawn_handler: S, + + /// Closure invoked when starting computations in a thread. + acquire_thread_handler: Option>, + + /// Closure invoked when blocking in a thread. + release_thread_handler: Option>, + + /// If false, worker threads will execute spawned jobs in a + /// "depth-first" fashion. If true, they will do a "breadth-first" + /// fashion. Depth-first is the default. + breadth_first: bool, +} + +/// Contains the rayon thread pool configuration. Use [`ThreadPoolBuilder`] instead. +/// +/// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html +#[deprecated(note = "Use `ThreadPoolBuilder`")] +#[derive(Default)] +pub struct Configuration { + builder: ThreadPoolBuilder, +} + +/// The type for a panic handling closure. Note that this same closure +/// may be invoked multiple times in parallel. +type PanicHandler = dyn Fn(Box) + Send + Sync; + +/// The type for a closure that gets invoked when the Rayon thread pool deadlocks +type DeadlockHandler = dyn Fn() + Send + Sync; + +/// The type for a closure that gets invoked when a thread starts. The +/// closure is passed the index of the thread on which it is invoked. +/// Note that this same closure may be invoked multiple times in parallel. +type StartHandler = dyn Fn(usize) + Send + Sync; + +/// The type for a closure that gets invoked when a thread exits. The +/// closure is passed the index of the thread on which it is invoked. +/// Note that this same closure may be invoked multiple times in parallel. +type ExitHandler = dyn Fn(usize) + Send + Sync; + +// NB: We can't `#[derive(Default)]` because `S` is left ambiguous. +impl Default for ThreadPoolBuilder { + fn default() -> Self { + ThreadPoolBuilder { + num_threads: 0, + panic_handler: None, + get_thread_name: None, + stack_size: None, + start_handler: None, + exit_handler: None, + deadlock_handler: None, + acquire_thread_handler: None, + release_thread_handler: None, + spawn_handler: DefaultSpawn, + breadth_first: false, + } + } +} + +/// The type for a closure that gets invoked before starting computations in a thread. +/// Note that this same closure may be invoked multiple times in parallel. +type AcquireThreadHandler = dyn Fn() + Send + Sync; + +/// The type for a closure that gets invoked before blocking in a thread. +/// Note that this same closure may be invoked multiple times in parallel. +type ReleaseThreadHandler = dyn Fn() + Send + Sync; + +impl ThreadPoolBuilder { + /// Creates and returns a valid rayon thread pool builder, but does not initialize it. + pub fn new() -> Self { + Self::default() + } +} + +/// Note: the `S: ThreadSpawn` constraint is an internal implementation detail for the +/// default spawn and those set by [`spawn_handler`](#method.spawn_handler). +impl ThreadPoolBuilder +where + S: ThreadSpawn, +{ + /// Creates a new `ThreadPool` initialized using this configuration. + pub fn build(self) -> Result { + ThreadPool::build(self) + } + + /// Initializes the global thread pool. This initialization is + /// **optional**. If you do not call this function, the thread pool + /// will be automatically initialized with the default + /// configuration. Calling `build_global` is not recommended, except + /// in two scenarios: + /// + /// - You wish to change the default configuration. + /// - You are running a benchmark, in which case initializing may + /// yield slightly more consistent results, since the worker threads + /// will already be ready to go even in the first iteration. But + /// this cost is minimal. + /// + /// Initialization of the global thread pool happens exactly + /// once. Once started, the configuration cannot be + /// changed. Therefore, if you call `build_global` a second time, it + /// will return an error. An `Ok` result indicates that this + /// is the first initialization of the thread pool. + pub fn build_global(self) -> Result<(), ThreadPoolBuildError> { + let registry = registry::init_global_registry(self)?; + registry.wait_until_primed(); + Ok(()) + } +} + +impl ThreadPoolBuilder { + /// Creates a scoped `ThreadPool` initialized using this configuration. + /// + /// This is a convenience function for building a pool using [`std::thread::scope`] + /// to spawn threads in a [`spawn_handler`](#method.spawn_handler). + /// The threads in this pool will start by calling `wrapper`, which should + /// do initialization and continue by calling `ThreadBuilder::run()`. + /// + /// [`std::thread::scope`]: https://doc.rust-lang.org/std/thread/fn.scope.html + /// + /// # Examples + /// + /// A scoped pool may be useful in combination with scoped thread-local variables. + /// + /// ``` + /// # use rayon_core as rayon; + /// + /// scoped_tls::scoped_thread_local!(static POOL_DATA: Vec); + /// + /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { + /// let pool_data = vec![1, 2, 3]; + /// + /// // We haven't assigned any TLS data yet. + /// assert!(!POOL_DATA.is_set()); + /// + /// rayon::ThreadPoolBuilder::new() + /// .build_scoped( + /// // Borrow `pool_data` in TLS for each thread. + /// |thread| POOL_DATA.set(&pool_data, || thread.run()), + /// // Do some work that needs the TLS data. + /// |pool| pool.install(|| assert!(POOL_DATA.is_set())), + /// )?; + /// + /// // Once we've returned, `pool_data` is no longer borrowed. + /// drop(pool_data); + /// Ok(()) + /// } + /// ``` + pub fn build_scoped(self, wrapper: W, with_pool: F) -> Result + where + W: Fn(ThreadBuilder) + Sync, // expected to call `run()` + F: FnOnce(&ThreadPool) -> R, + { + std::thread::scope(|scope| { + let pool = self + .spawn_handler(|thread| { + let mut builder = std::thread::Builder::new(); + if let Some(name) = thread.name() { + builder = builder.name(name.to_string()); + } + if let Some(size) = thread.stack_size() { + builder = builder.stack_size(size); + } + builder.spawn_scoped(scope, || wrapper(thread))?; + Ok(()) + }) + .build()?; + let result = unwind::halt_unwinding(|| with_pool(&pool)); + pool.wait_until_stopped(); + match result { + Ok(result) => Ok(result), + Err(err) => unwind::resume_unwinding(err), + } + }) + } +} + +impl ThreadPoolBuilder { + /// Sets a custom function for spawning threads. + /// + /// Note that the threads will not exit until after the pool is dropped. It + /// is up to the caller to wait for thread termination if that is important + /// for any invariants. For instance, threads created in [`std::thread::scope`] + /// will be joined before that scope returns, and this will block indefinitely + /// if the pool is leaked. Furthermore, the global thread pool doesn't terminate + /// until the entire process exits! + /// + /// # Examples + /// + /// A minimal spawn handler just needs to call `run()` from an independent thread. + /// + /// ``` + /// # use rayon_core as rayon; + /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { + /// let pool = rayon::ThreadPoolBuilder::new() + /// .spawn_handler(|thread| { + /// std::thread::spawn(|| thread.run()); + /// Ok(()) + /// }) + /// .build()?; + /// + /// pool.install(|| println!("Hello from my custom thread!")); + /// Ok(()) + /// } + /// ``` + /// + /// The default spawn handler sets the name and stack size if given, and propagates + /// any errors from the thread builder. + /// + /// ``` + /// # use rayon_core as rayon; + /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { + /// let pool = rayon::ThreadPoolBuilder::new() + /// .spawn_handler(|thread| { + /// let mut b = std::thread::Builder::new(); + /// if let Some(name) = thread.name() { + /// b = b.name(name.to_owned()); + /// } + /// if let Some(stack_size) = thread.stack_size() { + /// b = b.stack_size(stack_size); + /// } + /// b.spawn(|| thread.run())?; + /// Ok(()) + /// }) + /// .build()?; + /// + /// pool.install(|| println!("Hello from my fully custom thread!")); + /// Ok(()) + /// } + /// ``` + /// + /// This can also be used for a pool of scoped threads like [`crossbeam::scope`], + /// or [`std::thread::scope`] introduced in Rust 1.63, which is encapsulated in + /// [`build_scoped`](#method.build_scoped). + /// + /// [`crossbeam::scope`]: https://docs.rs/crossbeam/0.8/crossbeam/fn.scope.html + /// [`std::thread::scope`]: https://doc.rust-lang.org/std/thread/fn.scope.html + /// + /// ``` + /// # use rayon_core as rayon; + /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { + /// std::thread::scope(|scope| { + /// let pool = rayon::ThreadPoolBuilder::new() + /// .spawn_handler(|thread| { + /// let mut builder = std::thread::Builder::new(); + /// if let Some(name) = thread.name() { + /// builder = builder.name(name.to_string()); + /// } + /// if let Some(size) = thread.stack_size() { + /// builder = builder.stack_size(size); + /// } + /// builder.spawn_scoped(scope, || { + /// // Add any scoped initialization here, then run! + /// thread.run() + /// })?; + /// Ok(()) + /// }) + /// .build()?; + /// + /// pool.install(|| println!("Hello from my custom scoped thread!")); + /// Ok(()) + /// }) + /// } + /// ``` + pub fn spawn_handler(self, spawn: F) -> ThreadPoolBuilder> + where + F: FnMut(ThreadBuilder) -> io::Result<()>, + { + ThreadPoolBuilder { + spawn_handler: CustomSpawn::new(spawn), + // ..self + num_threads: self.num_threads, + panic_handler: self.panic_handler, + get_thread_name: self.get_thread_name, + stack_size: self.stack_size, + start_handler: self.start_handler, + exit_handler: self.exit_handler, + deadlock_handler: self.deadlock_handler, + acquire_thread_handler: self.acquire_thread_handler, + release_thread_handler: self.release_thread_handler, + breadth_first: self.breadth_first, + } + } + + /// Returns a reference to the current spawn handler. + fn get_spawn_handler(&mut self) -> &mut S { + &mut self.spawn_handler + } + + /// Get the number of threads that will be used for the thread + /// pool. See `num_threads()` for more information. + fn get_num_threads(&self) -> usize { + if self.num_threads > 0 { + self.num_threads + } else { + let default = || { + thread::available_parallelism() + .map(|n| n.get()) + .unwrap_or(1) + }; + + match env::var("RAYON_NUM_THREADS") + .ok() + .and_then(|s| usize::from_str(&s).ok()) + { + Some(x @ 1..) => return x, + Some(0) => return default(), + _ => {} + } + + // Support for deprecated `RAYON_RS_NUM_CPUS`. + match env::var("RAYON_RS_NUM_CPUS") + .ok() + .and_then(|s| usize::from_str(&s).ok()) + { + Some(x @ 1..) => x, + _ => default(), + } + } + } + + /// Get the thread name for the thread with the given index. + fn get_thread_name(&mut self, index: usize) -> Option { + let f = self.get_thread_name.as_mut()?; + Some(f(index)) + } + + /// Sets a closure which takes a thread index and returns + /// the thread's name. + pub fn thread_name(mut self, closure: F) -> Self + where + F: FnMut(usize) -> String + 'static, + { + self.get_thread_name = Some(Box::new(closure)); + self + } + + /// Sets the number of threads to be used in the rayon threadpool. + /// + /// If you specify a non-zero number of threads using this + /// function, then the resulting thread-pools are guaranteed to + /// start at most this number of threads. + /// + /// If `num_threads` is 0, or you do not call this function, then + /// the Rayon runtime will select the number of threads + /// automatically. At present, this is based on the + /// `RAYON_NUM_THREADS` environment variable (if set), + /// or the number of logical CPUs (otherwise). + /// In the future, however, the default behavior may + /// change to dynamically add or remove threads as needed. + /// + /// **Future compatibility warning:** Given the default behavior + /// may change in the future, if you wish to rely on a fixed + /// number of threads, you should use this function to specify + /// that number. To reproduce the current default behavior, you + /// may wish to use [`std::thread::available_parallelism`] + /// to query the number of CPUs dynamically. + /// + /// **Old environment variable:** `RAYON_NUM_THREADS` is a one-to-one + /// replacement of the now deprecated `RAYON_RS_NUM_CPUS` environment + /// variable. If both variables are specified, `RAYON_NUM_THREADS` will + /// be preferred. + pub fn num_threads(mut self, num_threads: usize) -> Self { + self.num_threads = num_threads; + self + } + + /// Returns a copy of the current panic handler. + fn take_panic_handler(&mut self) -> Option> { + self.panic_handler.take() + } + + /// Normally, whenever Rayon catches a panic, it tries to + /// propagate it to someplace sensible, to try and reflect the + /// semantics of sequential execution. But in some cases, + /// particularly with the `spawn()` APIs, there is no + /// obvious place where we should propagate the panic to. + /// In that case, this panic handler is invoked. + /// + /// If no panic handler is set, the default is to abort the + /// process, under the principle that panics should not go + /// unobserved. + /// + /// If the panic handler itself panics, this will abort the + /// process. To prevent this, wrap the body of your panic handler + /// in a call to `std::panic::catch_unwind()`. + pub fn panic_handler(mut self, panic_handler: H) -> Self + where + H: Fn(Box) + Send + Sync + 'static, + { + self.panic_handler = Some(Box::new(panic_handler)); + self + } + + /// Get the stack size of the worker threads + fn get_stack_size(&self) -> Option { + self.stack_size + } + + /// Sets the stack size of the worker threads + pub fn stack_size(mut self, stack_size: usize) -> Self { + self.stack_size = Some(stack_size); + self + } + + /// **(DEPRECATED)** Suggest to worker threads that they execute + /// spawned jobs in a "breadth-first" fashion. + /// + /// Typically, when a worker thread is idle or blocked, it will + /// attempt to execute the job from the *top* of its local deque of + /// work (i.e., the job most recently spawned). If this flag is set + /// to true, however, workers will prefer to execute in a + /// *breadth-first* fashion -- that is, they will search for jobs at + /// the *bottom* of their local deque. (At present, workers *always* + /// steal from the bottom of other workers' deques, regardless of + /// the setting of this flag.) + /// + /// If you think of the tasks as a tree, where a parent task + /// spawns its children in the tree, then this flag loosely + /// corresponds to doing a breadth-first traversal of the tree, + /// whereas the default would be to do a depth-first traversal. + /// + /// **Note that this is an "execution hint".** Rayon's task + /// execution is highly dynamic and the precise order in which + /// independent tasks are executed is not intended to be + /// guaranteed. + /// + /// This `breadth_first()` method is now deprecated per [RFC #1], + /// and in the future its effect may be removed. Consider using + /// [`scope_fifo()`] for a similar effect. + /// + /// [RFC #1]: https://github.com/rayon-rs/rfcs/blob/master/accepted/rfc0001-scope-scheduling.md + /// [`scope_fifo()`]: fn.scope_fifo.html + #[deprecated(note = "use `scope_fifo` and `spawn_fifo` for similar effect")] + pub fn breadth_first(mut self) -> Self { + self.breadth_first = true; + self + } + + fn get_breadth_first(&self) -> bool { + self.breadth_first + } + + /// Takes the current acquire thread callback, leaving `None`. + fn take_acquire_thread_handler(&mut self) -> Option> { + self.acquire_thread_handler.take() + } + + /// Set a callback to be invoked when starting computations in a thread. + pub fn acquire_thread_handler(mut self, acquire_thread_handler: H) -> Self + where + H: Fn() + Send + Sync + 'static, + { + self.acquire_thread_handler = Some(Box::new(acquire_thread_handler)); + self + } + + /// Takes the current release thread callback, leaving `None`. + fn take_release_thread_handler(&mut self) -> Option> { + self.release_thread_handler.take() + } + + /// Set a callback to be invoked when blocking in thread. + pub fn release_thread_handler(mut self, release_thread_handler: H) -> Self + where + H: Fn() + Send + Sync + 'static, + { + self.release_thread_handler = Some(Box::new(release_thread_handler)); + self + } + + /// Takes the current deadlock callback, leaving `None`. + fn take_deadlock_handler(&mut self) -> Option> { + self.deadlock_handler.take() + } + + /// Set a callback to be invoked on current deadlock. + pub fn deadlock_handler(mut self, deadlock_handler: H) -> Self + where + H: Fn() + Send + Sync + 'static, + { + self.deadlock_handler = Some(Box::new(deadlock_handler)); + self + } + + /// Takes the current thread start callback, leaving `None`. + fn take_start_handler(&mut self) -> Option> { + self.start_handler.take() + } + + /// Sets a callback to be invoked on thread start. + /// + /// The closure is passed the index of the thread on which it is invoked. + /// Note that this same closure may be invoked multiple times in parallel. + /// If this closure panics, the panic will be passed to the panic handler. + /// If that handler returns, then startup will continue normally. + pub fn start_handler(mut self, start_handler: H) -> Self + where + H: Fn(usize) + Send + Sync + 'static, + { + self.start_handler = Some(Box::new(start_handler)); + self + } + + /// Returns a current thread exit callback, leaving `None`. + fn take_exit_handler(&mut self) -> Option> { + self.exit_handler.take() + } + + /// Sets a callback to be invoked on thread exit. + /// + /// The closure is passed the index of the thread on which it is invoked. + /// Note that this same closure may be invoked multiple times in parallel. + /// If this closure panics, the panic will be passed to the panic handler. + /// If that handler returns, then the thread will exit normally. + pub fn exit_handler(mut self, exit_handler: H) -> Self + where + H: Fn(usize) + Send + Sync + 'static, + { + self.exit_handler = Some(Box::new(exit_handler)); + self + } +} + +#[allow(deprecated)] +impl Configuration { + /// Creates and return a valid rayon thread pool configuration, but does not initialize it. + pub fn new() -> Configuration { + Configuration { + builder: ThreadPoolBuilder::new(), + } + } + + /// Deprecated in favor of `ThreadPoolBuilder::build`. + pub fn build(self) -> Result> { + self.builder.build().map_err(Box::from) + } + + /// Deprecated in favor of `ThreadPoolBuilder::thread_name`. + pub fn thread_name(mut self, closure: F) -> Self + where + F: FnMut(usize) -> String + 'static, + { + self.builder = self.builder.thread_name(closure); + self + } + + /// Deprecated in favor of `ThreadPoolBuilder::num_threads`. + pub fn num_threads(mut self, num_threads: usize) -> Configuration { + self.builder = self.builder.num_threads(num_threads); + self + } + + /// Deprecated in favor of `ThreadPoolBuilder::panic_handler`. + pub fn panic_handler(mut self, panic_handler: H) -> Configuration + where + H: Fn(Box) + Send + Sync + 'static, + { + self.builder = self.builder.panic_handler(panic_handler); + self + } + + /// Deprecated in favor of `ThreadPoolBuilder::stack_size`. + pub fn stack_size(mut self, stack_size: usize) -> Self { + self.builder = self.builder.stack_size(stack_size); + self + } + + /// Deprecated in favor of `ThreadPoolBuilder::breadth_first`. + pub fn breadth_first(mut self) -> Self { + self.builder = self.builder.breadth_first(); + self + } + + /// Deprecated in favor of `ThreadPoolBuilder::start_handler`. + pub fn start_handler(mut self, start_handler: H) -> Configuration + where + H: Fn(usize) + Send + Sync + 'static, + { + self.builder = self.builder.start_handler(start_handler); + self + } + + /// Deprecated in favor of `ThreadPoolBuilder::exit_handler`. + pub fn exit_handler(mut self, exit_handler: H) -> Configuration + where + H: Fn(usize) + Send + Sync + 'static, + { + self.builder = self.builder.exit_handler(exit_handler); + self + } + + /// Returns a ThreadPoolBuilder with identical parameters. + fn into_builder(self) -> ThreadPoolBuilder { + self.builder + } +} + +impl ThreadPoolBuildError { + fn new(kind: ErrorKind) -> ThreadPoolBuildError { + ThreadPoolBuildError { kind } + } + + fn is_unsupported(&self) -> bool { + matches!(&self.kind, ErrorKind::IOError(e) if e.kind() == io::ErrorKind::Unsupported) + } +} + +const GLOBAL_POOL_ALREADY_INITIALIZED: &str = + "The global thread pool has already been initialized."; + +impl Error for ThreadPoolBuildError { + #[allow(deprecated)] + fn description(&self) -> &str { + match self.kind { + ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED, + ErrorKind::IOError(ref e) => e.description(), + } + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + match &self.kind { + ErrorKind::GlobalPoolAlreadyInitialized => None, + ErrorKind::IOError(e) => Some(e), + } + } +} + +impl fmt::Display for ThreadPoolBuildError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.kind { + ErrorKind::GlobalPoolAlreadyInitialized => GLOBAL_POOL_ALREADY_INITIALIZED.fmt(f), + ErrorKind::IOError(e) => e.fmt(f), + } + } +} + +/// Deprecated in favor of `ThreadPoolBuilder::build_global`. +#[deprecated(note = "use `ThreadPoolBuilder::build_global`")] +#[allow(deprecated)] +pub fn initialize(config: Configuration) -> Result<(), Box> { + config.into_builder().build_global().map_err(Box::from) +} + +impl fmt::Debug for ThreadPoolBuilder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ThreadPoolBuilder { + ref num_threads, + ref get_thread_name, + ref panic_handler, + ref stack_size, + ref deadlock_handler, + ref start_handler, + ref exit_handler, + ref acquire_thread_handler, + ref release_thread_handler, + spawn_handler: _, + ref breadth_first, + } = *self; + + // Just print `Some()` or `None` to the debug + // output. + struct ClosurePlaceholder; + impl fmt::Debug for ClosurePlaceholder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } + } + let get_thread_name = get_thread_name.as_ref().map(|_| ClosurePlaceholder); + let panic_handler = panic_handler.as_ref().map(|_| ClosurePlaceholder); + let deadlock_handler = deadlock_handler.as_ref().map(|_| ClosurePlaceholder); + let start_handler = start_handler.as_ref().map(|_| ClosurePlaceholder); + let exit_handler = exit_handler.as_ref().map(|_| ClosurePlaceholder); + let acquire_thread_handler = acquire_thread_handler.as_ref().map(|_| ClosurePlaceholder); + let release_thread_handler = release_thread_handler.as_ref().map(|_| ClosurePlaceholder); + + f.debug_struct("ThreadPoolBuilder") + .field("num_threads", num_threads) + .field("get_thread_name", &get_thread_name) + .field("panic_handler", &panic_handler) + .field("stack_size", &stack_size) + .field("deadlock_handler", &deadlock_handler) + .field("start_handler", &start_handler) + .field("exit_handler", &exit_handler) + .field("acquire_thread_handler", &acquire_thread_handler) + .field("release_thread_handler", &release_thread_handler) + .field("breadth_first", &breadth_first) + .finish() + } +} + +#[allow(deprecated)] +impl fmt::Debug for Configuration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.builder.fmt(f) + } +} + +/// Provides the calling context to a closure called by `join_context`. +#[derive(Debug)] +pub struct FnContext { + migrated: bool, + + /// disable `Send` and `Sync`, just for a little future-proofing. + _marker: PhantomData<*mut ()>, +} + +impl FnContext { + #[inline] + fn new(migrated: bool) -> Self { + FnContext { + migrated, + _marker: PhantomData, + } + } +} + +impl FnContext { + /// Returns `true` if the closure was called from a different thread + /// than it was provided from. + #[inline] + pub fn migrated(&self) -> bool { + self.migrated + } +} diff --git a/compiler/rustc_thread_pool/src/private.rs b/compiler/rustc_thread_pool/src/private.rs new file mode 100644 index 000000000000..c85e77b9cbb7 --- /dev/null +++ b/compiler/rustc_thread_pool/src/private.rs @@ -0,0 +1,26 @@ +//! The public parts of this private module are used to create traits +//! that cannot be implemented outside of our own crate. This way we +//! can feel free to extend those traits without worrying about it +//! being a breaking change for other implementations. + +/// If this type is pub but not publicly reachable, third parties +/// can't name it and can't implement traits using it. +#[allow(missing_debug_implementations)] +pub struct PrivateMarker; + +macro_rules! private_decl { + () => { + /// This trait is private; this method exists to make it + /// impossible to implement outside the crate. + #[doc(hidden)] + fn __rayon_private__(&self) -> crate::private::PrivateMarker; + }; +} + +macro_rules! private_impl { + () => { + fn __rayon_private__(&self) -> crate::private::PrivateMarker { + crate::private::PrivateMarker + } + }; +} diff --git a/compiler/rustc_thread_pool/src/registry.rs b/compiler/rustc_thread_pool/src/registry.rs new file mode 100644 index 000000000000..781b6827b829 --- /dev/null +++ b/compiler/rustc_thread_pool/src/registry.rs @@ -0,0 +1,1048 @@ +use crate::job::{JobFifo, JobRef, StackJob}; +use crate::latch::{AsCoreLatch, CoreLatch, Latch, LatchRef, LockLatch, OnceLatch, SpinLatch}; +use crate::sleep::Sleep; +use crate::tlv::Tlv; +use crate::unwind; +use crate::{ + AcquireThreadHandler, DeadlockHandler, ErrorKind, ExitHandler, PanicHandler, + ReleaseThreadHandler, StartHandler, ThreadPoolBuildError, ThreadPoolBuilder, Yield, +}; +use crossbeam_deque::{Injector, Steal, Stealer, Worker}; +use std::cell::Cell; +use std::collections::hash_map::DefaultHasher; +use std::fmt; +use std::hash::Hasher; +use std::io; +use std::mem; +use std::ptr; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex, Once}; +use std::thread; + +/// Thread builder used for customization via +/// [`ThreadPoolBuilder::spawn_handler`](struct.ThreadPoolBuilder.html#method.spawn_handler). +pub struct ThreadBuilder { + name: Option, + stack_size: Option, + worker: Worker, + stealer: Stealer, + registry: Arc, + index: usize, +} + +impl ThreadBuilder { + /// Gets the index of this thread in the pool, within `0..num_threads`. + pub fn index(&self) -> usize { + self.index + } + + /// Gets the string that was specified by `ThreadPoolBuilder::name()`. + pub fn name(&self) -> Option<&str> { + self.name.as_deref() + } + + /// Gets the value that was specified by `ThreadPoolBuilder::stack_size()`. + pub fn stack_size(&self) -> Option { + self.stack_size + } + + /// Executes the main loop for this thread. This will not return until the + /// thread pool is dropped. + pub fn run(self) { + unsafe { main_loop(self) } + } +} + +impl fmt::Debug for ThreadBuilder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ThreadBuilder") + .field("pool", &self.registry.id()) + .field("index", &self.index) + .field("name", &self.name) + .field("stack_size", &self.stack_size) + .finish() + } +} + +/// Generalized trait for spawning a thread in the `Registry`. +/// +/// This trait is pub-in-private -- E0445 forces us to make it public, +/// but we don't actually want to expose these details in the API. +pub trait ThreadSpawn { + private_decl! {} + + /// Spawn a thread with the `ThreadBuilder` parameters, and then + /// call `ThreadBuilder::run()`. + fn spawn(&mut self, thread: ThreadBuilder) -> io::Result<()>; +} + +/// Spawns a thread in the "normal" way with `std::thread::Builder`. +/// +/// This type is pub-in-private -- E0445 forces us to make it public, +/// but we don't actually want to expose these details in the API. +#[derive(Debug, Default)] +pub struct DefaultSpawn; + +impl ThreadSpawn for DefaultSpawn { + private_impl! {} + + fn spawn(&mut self, thread: ThreadBuilder) -> io::Result<()> { + let mut b = thread::Builder::new(); + if let Some(name) = thread.name() { + b = b.name(name.to_owned()); + } + if let Some(stack_size) = thread.stack_size() { + b = b.stack_size(stack_size); + } + b.spawn(|| thread.run())?; + Ok(()) + } +} + +/// Spawns a thread with a user's custom callback. +/// +/// This type is pub-in-private -- E0445 forces us to make it public, +/// but we don't actually want to expose these details in the API. +#[derive(Debug)] +pub struct CustomSpawn(F); + +impl CustomSpawn +where + F: FnMut(ThreadBuilder) -> io::Result<()>, +{ + pub(super) fn new(spawn: F) -> Self { + CustomSpawn(spawn) + } +} + +impl ThreadSpawn for CustomSpawn +where + F: FnMut(ThreadBuilder) -> io::Result<()>, +{ + private_impl! {} + + #[inline] + fn spawn(&mut self, thread: ThreadBuilder) -> io::Result<()> { + (self.0)(thread) + } +} + +pub struct Registry { + thread_infos: Vec, + sleep: Sleep, + injected_jobs: Injector, + broadcasts: Mutex>>, + panic_handler: Option>, + pub(crate) deadlock_handler: Option>, + start_handler: Option>, + exit_handler: Option>, + pub(crate) acquire_thread_handler: Option>, + pub(crate) release_thread_handler: Option>, + + // When this latch reaches 0, it means that all work on this + // registry must be complete. This is ensured in the following ways: + // + // - if this is the global registry, there is a ref-count that never + // gets released. + // - if this is a user-created thread-pool, then so long as the thread-pool + // exists, it holds a reference. + // - when we inject a "blocking job" into the registry with `ThreadPool::install()`, + // no adjustment is needed; the `ThreadPool` holds the reference, and since we won't + // return until the blocking job is complete, that ref will continue to be held. + // - when `join()` or `scope()` is invoked, similarly, no adjustments are needed. + // These are always owned by some other job (e.g., one injected by `ThreadPool::install()`) + // and that job will keep the pool alive. + terminate_count: AtomicUsize, +} + +/// //////////////////////////////////////////////////////////////////////// +/// Initialization + +static mut THE_REGISTRY: Option> = None; +static THE_REGISTRY_SET: Once = Once::new(); + +/// Starts the worker threads (if that has not already happened). If +/// initialization has not already occurred, use the default +/// configuration. +pub(super) fn global_registry() -> &'static Arc { + set_global_registry(default_global_registry) + .or_else(|err| { + // SAFETY: we only create a shared reference to `THE_REGISTRY` after the `call_once` + // that initializes it, and there will be no more mutable accesses at all. + debug_assert!(THE_REGISTRY_SET.is_completed()); + let the_registry = unsafe { &*ptr::addr_of!(THE_REGISTRY) }; + the_registry.as_ref().ok_or(err) + }) + .expect("The global thread pool has not been initialized.") +} + +/// Starts the worker threads (if that has not already happened) with +/// the given builder. +pub(super) fn init_global_registry( + builder: ThreadPoolBuilder, +) -> Result<&'static Arc, ThreadPoolBuildError> +where + S: ThreadSpawn, +{ + set_global_registry(|| Registry::new(builder)) +} + +/// Starts the worker threads (if that has not already happened) +/// by creating a registry with the given callback. +fn set_global_registry(registry: F) -> Result<&'static Arc, ThreadPoolBuildError> +where + F: FnOnce() -> Result, ThreadPoolBuildError>, +{ + let mut result = Err(ThreadPoolBuildError::new( + ErrorKind::GlobalPoolAlreadyInitialized, + )); + + THE_REGISTRY_SET.call_once(|| { + result = registry().map(|registry: Arc| { + // SAFETY: this is the only mutable access to `THE_REGISTRY`, thanks to `Once`, and + // `global_registry()` only takes a shared reference **after** this `call_once`. + unsafe { + ptr::addr_of_mut!(THE_REGISTRY).write(Some(registry)); + (*ptr::addr_of!(THE_REGISTRY)).as_ref().unwrap_unchecked() + } + }) + }); + + result +} + +fn default_global_registry() -> Result, ThreadPoolBuildError> { + let result = Registry::new(ThreadPoolBuilder::new()); + + // If we're running in an environment that doesn't support threads at all, we can fall back to + // using the current thread alone. This is crude, and probably won't work for non-blocking + // calls like `spawn` or `broadcast_spawn`, but a lot of stuff does work fine. + // + // Notably, this allows current WebAssembly targets to work even though their threading support + // is stubbed out, and we won't have to change anything if they do add real threading. + let unsupported = matches!(&result, Err(e) if e.is_unsupported()); + if unsupported && WorkerThread::current().is_null() { + let builder = ThreadPoolBuilder::new() + .num_threads(1) + .spawn_handler(|thread| { + // Rather than starting a new thread, we're just taking over the current thread + // *without* running the main loop, so we can still return from here. + // The WorkerThread is leaked, but we never shutdown the global pool anyway. + let worker_thread = Box::leak(Box::new(WorkerThread::from(thread))); + let registry = &*worker_thread.registry; + let index = worker_thread.index; + + unsafe { + WorkerThread::set_current(worker_thread); + + // let registry know we are ready to do work + Latch::set(®istry.thread_infos[index].primed); + } + + Ok(()) + }); + + let fallback_result = Registry::new(builder); + if fallback_result.is_ok() { + return fallback_result; + } + } + + result +} + +struct Terminator<'a>(&'a Arc); + +impl<'a> Drop for Terminator<'a> { + fn drop(&mut self) { + self.0.terminate() + } +} + +impl Registry { + pub(super) fn new( + mut builder: ThreadPoolBuilder, + ) -> Result, ThreadPoolBuildError> + where + S: ThreadSpawn, + { + // Soft-limit the number of threads that we can actually support. + let n_threads = Ord::min(builder.get_num_threads(), crate::max_num_threads()); + + let breadth_first = builder.get_breadth_first(); + + let (workers, stealers): (Vec<_>, Vec<_>) = (0..n_threads) + .map(|_| { + let worker = if breadth_first { + Worker::new_fifo() + } else { + Worker::new_lifo() + }; + + let stealer = worker.stealer(); + (worker, stealer) + }) + .unzip(); + + let (broadcasts, broadcast_stealers): (Vec<_>, Vec<_>) = (0..n_threads) + .map(|_| { + let worker = Worker::new_fifo(); + let stealer = worker.stealer(); + (worker, stealer) + }) + .unzip(); + + let registry = Arc::new(Registry { + thread_infos: stealers.into_iter().map(ThreadInfo::new).collect(), + sleep: Sleep::new(n_threads), + injected_jobs: Injector::new(), + broadcasts: Mutex::new(broadcasts), + terminate_count: AtomicUsize::new(1), + panic_handler: builder.take_panic_handler(), + deadlock_handler: builder.take_deadlock_handler(), + start_handler: builder.take_start_handler(), + exit_handler: builder.take_exit_handler(), + acquire_thread_handler: builder.take_acquire_thread_handler(), + release_thread_handler: builder.take_release_thread_handler(), + }); + + // If we return early or panic, make sure to terminate existing threads. + let t1000 = Terminator(®istry); + + for (index, (worker, stealer)) in workers.into_iter().zip(broadcast_stealers).enumerate() { + let thread = ThreadBuilder { + name: builder.get_thread_name(index), + stack_size: builder.get_stack_size(), + registry: Arc::clone(®istry), + worker, + stealer, + index, + }; + if let Err(e) = builder.get_spawn_handler().spawn(thread) { + return Err(ThreadPoolBuildError::new(ErrorKind::IOError(e))); + } + } + + // Returning normally now, without termination. + mem::forget(t1000); + + Ok(registry) + } + + pub fn current() -> Arc { + unsafe { + let worker_thread = WorkerThread::current(); + let registry = if worker_thread.is_null() { + global_registry() + } else { + &(*worker_thread).registry + }; + Arc::clone(registry) + } + } + + /// Returns the number of threads in the current registry. This + /// is better than `Registry::current().num_threads()` because it + /// avoids incrementing the `Arc`. + pub(super) fn current_num_threads() -> usize { + unsafe { + let worker_thread = WorkerThread::current(); + if worker_thread.is_null() { + global_registry().num_threads() + } else { + (*worker_thread).registry.num_threads() + } + } + } + + /// Returns the current `WorkerThread` if it's part of this `Registry`. + pub(super) fn current_thread(&self) -> Option<&WorkerThread> { + unsafe { + let worker = WorkerThread::current().as_ref()?; + if worker.registry().id() == self.id() { + Some(worker) + } else { + None + } + } + } + + /// Returns an opaque identifier for this registry. + pub(super) fn id(&self) -> RegistryId { + // We can rely on `self` not to change since we only ever create + // registries that are boxed up in an `Arc` (see `new()` above). + RegistryId { + addr: self as *const Self as usize, + } + } + + pub(super) fn num_threads(&self) -> usize { + self.thread_infos.len() + } + + pub(super) fn catch_unwind(&self, f: impl FnOnce()) { + if let Err(err) = unwind::halt_unwinding(f) { + // If there is no handler, or if that handler itself panics, then we abort. + let abort_guard = unwind::AbortIfPanic; + if let Some(ref handler) = self.panic_handler { + handler(err); + mem::forget(abort_guard); + } + } + } + + /// Waits for the worker threads to get up and running. This is + /// meant to be used for benchmarking purposes, primarily, so that + /// you can get more consistent numbers by having everything + /// "ready to go". + pub(super) fn wait_until_primed(&self) { + for info in &self.thread_infos { + info.primed.wait(); + } + } + + /// Waits for the worker threads to stop. This is used for testing + /// -- so we can check that termination actually works. + pub(super) fn wait_until_stopped(&self) { + self.release_thread(); + for info in &self.thread_infos { + info.stopped.wait(); + } + self.acquire_thread(); + } + + pub(crate) fn acquire_thread(&self) { + if let Some(ref acquire_thread_handler) = self.acquire_thread_handler { + acquire_thread_handler(); + } + } + + pub(crate) fn release_thread(&self) { + if let Some(ref release_thread_handler) = self.release_thread_handler { + release_thread_handler(); + } + } + + /// //////////////////////////////////////////////////////////////////////// + /// MAIN LOOP + /// + /// So long as all of the worker threads are hanging out in their + /// top-level loop, there is no work to be done. + + /// Push a job into the given `registry`. If we are running on a + /// worker thread for the registry, this will push onto the + /// deque. Else, it will inject from the outside (which is slower). + pub(super) fn inject_or_push(&self, job_ref: JobRef) { + let worker_thread = WorkerThread::current(); + unsafe { + if !worker_thread.is_null() && (*worker_thread).registry().id() == self.id() { + (*worker_thread).push(job_ref); + } else { + self.inject(job_ref); + } + } + } + + /// Push a job into the "external jobs" queue; it will be taken by + /// whatever worker has nothing to do. Use this if you know that + /// you are not on a worker of this registry. + pub(super) fn inject(&self, injected_job: JobRef) { + // It should not be possible for `state.terminate` to be true + // here. It is only set to true when the user creates (and + // drops) a `ThreadPool`; and, in that case, they cannot be + // calling `inject()` later, since they dropped their + // `ThreadPool`. + debug_assert_ne!( + self.terminate_count.load(Ordering::Acquire), + 0, + "inject() sees state.terminate as true" + ); + + let queue_was_empty = self.injected_jobs.is_empty(); + + self.injected_jobs.push(injected_job); + self.sleep.new_injected_jobs(1, queue_was_empty); + } + + pub(crate) fn has_injected_job(&self) -> bool { + !self.injected_jobs.is_empty() + } + + fn pop_injected_job(&self) -> Option { + loop { + match self.injected_jobs.steal() { + Steal::Success(job) => return Some(job), + Steal::Empty => return None, + Steal::Retry => {} + } + } + } + + /// Push a job into each thread's own "external jobs" queue; it will be + /// executed only on that thread, when it has nothing else to do locally, + /// before it tries to steal other work. + /// + /// **Panics** if not given exactly as many jobs as there are threads. + pub(super) fn inject_broadcast(&self, injected_jobs: impl ExactSizeIterator) { + assert_eq!(self.num_threads(), injected_jobs.len()); + { + let broadcasts = self.broadcasts.lock().unwrap(); + + // It should not be possible for `state.terminate` to be true + // here. It is only set to true when the user creates (and + // drops) a `ThreadPool`; and, in that case, they cannot be + // calling `inject_broadcast()` later, since they dropped their + // `ThreadPool`. + debug_assert_ne!( + self.terminate_count.load(Ordering::Acquire), + 0, + "inject_broadcast() sees state.terminate as true" + ); + + assert_eq!(broadcasts.len(), injected_jobs.len()); + for (worker, job_ref) in broadcasts.iter().zip(injected_jobs) { + worker.push(job_ref); + } + } + for i in 0..self.num_threads() { + self.sleep.notify_worker_latch_is_set(i); + } + } + + /// If already in a worker-thread of this registry, just execute `op`. + /// Otherwise, inject `op` in this thread-pool. Either way, block until `op` + /// completes and return its return value. If `op` panics, that panic will + /// be propagated as well. The second argument indicates `true` if injection + /// was performed, `false` if executed directly. + pub(super) fn in_worker(&self, op: OP) -> R + where + OP: FnOnce(&WorkerThread, bool) -> R + Send, + R: Send, + { + unsafe { + let worker_thread = WorkerThread::current(); + if worker_thread.is_null() { + self.in_worker_cold(op) + } else if (*worker_thread).registry().id() != self.id() { + self.in_worker_cross(&*worker_thread, op) + } else { + // Perfectly valid to give them a `&T`: this is the + // current thread, so we know the data structure won't be + // invalidated until we return. + op(&*worker_thread, false) + } + } + } + + #[cold] + unsafe fn in_worker_cold(&self, op: OP) -> R + where + OP: FnOnce(&WorkerThread, bool) -> R + Send, + R: Send, + { + thread_local!(static LOCK_LATCH: LockLatch = LockLatch::new()); + + LOCK_LATCH.with(|l| { + // This thread isn't a member of *any* thread pool, so just block. + debug_assert!(WorkerThread::current().is_null()); + let job = StackJob::new( + Tlv::null(), + |injected| { + let worker_thread = WorkerThread::current(); + assert!(injected && !worker_thread.is_null()); + op(&*worker_thread, true) + }, + LatchRef::new(l), + ); + self.inject(job.as_job_ref()); + self.release_thread(); + job.latch.wait_and_reset(); // Make sure we can use the same latch again next time. + self.acquire_thread(); + + job.into_result() + }) + } + + #[cold] + unsafe fn in_worker_cross(&self, current_thread: &WorkerThread, op: OP) -> R + where + OP: FnOnce(&WorkerThread, bool) -> R + Send, + R: Send, + { + // This thread is a member of a different pool, so let it process + // other work while waiting for this `op` to complete. + debug_assert!(current_thread.registry().id() != self.id()); + let latch = SpinLatch::cross(current_thread); + let job = StackJob::new( + Tlv::null(), + |injected| { + let worker_thread = WorkerThread::current(); + assert!(injected && !worker_thread.is_null()); + op(&*worker_thread, true) + }, + latch, + ); + self.inject(job.as_job_ref()); + current_thread.wait_until(&job.latch); + job.into_result() + } + + /// Increments the terminate counter. This increment should be + /// balanced by a call to `terminate`, which will decrement. This + /// is used when spawning asynchronous work, which needs to + /// prevent the registry from terminating so long as it is active. + /// + /// Note that blocking functions such as `join` and `scope` do not + /// need to concern themselves with this fn; their context is + /// responsible for ensuring the current thread-pool will not + /// terminate until they return. + /// + /// The global thread-pool always has an outstanding reference + /// (the initial one). Custom thread-pools have one outstanding + /// reference that is dropped when the `ThreadPool` is dropped: + /// since installing the thread-pool blocks until any joins/scopes + /// complete, this ensures that joins/scopes are covered. + /// + /// The exception is `::spawn()`, which can create a job outside + /// of any blocking scope. In that case, the job itself holds a + /// terminate count and is responsible for invoking `terminate()` + /// when finished. + pub(super) fn increment_terminate_count(&self) { + let previous = self.terminate_count.fetch_add(1, Ordering::AcqRel); + debug_assert!(previous != 0, "registry ref count incremented from zero"); + assert!(previous != usize::MAX, "overflow in registry ref count"); + } + + /// Signals that the thread-pool which owns this registry has been + /// dropped. The worker threads will gradually terminate, once any + /// extant work is completed. + pub(super) fn terminate(&self) { + if self.terminate_count.fetch_sub(1, Ordering::AcqRel) == 1 { + for (i, thread_info) in self.thread_infos.iter().enumerate() { + unsafe { OnceLatch::set_and_tickle_one(&thread_info.terminate, self, i) }; + } + } + } + + /// Notify the worker that the latch they are sleeping on has been "set". + pub(super) fn notify_worker_latch_is_set(&self, target_worker_index: usize) { + self.sleep.notify_worker_latch_is_set(target_worker_index); + } +} + +/// Mark a Rayon worker thread as blocked. This triggers the deadlock handler +/// if no other worker thread is active +#[inline] +pub fn mark_blocked() { + let worker_thread = WorkerThread::current(); + assert!(!worker_thread.is_null()); + unsafe { + let registry = &(*worker_thread).registry; + registry.sleep.mark_blocked(®istry.deadlock_handler) + } +} + +/// Mark a previously blocked Rayon worker thread as unblocked +#[inline] +pub fn mark_unblocked(registry: &Registry) { + registry.sleep.mark_unblocked() +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub(super) struct RegistryId { + addr: usize, +} + +struct ThreadInfo { + /// Latch set once thread has started and we are entering into the + /// main loop. Used to wait for worker threads to become primed, + /// primarily of interest for benchmarking. + primed: LockLatch, + + /// Latch is set once worker thread has completed. Used to wait + /// until workers have stopped; only used for tests. + stopped: LockLatch, + + /// The latch used to signal that terminated has been requested. + /// This latch is *set* by the `terminate` method on the + /// `Registry`, once the registry's main "terminate" counter + /// reaches zero. + terminate: OnceLatch, + + /// the "stealer" half of the worker's deque + stealer: Stealer, +} + +impl ThreadInfo { + fn new(stealer: Stealer) -> ThreadInfo { + ThreadInfo { + primed: LockLatch::new(), + stopped: LockLatch::new(), + terminate: OnceLatch::new(), + stealer, + } + } +} + +/// //////////////////////////////////////////////////////////////////////// +/// WorkerThread identifiers + +pub(super) struct WorkerThread { + /// the "worker" half of our local deque + worker: Worker, + + /// the "stealer" half of the worker's broadcast deque + stealer: Stealer, + + /// local queue used for `spawn_fifo` indirection + fifo: JobFifo, + + pub(crate) index: usize, + + /// A weak random number generator. + rng: XorShift64Star, + + pub(crate) registry: Arc, +} + +// This is a bit sketchy, but basically: the WorkerThread is +// allocated on the stack of the worker on entry and stored into this +// thread local variable. So it will remain valid at least until the +// worker is fully unwound. Using an unsafe pointer avoids the need +// for a RefCell etc. +thread_local! { + static WORKER_THREAD_STATE: Cell<*const WorkerThread> = const { Cell::new(ptr::null()) }; +} + +impl From for WorkerThread { + fn from(thread: ThreadBuilder) -> Self { + Self { + worker: thread.worker, + stealer: thread.stealer, + fifo: JobFifo::new(), + index: thread.index, + rng: XorShift64Star::new(), + registry: thread.registry, + } + } +} + +impl Drop for WorkerThread { + fn drop(&mut self) { + // Undo `set_current` + WORKER_THREAD_STATE.with(|t| { + assert!(t.get().eq(&(self as *const _))); + t.set(ptr::null()); + }); + } +} + +impl WorkerThread { + /// Gets the `WorkerThread` index for the current thread; returns + /// NULL if this is not a worker thread. This pointer is valid + /// anywhere on the current thread. + #[inline] + pub(super) fn current() -> *const WorkerThread { + WORKER_THREAD_STATE.with(Cell::get) + } + + /// Sets `self` as the worker thread index for the current thread. + /// This is done during worker thread startup. + unsafe fn set_current(thread: *const WorkerThread) { + WORKER_THREAD_STATE.with(|t| { + assert!(t.get().is_null()); + t.set(thread); + }); + } + + /// Returns the registry that owns this worker thread. + #[inline] + pub(super) fn registry(&self) -> &Arc { + &self.registry + } + + /// Our index amongst the worker threads (ranges from `0..self.num_threads()`). + #[inline] + pub(super) fn index(&self) -> usize { + self.index + } + + #[inline] + pub(super) unsafe fn push(&self, job: JobRef) { + let queue_was_empty = self.worker.is_empty(); + self.worker.push(job); + self.registry.sleep.new_internal_jobs(1, queue_was_empty); + } + + #[inline] + pub(super) unsafe fn push_fifo(&self, job: JobRef) { + self.push(self.fifo.push(job)); + } + + #[inline] + pub(super) fn local_deque_is_empty(&self) -> bool { + self.worker.is_empty() + } + + /// Attempts to obtain a "local" job -- typically this means + /// popping from the top of the stack, though if we are configured + /// for breadth-first execution, it would mean dequeuing from the + /// bottom. + #[inline] + pub(super) fn take_local_job(&self) -> Option { + let popped_job = self.worker.pop(); + + if popped_job.is_some() { + return popped_job; + } + + loop { + match self.stealer.steal() { + Steal::Success(job) => return Some(job), + Steal::Empty => return None, + Steal::Retry => {} + } + } + } + + pub(super) fn has_injected_job(&self) -> bool { + !self.stealer.is_empty() || self.registry.has_injected_job() + } + + /// Wait until the latch is set. Try to keep busy by popping and + /// stealing tasks as necessary. + #[inline] + pub(super) unsafe fn wait_until(&self, latch: &L) { + let latch = latch.as_core_latch(); + if !latch.probe() { + self.wait_until_cold(latch); + } + } + + #[cold] + unsafe fn wait_until_cold(&self, latch: &CoreLatch) { + // the code below should swallow all panics and hence never + // unwind; but if something does wrong, we want to abort, + // because otherwise other code in rayon may assume that the + // latch has been signaled, and that can lead to random memory + // accesses, which would be *very bad* + let abort_guard = unwind::AbortIfPanic; + + 'outer: while !latch.probe() { + // Check for local work *before* we start marking ourself idle, + // especially to avoid modifying shared sleep state. + if let Some(job) = self.take_local_job() { + self.execute(job); + continue; + } + + let mut idle_state = self.registry.sleep.start_looking(self.index); + while !latch.probe() { + if let Some(job) = self.find_work() { + self.registry.sleep.work_found(); + self.execute(job); + // The job might have injected local work, so go back to the outer loop. + continue 'outer; + } else { + self.registry + .sleep + .no_work_found(&mut idle_state, latch, &self) + } + } + + // If we were sleepy, we are not anymore. We "found work" -- + // whatever the surrounding thread was doing before it had to wait. + self.registry.sleep.work_found(); + break; + } + + mem::forget(abort_guard); // successful execution, do not abort + } + + unsafe fn wait_until_out_of_work(&self) { + debug_assert_eq!(self as *const _, WorkerThread::current()); + let registry = &*self.registry; + let index = self.index; + + registry.acquire_thread(); + self.wait_until(®istry.thread_infos[index].terminate); + + // Should not be any work left in our queue. + debug_assert!(self.take_local_job().is_none()); + + // Let registry know we are done + Latch::set(®istry.thread_infos[index].stopped); + } + + fn find_work(&self) -> Option { + // Try to find some work to do. We give preference first + // to things in our local deque, then in other workers + // deques, and finally to injected jobs from the + // outside. The idea is to finish what we started before + // we take on something new. + self.take_local_job() + .or_else(|| self.steal()) + .or_else(|| self.registry.pop_injected_job()) + } + + pub(super) fn yield_now(&self) -> Yield { + match self.find_work() { + Some(job) => unsafe { + self.execute(job); + Yield::Executed + }, + None => Yield::Idle, + } + } + + pub(super) fn yield_local(&self) -> Yield { + match self.take_local_job() { + Some(job) => unsafe { + self.execute(job); + Yield::Executed + }, + None => Yield::Idle, + } + } + + #[inline] + pub(super) unsafe fn execute(&self, job: JobRef) { + job.execute(); + } + + /// Try to steal a single job and return it. + /// + /// This should only be done as a last resort, when there is no + /// local work to do. + fn steal(&self) -> Option { + // we only steal when we don't have any work to do locally + debug_assert!(self.local_deque_is_empty()); + + // otherwise, try to steal + let thread_infos = &self.registry.thread_infos.as_slice(); + let num_threads = thread_infos.len(); + if num_threads <= 1 { + return None; + } + + loop { + let mut retry = false; + let start = self.rng.next_usize(num_threads); + let job = (start..num_threads) + .chain(0..start) + .filter(move |&i| i != self.index) + .find_map(|victim_index| { + let victim = &thread_infos[victim_index]; + match victim.stealer.steal() { + Steal::Success(job) => Some(job), + Steal::Empty => None, + Steal::Retry => { + retry = true; + None + } + } + }); + if job.is_some() || !retry { + return job; + } + } + } +} + +/// //////////////////////////////////////////////////////////////////////// + +unsafe fn main_loop(thread: ThreadBuilder) { + let worker_thread = &WorkerThread::from(thread); + WorkerThread::set_current(worker_thread); + let registry = &*worker_thread.registry; + let index = worker_thread.index; + + // let registry know we are ready to do work + Latch::set(®istry.thread_infos[index].primed); + + // Worker threads should not panic. If they do, just abort, as the + // internal state of the threadpool is corrupted. Note that if + // **user code** panics, we should catch that and redirect. + let abort_guard = unwind::AbortIfPanic; + + // Inform a user callback that we started a thread. + if let Some(ref handler) = registry.start_handler { + registry.catch_unwind(|| handler(index)); + } + + worker_thread.wait_until_out_of_work(); + + // Normal termination, do not abort. + mem::forget(abort_guard); + + // Inform a user callback that we exited a thread. + if let Some(ref handler) = registry.exit_handler { + registry.catch_unwind(|| handler(index)); + // We're already exiting the thread, there's nothing else to do. + } + + registry.release_thread(); +} + +/// If already in a worker-thread, just execute `op`. Otherwise, +/// execute `op` in the default thread-pool. Either way, block until +/// `op` completes and return its return value. If `op` panics, that +/// panic will be propagated as well. The second argument indicates +/// `true` if injection was performed, `false` if executed directly. +pub(super) fn in_worker(op: OP) -> R +where + OP: FnOnce(&WorkerThread, bool) -> R + Send, + R: Send, +{ + unsafe { + let owner_thread = WorkerThread::current(); + if !owner_thread.is_null() { + // Perfectly valid to give them a `&T`: this is the + // current thread, so we know the data structure won't be + // invalidated until we return. + op(&*owner_thread, false) + } else { + global_registry().in_worker(op) + } + } +} + +/// [xorshift*] is a fast pseudorandom number generator which will +/// even tolerate weak seeding, as long as it's not zero. +/// +/// [xorshift*]: https://en.wikipedia.org/wiki/Xorshift#xorshift* +struct XorShift64Star { + state: Cell, +} + +impl XorShift64Star { + fn new() -> Self { + // Any non-zero seed will do -- this uses the hash of a global counter. + let mut seed = 0; + while seed == 0 { + let mut hasher = DefaultHasher::new(); + static COUNTER: AtomicUsize = AtomicUsize::new(0); + hasher.write_usize(COUNTER.fetch_add(1, Ordering::Relaxed)); + seed = hasher.finish(); + } + + XorShift64Star { + state: Cell::new(seed), + } + } + + fn next(&self) -> u64 { + let mut x = self.state.get(); + debug_assert_ne!(x, 0); + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + self.state.set(x); + x.wrapping_mul(0x2545_f491_4f6c_dd1d) + } + + /// Return a value from `0..n`. + fn next_usize(&self, n: usize) -> usize { + (self.next() % n as u64) as usize + } +} diff --git a/compiler/rustc_thread_pool/src/scope/mod.rs b/compiler/rustc_thread_pool/src/scope/mod.rs new file mode 100644 index 000000000000..364b322baadf --- /dev/null +++ b/compiler/rustc_thread_pool/src/scope/mod.rs @@ -0,0 +1,783 @@ +//! Methods for custom fork-join scopes, created by the [`scope()`] +//! and [`in_place_scope()`] functions. These are a more flexible alternative to [`join()`]. +//! +//! [`scope()`]: fn.scope.html +//! [`in_place_scope()`]: fn.in_place_scope.html +//! [`join()`]: ../join/join.fn.html + +use crate::broadcast::BroadcastContext; +use crate::job::{ArcJob, HeapJob, JobFifo, JobRef}; +use crate::latch::{CountLatch, Latch}; +use crate::registry::{global_registry, in_worker, Registry, WorkerThread}; +use crate::tlv::{self, Tlv}; +use crate::unwind; +use std::any::Any; +use std::fmt; +use std::marker::PhantomData; +use std::mem::ManuallyDrop; +use std::ptr; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::sync::Arc; + +#[cfg(test)] +mod test; + +/// Represents a fork-join scope which can be used to spawn any number of tasks. +/// See [`scope()`] for more information. +/// +///[`scope()`]: fn.scope.html +pub struct Scope<'scope> { + base: ScopeBase<'scope>, +} + +/// Represents a fork-join scope which can be used to spawn any number of tasks. +/// Those spawned from the same thread are prioritized in relative FIFO order. +/// See [`scope_fifo()`] for more information. +/// +///[`scope_fifo()`]: fn.scope_fifo.html +pub struct ScopeFifo<'scope> { + base: ScopeBase<'scope>, + fifos: Vec, +} + +struct ScopeBase<'scope> { + /// thread registry where `scope()` was executed or where `in_place_scope()` + /// should spawn jobs. + registry: Arc, + + /// if some job panicked, the error is stored here; it will be + /// propagated to the one who created the scope + panic: AtomicPtr>, + + /// latch to track job counts + job_completed_latch: CountLatch, + + /// You can think of a scope as containing a list of closures to execute, + /// all of which outlive `'scope`. They're not actually required to be + /// `Sync`, but it's still safe to let the `Scope` implement `Sync` because + /// the closures are only *moved* across threads to be executed. + #[allow(clippy::type_complexity)] + marker: PhantomData) + Send + Sync + 'scope>>, + + /// The TLV at the scope's creation. Used to set the TLV for spawned jobs. + tlv: Tlv, +} + +/// Creates a "fork-join" scope `s` and invokes the closure with a +/// reference to `s`. This closure can then spawn asynchronous tasks +/// into `s`. Those tasks may run asynchronously with respect to the +/// closure; they may themselves spawn additional tasks into `s`. When +/// the closure returns, it will block until all tasks that have been +/// spawned into `s` complete. +/// +/// `scope()` is a more flexible building block compared to `join()`, +/// since a loop can be used to spawn any number of tasks without +/// recursing. However, that flexibility comes at a performance price: +/// tasks spawned using `scope()` must be allocated onto the heap, +/// whereas `join()` can make exclusive use of the stack. **Prefer +/// `join()` (or, even better, parallel iterators) where possible.** +/// +/// # Example +/// +/// The Rayon `join()` function launches two closures and waits for them +/// to stop. One could implement `join()` using a scope like so, although +/// it would be less efficient than the real implementation: +/// +/// ```rust +/// # use rayon_core as rayon; +/// pub fn join(oper_a: A, oper_b: B) -> (RA, RB) +/// where A: FnOnce() -> RA + Send, +/// B: FnOnce() -> RB + Send, +/// RA: Send, +/// RB: Send, +/// { +/// let mut result_a: Option = None; +/// let mut result_b: Option = None; +/// rayon::scope(|s| { +/// s.spawn(|_| result_a = Some(oper_a())); +/// s.spawn(|_| result_b = Some(oper_b())); +/// }); +/// (result_a.unwrap(), result_b.unwrap()) +/// } +/// ``` +/// +/// # A note on threading +/// +/// The closure given to `scope()` executes in the Rayon thread-pool, +/// as do those given to `spawn()`. This means that you can't access +/// thread-local variables (well, you can, but they may have +/// unexpected values). +/// +/// # Task execution +/// +/// Task execution potentially starts as soon as `spawn()` is called. +/// The task will end sometime before `scope()` returns. Note that the +/// *closure* given to scope may return much earlier. In general +/// the lifetime of a scope created like `scope(body)` goes something like this: +/// +/// - Scope begins when `scope(body)` is called +/// - Scope body `body()` is invoked +/// - Scope tasks may be spawned +/// - Scope body returns +/// - Scope tasks execute, possibly spawning more tasks +/// - Once all tasks are done, scope ends and `scope()` returns +/// +/// To see how and when tasks are joined, consider this example: +/// +/// ```rust +/// # use rayon_core as rayon; +/// // point start +/// rayon::scope(|s| { +/// s.spawn(|s| { // task s.1 +/// s.spawn(|s| { // task s.1.1 +/// rayon::scope(|t| { +/// t.spawn(|_| ()); // task t.1 +/// t.spawn(|_| ()); // task t.2 +/// }); +/// }); +/// }); +/// s.spawn(|s| { // task s.2 +/// }); +/// // point mid +/// }); +/// // point end +/// ``` +/// +/// The various tasks that are run will execute roughly like so: +/// +/// ```notrust +/// | (start) +/// | +/// | (scope `s` created) +/// +-----------------------------------------------+ (task s.2) +/// +-------+ (task s.1) | +/// | | | +/// | +---+ (task s.1.1) | +/// | | | | +/// | | | (scope `t` created) | +/// | | +----------------+ (task t.2) | +/// | | +---+ (task t.1) | | +/// | (mid) | | | | | +/// : | + <-+------------+ (scope `t` ends) | +/// : | | | +/// |<------+---+-----------------------------------+ (scope `s` ends) +/// | +/// | (end) +/// ``` +/// +/// The point here is that everything spawned into scope `s` will +/// terminate (at latest) at the same point -- right before the +/// original call to `rayon::scope` returns. This includes new +/// subtasks created by other subtasks (e.g., task `s.1.1`). If a new +/// scope is created (such as `t`), the things spawned into that scope +/// will be joined before that scope returns, which in turn occurs +/// before the creating task (task `s.1.1` in this case) finishes. +/// +/// There is no guaranteed order of execution for spawns in a scope, +/// given that other threads may steal tasks at any time. However, they +/// are generally prioritized in a LIFO order on the thread from which +/// they were spawned. So in this example, absent any stealing, we can +/// expect `s.2` to execute before `s.1`, and `t.2` before `t.1`. Other +/// threads always steal from the other end of the deque, like FIFO +/// order. The idea is that "recent" tasks are most likely to be fresh +/// in the local CPU's cache, while other threads can steal older +/// "stale" tasks. For an alternate approach, consider +/// [`scope_fifo()`] instead. +/// +/// [`scope_fifo()`]: fn.scope_fifo.html +/// +/// # Accessing stack data +/// +/// In general, spawned tasks may access stack data in place that +/// outlives the scope itself. Other data must be fully owned by the +/// spawned task. +/// +/// ```rust +/// # use rayon_core as rayon; +/// let ok: Vec = vec![1, 2, 3]; +/// rayon::scope(|s| { +/// let bad: Vec = vec![4, 5, 6]; +/// s.spawn(|_| { +/// // We can access `ok` because outlives the scope `s`. +/// println!("ok: {:?}", ok); +/// +/// // If we just try to use `bad` here, the closure will borrow `bad` +/// // (because we are just printing it out, and that only requires a +/// // borrow), which will result in a compilation error. Read on +/// // for options. +/// // println!("bad: {:?}", bad); +/// }); +/// }); +/// ``` +/// +/// As the comments example above suggest, to reference `bad` we must +/// take ownership of it. One way to do this is to detach the closure +/// from the surrounding stack frame, using the `move` keyword. This +/// will cause it to take ownership of *all* the variables it touches, +/// in this case including both `ok` *and* `bad`: +/// +/// ```rust +/// # use rayon_core as rayon; +/// let ok: Vec = vec![1, 2, 3]; +/// rayon::scope(|s| { +/// let bad: Vec = vec![4, 5, 6]; +/// s.spawn(move |_| { +/// println!("ok: {:?}", ok); +/// println!("bad: {:?}", bad); +/// }); +/// +/// // That closure is fine, but now we can't use `ok` anywhere else, +/// // since it is owned by the previous task: +/// // s.spawn(|_| println!("ok: {:?}", ok)); +/// }); +/// ``` +/// +/// While this works, it could be a problem if we want to use `ok` elsewhere. +/// There are two choices. We can keep the closure as a `move` closure, but +/// instead of referencing the variable `ok`, we create a shadowed variable that +/// is a borrow of `ok` and capture *that*: +/// +/// ```rust +/// # use rayon_core as rayon; +/// let ok: Vec = vec![1, 2, 3]; +/// rayon::scope(|s| { +/// let bad: Vec = vec![4, 5, 6]; +/// let ok: &Vec = &ok; // shadow the original `ok` +/// s.spawn(move |_| { +/// println!("ok: {:?}", ok); // captures the shadowed version +/// println!("bad: {:?}", bad); +/// }); +/// +/// // Now we too can use the shadowed `ok`, since `&Vec` references +/// // can be shared freely. Note that we need a `move` closure here though, +/// // because otherwise we'd be trying to borrow the shadowed `ok`, +/// // and that doesn't outlive `scope`. +/// s.spawn(move |_| println!("ok: {:?}", ok)); +/// }); +/// ``` +/// +/// Another option is not to use the `move` keyword but instead to take ownership +/// of individual variables: +/// +/// ```rust +/// # use rayon_core as rayon; +/// let ok: Vec = vec![1, 2, 3]; +/// rayon::scope(|s| { +/// let bad: Vec = vec![4, 5, 6]; +/// s.spawn(|_| { +/// // Transfer ownership of `bad` into a local variable (also named `bad`). +/// // This will force the closure to take ownership of `bad` from the environment. +/// let bad = bad; +/// println!("ok: {:?}", ok); // `ok` is only borrowed. +/// println!("bad: {:?}", bad); // refers to our local variable, above. +/// }); +/// +/// s.spawn(|_| println!("ok: {:?}", ok)); // we too can borrow `ok` +/// }); +/// ``` +/// +/// # Panics +/// +/// If a panic occurs, either in the closure given to `scope()` or in +/// any of the spawned jobs, that panic will be propagated and the +/// call to `scope()` will panic. If multiple panics occurs, it is +/// non-deterministic which of their panic values will propagate. +/// Regardless, once a task is spawned using `scope.spawn()`, it will +/// execute, even if the spawning task should later panic. `scope()` +/// returns once all spawned jobs have completed, and any panics are +/// propagated at that point. +pub fn scope<'scope, OP, R>(op: OP) -> R +where + OP: FnOnce(&Scope<'scope>) -> R + Send, + R: Send, +{ + in_worker(|owner_thread, _| { + let scope = Scope::<'scope>::new(Some(owner_thread), None); + scope.base.complete(Some(owner_thread), || op(&scope)) + }) +} + +/// Creates a "fork-join" scope `s` with FIFO order, and invokes the +/// closure with a reference to `s`. This closure can then spawn +/// asynchronous tasks into `s`. Those tasks may run asynchronously with +/// respect to the closure; they may themselves spawn additional tasks +/// into `s`. When the closure returns, it will block until all tasks +/// that have been spawned into `s` complete. +/// +/// # Task execution +/// +/// Tasks in a `scope_fifo()` run similarly to [`scope()`], but there's a +/// difference in the order of execution. Consider a similar example: +/// +/// [`scope()`]: fn.scope.html +/// +/// ```rust +/// # use rayon_core as rayon; +/// // point start +/// rayon::scope_fifo(|s| { +/// s.spawn_fifo(|s| { // task s.1 +/// s.spawn_fifo(|s| { // task s.1.1 +/// rayon::scope_fifo(|t| { +/// t.spawn_fifo(|_| ()); // task t.1 +/// t.spawn_fifo(|_| ()); // task t.2 +/// }); +/// }); +/// }); +/// s.spawn_fifo(|s| { // task s.2 +/// }); +/// // point mid +/// }); +/// // point end +/// ``` +/// +/// The various tasks that are run will execute roughly like so: +/// +/// ```notrust +/// | (start) +/// | +/// | (FIFO scope `s` created) +/// +--------------------+ (task s.1) +/// +-------+ (task s.2) | +/// | | +---+ (task s.1.1) +/// | | | | +/// | | | | (FIFO scope `t` created) +/// | | | +----------------+ (task t.1) +/// | | | +---+ (task t.2) | +/// | (mid) | | | | | +/// : | | + <-+------------+ (scope `t` ends) +/// : | | | +/// |<------+------------+---+ (scope `s` ends) +/// | +/// | (end) +/// ``` +/// +/// Under `scope_fifo()`, the spawns are prioritized in a FIFO order on +/// the thread from which they were spawned, as opposed to `scope()`'s +/// LIFO. So in this example, we can expect `s.1` to execute before +/// `s.2`, and `t.1` before `t.2`. Other threads also steal tasks in +/// FIFO order, as usual. Overall, this has roughly the same order as +/// the now-deprecated [`breadth_first`] option, except the effect is +/// isolated to a particular scope. If spawns are intermingled from any +/// combination of `scope()` and `scope_fifo()`, or from different +/// threads, their order is only specified with respect to spawns in the +/// same scope and thread. +/// +/// For more details on this design, see Rayon [RFC #1]. +/// +/// [`breadth_first`]: struct.ThreadPoolBuilder.html#method.breadth_first +/// [RFC #1]: https://github.com/rayon-rs/rfcs/blob/master/accepted/rfc0001-scope-scheduling.md +/// +/// # Panics +/// +/// If a panic occurs, either in the closure given to `scope_fifo()` or +/// in any of the spawned jobs, that panic will be propagated and the +/// call to `scope_fifo()` will panic. If multiple panics occurs, it is +/// non-deterministic which of their panic values will propagate. +/// Regardless, once a task is spawned using `scope.spawn_fifo()`, it +/// will execute, even if the spawning task should later panic. +/// `scope_fifo()` returns once all spawned jobs have completed, and any +/// panics are propagated at that point. +pub fn scope_fifo<'scope, OP, R>(op: OP) -> R +where + OP: FnOnce(&ScopeFifo<'scope>) -> R + Send, + R: Send, +{ + in_worker(|owner_thread, _| { + let scope = ScopeFifo::<'scope>::new(Some(owner_thread), None); + scope.base.complete(Some(owner_thread), || op(&scope)) + }) +} + +/// Creates a "fork-join" scope `s` and invokes the closure with a +/// reference to `s`. This closure can then spawn asynchronous tasks +/// into `s`. Those tasks may run asynchronously with respect to the +/// closure; they may themselves spawn additional tasks into `s`. When +/// the closure returns, it will block until all tasks that have been +/// spawned into `s` complete. +/// +/// This is just like `scope()` except the closure runs on the same thread +/// that calls `in_place_scope()`. Only work that it spawns runs in the +/// thread pool. +/// +/// # Panics +/// +/// If a panic occurs, either in the closure given to `in_place_scope()` or in +/// any of the spawned jobs, that panic will be propagated and the +/// call to `in_place_scope()` will panic. If multiple panics occurs, it is +/// non-deterministic which of their panic values will propagate. +/// Regardless, once a task is spawned using `scope.spawn()`, it will +/// execute, even if the spawning task should later panic. `in_place_scope()` +/// returns once all spawned jobs have completed, and any panics are +/// propagated at that point. +pub fn in_place_scope<'scope, OP, R>(op: OP) -> R +where + OP: FnOnce(&Scope<'scope>) -> R, +{ + do_in_place_scope(None, op) +} + +pub(crate) fn do_in_place_scope<'scope, OP, R>(registry: Option<&Arc>, op: OP) -> R +where + OP: FnOnce(&Scope<'scope>) -> R, +{ + let thread = unsafe { WorkerThread::current().as_ref() }; + let scope = Scope::<'scope>::new(thread, registry); + scope.base.complete(thread, || op(&scope)) +} + +/// Creates a "fork-join" scope `s` with FIFO order, and invokes the +/// closure with a reference to `s`. This closure can then spawn +/// asynchronous tasks into `s`. Those tasks may run asynchronously with +/// respect to the closure; they may themselves spawn additional tasks +/// into `s`. When the closure returns, it will block until all tasks +/// that have been spawned into `s` complete. +/// +/// This is just like `scope_fifo()` except the closure runs on the same thread +/// that calls `in_place_scope_fifo()`. Only work that it spawns runs in the +/// thread pool. +/// +/// # Panics +/// +/// If a panic occurs, either in the closure given to `in_place_scope_fifo()` or in +/// any of the spawned jobs, that panic will be propagated and the +/// call to `in_place_scope_fifo()` will panic. If multiple panics occurs, it is +/// non-deterministic which of their panic values will propagate. +/// Regardless, once a task is spawned using `scope.spawn_fifo()`, it will +/// execute, even if the spawning task should later panic. `in_place_scope_fifo()` +/// returns once all spawned jobs have completed, and any panics are +/// propagated at that point. +pub fn in_place_scope_fifo<'scope, OP, R>(op: OP) -> R +where + OP: FnOnce(&ScopeFifo<'scope>) -> R, +{ + do_in_place_scope_fifo(None, op) +} + +pub(crate) fn do_in_place_scope_fifo<'scope, OP, R>(registry: Option<&Arc>, op: OP) -> R +where + OP: FnOnce(&ScopeFifo<'scope>) -> R, +{ + let thread = unsafe { WorkerThread::current().as_ref() }; + let scope = ScopeFifo::<'scope>::new(thread, registry); + scope.base.complete(thread, || op(&scope)) +} + +impl<'scope> Scope<'scope> { + fn new(owner: Option<&WorkerThread>, registry: Option<&Arc>) -> Self { + let base = ScopeBase::new(owner, registry); + Scope { base } + } + + /// Spawns a job into the fork-join scope `self`. This job will + /// execute sometime before the fork-join scope completes. The + /// job is specified as a closure, and this closure receives its + /// own reference to the scope `self` as argument. This can be + /// used to inject new jobs into `self`. + /// + /// # Returns + /// + /// Nothing. The spawned closures cannot pass back values to the + /// caller directly, though they can write to local variables on + /// the stack (if those variables outlive the scope) or + /// communicate through shared channels. + /// + /// (The intention is to eventually integrate with Rust futures to + /// support spawns of functions that compute a value.) + /// + /// # Examples + /// + /// ```rust + /// # use rayon_core as rayon; + /// let mut value_a = None; + /// let mut value_b = None; + /// let mut value_c = None; + /// rayon::scope(|s| { + /// s.spawn(|s1| { + /// // ^ this is the same scope as `s`; this handle `s1` + /// // is intended for use by the spawned task, + /// // since scope handles cannot cross thread boundaries. + /// + /// value_a = Some(22); + /// + /// // the scope `s` will not end until all these tasks are done + /// s1.spawn(|_| { + /// value_b = Some(44); + /// }); + /// }); + /// + /// s.spawn(|_| { + /// value_c = Some(66); + /// }); + /// }); + /// assert_eq!(value_a, Some(22)); + /// assert_eq!(value_b, Some(44)); + /// assert_eq!(value_c, Some(66)); + /// ``` + /// + /// # See also + /// + /// The [`scope` function] has more extensive documentation about + /// task spawning. + /// + /// [`scope` function]: fn.scope.html + pub fn spawn(&self, body: BODY) + where + BODY: FnOnce(&Scope<'scope>) + Send + 'scope, + { + let scope_ptr = ScopePtr(self); + let job = HeapJob::new(self.base.tlv, move || unsafe { + // SAFETY: this job will execute before the scope ends. + let scope = scope_ptr.as_ref(); + ScopeBase::execute_job(&scope.base, move || body(scope)) + }); + let job_ref = self.base.heap_job_ref(job); + + // Since `Scope` implements `Sync`, we can't be sure that we're still in a + // thread of this pool, so we can't just push to the local worker thread. + // Also, this might be an in-place scope. + self.base.registry.inject_or_push(job_ref); + } + + /// Spawns a job into every thread of the fork-join scope `self`. This job will + /// execute on each thread sometime before the fork-join scope completes. The + /// job is specified as a closure, and this closure receives its own reference + /// to the scope `self` as argument, as well as a `BroadcastContext`. + pub fn spawn_broadcast(&self, body: BODY) + where + BODY: Fn(&Scope<'scope>, BroadcastContext<'_>) + Send + Sync + 'scope, + { + let scope_ptr = ScopePtr(self); + let job = ArcJob::new(move || unsafe { + // SAFETY: this job will execute before the scope ends. + let scope = scope_ptr.as_ref(); + let body = &body; + let func = move || BroadcastContext::with(move |ctx| body(scope, ctx)); + ScopeBase::execute_job(&scope.base, func) + }); + self.base.inject_broadcast(job) + } +} + +impl<'scope> ScopeFifo<'scope> { + fn new(owner: Option<&WorkerThread>, registry: Option<&Arc>) -> Self { + let base = ScopeBase::new(owner, registry); + let num_threads = base.registry.num_threads(); + let fifos = (0..num_threads).map(|_| JobFifo::new()).collect(); + ScopeFifo { base, fifos } + } + + /// Spawns a job into the fork-join scope `self`. This job will + /// execute sometime before the fork-join scope completes. The + /// job is specified as a closure, and this closure receives its + /// own reference to the scope `self` as argument. This can be + /// used to inject new jobs into `self`. + /// + /// # See also + /// + /// This method is akin to [`Scope::spawn()`], but with a FIFO + /// priority. The [`scope_fifo` function] has more details about + /// this distinction. + /// + /// [`Scope::spawn()`]: struct.Scope.html#method.spawn + /// [`scope_fifo` function]: fn.scope_fifo.html + pub fn spawn_fifo(&self, body: BODY) + where + BODY: FnOnce(&ScopeFifo<'scope>) + Send + 'scope, + { + let scope_ptr = ScopePtr(self); + let job = HeapJob::new(self.base.tlv, move || unsafe { + // SAFETY: this job will execute before the scope ends. + let scope = scope_ptr.as_ref(); + ScopeBase::execute_job(&scope.base, move || body(scope)) + }); + let job_ref = self.base.heap_job_ref(job); + + // If we're in the pool, use our scope's private fifo for this thread to execute + // in a locally-FIFO order. Otherwise, just use the pool's global injector. + match self.base.registry.current_thread() { + Some(worker) => { + let fifo = &self.fifos[worker.index()]; + // SAFETY: this job will execute before the scope ends. + unsafe { worker.push(fifo.push(job_ref)) }; + } + None => self.base.registry.inject(job_ref), + } + } + + /// Spawns a job into every thread of the fork-join scope `self`. This job will + /// execute on each thread sometime before the fork-join scope completes. The + /// job is specified as a closure, and this closure receives its own reference + /// to the scope `self` as argument, as well as a `BroadcastContext`. + pub fn spawn_broadcast(&self, body: BODY) + where + BODY: Fn(&ScopeFifo<'scope>, BroadcastContext<'_>) + Send + Sync + 'scope, + { + let scope_ptr = ScopePtr(self); + let job = ArcJob::new(move || unsafe { + // SAFETY: this job will execute before the scope ends. + let scope = scope_ptr.as_ref(); + let body = &body; + let func = move || BroadcastContext::with(move |ctx| body(scope, ctx)); + ScopeBase::execute_job(&scope.base, func) + }); + self.base.inject_broadcast(job) + } +} + +impl<'scope> ScopeBase<'scope> { + /// Creates the base of a new scope for the given registry + fn new(owner: Option<&WorkerThread>, registry: Option<&Arc>) -> Self { + let registry = registry.unwrap_or_else(|| match owner { + Some(owner) => owner.registry(), + None => global_registry(), + }); + + ScopeBase { + registry: Arc::clone(registry), + panic: AtomicPtr::new(ptr::null_mut()), + job_completed_latch: CountLatch::new(owner), + marker: PhantomData, + tlv: tlv::get(), + } + } + + fn heap_job_ref(&self, job: Box>) -> JobRef + where + FUNC: FnOnce() + Send + 'scope, + { + unsafe { + self.job_completed_latch.increment(); + job.into_job_ref() + } + } + + fn inject_broadcast(&self, job: Arc>) + where + FUNC: Fn() + Send + Sync + 'scope, + { + let n_threads = self.registry.num_threads(); + let job_refs = (0..n_threads).map(|_| unsafe { + self.job_completed_latch.increment(); + ArcJob::as_job_ref(&job) + }); + + self.registry.inject_broadcast(job_refs); + } + + /// Executes `func` as a job, either aborting or executing as + /// appropriate. + fn complete(&self, owner: Option<&WorkerThread>, func: FUNC) -> R + where + FUNC: FnOnce() -> R, + { + let result = unsafe { Self::execute_job_closure(self, func) }; + self.job_completed_latch.wait(owner); + + // Restore the TLV if we ran some jobs while waiting + tlv::set(self.tlv); + + self.maybe_propagate_panic(); + result.unwrap() // only None if `op` panicked, and that would have been propagated + } + + /// Executes `func` as a job, either aborting or executing as + /// appropriate. + unsafe fn execute_job(this: *const Self, func: FUNC) + where + FUNC: FnOnce(), + { + let _: Option<()> = Self::execute_job_closure(this, func); + } + + /// Executes `func` as a job in scope. Adjusts the "job completed" + /// counters and also catches any panic and stores it into + /// `scope`. + unsafe fn execute_job_closure(this: *const Self, func: FUNC) -> Option + where + FUNC: FnOnce() -> R, + { + let result = match unwind::halt_unwinding(func) { + Ok(r) => Some(r), + Err(err) => { + (*this).job_panicked(err); + None + } + }; + Latch::set(&(*this).job_completed_latch); + result + } + + fn job_panicked(&self, err: Box) { + // capture the first error we see, free the rest + if self.panic.load(Ordering::Relaxed).is_null() { + let nil = ptr::null_mut(); + let mut err = ManuallyDrop::new(Box::new(err)); // box up the fat ptr + let err_ptr: *mut Box = &mut **err; + if self + .panic + .compare_exchange(nil, err_ptr, Ordering::Release, Ordering::Relaxed) + .is_ok() + { + // ownership now transferred into self.panic + } else { + // another panic raced in ahead of us, so drop ours + let _: Box> = ManuallyDrop::into_inner(err); + } + } + } + + fn maybe_propagate_panic(&self) { + // propagate panic, if any occurred; at this point, all + // outstanding jobs have completed, so we can use a relaxed + // ordering: + let panic = self.panic.swap(ptr::null_mut(), Ordering::Relaxed); + if !panic.is_null() { + let value = unsafe { Box::from_raw(panic) }; + + // Restore the TLV if we ran some jobs while waiting + tlv::set(self.tlv); + + unwind::resume_unwinding(*value); + } + } +} + +impl<'scope> fmt::Debug for Scope<'scope> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Scope") + .field("pool_id", &self.base.registry.id()) + .field("panic", &self.base.panic) + .field("job_completed_latch", &self.base.job_completed_latch) + .finish() + } +} + +impl<'scope> fmt::Debug for ScopeFifo<'scope> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("ScopeFifo") + .field("num_fifos", &self.fifos.len()) + .field("pool_id", &self.base.registry.id()) + .field("panic", &self.base.panic) + .field("job_completed_latch", &self.base.job_completed_latch) + .finish() + } +} + +/// Used to capture a scope `&Self` pointer in jobs, without faking a lifetime. +/// +/// Unsafe code is still required to dereference the pointer, but that's fine in +/// scope jobs that are guaranteed to execute before the scope ends. +struct ScopePtr(*const T); + +// SAFETY: !Send for raw pointers is not for safety, just as a lint +unsafe impl Send for ScopePtr {} + +// SAFETY: !Sync for raw pointers is not for safety, just as a lint +unsafe impl Sync for ScopePtr {} + +impl ScopePtr { + // Helper to avoid disjoint captures of `scope_ptr.0` + unsafe fn as_ref(&self) -> &T { + &*self.0 + } +} diff --git a/compiler/rustc_thread_pool/src/scope/test.rs b/compiler/rustc_thread_pool/src/scope/test.rs new file mode 100644 index 000000000000..4505ba7c4fba --- /dev/null +++ b/compiler/rustc_thread_pool/src/scope/test.rs @@ -0,0 +1,622 @@ +use crate::unwind; +use crate::ThreadPoolBuilder; +use crate::{scope, scope_fifo, Scope, ScopeFifo}; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; +use std::iter::once; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Barrier, Mutex}; +use std::vec; + +#[test] +fn scope_empty() { + scope(|_| {}); +} + +#[test] +fn scope_result() { + let x = scope(|_| 22); + assert_eq!(x, 22); +} + +#[test] +fn scope_two() { + let counter = &AtomicUsize::new(0); + scope(|s| { + s.spawn(move |_| { + counter.fetch_add(1, Ordering::SeqCst); + }); + s.spawn(move |_| { + counter.fetch_add(10, Ordering::SeqCst); + }); + }); + + let v = counter.load(Ordering::SeqCst); + assert_eq!(v, 11); +} + +#[test] +fn scope_divide_and_conquer() { + let counter_p = &AtomicUsize::new(0); + scope(|s| s.spawn(move |s| divide_and_conquer(s, counter_p, 1024))); + + let counter_s = &AtomicUsize::new(0); + divide_and_conquer_seq(counter_s, 1024); + + let p = counter_p.load(Ordering::SeqCst); + let s = counter_s.load(Ordering::SeqCst); + assert_eq!(p, s); +} + +fn divide_and_conquer<'scope>(scope: &Scope<'scope>, counter: &'scope AtomicUsize, size: usize) { + if size > 1 { + scope.spawn(move |scope| divide_and_conquer(scope, counter, size / 2)); + scope.spawn(move |scope| divide_and_conquer(scope, counter, size / 2)); + } else { + // count the leaves + counter.fetch_add(1, Ordering::SeqCst); + } +} + +fn divide_and_conquer_seq(counter: &AtomicUsize, size: usize) { + if size > 1 { + divide_and_conquer_seq(counter, size / 2); + divide_and_conquer_seq(counter, size / 2); + } else { + // count the leaves + counter.fetch_add(1, Ordering::SeqCst); + } +} + +struct Tree { + value: T, + children: Vec>, +} + +impl Tree { + fn iter(&self) -> vec::IntoIter<&T> { + once(&self.value) + .chain(self.children.iter().flat_map(Tree::iter)) + .collect::>() // seems like it shouldn't be needed... but prevents overflow + .into_iter() + } + + fn update(&mut self, op: OP) + where + OP: Fn(&mut T) + Sync, + T: Send, + { + scope(|s| self.update_in_scope(&op, s)); + } + + fn update_in_scope<'scope, OP>(&'scope mut self, op: &'scope OP, scope: &Scope<'scope>) + where + OP: Fn(&mut T) + Sync, + { + let Tree { + ref mut value, + ref mut children, + } = *self; + scope.spawn(move |scope| { + for child in children { + scope.spawn(move |scope| child.update_in_scope(op, scope)); + } + }); + + op(value); + } +} + +fn random_tree(depth: usize) -> Tree { + assert!(depth > 0); + let mut seed = ::Seed::default(); + (0..).zip(seed.as_mut()).for_each(|(i, x)| *x = i); + let mut rng = XorShiftRng::from_seed(seed); + random_tree1(depth, &mut rng) +} + +fn random_tree1(depth: usize, rng: &mut XorShiftRng) -> Tree { + let children = if depth == 0 { + vec![] + } else { + (0..rng.random_range(0..4)) // somewhere between 0 and 3 children at each level + .map(|_| random_tree1(depth - 1, rng)) + .collect() + }; + + Tree { + value: rng.random_range(0..1_000_000), + children, + } +} + +#[test] +fn update_tree() { + let mut tree: Tree = random_tree(10); + let values: Vec = tree.iter().cloned().collect(); + tree.update(|v| *v += 1); + let new_values: Vec = tree.iter().cloned().collect(); + assert_eq!(values.len(), new_values.len()); + for (&i, &j) in values.iter().zip(&new_values) { + assert_eq!(i + 1, j); + } +} + +/// Check that if you have a chain of scoped tasks where T0 spawns T1 +/// spawns T2 and so forth down to Tn, the stack space should not grow +/// linearly with N. We test this by some unsafe hackery and +/// permitting an approx 10% change with a 10x input change. +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn linear_stack_growth() { + let builder = ThreadPoolBuilder::new().num_threads(1); + let pool = builder.build().unwrap(); + pool.install(|| { + let mut max_diff = Mutex::new(0); + let bottom_of_stack = 0; + scope(|s| the_final_countdown(s, &bottom_of_stack, &max_diff, 5)); + let diff_when_5 = *max_diff.get_mut().unwrap() as f64; + + scope(|s| the_final_countdown(s, &bottom_of_stack, &max_diff, 500)); + let diff_when_500 = *max_diff.get_mut().unwrap() as f64; + + let ratio = diff_when_5 / diff_when_500; + assert!( + ratio > 0.9 && ratio < 1.1, + "stack usage ratio out of bounds: {}", + ratio + ); + }); +} + +fn the_final_countdown<'scope>( + s: &Scope<'scope>, + bottom_of_stack: &'scope i32, + max: &'scope Mutex, + n: usize, +) { + let top_of_stack = 0; + let p = bottom_of_stack as *const i32 as usize; + let q = &top_of_stack as *const i32 as usize; + let diff = if p > q { p - q } else { q - p }; + + let mut data = max.lock().unwrap(); + *data = Ord::max(diff, *data); + + if n > 0 { + s.spawn(move |s| the_final_countdown(s, bottom_of_stack, max, n - 1)); + } +} + +#[test] +#[should_panic(expected = "Hello, world!")] +fn panic_propagate_scope() { + scope(|_| panic!("Hello, world!")); +} + +#[test] +#[should_panic(expected = "Hello, world!")] +fn panic_propagate_spawn() { + scope(|s| s.spawn(|_| panic!("Hello, world!"))); +} + +#[test] +#[should_panic(expected = "Hello, world!")] +fn panic_propagate_nested_spawn() { + scope(|s| s.spawn(|s| s.spawn(|s| s.spawn(|_| panic!("Hello, world!"))))); +} + +#[test] +#[should_panic(expected = "Hello, world!")] +fn panic_propagate_nested_scope_spawn() { + scope(|s| s.spawn(|_| scope(|s| s.spawn(|_| panic!("Hello, world!"))))); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn panic_propagate_still_execute_1() { + let mut x = false; + let result = unwind::halt_unwinding(|| { + scope(|s| { + s.spawn(|_| panic!("Hello, world!")); // job A + s.spawn(|_| x = true); // job B, should still execute even though A panics + }); + }); + match result { + Ok(_) => panic!("failed to propagate panic"), + Err(_) => assert!(x, "job b failed to execute"), + } +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn panic_propagate_still_execute_2() { + let mut x = false; + let result = unwind::halt_unwinding(|| { + scope(|s| { + s.spawn(|_| x = true); // job B, should still execute even though A panics + s.spawn(|_| panic!("Hello, world!")); // job A + }); + }); + match result { + Ok(_) => panic!("failed to propagate panic"), + Err(_) => assert!(x, "job b failed to execute"), + } +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn panic_propagate_still_execute_3() { + let mut x = false; + let result = unwind::halt_unwinding(|| { + scope(|s| { + s.spawn(|_| x = true); // spawned job should still execute despite later panic + panic!("Hello, world!"); + }); + }); + match result { + Ok(_) => panic!("failed to propagate panic"), + Err(_) => assert!(x, "panic after spawn, spawn failed to execute"), + } +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn panic_propagate_still_execute_4() { + let mut x = false; + let result = unwind::halt_unwinding(|| { + scope(|s| { + s.spawn(|_| panic!("Hello, world!")); + x = true; + }); + }); + match result { + Ok(_) => panic!("failed to propagate panic"), + Err(_) => assert!(x, "panic in spawn tainted scope"), + } +} + +macro_rules! test_order { + ($scope:ident => $spawn:ident) => {{ + let builder = ThreadPoolBuilder::new().num_threads(1); + let pool = builder.build().unwrap(); + pool.install(|| { + let vec = Mutex::new(vec![]); + $scope(|scope| { + let vec = &vec; + for i in 0..10 { + scope.$spawn(move |scope| { + for j in 0..10 { + scope.$spawn(move |_| { + vec.lock().unwrap().push(i * 10 + j); + }); + } + }); + } + }); + vec.into_inner().unwrap() + }) + }}; +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn lifo_order() { + // In the absence of stealing, `scope()` runs its `spawn()` jobs in LIFO order. + let vec = test_order!(scope => spawn); + let expected: Vec = (0..100).rev().collect(); // LIFO -> reversed + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn fifo_order() { + // In the absence of stealing, `scope_fifo()` runs its `spawn_fifo()` jobs in FIFO order. + let vec = test_order!(scope_fifo => spawn_fifo); + let expected: Vec = (0..100).collect(); // FIFO -> natural order + assert_eq!(vec, expected); +} + +macro_rules! test_nested_order { + ($outer_scope:ident => $outer_spawn:ident, + $inner_scope:ident => $inner_spawn:ident) => {{ + let builder = ThreadPoolBuilder::new().num_threads(1); + let pool = builder.build().unwrap(); + pool.install(|| { + let vec = Mutex::new(vec![]); + $outer_scope(|scope| { + let vec = &vec; + for i in 0..10 { + scope.$outer_spawn(move |_| { + $inner_scope(|scope| { + for j in 0..10 { + scope.$inner_spawn(move |_| { + vec.lock().unwrap().push(i * 10 + j); + }); + } + }); + }); + } + }); + vec.into_inner().unwrap() + }) + }}; +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn nested_lifo_order() { + // In the absence of stealing, `scope()` runs its `spawn()` jobs in LIFO order. + let vec = test_nested_order!(scope => spawn, scope => spawn); + let expected: Vec = (0..100).rev().collect(); // LIFO -> reversed + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn nested_fifo_order() { + // In the absence of stealing, `scope_fifo()` runs its `spawn_fifo()` jobs in FIFO order. + let vec = test_nested_order!(scope_fifo => spawn_fifo, scope_fifo => spawn_fifo); + let expected: Vec = (0..100).collect(); // FIFO -> natural order + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn nested_lifo_fifo_order() { + // LIFO on the outside, FIFO on the inside + let vec = test_nested_order!(scope => spawn, scope_fifo => spawn_fifo); + let expected: Vec = (0..10) + .rev() + .flat_map(|i| (0..10).map(move |j| i * 10 + j)) + .collect(); + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn nested_fifo_lifo_order() { + // FIFO on the outside, LIFO on the inside + let vec = test_nested_order!(scope_fifo => spawn_fifo, scope => spawn); + let expected: Vec = (0..10) + .flat_map(|i| (0..10).rev().map(move |j| i * 10 + j)) + .collect(); + assert_eq!(vec, expected); +} + +macro_rules! spawn_push { + ($scope:ident . $spawn:ident, $vec:ident, $i:expr) => {{ + $scope.$spawn(move |_| $vec.lock().unwrap().push($i)); + }}; +} + +/// Test spawns pushing a series of numbers, interleaved +/// such that negative values are using an inner scope. +macro_rules! test_mixed_order { + ($outer_scope:ident => $outer_spawn:ident, + $inner_scope:ident => $inner_spawn:ident) => {{ + let builder = ThreadPoolBuilder::new().num_threads(1); + let pool = builder.build().unwrap(); + pool.install(|| { + let vec = Mutex::new(vec![]); + $outer_scope(|outer_scope| { + let vec = &vec; + spawn_push!(outer_scope.$outer_spawn, vec, 0); + $inner_scope(|inner_scope| { + spawn_push!(inner_scope.$inner_spawn, vec, -1); + spawn_push!(outer_scope.$outer_spawn, vec, 1); + spawn_push!(inner_scope.$inner_spawn, vec, -2); + spawn_push!(outer_scope.$outer_spawn, vec, 2); + spawn_push!(inner_scope.$inner_spawn, vec, -3); + }); + spawn_push!(outer_scope.$outer_spawn, vec, 3); + }); + vec.into_inner().unwrap() + }) + }}; +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn mixed_lifo_order() { + // NB: the end of the inner scope makes us execute some of the outer scope + // before they've all been spawned, so they're not perfectly LIFO. + let vec = test_mixed_order!(scope => spawn, scope => spawn); + let expected = vec![-3, 2, -2, 1, -1, 3, 0]; + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn mixed_fifo_order() { + let vec = test_mixed_order!(scope_fifo => spawn_fifo, scope_fifo => spawn_fifo); + let expected = vec![-1, 0, -2, 1, -3, 2, 3]; + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn mixed_lifo_fifo_order() { + // NB: the end of the inner scope makes us execute some of the outer scope + // before they've all been spawned, so they're not perfectly LIFO. + let vec = test_mixed_order!(scope => spawn, scope_fifo => spawn_fifo); + let expected = vec![-1, 2, -2, 1, -3, 3, 0]; + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn mixed_fifo_lifo_order() { + let vec = test_mixed_order!(scope_fifo => spawn_fifo, scope => spawn); + let expected = vec![-3, 0, -2, 1, -1, 2, 3]; + assert_eq!(vec, expected); +} + +#[test] +fn static_scope() { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + let mut range = 0..100; + let sum = range.clone().sum(); + let iter = &mut range; + + COUNTER.store(0, Ordering::Relaxed); + scope(|s: &Scope<'static>| { + // While we're allowed the locally borrowed iterator, + // the spawns must be static. + for i in iter { + s.spawn(move |_| { + COUNTER.fetch_add(i, Ordering::Relaxed); + }); + } + }); + + assert_eq!(COUNTER.load(Ordering::Relaxed), sum); +} + +#[test] +fn static_scope_fifo() { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + let mut range = 0..100; + let sum = range.clone().sum(); + let iter = &mut range; + + COUNTER.store(0, Ordering::Relaxed); + scope_fifo(|s: &ScopeFifo<'static>| { + // While we're allowed the locally borrowed iterator, + // the spawns must be static. + for i in iter { + s.spawn_fifo(move |_| { + COUNTER.fetch_add(i, Ordering::Relaxed); + }); + } + }); + + assert_eq!(COUNTER.load(Ordering::Relaxed), sum); +} + +#[test] +fn mixed_lifetime_scope() { + fn increment<'slice, 'counter>(counters: &'slice [&'counter AtomicUsize]) { + scope(move |s: &Scope<'counter>| { + // We can borrow 'slice here, but the spawns can only borrow 'counter. + for &c in counters { + s.spawn(move |_| { + c.fetch_add(1, Ordering::Relaxed); + }); + } + }); + } + + let counter = AtomicUsize::new(0); + increment(&[&counter; 100]); + assert_eq!(counter.into_inner(), 100); +} + +#[test] +fn mixed_lifetime_scope_fifo() { + fn increment<'slice, 'counter>(counters: &'slice [&'counter AtomicUsize]) { + scope_fifo(move |s: &ScopeFifo<'counter>| { + // We can borrow 'slice here, but the spawns can only borrow 'counter. + for &c in counters { + s.spawn_fifo(move |_| { + c.fetch_add(1, Ordering::Relaxed); + }); + } + }); + } + + let counter = AtomicUsize::new(0); + increment(&[&counter; 100]); + assert_eq!(counter.into_inner(), 100); +} + +#[test] +fn scope_spawn_broadcast() { + let sum = AtomicUsize::new(0); + let n = scope(|s| { + s.spawn_broadcast(|_, ctx| { + sum.fetch_add(ctx.index(), Ordering::Relaxed); + }); + crate::current_num_threads() + }); + assert_eq!(sum.into_inner(), n * (n - 1) / 2); +} + +#[test] +fn scope_fifo_spawn_broadcast() { + let sum = AtomicUsize::new(0); + let n = scope_fifo(|s| { + s.spawn_broadcast(|_, ctx| { + sum.fetch_add(ctx.index(), Ordering::Relaxed); + }); + crate::current_num_threads() + }); + assert_eq!(sum.into_inner(), n * (n - 1) / 2); +} + +#[test] +fn scope_spawn_broadcast_nested() { + let sum = AtomicUsize::new(0); + let n = scope(|s| { + s.spawn_broadcast(|s, _| { + s.spawn_broadcast(|_, ctx| { + sum.fetch_add(ctx.index(), Ordering::Relaxed); + }); + }); + crate::current_num_threads() + }); + assert_eq!(sum.into_inner(), n * n * (n - 1) / 2); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn scope_spawn_broadcast_barrier() { + let barrier = Barrier::new(8); + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + pool.in_place_scope(|s| { + s.spawn_broadcast(|_, _| { + barrier.wait(); + }); + barrier.wait(); + }); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn scope_spawn_broadcast_panic_one() { + let count = AtomicUsize::new(0); + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + let result = crate::unwind::halt_unwinding(|| { + pool.scope(|s| { + s.spawn_broadcast(|_, ctx| { + count.fetch_add(1, Ordering::Relaxed); + if ctx.index() == 3 { + panic!("Hello, world!"); + } + }); + }); + }); + assert_eq!(count.into_inner(), 7); + assert!(result.is_err(), "broadcast panic should propagate!"); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn scope_spawn_broadcast_panic_many() { + let count = AtomicUsize::new(0); + let pool = ThreadPoolBuilder::new().num_threads(7).build().unwrap(); + let result = crate::unwind::halt_unwinding(|| { + pool.scope(|s| { + s.spawn_broadcast(|_, ctx| { + count.fetch_add(1, Ordering::Relaxed); + if ctx.index() % 2 == 0 { + panic!("Hello, world!"); + } + }); + }); + }); + assert_eq!(count.into_inner(), 7); + assert!(result.is_err(), "broadcast panic should propagate!"); +} diff --git a/compiler/rustc_thread_pool/src/sleep/README.md b/compiler/rustc_thread_pool/src/sleep/README.md new file mode 100644 index 000000000000..e79efd15ca9b --- /dev/null +++ b/compiler/rustc_thread_pool/src/sleep/README.md @@ -0,0 +1,252 @@ +# Introduction: the sleep module + +The code in this module governs when worker threads should go to +sleep. The system used in this code was introduced in [Rayon RFC #5]. +There is also a [video walkthrough] available. Both of those may be +valuable resources to understanding the code, though naturally they +will also grow stale over time. The comments in this file are +extracted from the RFC and meant to be kept up to date. + +[Rayon RFC #5]: https://github.com/rayon-rs/rfcs/pull/5 +[video walkthrough]: https://youtu.be/HvmQsE5M4cY + +# The `Sleep` struct + +The `Sleep` struct is embedded into each registry. It performs several functions: + +* It tracks when workers are awake or asleep. +* It decides how long a worker should look for work before it goes to sleep, + via a callback that is invoked periodically from the worker's search loop. +* It is notified when latches are set, jobs are published, or other + events occur, and it will go and wake the appropriate threads if + they are sleeping. + +# Thread states + +There are three main thread states: + +* An **active** thread is one that is actively executing a job. +* An **idle** thread is one that is searching for work to do. It will be + trying to steal work or pop work from the global injector queue. +* A **sleeping** thread is one that is blocked on a condition variable, + waiting to be awoken. + +We sometimes refer to the final two states collectively as **inactive**. +Threads begin as idle but transition to idle and finally sleeping when +they're unable to find work to do. + +## Sleepy threads + +There is one other special state worth mentioning. During the idle state, +threads can get **sleepy**. A sleepy thread is still idle, in that it is still +searching for work, but it is *about* to go to sleep after it does one more +search (or some other number, potentially). When a thread enters the sleepy +state, it signals (via the **jobs event counter**, described below) that it is +about to go to sleep. If new work is published, this will lead to the counter +being adjusted. When the thread actually goes to sleep, it will (hopefully, but +not guaranteed) see that the counter has changed and elect not to sleep, but +instead to search again. See the section on the **jobs event counter** for more +details. + +# The counters + +One of the key structs in the sleep module is `AtomicCounters`, found in +`counters.rs`. It packs three counters into one atomically managed value: + +* Two **thread counters**, which track the number of threads in a particular state. +* The **jobs event counter**, which is used to signal when new work is available. + It (sort of) tracks the number of jobs posted, but not quite, and it can rollover. + +## Thread counters + +There are two thread counters, one that tracks **inactive** threads and one that +tracks **sleeping** threads. From this, one can deduce the number of threads +that are idle by subtracting sleeping threads from inactive threads. We track +the counters in this way because it permits simpler atomic operations. One can +increment the number of sleeping threads (and thus decrease the number of idle +threads) simply by doing one atomic increment, for example. Similarly, one can +decrease the number of sleeping threads (and increase the number of idle +threads) through one atomic decrement. + +These counters are adjusted as follows: + +* When a thread enters the idle state: increment the inactive thread counter. +* When a thread enters the sleeping state: increment the sleeping thread counter. +* When a thread awakens a sleeping thread: decrement the sleeping thread counter. + * Subtle point: the thread that *awakens* the sleeping thread decrements the + counter, not the thread that is *sleeping*. This is because there is a delay + between signaling a thread to wake and the thread actually waking: + decrementing the counter when awakening the thread means that other threads + that may be posting work will see the up-to-date value that much faster. +* When a thread finds work, exiting the idle state: decrement the inactive + thread counter. + +## Jobs event counter + +The final counter is the **jobs event counter**. The role of this counter is to +help sleepy threads detect when new work is posted in a lightweight fashion. In +its simplest form, we would simply have a counter that gets incremented each +time a new job is posted. This way, when a thread gets sleepy, it could read the +counter, and then compare to see if the value has changed before it actually +goes to sleep. But this [turns out to be too expensive] in practice, so we use a +somewhat more complex scheme. + +[turns out to be too expensive]: https://github.com/rayon-rs/rayon/pull/746#issuecomment-624802747 + +The idea is that the counter toggles between two states, depending on whether +its value is even or odd (or, equivalently, on the value of its low bit): + +* Even -- If the low bit is zero, then it means that there has been no new work + since the last thread got sleepy. +* Odd -- If the low bit is one, then it means that new work was posted since + the last thread got sleepy. + +### New work is posted + +When new work is posted, we check the value of the counter: if it is even, +then we increment it by one, so that it becomes odd. + +### Worker thread gets sleepy + +When a worker thread gets sleepy, it will read the value of the counter. If the +counter is odd, it will increment the counter so that it is even. Either way, it +remembers the final value of the counter. The final value will be used later, +when the thread is going to sleep. If at that time the counter has not changed, +then we can assume no new jobs have been posted (though note the remote +possibility of rollover, discussed in detail below). + +# Protocol for a worker thread to post work + +The full protocol for a thread to post work is as follows + +* If the work is posted into the injection queue, then execute a seq-cst fence (see below). +* Load the counters, incrementing the JEC if it is even so that it is odd. +* Check if there are idle threads available to handle this new job. If not, + and there are sleeping threads, then wake one or more threads. + +# Protocol for a worker thread to fall asleep + +The full protocol for a thread to fall asleep is as follows: + +* After completing all its jobs, the worker goes idle and begins to + search for work. As it searches, it counts "rounds". In each round, + it searches all other work threads' queues, plus the 'injector queue' for + work injected from the outside. If work is found in this search, the thread + becomes active again and hence restarts this protocol from the top. +* After a certain number of rounds, the thread "gets sleepy" and executes `get_sleepy` + above, remembering the `final_value` of the JEC. It does one more search for work. +* If no work is found, the thread atomically: + * Checks the JEC to see that it has not changed from `final_value`. + * If it has, then the thread goes back to searching for work. We reset to + just before we got sleepy, so that we will do one more search + before attempting to sleep again (rather than searching for many rounds). + * Increments the number of sleeping threads by 1. +* The thread then executes a seq-cst fence operation (see below). +* The thread then does one final check for injected jobs (see below). If any + are available, it returns to the 'pre-sleepy' state as if the JEC had changed. +* The thread waits to be signaled. Once signaled, it returns to the idle state. + +# The jobs event counter and deadlock + +As described in the section on the JEC, the main concern around going to sleep +is avoiding a race condition wherein: + +* Thread A looks for work, finds none. +* Thread B posts work but sees no sleeping threads. +* Thread A goes to sleep. + +The JEC protocol largely prevents this, but due to rollover, this prevention is +not complete. It is possible -- if unlikely -- that enough activity occurs for +Thread A to observe the same JEC value that it saw when getting sleepy. If the +new work being published came from *inside* the thread-pool, then this race +condition isn't too harmful. It means that we have fewer workers processing the +work then we should, but we won't deadlock. This seems like an acceptable risk +given that this is unlikely in practice. + +However, if the work was posted as an *external* job, that is a problem. In that +case, it's possible that all of our workers could go to sleep, and the external +job would never get processed. To prevent that, the sleeping protocol includes +one final check to see if the injector queue is empty before fully falling +asleep. Note that this final check occurs **after** the number of sleeping +threads has been incremented. We are not concerned therefore with races against +injections that occur after that increment, only before. + +Unfortunately, there is one rather subtle point concerning this final check: +we wish to avoid the possibility that: + +* work is pushed into the injection queue by an outside thread X, +* the sleepy thread S sees the JEC but it has rolled over and is equal +* the sleepy thread S reads the injection queue but does not see the work posted by X. + +This is possible because the C++ memory model typically offers guarantees of the +form "if you see the access A, then you must see those other accesses" -- but it +doesn't guarantee that you will see the access A (i.e., if you think of +processors with independent caches, you may be operating on very out of date +cache state). + +## Using seq-cst fences to prevent deadlock + +To overcome this problem, we have inserted two sequentially consistent fence +operations into the protocols above: + +* One fence occurs after work is posted into the injection queue, but before the + counters are read (including the number of sleeping threads). + * Note that no fence is needed for work posted to internal queues, since it is ok + to overlook work in that case. +* One fence occurs after the number of sleeping threads is incremented, but + before the injection queue is read. + +### Proof sketch + +What follows is a "proof sketch" that the protocol is deadlock free. We model +two relevant bits of memory, the job injector queue J and the atomic counters C. + +Consider the actions of the injecting thread: + +* PushJob: Job is injected, which can be modeled as an atomic write to J with release semantics. +* PushFence: A sequentially consistent fence is executed. +* ReadSleepers: The counters C are read (they may also be incremented, but we just consider the read that comes first). + +Meanwhile, the sleepy thread does the following: + +* IncSleepers: The number of sleeping threads is incremented, which is atomic exchange to C. +* SleepFence: A sequentially consistent fence is executed. +* ReadJob: We look to see if the queue is empty, which is a read of J with acquire semantics. + +Either PushFence or SleepFence must come first: + +* If PushFence comes first, then PushJob must be visible to ReadJob. +* If SleepFence comes first, then IncSleepers is visible to ReadSleepers. + +# Deadlock detection + +This module tracks a number of variables in order to detect deadlocks due to user code blocking. +These variables are stored in the `SleepData` struct which itself is kept behind a mutex. +It contains the following fields: +- `worker_count` - The number of threads in the thread pool. +- `active_threads` - The number of threads in the thread pool which are running + and aren't blocked in user code or sleeping. +- `blocked_threads` - The number of threads which are blocked in user code. + This doesn't include threads blocked by Rayon. + +User code can indicate blocking by calling `mark_blocked` before blocking and +calling `mark_unblocked` before unblocking a thread. +This will adjust `active_threads` and `blocked_threads` accordingly. + +When we tickle the thread pool in `Sleep::tickle_cold`, we set `active_threads` to +`worker_count` - `blocked_threads` since we wake up all Rayon threads, but not thread blocked +by user code. + +A deadlock is detected by checking if `active_threads` is 0 and `blocked_threads` is above 0. +If we ignored `blocked_threads` we would have a deadlock +immediately when creating the thread pool. +We would also deadlock once the thread pool ran out of work. +It is not possible for Rayon itself to deadlock. +Deadlocks can only be caused by user code blocking, so this condition doesn't miss any deadlocks. + +We check for the deadlock condition when +threads fall asleep in `mark_unblocked` and in `Sleep::sleep`. +If there's a deadlock detected we call the user provided deadlock handler while we hold the +lock to `SleepData`. This means the deadlock handler cannot call `mark_blocked` and +`mark_unblocked`. The user is expected to handle the deadlock in some non-Rayon thread. +Once the deadlock handler returns, the thread which called the deadlock handler will go to sleep. diff --git a/compiler/rustc_thread_pool/src/sleep/counters.rs b/compiler/rustc_thread_pool/src/sleep/counters.rs new file mode 100644 index 000000000000..05941becd1c6 --- /dev/null +++ b/compiler/rustc_thread_pool/src/sleep/counters.rs @@ -0,0 +1,277 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub(super) struct AtomicCounters { + /// Packs together a number of counters. The counters are ordered as + /// follows, from least to most significant bits (here, we assuming + /// that [`THREADS_BITS`] is equal to 10): + /// + /// * Bits 0..10: Stores the number of **sleeping threads** + /// * Bits 10..20: Stores the number of **inactive threads** + /// * Bits 20..: Stores the **job event counter** (JEC) + /// + /// This uses 10 bits ([`THREADS_BITS`]) to encode the number of threads. Note + /// that the total number of bits (and hence the number of bits used for the + /// JEC) will depend on whether we are using a 32- or 64-bit architecture. + value: AtomicUsize, +} + +#[derive(Copy, Clone)] +pub(super) struct Counters { + word: usize, +} + +/// A value read from the **Jobs Event Counter**. +/// See the [`README.md`](README.md) for more +/// coverage of how the jobs event counter works. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub(super) struct JobsEventCounter(usize); + +impl JobsEventCounter { + pub(super) const DUMMY: JobsEventCounter = JobsEventCounter(usize::MAX); + + #[inline] + pub(super) fn as_usize(self) -> usize { + self.0 + } + + /// The JEC "is sleepy" if the last thread to increment it was in the + /// process of becoming sleepy. This is indicated by its value being *even*. + /// When new jobs are posted, they check if the JEC is sleepy, and if so + /// they incremented it. + #[inline] + pub(super) fn is_sleepy(self) -> bool { + (self.as_usize() & 1) == 0 + } + + /// The JEC "is active" if the last thread to increment it was posting new + /// work. This is indicated by its value being *odd*. When threads get + /// sleepy, they will check if the JEC is active, and increment it. + #[inline] + pub(super) fn is_active(self) -> bool { + !self.is_sleepy() + } +} + +/// Number of bits used for the thread counters. +#[cfg(target_pointer_width = "64")] +const THREADS_BITS: usize = 16; + +#[cfg(target_pointer_width = "32")] +const THREADS_BITS: usize = 8; + +/// Bits to shift to select the sleeping threads +/// (used with `select_bits`). +#[allow(clippy::erasing_op)] +const SLEEPING_SHIFT: usize = 0 * THREADS_BITS; + +/// Bits to shift to select the inactive threads +/// (used with `select_bits`). +#[allow(clippy::identity_op)] +const INACTIVE_SHIFT: usize = 1 * THREADS_BITS; + +/// Bits to shift to select the JEC +/// (use JOBS_BITS). +const JEC_SHIFT: usize = 2 * THREADS_BITS; + +/// Max value for the thread counters. +pub(crate) const THREADS_MAX: usize = (1 << THREADS_BITS) - 1; + +/// Constant that can be added to add one sleeping thread. +const ONE_SLEEPING: usize = 1; + +/// Constant that can be added to add one inactive thread. +/// An inactive thread is either idle, sleepy, or sleeping. +const ONE_INACTIVE: usize = 1 << INACTIVE_SHIFT; + +/// Constant that can be added to add one to the JEC. +const ONE_JEC: usize = 1 << JEC_SHIFT; + +impl AtomicCounters { + #[inline] + pub(super) fn new() -> AtomicCounters { + AtomicCounters { + value: AtomicUsize::new(0), + } + } + + /// Load and return the current value of the various counters. + /// This value can then be given to other method which will + /// attempt to update the counters via compare-and-swap. + #[inline] + pub(super) fn load(&self, ordering: Ordering) -> Counters { + Counters::new(self.value.load(ordering)) + } + + #[inline] + fn try_exchange(&self, old_value: Counters, new_value: Counters, ordering: Ordering) -> bool { + self.value + .compare_exchange(old_value.word, new_value.word, ordering, Ordering::Relaxed) + .is_ok() + } + + /// Adds an inactive thread. This cannot fail. + /// + /// This should be invoked when a thread enters its idle loop looking + /// for work. It is decremented when work is found. Note that it is + /// not decremented if the thread transitions from idle to sleepy or sleeping; + /// so the number of inactive threads is always greater-than-or-equal + /// to the number of sleeping threads. + #[inline] + pub(super) fn add_inactive_thread(&self) { + self.value.fetch_add(ONE_INACTIVE, Ordering::SeqCst); + } + + /// Increments the jobs event counter if `increment_when`, when applied to + /// the current value, is true. Used to toggle the JEC from even (sleepy) to + /// odd (active) or vice versa. Returns the final value of the counters, for + /// which `increment_when` is guaranteed to return false. + pub(super) fn increment_jobs_event_counter_if( + &self, + increment_when: impl Fn(JobsEventCounter) -> bool, + ) -> Counters { + loop { + let old_value = self.load(Ordering::SeqCst); + if increment_when(old_value.jobs_counter()) { + let new_value = old_value.increment_jobs_counter(); + if self.try_exchange(old_value, new_value, Ordering::SeqCst) { + return new_value; + } + } else { + return old_value; + } + } + } + + /// Subtracts an inactive thread. This cannot fail. It is invoked + /// when a thread finds work and hence becomes active. It returns the + /// number of sleeping threads to wake up (if any). + /// + /// See `add_inactive_thread`. + #[inline] + pub(super) fn sub_inactive_thread(&self) -> usize { + let old_value = Counters::new(self.value.fetch_sub(ONE_INACTIVE, Ordering::SeqCst)); + debug_assert!( + old_value.inactive_threads() > 0, + "sub_inactive_thread: old_value {:?} has no inactive threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() <= old_value.inactive_threads(), + "sub_inactive_thread: old_value {:?} had {} sleeping threads and {} inactive threads", + old_value, + old_value.sleeping_threads(), + old_value.inactive_threads(), + ); + + // Current heuristic: whenever an inactive thread goes away, if + // there are any sleeping threads, wake 'em up. + let sleeping_threads = old_value.sleeping_threads(); + Ord::min(sleeping_threads, 2) + } + + /// Subtracts a sleeping thread. This cannot fail, but it is only + /// safe to do if you you know the number of sleeping threads is + /// non-zero (i.e., because you have just awoken a sleeping + /// thread). + #[inline] + pub(super) fn sub_sleeping_thread(&self) { + let old_value = Counters::new(self.value.fetch_sub(ONE_SLEEPING, Ordering::SeqCst)); + debug_assert!( + old_value.sleeping_threads() > 0, + "sub_sleeping_thread: old_value {:?} had no sleeping threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() <= old_value.inactive_threads(), + "sub_sleeping_thread: old_value {:?} had {} sleeping threads and {} inactive threads", + old_value, + old_value.sleeping_threads(), + old_value.inactive_threads(), + ); + } + + #[inline] + pub(super) fn try_add_sleeping_thread(&self, old_value: Counters) -> bool { + debug_assert!( + old_value.inactive_threads() > 0, + "try_add_sleeping_thread: old_value {:?} has no inactive threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() < THREADS_MAX, + "try_add_sleeping_thread: old_value {:?} has too many sleeping threads", + old_value, + ); + + let mut new_value = old_value; + new_value.word += ONE_SLEEPING; + + self.try_exchange(old_value, new_value, Ordering::SeqCst) + } +} + +#[inline] +fn select_thread(word: usize, shift: usize) -> usize { + (word >> shift) & THREADS_MAX +} + +#[inline] +fn select_jec(word: usize) -> usize { + word >> JEC_SHIFT +} + +impl Counters { + #[inline] + fn new(word: usize) -> Counters { + Counters { word } + } + + #[inline] + fn increment_jobs_counter(self) -> Counters { + // We can freely add to JEC because it occupies the most significant bits. + // Thus it doesn't overflow into the other counters, just wraps itself. + Counters { + word: self.word.wrapping_add(ONE_JEC), + } + } + + #[inline] + pub(super) fn jobs_counter(self) -> JobsEventCounter { + JobsEventCounter(select_jec(self.word)) + } + + /// The number of threads that are not actively + /// executing work. They may be idle, sleepy, or asleep. + #[inline] + pub(super) fn inactive_threads(self) -> usize { + select_thread(self.word, INACTIVE_SHIFT) + } + + #[inline] + pub(super) fn awake_but_idle_threads(self) -> usize { + debug_assert!( + self.sleeping_threads() <= self.inactive_threads(), + "sleeping threads: {} > raw idle threads {}", + self.sleeping_threads(), + self.inactive_threads() + ); + self.inactive_threads() - self.sleeping_threads() + } + + #[inline] + pub(super) fn sleeping_threads(self) -> usize { + select_thread(self.word, SLEEPING_SHIFT) + } +} + +impl std::fmt::Debug for Counters { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let word = format!("{:016x}", self.word); + fmt.debug_struct("Counters") + .field("word", &word) + .field("jobs", &self.jobs_counter().0) + .field("inactive", &self.inactive_threads()) + .field("sleeping", &self.sleeping_threads()) + .finish() + } +} diff --git a/compiler/rustc_thread_pool/src/sleep/mod.rs b/compiler/rustc_thread_pool/src/sleep/mod.rs new file mode 100644 index 000000000000..7d88ece21076 --- /dev/null +++ b/compiler/rustc_thread_pool/src/sleep/mod.rs @@ -0,0 +1,392 @@ +//! Code that decides when workers should go to sleep. See README.md +//! for an overview. + +use crate::latch::CoreLatch; +use crate::registry::WorkerThread; +use crate::DeadlockHandler; +use crossbeam_utils::CachePadded; +use std::sync::atomic::Ordering; +use std::sync::{Condvar, Mutex}; +use std::thread; + +mod counters; +pub(crate) use self::counters::THREADS_MAX; +use self::counters::{AtomicCounters, JobsEventCounter}; + +struct SleepData { + /// The number of threads in the thread pool. + worker_count: usize, + + /// The number of threads in the thread pool which are running and + /// aren't blocked in user code or sleeping. + active_threads: usize, + + /// The number of threads which are blocked in user code. + /// This doesn't include threads blocked by this module. + blocked_threads: usize, +} + +impl SleepData { + /// Checks if the conditions for a deadlock holds and if so calls the deadlock handler + #[inline] + pub fn deadlock_check(&self, deadlock_handler: &Option>) { + if self.active_threads == 0 && self.blocked_threads > 0 { + (deadlock_handler.as_ref().unwrap())(); + } + } +} + +/// The `Sleep` struct is embedded into each registry. It governs the waking and sleeping +/// of workers. It has callbacks that are invoked periodically at significant events, +/// such as when workers are looping and looking for work, when latches are set, or when +/// jobs are published, and it either blocks threads or wakes them in response to these +/// events. See the [`README.md`] in this module for more details. +/// +/// [`README.md`] README.md +pub(super) struct Sleep { + /// One "sleep state" per worker. Used to track if a worker is sleeping and to have + /// them block. + worker_sleep_states: Vec>, + + counters: AtomicCounters, + + data: Mutex, +} + +/// An instance of this struct is created when a thread becomes idle. +/// It is consumed when the thread finds work, and passed by `&mut` +/// reference for operations that preserve the idle state. (In other +/// words, producing one of these structs is evidence the thread is +/// idle.) It tracks state such as how long the thread has been idle. +pub(super) struct IdleState { + /// What is worker index of the idle thread? + worker_index: usize, + + /// How many rounds have we been circling without sleeping? + rounds: u32, + + /// Once we become sleepy, what was the sleepy counter value? + /// Set to `INVALID_SLEEPY_COUNTER` otherwise. + jobs_counter: JobsEventCounter, +} + +/// The "sleep state" for an individual worker. +#[derive(Default)] +struct WorkerSleepState { + /// Set to true when the worker goes to sleep; set to false when + /// the worker is notified or when it wakes. + is_blocked: Mutex, + + condvar: Condvar, +} + +const ROUNDS_UNTIL_SLEEPY: u32 = 32; +const ROUNDS_UNTIL_SLEEPING: u32 = ROUNDS_UNTIL_SLEEPY + 1; + +impl Sleep { + pub(super) fn new(n_threads: usize) -> Sleep { + assert!(n_threads <= THREADS_MAX); + Sleep { + worker_sleep_states: (0..n_threads).map(|_| Default::default()).collect(), + counters: AtomicCounters::new(), + data: Mutex::new(SleepData { + worker_count: n_threads, + active_threads: n_threads, + blocked_threads: 0, + }), + } + } + + /// Mark a Rayon worker thread as blocked. This triggers the deadlock handler + /// if no other worker thread is active + #[inline] + pub fn mark_blocked(&self, deadlock_handler: &Option>) { + let mut data = self.data.lock().unwrap(); + debug_assert!(data.active_threads > 0); + debug_assert!(data.blocked_threads < data.worker_count); + debug_assert!(data.active_threads > 0); + data.active_threads -= 1; + data.blocked_threads += 1; + + data.deadlock_check(deadlock_handler); + } + + /// Mark a previously blocked Rayon worker thread as unblocked + #[inline] + pub fn mark_unblocked(&self) { + let mut data = self.data.lock().unwrap(); + debug_assert!(data.active_threads < data.worker_count); + debug_assert!(data.blocked_threads > 0); + data.active_threads += 1; + data.blocked_threads -= 1; + } + + #[inline] + pub(super) fn start_looking(&self, worker_index: usize) -> IdleState { + self.counters.add_inactive_thread(); + + IdleState { + worker_index, + rounds: 0, + jobs_counter: JobsEventCounter::DUMMY, + } + } + + #[inline] + pub(super) fn work_found(&self) { + // If we were the last idle thread and other threads are still sleeping, + // then we should wake up another thread. + let threads_to_wake = self.counters.sub_inactive_thread(); + self.wake_any_threads(threads_to_wake as u32); + } + + #[inline] + pub(super) fn no_work_found( + &self, + idle_state: &mut IdleState, + latch: &CoreLatch, + thread: &WorkerThread, + ) { + if idle_state.rounds < ROUNDS_UNTIL_SLEEPY { + thread::yield_now(); + idle_state.rounds += 1; + } else if idle_state.rounds == ROUNDS_UNTIL_SLEEPY { + idle_state.jobs_counter = self.announce_sleepy(); + idle_state.rounds += 1; + thread::yield_now(); + } else if idle_state.rounds < ROUNDS_UNTIL_SLEEPING { + idle_state.rounds += 1; + thread::yield_now(); + } else { + debug_assert_eq!(idle_state.rounds, ROUNDS_UNTIL_SLEEPING); + self.sleep(idle_state, latch, thread); + } + } + + #[cold] + fn announce_sleepy(&self) -> JobsEventCounter { + self.counters + .increment_jobs_event_counter_if(JobsEventCounter::is_active) + .jobs_counter() + } + + #[cold] + fn sleep(&self, idle_state: &mut IdleState, latch: &CoreLatch, thread: &WorkerThread) { + let worker_index = idle_state.worker_index; + + if !latch.get_sleepy() { + return; + } + + let sleep_state = &self.worker_sleep_states[worker_index]; + let mut is_blocked = sleep_state.is_blocked.lock().unwrap(); + debug_assert!(!*is_blocked); + + // Our latch was signalled. We should wake back up fully as we + // will have some stuff to do. + if !latch.fall_asleep() { + idle_state.wake_fully(); + return; + } + + loop { + let counters = self.counters.load(Ordering::SeqCst); + + // Check if the JEC has changed since we got sleepy. + debug_assert!(idle_state.jobs_counter.is_sleepy()); + if counters.jobs_counter() != idle_state.jobs_counter { + // JEC has changed, so a new job was posted, but for some reason + // we didn't see it. We should return to just before the SLEEPY + // state so we can do another search and (if we fail to find + // work) go back to sleep. + idle_state.wake_partly(); + latch.wake_up(); + return; + } + + // Otherwise, let's move from IDLE to SLEEPING. + if self.counters.try_add_sleeping_thread(counters) { + break; + } + } + + // Successfully registered as asleep. + + // We have one last check for injected jobs to do. This protects against + // deadlock in the very unlikely event that + // + // - an external job is being injected while we are sleepy + // - that job triggers the rollover over the JEC such that we don't see it + // - we are the last active worker thread + std::sync::atomic::fence(Ordering::SeqCst); + if thread.has_injected_job() { + // If we see an externally injected job, then we have to 'wake + // ourselves up'. (Ordinarily, `sub_sleeping_thread` is invoked by + // the one that wakes us.) + self.counters.sub_sleeping_thread(); + } else { + { + // Decrement the number of active threads and check for a deadlock + let mut data = self.data.lock().unwrap(); + data.active_threads -= 1; + data.deadlock_check(&thread.registry.deadlock_handler); + } + + // If we don't see an injected job (the normal case), then flag + // ourselves as asleep and wait till we are notified. + // + // (Note that `is_blocked` is held under a mutex and the mutex was + // acquired *before* we incremented the "sleepy counter". This means + // that whomever is coming to wake us will have to wait until we + // release the mutex in the call to `wait`, so they will see this + // boolean as true.) + thread.registry.release_thread(); + *is_blocked = true; + while *is_blocked { + is_blocked = sleep_state.condvar.wait(is_blocked).unwrap(); + } + + // Drop `is_blocked` now in case `acquire_thread` blocks + drop(is_blocked); + + thread.registry.acquire_thread(); + } + + // Update other state: + idle_state.wake_fully(); + latch.wake_up(); + } + + /// Notify the given thread that it should wake up (if it is + /// sleeping). When this method is invoked, we typically know the + /// thread is asleep, though in rare cases it could have been + /// awoken by (e.g.) new work having been posted. + pub(super) fn notify_worker_latch_is_set(&self, target_worker_index: usize) { + self.wake_specific_thread(target_worker_index); + } + + /// Signals that `num_jobs` new jobs were injected into the thread + /// pool from outside. This function will ensure that there are + /// threads available to process them, waking threads from sleep + /// if necessary. + /// + /// # Parameters + /// + /// - `num_jobs` -- lower bound on number of jobs available for stealing. + /// We'll try to get at least one thread per job. + #[inline] + pub(super) fn new_injected_jobs(&self, num_jobs: u32, queue_was_empty: bool) { + // This fence is needed to guarantee that threads + // as they are about to fall asleep, observe any + // new jobs that may have been injected. + std::sync::atomic::fence(Ordering::SeqCst); + + self.new_jobs(num_jobs, queue_was_empty) + } + + /// Signals that `num_jobs` new jobs were pushed onto a thread's + /// local deque. This function will try to ensure that there are + /// threads available to process them, waking threads from sleep + /// if necessary. However, this is not guaranteed: under certain + /// race conditions, the function may fail to wake any new + /// threads; in that case the existing thread should eventually + /// pop the job. + /// + /// # Parameters + /// + /// - `num_jobs` -- lower bound on number of jobs available for stealing. + /// We'll try to get at least one thread per job. + #[inline] + pub(super) fn new_internal_jobs(&self, num_jobs: u32, queue_was_empty: bool) { + self.new_jobs(num_jobs, queue_was_empty) + } + + /// Common helper for `new_injected_jobs` and `new_internal_jobs`. + #[inline] + fn new_jobs(&self, num_jobs: u32, queue_was_empty: bool) { + // Read the counters and -- if sleepy workers have announced themselves + // -- announce that there is now work available. The final value of `counters` + // with which we exit the loop thus corresponds to a state when + let counters = self + .counters + .increment_jobs_event_counter_if(JobsEventCounter::is_sleepy); + let num_awake_but_idle = counters.awake_but_idle_threads(); + let num_sleepers = counters.sleeping_threads(); + + if num_sleepers == 0 { + // nobody to wake + return; + } + + // Promote from u16 to u32 so we can interoperate with + // num_jobs more easily. + let num_awake_but_idle = num_awake_but_idle as u32; + let num_sleepers = num_sleepers as u32; + + // If the queue is non-empty, then we always wake up a worker + // -- clearly the existing idle jobs aren't enough. Otherwise, + // check to see if we have enough idle workers. + if !queue_was_empty { + let num_to_wake = Ord::min(num_jobs, num_sleepers); + self.wake_any_threads(num_to_wake); + } else if num_awake_but_idle < num_jobs { + let num_to_wake = Ord::min(num_jobs - num_awake_but_idle, num_sleepers); + self.wake_any_threads(num_to_wake); + } + } + + #[cold] + fn wake_any_threads(&self, mut num_to_wake: u32) { + if num_to_wake > 0 { + for i in 0..self.worker_sleep_states.len() { + if self.wake_specific_thread(i) { + num_to_wake -= 1; + if num_to_wake == 0 { + return; + } + } + } + } + } + + fn wake_specific_thread(&self, index: usize) -> bool { + let sleep_state = &self.worker_sleep_states[index]; + + let mut is_blocked = sleep_state.is_blocked.lock().unwrap(); + if *is_blocked { + *is_blocked = false; + + // Increment the number of active threads + self.data.lock().unwrap().active_threads += 1; + + sleep_state.condvar.notify_one(); + + // When the thread went to sleep, it will have incremented + // this value. When we wake it, its our job to decrement + // it. We could have the thread do it, but that would + // introduce a delay between when the thread was + // *notified* and when this counter was decremented. That + // might mislead people with new work into thinking that + // there are sleeping threads that they should try to + // wake, when in fact there is nothing left for them to + // do. + self.counters.sub_sleeping_thread(); + + true + } else { + false + } + } +} + +impl IdleState { + fn wake_fully(&mut self) { + self.rounds = 0; + self.jobs_counter = JobsEventCounter::DUMMY; + } + + fn wake_partly(&mut self) { + self.rounds = ROUNDS_UNTIL_SLEEPY; + self.jobs_counter = JobsEventCounter::DUMMY; + } +} diff --git a/compiler/rustc_thread_pool/src/spawn/mod.rs b/compiler/rustc_thread_pool/src/spawn/mod.rs new file mode 100644 index 000000000000..034df30dcfb3 --- /dev/null +++ b/compiler/rustc_thread_pool/src/spawn/mod.rs @@ -0,0 +1,164 @@ +use crate::job::*; +use crate::registry::Registry; +use crate::tlv::Tlv; +use crate::unwind; +use std::mem; +use std::sync::Arc; + +/// Puts the task into the Rayon threadpool's job queue in the "static" +/// or "global" scope. Just like a standard thread, this task is not +/// tied to the current stack frame, and hence it cannot hold any +/// references other than those with `'static` lifetime. If you want +/// to spawn a task that references stack data, use [the `scope()` +/// function][scope] to create a scope. +/// +/// [scope]: fn.scope.html +/// +/// Since tasks spawned with this function cannot hold references into +/// the enclosing stack frame, you almost certainly want to use a +/// `move` closure as their argument (otherwise, the closure will +/// typically hold references to any variables from the enclosing +/// function that you happen to use). +/// +/// This API assumes that the closure is executed purely for its +/// side-effects (i.e., it might send messages, modify data protected +/// by a mutex, or some such thing). +/// +/// There is no guaranteed order of execution for spawns, given that +/// other threads may steal tasks at any time. However, they are +/// generally prioritized in a LIFO order on the thread from which +/// they were spawned. Other threads always steal from the other end of +/// the deque, like FIFO order. The idea is that "recent" tasks are +/// most likely to be fresh in the local CPU's cache, while other +/// threads can steal older "stale" tasks. For an alternate approach, +/// consider [`spawn_fifo()`] instead. +/// +/// [`spawn_fifo()`]: fn.spawn_fifo.html +/// +/// # Panic handling +/// +/// If this closure should panic, the resulting panic will be +/// propagated to the panic handler registered in the `ThreadPoolBuilder`, +/// if any. See [`ThreadPoolBuilder::panic_handler()`][ph] for more +/// details. +/// +/// [ph]: struct.ThreadPoolBuilder.html#method.panic_handler +/// +/// # Examples +/// +/// This code creates a Rayon task that increments a global counter. +/// +/// ```rust +/// # use rayon_core as rayon; +/// use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; +/// +/// static GLOBAL_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; +/// +/// rayon::spawn(move || { +/// GLOBAL_COUNTER.fetch_add(1, Ordering::SeqCst); +/// }); +/// ``` +pub fn spawn(func: F) +where + F: FnOnce() + Send + 'static, +{ + // We assert that current registry has not terminated. + unsafe { spawn_in(func, &Registry::current()) } +} + +/// Spawns an asynchronous job in `registry.` +/// +/// Unsafe because `registry` must not yet have terminated. +pub(super) unsafe fn spawn_in(func: F, registry: &Arc) +where + F: FnOnce() + Send + 'static, +{ + // We assert that this does not hold any references (we know + // this because of the `'static` bound in the interface); + // moreover, we assert that the code below is not supposed to + // be able to panic, and hence the data won't leak but will be + // enqueued into some deque for later execution. + let abort_guard = unwind::AbortIfPanic; // just in case we are wrong, and code CAN panic + let job_ref = spawn_job(func, registry); + registry.inject_or_push(job_ref); + mem::forget(abort_guard); +} + +unsafe fn spawn_job(func: F, registry: &Arc) -> JobRef +where + F: FnOnce() + Send + 'static, +{ + // Ensure that registry cannot terminate until this job has + // executed. This ref is decremented at the (*) below. + registry.increment_terminate_count(); + + HeapJob::new(Tlv::null(), { + let registry = Arc::clone(registry); + move || { + registry.catch_unwind(func); + registry.terminate(); // (*) permit registry to terminate now + } + }) + .into_static_job_ref() +} + +/// Fires off a task into the Rayon threadpool in the "static" or +/// "global" scope. Just like a standard thread, this task is not +/// tied to the current stack frame, and hence it cannot hold any +/// references other than those with `'static` lifetime. If you want +/// to spawn a task that references stack data, use [the `scope_fifo()` +/// function](fn.scope_fifo.html) to create a scope. +/// +/// The behavior is essentially the same as [the `spawn` +/// function](fn.spawn.html), except that calls from the same thread +/// will be prioritized in FIFO order. This is similar to the now- +/// deprecated [`breadth_first`] option, except the effect is isolated +/// to relative `spawn_fifo` calls, not all threadpool tasks. +/// +/// For more details on this design, see Rayon [RFC #1]. +/// +/// [`breadth_first`]: struct.ThreadPoolBuilder.html#method.breadth_first +/// [RFC #1]: https://github.com/rayon-rs/rfcs/blob/master/accepted/rfc0001-scope-scheduling.md +/// +/// # Panic handling +/// +/// If this closure should panic, the resulting panic will be +/// propagated to the panic handler registered in the `ThreadPoolBuilder`, +/// if any. See [`ThreadPoolBuilder::panic_handler()`][ph] for more +/// details. +/// +/// [ph]: struct.ThreadPoolBuilder.html#method.panic_handler +pub fn spawn_fifo(func: F) +where + F: FnOnce() + Send + 'static, +{ + // We assert that current registry has not terminated. + unsafe { spawn_fifo_in(func, &Registry::current()) } +} + +/// Spawns an asynchronous FIFO job in `registry.` +/// +/// Unsafe because `registry` must not yet have terminated. +pub(super) unsafe fn spawn_fifo_in(func: F, registry: &Arc) +where + F: FnOnce() + Send + 'static, +{ + // We assert that this does not hold any references (we know + // this because of the `'static` bound in the interface); + // moreover, we assert that the code below is not supposed to + // be able to panic, and hence the data won't leak but will be + // enqueued into some deque for later execution. + let abort_guard = unwind::AbortIfPanic; // just in case we are wrong, and code CAN panic + let job_ref = spawn_job(func, registry); + + // If we're in the pool, use our thread's private fifo for this thread to execute + // in a locally-FIFO order. Otherwise, just use the pool's global injector. + match registry.current_thread() { + Some(worker) => worker.push_fifo(job_ref), + None => registry.inject(job_ref), + } + mem::forget(abort_guard); +} + +#[cfg(test)] +mod test; diff --git a/compiler/rustc_thread_pool/src/spawn/test.rs b/compiler/rustc_thread_pool/src/spawn/test.rs new file mode 100644 index 000000000000..b7a0535aabf6 --- /dev/null +++ b/compiler/rustc_thread_pool/src/spawn/test.rs @@ -0,0 +1,255 @@ +use crate::scope; +use std::any::Any; +use std::sync::mpsc::channel; +use std::sync::Mutex; + +use super::{spawn, spawn_fifo}; +use crate::ThreadPoolBuilder; + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_then_join_in_worker() { + let (tx, rx) = channel(); + scope(move |_| { + spawn(move || tx.send(22).unwrap()); + }); + assert_eq!(22, rx.recv().unwrap()); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_then_join_outside_worker() { + let (tx, rx) = channel(); + spawn(move || tx.send(22).unwrap()); + assert_eq!(22, rx.recv().unwrap()); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn panic_fwd() { + let (tx, rx) = channel(); + + let tx = Mutex::new(tx); + let panic_handler = move |err: Box| { + let tx = tx.lock().unwrap(); + if let Some(&msg) = err.downcast_ref::<&str>() { + if msg == "Hello, world!" { + tx.send(1).unwrap(); + } else { + tx.send(2).unwrap(); + } + } else { + tx.send(3).unwrap(); + } + }; + + let builder = ThreadPoolBuilder::new().panic_handler(panic_handler); + + builder + .build() + .unwrap() + .spawn(move || panic!("Hello, world!")); + + assert_eq!(1, rx.recv().unwrap()); +} + +/// Test what happens when the thread-pool is dropped but there are +/// still active asynchronous tasks. We expect the thread-pool to stay +/// alive and executing until those threads are complete. +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn termination_while_things_are_executing() { + let (tx0, rx0) = channel(); + let (tx1, rx1) = channel(); + + // Create a thread-pool and spawn some code in it, but then drop + // our reference to it. + { + let thread_pool = ThreadPoolBuilder::new().build().unwrap(); + thread_pool.spawn(move || { + let data = rx0.recv().unwrap(); + + // At this point, we know the "main" reference to the + // `ThreadPool` has been dropped, but there are still + // active threads. Launch one more. + spawn(move || { + tx1.send(data).unwrap(); + }); + }); + } + + tx0.send(22).unwrap(); + let v = rx1.recv().unwrap(); + assert_eq!(v, 22); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn custom_panic_handler_and_spawn() { + let (tx, rx) = channel(); + + // Create a parallel closure that will send panics on the + // channel; since the closure is potentially executed in parallel + // with itself, we have to wrap `tx` in a mutex. + let tx = Mutex::new(tx); + let panic_handler = move |e: Box| { + tx.lock().unwrap().send(e).unwrap(); + }; + + // Execute an async that will panic. + let builder = ThreadPoolBuilder::new().panic_handler(panic_handler); + builder.build().unwrap().spawn(move || { + panic!("Hello, world!"); + }); + + // Check that we got back the panic we expected. + let error = rx.recv().unwrap(); + if let Some(&msg) = error.downcast_ref::<&str>() { + assert_eq!(msg, "Hello, world!"); + } else { + panic!("did not receive a string from panic handler"); + } +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn custom_panic_handler_and_nested_spawn() { + let (tx, rx) = channel(); + + // Create a parallel closure that will send panics on the + // channel; since the closure is potentially executed in parallel + // with itself, we have to wrap `tx` in a mutex. + let tx = Mutex::new(tx); + let panic_handler = move |e| { + tx.lock().unwrap().send(e).unwrap(); + }; + + // Execute an async that will (eventually) panic. + const PANICS: usize = 3; + let builder = ThreadPoolBuilder::new().panic_handler(panic_handler); + builder.build().unwrap().spawn(move || { + // launch 3 nested spawn-asyncs; these should be in the same + // thread-pool and hence inherit the same panic handler + for _ in 0..PANICS { + spawn(move || { + panic!("Hello, world!"); + }); + } + }); + + // Check that we get back the panics we expected. + for _ in 0..PANICS { + let error = rx.recv().unwrap(); + if let Some(&msg) = error.downcast_ref::<&str>() { + assert_eq!(msg, "Hello, world!"); + } else { + panic!("did not receive a string from panic handler"); + } + } +} + +macro_rules! test_order { + ($outer_spawn:ident, $inner_spawn:ident) => {{ + let builder = ThreadPoolBuilder::new().num_threads(1); + let pool = builder.build().unwrap(); + let (tx, rx) = channel(); + pool.install(move || { + for i in 0..10 { + let tx = tx.clone(); + $outer_spawn(move || { + for j in 0..10 { + let tx = tx.clone(); + $inner_spawn(move || { + tx.send(i * 10 + j).unwrap(); + }); + } + }); + } + }); + rx.iter().collect::>() + }}; +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn lifo_order() { + // In the absence of stealing, `spawn()` jobs on a thread will run in LIFO order. + let vec = test_order!(spawn, spawn); + let expected: Vec = (0..100).rev().collect(); // LIFO -> reversed + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn fifo_order() { + // In the absence of stealing, `spawn_fifo()` jobs on a thread will run in FIFO order. + let vec = test_order!(spawn_fifo, spawn_fifo); + let expected: Vec = (0..100).collect(); // FIFO -> natural order + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn lifo_fifo_order() { + // LIFO on the outside, FIFO on the inside + let vec = test_order!(spawn, spawn_fifo); + let expected: Vec = (0..10) + .rev() + .flat_map(|i| (0..10).map(move |j| i * 10 + j)) + .collect(); + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn fifo_lifo_order() { + // FIFO on the outside, LIFO on the inside + let vec = test_order!(spawn_fifo, spawn); + let expected: Vec = (0..10) + .flat_map(|i| (0..10).rev().map(move |j| i * 10 + j)) + .collect(); + assert_eq!(vec, expected); +} + +macro_rules! spawn_send { + ($spawn:ident, $tx:ident, $i:expr) => {{ + let tx = $tx.clone(); + $spawn(move || tx.send($i).unwrap()); + }}; +} + +/// Test mixed spawns pushing a series of numbers, interleaved such +/// such that negative values are using the second kind of spawn. +macro_rules! test_mixed_order { + ($pos_spawn:ident, $neg_spawn:ident) => {{ + let builder = ThreadPoolBuilder::new().num_threads(1); + let pool = builder.build().unwrap(); + let (tx, rx) = channel(); + pool.install(move || { + spawn_send!($pos_spawn, tx, 0); + spawn_send!($neg_spawn, tx, -1); + spawn_send!($pos_spawn, tx, 1); + spawn_send!($neg_spawn, tx, -2); + spawn_send!($pos_spawn, tx, 2); + spawn_send!($neg_spawn, tx, -3); + spawn_send!($pos_spawn, tx, 3); + }); + rx.iter().collect::>() + }}; +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn mixed_lifo_fifo_order() { + let vec = test_mixed_order!(spawn, spawn_fifo); + let expected = vec![3, -1, 2, -2, 1, -3, 0]; + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn mixed_fifo_lifo_order() { + let vec = test_mixed_order!(spawn_fifo, spawn); + let expected = vec![0, -3, 1, -2, 2, -1, 3]; + assert_eq!(vec, expected); +} diff --git a/compiler/rustc_thread_pool/src/test.rs b/compiler/rustc_thread_pool/src/test.rs new file mode 100644 index 000000000000..25b8487f73bc --- /dev/null +++ b/compiler/rustc_thread_pool/src/test.rs @@ -0,0 +1,200 @@ +#![cfg(test)] + +use crate::{ThreadPoolBuildError, ThreadPoolBuilder}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Barrier}; + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn worker_thread_index() { + let pool = ThreadPoolBuilder::new().num_threads(22).build().unwrap(); + assert_eq!(pool.current_num_threads(), 22); + assert_eq!(pool.current_thread_index(), None); + let index = pool.install(|| pool.current_thread_index().unwrap()); + assert!(index < 22); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn start_callback_called() { + let n_threads = 16; + let n_called = Arc::new(AtomicUsize::new(0)); + // Wait for all the threads in the pool plus the one running tests. + let barrier = Arc::new(Barrier::new(n_threads + 1)); + + let b = Arc::clone(&barrier); + let nc = Arc::clone(&n_called); + let start_handler = move |_| { + nc.fetch_add(1, Ordering::SeqCst); + b.wait(); + }; + + let conf = ThreadPoolBuilder::new() + .num_threads(n_threads) + .start_handler(start_handler); + let _ = conf.build().unwrap(); + + // Wait for all the threads to have been scheduled to run. + barrier.wait(); + + // The handler must have been called on every started thread. + assert_eq!(n_called.load(Ordering::SeqCst), n_threads); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn exit_callback_called() { + let n_threads = 16; + let n_called = Arc::new(AtomicUsize::new(0)); + // Wait for all the threads in the pool plus the one running tests. + let barrier = Arc::new(Barrier::new(n_threads + 1)); + + let b = Arc::clone(&barrier); + let nc = Arc::clone(&n_called); + let exit_handler = move |_| { + nc.fetch_add(1, Ordering::SeqCst); + b.wait(); + }; + + let conf = ThreadPoolBuilder::new() + .num_threads(n_threads) + .exit_handler(exit_handler); + { + let _ = conf.build().unwrap(); + // Drop the pool so it stops the running threads. + } + + // Wait for all the threads to have been scheduled to run. + barrier.wait(); + + // The handler must have been called on every exiting thread. + assert_eq!(n_called.load(Ordering::SeqCst), n_threads); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn handler_panics_handled_correctly() { + let n_threads = 16; + let n_called = Arc::new(AtomicUsize::new(0)); + // Wait for all the threads in the pool plus the one running tests. + let start_barrier = Arc::new(Barrier::new(n_threads + 1)); + let exit_barrier = Arc::new(Barrier::new(n_threads + 1)); + + let start_handler = move |_| { + panic!("ensure panic handler is called when starting"); + }; + let exit_handler = move |_| { + panic!("ensure panic handler is called when exiting"); + }; + + let sb = Arc::clone(&start_barrier); + let eb = Arc::clone(&exit_barrier); + let nc = Arc::clone(&n_called); + let panic_handler = move |_| { + let val = nc.fetch_add(1, Ordering::SeqCst); + if val < n_threads { + sb.wait(); + } else { + eb.wait(); + } + }; + + let conf = ThreadPoolBuilder::new() + .num_threads(n_threads) + .start_handler(start_handler) + .exit_handler(exit_handler) + .panic_handler(panic_handler); + { + let _ = conf.build().unwrap(); + + // Wait for all the threads to start, panic in the start handler, + // and been taken care of by the panic handler. + start_barrier.wait(); + + // Drop the pool so it stops the running threads. + } + + // Wait for all the threads to exit, panic in the exit handler, + // and been taken care of by the panic handler. + exit_barrier.wait(); + + // The panic handler must have been called twice on every thread. + assert_eq!(n_called.load(Ordering::SeqCst), 2 * n_threads); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn check_config_build() { + let pool = ThreadPoolBuilder::new().num_threads(22).build().unwrap(); + assert_eq!(pool.current_num_threads(), 22); +} + +/// Helper used by check_error_send_sync to ensure ThreadPoolBuildError is Send + Sync +fn _send_sync() {} + +#[test] +fn check_error_send_sync() { + _send_sync::(); +} + +#[allow(deprecated)] +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn configuration() { + let start_handler = move |_| {}; + let exit_handler = move |_| {}; + let panic_handler = move |_| {}; + let thread_name = move |i| format!("thread_name_{}", i); + + // Ensure we can call all public methods on Configuration + crate::Configuration::new() + .thread_name(thread_name) + .num_threads(5) + .panic_handler(panic_handler) + .stack_size(4e6 as usize) + .breadth_first() + .start_handler(start_handler) + .exit_handler(exit_handler) + .build() + .unwrap(); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn default_pool() { + ThreadPoolBuilder::default().build().unwrap(); +} + +/// Test that custom spawned threads get their `WorkerThread` cleared once +/// the pool is done with them, allowing them to be used with rayon again +/// later. e.g. WebAssembly want to have their own pool of available threads. +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn cleared_current_thread() -> Result<(), ThreadPoolBuildError> { + let n_threads = 5; + let mut handles = vec![]; + let pool = ThreadPoolBuilder::new() + .num_threads(n_threads) + .spawn_handler(|thread| { + let handle = std::thread::spawn(move || { + thread.run(); + + // Afterward, the current thread shouldn't be set anymore. + assert_eq!(crate::current_thread_index(), None); + }); + handles.push(handle); + Ok(()) + }) + .build()?; + assert_eq!(handles.len(), n_threads); + + pool.install(|| assert!(crate::current_thread_index().is_some())); + drop(pool); + + // Wait for all threads to make their assertions and exit + for handle in handles { + handle.join().unwrap(); + } + + Ok(()) +} diff --git a/compiler/rustc_thread_pool/src/thread_pool/mod.rs b/compiler/rustc_thread_pool/src/thread_pool/mod.rs new file mode 100644 index 000000000000..65af6d7106e6 --- /dev/null +++ b/compiler/rustc_thread_pool/src/thread_pool/mod.rs @@ -0,0 +1,514 @@ +//! Contains support for user-managed thread pools, represented by the +//! the [`ThreadPool`] type (see that struct for details). +//! +//! [`ThreadPool`]: struct.ThreadPool.html + +use crate::broadcast::{self, BroadcastContext}; +use crate::join; +use crate::registry::{Registry, ThreadSpawn, WorkerThread}; +use crate::scope::{do_in_place_scope, do_in_place_scope_fifo}; +use crate::spawn; +use crate::{scope, Scope}; +use crate::{scope_fifo, ScopeFifo}; +use crate::{ThreadPoolBuildError, ThreadPoolBuilder}; +use std::error::Error; +use std::fmt; +use std::sync::Arc; + +mod test; + +/// Represents a user created [thread-pool]. +/// +/// Use a [`ThreadPoolBuilder`] to specify the number and/or names of threads +/// in the pool. After calling [`ThreadPoolBuilder::build()`], you can then +/// execute functions explicitly within this [`ThreadPool`] using +/// [`ThreadPool::install()`]. By contrast, top level rayon functions +/// (like `join()`) will execute implicitly within the current thread-pool. +/// +/// +/// ## Creating a ThreadPool +/// +/// ```rust +/// # use rayon_core as rayon; +/// let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap(); +/// ``` +/// +/// [`install()`][`ThreadPool::install()`] executes a closure in one of the `ThreadPool`'s +/// threads. In addition, any other rayon operations called inside of `install()` will also +/// execute in the context of the `ThreadPool`. +/// +/// When the `ThreadPool` is dropped, that's a signal for the threads it manages to terminate, +/// they will complete executing any remaining work that you have spawned, and automatically +/// terminate. +/// +/// +/// [thread-pool]: https://en.wikipedia.org/wiki/Thread_pool +/// [`ThreadPool`]: struct.ThreadPool.html +/// [`ThreadPool::new()`]: struct.ThreadPool.html#method.new +/// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html +/// [`ThreadPoolBuilder::build()`]: struct.ThreadPoolBuilder.html#method.build +/// [`ThreadPool::install()`]: struct.ThreadPool.html#method.install +pub struct ThreadPool { + registry: Arc, +} + +impl ThreadPool { + #[deprecated(note = "Use `ThreadPoolBuilder::build`")] + #[allow(deprecated)] + /// Deprecated in favor of `ThreadPoolBuilder::build`. + pub fn new(configuration: crate::Configuration) -> Result> { + Self::build(configuration.into_builder()).map_err(Box::from) + } + + pub(super) fn build( + builder: ThreadPoolBuilder, + ) -> Result + where + S: ThreadSpawn, + { + let registry = Registry::new(builder)?; + Ok(ThreadPool { registry }) + } + + /// Executes `op` within the threadpool. Any attempts to use + /// `join`, `scope`, or parallel iterators will then operate + /// within that threadpool. + /// + /// # Warning: thread-local data + /// + /// Because `op` is executing within the Rayon thread-pool, + /// thread-local data from the current thread will not be + /// accessible. + /// + /// # Warning: execution order + /// + /// If the current thread is part of a different thread pool, it will try to + /// keep busy while the `op` completes in its target pool, similar to + /// calling [`ThreadPool::yield_now()`] in a loop. Therefore, it may + /// potentially schedule other tasks to run on the current thread in the + /// meantime. For example + /// + /// ```rust + /// # use rayon_core as rayon; + /// fn main() { + /// rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap(); + /// let pool = rayon_core::ThreadPoolBuilder::default().build().unwrap(); + /// let do_it = || { + /// print!("one "); + /// pool.install(||{}); + /// print!("two "); + /// }; + /// rayon::join(|| do_it(), || do_it()); + /// } + /// ``` + /// + /// Since we configured just one thread in the global pool, one might + /// expect `do_it()` to run sequentially, producing: + /// + /// ```ascii + /// one two one two + /// ``` + /// + /// However each call to `install()` yields implicitly, allowing rayon to + /// run multiple instances of `do_it()` concurrently on the single, global + /// thread. The following output would be equally valid: + /// + /// ```ascii + /// one one two two + /// ``` + /// + /// # Panics + /// + /// If `op` should panic, that panic will be propagated. + /// + /// ## Using `install()` + /// + /// ```rust + /// # use rayon_core as rayon; + /// fn main() { + /// let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap(); + /// let n = pool.install(|| fib(20)); + /// println!("{}", n); + /// } + /// + /// fn fib(n: usize) -> usize { + /// if n == 0 || n == 1 { + /// return n; + /// } + /// let (a, b) = rayon::join(|| fib(n - 1), || fib(n - 2)); // runs inside of `pool` + /// return a + b; + /// } + /// ``` + pub fn install(&self, op: OP) -> R + where + OP: FnOnce() -> R + Send, + R: Send, + { + self.registry.in_worker(|_, _| op()) + } + + /// Executes `op` within every thread in the threadpool. Any attempts to use + /// `join`, `scope`, or parallel iterators will then operate within that + /// threadpool. + /// + /// Broadcasts are executed on each thread after they have exhausted their + /// local work queue, before they attempt work-stealing from other threads. + /// The goal of that strategy is to run everywhere in a timely manner + /// *without* being too disruptive to current work. There may be alternative + /// broadcast styles added in the future for more or less aggressive + /// injection, if the need arises. + /// + /// # Warning: thread-local data + /// + /// Because `op` is executing within the Rayon thread-pool, + /// thread-local data from the current thread will not be + /// accessible. + /// + /// # Panics + /// + /// If `op` should panic on one or more threads, exactly one panic + /// will be propagated, only after all threads have completed + /// (or panicked) their own `op`. + /// + /// # Examples + /// + /// ``` + /// # use rayon_core as rayon; + /// use std::sync::atomic::{AtomicUsize, Ordering}; + /// + /// fn main() { + /// let pool = rayon::ThreadPoolBuilder::new().num_threads(5).build().unwrap(); + /// + /// // The argument gives context, including the index of each thread. + /// let v: Vec = pool.broadcast(|ctx| ctx.index() * ctx.index()); + /// assert_eq!(v, &[0, 1, 4, 9, 16]); + /// + /// // The closure can reference the local stack + /// let count = AtomicUsize::new(0); + /// pool.broadcast(|_| count.fetch_add(1, Ordering::Relaxed)); + /// assert_eq!(count.into_inner(), 5); + /// } + /// ``` + pub fn broadcast(&self, op: OP) -> Vec + where + OP: Fn(BroadcastContext<'_>) -> R + Sync, + R: Send, + { + // We assert that `self.registry` has not terminated. + unsafe { broadcast::broadcast_in(op, &self.registry) } + } + + /// Returns the (current) number of threads in the thread pool. + /// + /// # Future compatibility note + /// + /// Note that unless this thread-pool was created with a + /// [`ThreadPoolBuilder`] that specifies the number of threads, + /// then this number may vary over time in future versions (see [the + /// `num_threads()` method for details][snt]). + /// + /// [snt]: struct.ThreadPoolBuilder.html#method.num_threads + /// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html + #[inline] + pub fn current_num_threads(&self) -> usize { + self.registry.num_threads() + } + + /// If called from a Rayon worker thread in this thread-pool, + /// returns the index of that thread; if not called from a Rayon + /// thread, or called from a Rayon thread that belongs to a + /// different thread-pool, returns `None`. + /// + /// The index for a given thread will not change over the thread's + /// lifetime. However, multiple threads may share the same index if + /// they are in distinct thread-pools. + /// + /// # Future compatibility note + /// + /// Currently, every thread-pool (including the global + /// thread-pool) has a fixed number of threads, but this may + /// change in future Rayon versions (see [the `num_threads()` method + /// for details][snt]). In that case, the index for a + /// thread would not change during its lifetime, but thread + /// indices may wind up being reused if threads are terminated and + /// restarted. + /// + /// [snt]: struct.ThreadPoolBuilder.html#method.num_threads + #[inline] + pub fn current_thread_index(&self) -> Option { + let curr = self.registry.current_thread()?; + Some(curr.index()) + } + + /// Returns true if the current worker thread currently has "local + /// tasks" pending. This can be useful as part of a heuristic for + /// deciding whether to spawn a new task or execute code on the + /// current thread, particularly in breadth-first + /// schedulers. However, keep in mind that this is an inherently + /// racy check, as other worker threads may be actively "stealing" + /// tasks from our local deque. + /// + /// **Background:** Rayon's uses a [work-stealing] scheduler. The + /// key idea is that each thread has its own [deque] of + /// tasks. Whenever a new task is spawned -- whether through + /// `join()`, `Scope::spawn()`, or some other means -- that new + /// task is pushed onto the thread's *local* deque. Worker threads + /// have a preference for executing their own tasks; if however + /// they run out of tasks, they will go try to "steal" tasks from + /// other threads. This function therefore has an inherent race + /// with other active worker threads, which may be removing items + /// from the local deque. + /// + /// [work-stealing]: https://en.wikipedia.org/wiki/Work_stealing + /// [deque]: https://en.wikipedia.org/wiki/Double-ended_queue + #[inline] + pub fn current_thread_has_pending_tasks(&self) -> Option { + let curr = self.registry.current_thread()?; + Some(!curr.local_deque_is_empty()) + } + + /// Execute `oper_a` and `oper_b` in the thread-pool and return + /// the results. Equivalent to `self.install(|| join(oper_a, + /// oper_b))`. + pub fn join(&self, oper_a: A, oper_b: B) -> (RA, RB) + where + A: FnOnce() -> RA + Send, + B: FnOnce() -> RB + Send, + RA: Send, + RB: Send, + { + self.install(|| join(oper_a, oper_b)) + } + + /// Creates a scope that executes within this thread-pool. + /// Equivalent to `self.install(|| scope(...))`. + /// + /// See also: [the `scope()` function][scope]. + /// + /// [scope]: fn.scope.html + pub fn scope<'scope, OP, R>(&self, op: OP) -> R + where + OP: FnOnce(&Scope<'scope>) -> R + Send, + R: Send, + { + self.install(|| scope(op)) + } + + /// Creates a scope that executes within this thread-pool. + /// Spawns from the same thread are prioritized in relative FIFO order. + /// Equivalent to `self.install(|| scope_fifo(...))`. + /// + /// See also: [the `scope_fifo()` function][scope_fifo]. + /// + /// [scope_fifo]: fn.scope_fifo.html + pub fn scope_fifo<'scope, OP, R>(&self, op: OP) -> R + where + OP: FnOnce(&ScopeFifo<'scope>) -> R + Send, + R: Send, + { + self.install(|| scope_fifo(op)) + } + + /// Creates a scope that spawns work into this thread-pool. + /// + /// See also: [the `in_place_scope()` function][in_place_scope]. + /// + /// [in_place_scope]: fn.in_place_scope.html + pub fn in_place_scope<'scope, OP, R>(&self, op: OP) -> R + where + OP: FnOnce(&Scope<'scope>) -> R, + { + do_in_place_scope(Some(&self.registry), op) + } + + /// Creates a scope that spawns work into this thread-pool in FIFO order. + /// + /// See also: [the `in_place_scope_fifo()` function][in_place_scope_fifo]. + /// + /// [in_place_scope_fifo]: fn.in_place_scope_fifo.html + pub fn in_place_scope_fifo<'scope, OP, R>(&self, op: OP) -> R + where + OP: FnOnce(&ScopeFifo<'scope>) -> R, + { + do_in_place_scope_fifo(Some(&self.registry), op) + } + + /// Spawns an asynchronous task in this thread-pool. This task will + /// run in the implicit, global scope, which means that it may outlast + /// the current stack frame -- therefore, it cannot capture any references + /// onto the stack (you will likely need a `move` closure). + /// + /// See also: [the `spawn()` function defined on scopes][spawn]. + /// + /// [spawn]: struct.Scope.html#method.spawn + pub fn spawn(&self, op: OP) + where + OP: FnOnce() + Send + 'static, + { + // We assert that `self.registry` has not terminated. + unsafe { spawn::spawn_in(op, &self.registry) } + } + + /// Spawns an asynchronous task in this thread-pool. This task will + /// run in the implicit, global scope, which means that it may outlast + /// the current stack frame -- therefore, it cannot capture any references + /// onto the stack (you will likely need a `move` closure). + /// + /// See also: [the `spawn_fifo()` function defined on scopes][spawn_fifo]. + /// + /// [spawn_fifo]: struct.ScopeFifo.html#method.spawn_fifo + pub fn spawn_fifo(&self, op: OP) + where + OP: FnOnce() + Send + 'static, + { + // We assert that `self.registry` has not terminated. + unsafe { spawn::spawn_fifo_in(op, &self.registry) } + } + + /// Spawns an asynchronous task on every thread in this thread-pool. This task + /// will run in the implicit, global scope, which means that it may outlast the + /// current stack frame -- therefore, it cannot capture any references onto the + /// stack (you will likely need a `move` closure). + pub fn spawn_broadcast(&self, op: OP) + where + OP: Fn(BroadcastContext<'_>) + Send + Sync + 'static, + { + // We assert that `self.registry` has not terminated. + unsafe { broadcast::spawn_broadcast_in(op, &self.registry) } + } + + /// Cooperatively yields execution to Rayon. + /// + /// This is similar to the general [`yield_now()`], but only if the current + /// thread is part of *this* thread pool. + /// + /// Returns `Some(Yield::Executed)` if anything was executed, `Some(Yield::Idle)` if + /// nothing was available, or `None` if the current thread is not part this pool. + pub fn yield_now(&self) -> Option { + let curr = self.registry.current_thread()?; + Some(curr.yield_now()) + } + + /// Cooperatively yields execution to local Rayon work. + /// + /// This is similar to the general [`yield_local()`], but only if the current + /// thread is part of *this* thread pool. + /// + /// Returns `Some(Yield::Executed)` if anything was executed, `Some(Yield::Idle)` if + /// nothing was available, or `None` if the current thread is not part this pool. + pub fn yield_local(&self) -> Option { + let curr = self.registry.current_thread()?; + Some(curr.yield_local()) + } + + pub(crate) fn wait_until_stopped(self) { + let registry = self.registry.clone(); + drop(self); + registry.wait_until_stopped(); + } +} + +impl Drop for ThreadPool { + fn drop(&mut self) { + self.registry.terminate(); + } +} + +impl fmt::Debug for ThreadPool { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("ThreadPool") + .field("num_threads", &self.current_num_threads()) + .field("id", &self.registry.id()) + .finish() + } +} + +/// If called from a Rayon worker thread, returns the index of that +/// thread within its current pool; if not called from a Rayon thread, +/// returns `None`. +/// +/// The index for a given thread will not change over the thread's +/// lifetime. However, multiple threads may share the same index if +/// they are in distinct thread-pools. +/// +/// See also: [the `ThreadPool::current_thread_index()` method]. +/// +/// [m]: struct.ThreadPool.html#method.current_thread_index +/// +/// # Future compatibility note +/// +/// Currently, every thread-pool (including the global +/// thread-pool) has a fixed number of threads, but this may +/// change in future Rayon versions (see [the `num_threads()` method +/// for details][snt]). In that case, the index for a +/// thread would not change during its lifetime, but thread +/// indices may wind up being reused if threads are terminated and +/// restarted. +/// +/// [snt]: struct.ThreadPoolBuilder.html#method.num_threads +#[inline] +pub fn current_thread_index() -> Option { + unsafe { + let curr = WorkerThread::current().as_ref()?; + Some(curr.index()) + } +} + +/// If called from a Rayon worker thread, indicates whether that +/// thread's local deque still has pending tasks. Otherwise, returns +/// `None`. For more information, see [the +/// `ThreadPool::current_thread_has_pending_tasks()` method][m]. +/// +/// [m]: struct.ThreadPool.html#method.current_thread_has_pending_tasks +#[inline] +pub fn current_thread_has_pending_tasks() -> Option { + unsafe { + let curr = WorkerThread::current().as_ref()?; + Some(!curr.local_deque_is_empty()) + } +} + +/// Cooperatively yields execution to Rayon. +/// +/// If the current thread is part of a rayon thread pool, this looks for a +/// single unit of pending work in the pool, then executes it. Completion of +/// that work might include nested work or further work stealing. +/// +/// This is similar to [`std::thread::yield_now()`], but does not literally make +/// that call. If you are implementing a polling loop, you may want to also +/// yield to the OS scheduler yourself if no Rayon work was found. +/// +/// Returns `Some(Yield::Executed)` if anything was executed, `Some(Yield::Idle)` if +/// nothing was available, or `None` if this thread is not part of any pool at all. +pub fn yield_now() -> Option { + unsafe { + let thread = WorkerThread::current().as_ref()?; + Some(thread.yield_now()) + } +} + +/// Cooperatively yields execution to local Rayon work. +/// +/// If the current thread is part of a rayon thread pool, this looks for a +/// single unit of pending work in this thread's queue, then executes it. +/// Completion of that work might include nested work or further work stealing. +/// +/// This is similar to [`yield_now()`], but does not steal from other threads. +/// +/// Returns `Some(Yield::Executed)` if anything was executed, `Some(Yield::Idle)` if +/// nothing was available, or `None` if this thread is not part of any pool at all. +pub fn yield_local() -> Option { + unsafe { + let thread = WorkerThread::current().as_ref()?; + Some(thread.yield_local()) + } +} + +/// Result of [`yield_now()`] or [`yield_local()`]. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Yield { + /// Work was found and executed. + Executed, + /// No available work was found. + Idle, +} diff --git a/compiler/rustc_thread_pool/src/thread_pool/test.rs b/compiler/rustc_thread_pool/src/thread_pool/test.rs new file mode 100644 index 000000000000..88b36282d481 --- /dev/null +++ b/compiler/rustc_thread_pool/src/thread_pool/test.rs @@ -0,0 +1,418 @@ +#![cfg(test)] + +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::mpsc::channel; +use std::sync::{Arc, Mutex}; + +use crate::{join, Scope, ScopeFifo, ThreadPool, ThreadPoolBuilder}; + +#[test] +#[should_panic(expected = "Hello, world!")] +fn panic_propagate() { + let thread_pool = ThreadPoolBuilder::new().build().unwrap(); + thread_pool.install(|| { + panic!("Hello, world!"); + }); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn workers_stop() { + let registry; + + { + // once we exit this block, thread-pool will be dropped + let thread_pool = ThreadPoolBuilder::new().num_threads(22).build().unwrap(); + registry = thread_pool.install(|| { + // do some work on these threads + join_a_lot(22); + + Arc::clone(&thread_pool.registry) + }); + assert_eq!(registry.num_threads(), 22); + } + + // once thread-pool is dropped, registry should terminate, which + // should lead to worker threads stopping + registry.wait_until_stopped(); +} + +fn join_a_lot(n: usize) { + if n > 0 { + join(|| join_a_lot(n - 1), || join_a_lot(n - 1)); + } +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn sleeper_stop() { + use std::{thread, time}; + + let registry; + + { + // once we exit this block, thread-pool will be dropped + let thread_pool = ThreadPoolBuilder::new().num_threads(22).build().unwrap(); + registry = Arc::clone(&thread_pool.registry); + + // Give time for at least some of the thread pool to fall asleep. + thread::sleep(time::Duration::from_secs(1)); + } + + // once thread-pool is dropped, registry should terminate, which + // should lead to worker threads stopping + registry.wait_until_stopped(); +} + +/// Creates a start/exit handler that increments an atomic counter. +fn count_handler() -> (Arc, impl Fn(usize)) { + let count = Arc::new(AtomicUsize::new(0)); + (Arc::clone(&count), move |_| { + count.fetch_add(1, Ordering::SeqCst); + }) +} + +/// Wait until a counter is no longer shared, then return its value. +fn wait_for_counter(mut counter: Arc) -> usize { + use std::{thread, time}; + + for _ in 0..60 { + counter = match Arc::try_unwrap(counter) { + Ok(counter) => return counter.into_inner(), + Err(counter) => { + thread::sleep(time::Duration::from_secs(1)); + counter + } + }; + } + + // That's too long! + panic!("Counter is still shared!"); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn failed_thread_stack() { + // Note: we first tried to force failure with a `usize::MAX` stack, but + // macOS and Windows weren't fazed, or at least didn't fail the way we want. + // They work with `isize::MAX`, but 32-bit platforms may feasibly allocate a + // 2GB stack, so it might not fail until the second thread. + let stack_size = ::std::isize::MAX as usize; + + let (start_count, start_handler) = count_handler(); + let (exit_count, exit_handler) = count_handler(); + let builder = ThreadPoolBuilder::new() + .num_threads(10) + .stack_size(stack_size) + .start_handler(start_handler) + .exit_handler(exit_handler); + + let pool = builder.build(); + assert!(pool.is_err(), "thread stack should have failed!"); + + // With such a huge stack, 64-bit will probably fail on the first thread; + // 32-bit might manage the first 2GB, but certainly fail the second. + let start_count = wait_for_counter(start_count); + assert!(start_count <= 1); + assert_eq!(start_count, wait_for_counter(exit_count)); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore)] +fn panic_thread_name() { + let (start_count, start_handler) = count_handler(); + let (exit_count, exit_handler) = count_handler(); + let builder = ThreadPoolBuilder::new() + .num_threads(10) + .start_handler(start_handler) + .exit_handler(exit_handler) + .thread_name(|i| { + if i >= 5 { + panic!(); + } + format!("panic_thread_name#{}", i) + }); + + let pool = crate::unwind::halt_unwinding(|| builder.build()); + assert!(pool.is_err(), "thread-name panic should propagate!"); + + // Assuming they're created in order, threads 0 through 4 should have + // been started already, and then terminated by the panic. + assert_eq!(5, wait_for_counter(start_count)); + assert_eq!(5, wait_for_counter(exit_count)); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn self_install() { + let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); + + // If the inner `install` blocks, then nothing will actually run it! + assert!(pool.install(|| pool.install(|| true))); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn mutual_install() { + let pool1 = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); + let pool2 = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); + + let ok = pool1.install(|| { + // This creates a dependency from `pool1` -> `pool2` + pool2.install(|| { + // This creates a dependency from `pool2` -> `pool1` + pool1.install(|| { + // If they blocked on inter-pool installs, there would be no + // threads left to run this! + true + }) + }) + }); + assert!(ok); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn mutual_install_sleepy() { + use std::{thread, time}; + + let pool1 = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); + let pool2 = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); + + let ok = pool1.install(|| { + // This creates a dependency from `pool1` -> `pool2` + pool2.install(|| { + // Give `pool1` time to fall asleep. + thread::sleep(time::Duration::from_secs(1)); + + // This creates a dependency from `pool2` -> `pool1` + pool1.install(|| { + // Give `pool2` time to fall asleep. + thread::sleep(time::Duration::from_secs(1)); + + // If they blocked on inter-pool installs, there would be no + // threads left to run this! + true + }) + }) + }); + assert!(ok); +} + +#[test] +#[allow(deprecated)] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn check_thread_pool_new() { + let pool = ThreadPool::new(crate::Configuration::new().num_threads(22)).unwrap(); + assert_eq!(pool.current_num_threads(), 22); +} + +macro_rules! test_scope_order { + ($scope:ident => $spawn:ident) => {{ + let builder = ThreadPoolBuilder::new().num_threads(1); + let pool = builder.build().unwrap(); + pool.install(|| { + let vec = Mutex::new(vec![]); + pool.$scope(|scope| { + let vec = &vec; + for i in 0..10 { + scope.$spawn(move |_| { + vec.lock().unwrap().push(i); + }); + } + }); + vec.into_inner().unwrap() + }) + }}; +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn scope_lifo_order() { + let vec = test_scope_order!(scope => spawn); + let expected: Vec = (0..10).rev().collect(); // LIFO -> reversed + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn scope_fifo_order() { + let vec = test_scope_order!(scope_fifo => spawn_fifo); + let expected: Vec = (0..10).collect(); // FIFO -> natural order + assert_eq!(vec, expected); +} + +macro_rules! test_spawn_order { + ($spawn:ident) => {{ + let builder = ThreadPoolBuilder::new().num_threads(1); + let pool = &builder.build().unwrap(); + let (tx, rx) = channel(); + pool.install(move || { + for i in 0..10 { + let tx = tx.clone(); + pool.$spawn(move || { + tx.send(i).unwrap(); + }); + } + }); + rx.iter().collect::>() + }}; +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_lifo_order() { + let vec = test_spawn_order!(spawn); + let expected: Vec = (0..10).rev().collect(); // LIFO -> reversed + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_fifo_order() { + let vec = test_spawn_order!(spawn_fifo); + let expected: Vec = (0..10).collect(); // FIFO -> natural order + assert_eq!(vec, expected); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn nested_scopes() { + // Create matching scopes for every thread pool. + fn nest<'scope, OP>(pools: &[ThreadPool], scopes: Vec<&Scope<'scope>>, op: OP) + where + OP: FnOnce(&[&Scope<'scope>]) + Send, + { + if let Some((pool, tail)) = pools.split_first() { + pool.scope(move |s| { + // This move reduces the reference lifetimes by variance to match s, + // but the actual scopes are still tied to the invariant 'scope. + let mut scopes = scopes; + scopes.push(s); + nest(tail, scopes, op) + }) + } else { + (op)(&scopes) + } + } + + let pools: Vec<_> = (0..10) + .map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()) + .collect(); + + let counter = AtomicUsize::new(0); + nest(&pools, vec![], |scopes| { + for &s in scopes { + s.spawn(|_| { + // Our 'scope lets us borrow the counter in every pool. + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }); + assert_eq!(counter.into_inner(), pools.len()); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn nested_fifo_scopes() { + // Create matching fifo scopes for every thread pool. + fn nest<'scope, OP>(pools: &[ThreadPool], scopes: Vec<&ScopeFifo<'scope>>, op: OP) + where + OP: FnOnce(&[&ScopeFifo<'scope>]) + Send, + { + if let Some((pool, tail)) = pools.split_first() { + pool.scope_fifo(move |s| { + // This move reduces the reference lifetimes by variance to match s, + // but the actual scopes are still tied to the invariant 'scope. + let mut scopes = scopes; + scopes.push(s); + nest(tail, scopes, op) + }) + } else { + (op)(&scopes) + } + } + + let pools: Vec<_> = (0..10) + .map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()) + .collect(); + + let counter = AtomicUsize::new(0); + nest(&pools, vec![], |scopes| { + for &s in scopes { + s.spawn_fifo(|_| { + // Our 'scope lets us borrow the counter in every pool. + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }); + assert_eq!(counter.into_inner(), pools.len()); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn in_place_scope_no_deadlock() { + let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); + let (tx, rx) = channel(); + let rx_ref = ℞ + pool.in_place_scope(move |s| { + // With regular scopes this closure would never run because this scope op + // itself would block the only worker thread. + s.spawn(move |_| { + tx.send(()).unwrap(); + }); + rx_ref.recv().unwrap(); + }); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn in_place_scope_fifo_no_deadlock() { + let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); + let (tx, rx) = channel(); + let rx_ref = ℞ + pool.in_place_scope_fifo(move |s| { + // With regular scopes this closure would never run because this scope op + // itself would block the only worker thread. + s.spawn_fifo(move |_| { + tx.send(()).unwrap(); + }); + rx_ref.recv().unwrap(); + }); +} + +#[test] +fn yield_now_to_spawn() { + let (tx, rx) = channel(); + + // Queue a regular spawn. + crate::spawn(move || tx.send(22).unwrap()); + + // The single-threaded fallback mode (for wasm etc.) won't + // get a chance to run the spawn if we never yield to it. + crate::registry::in_worker(move |_, _| { + crate::yield_now(); + }); + + // The spawn **must** have started by now, but we still might have to wait + // for it to finish if a different thread stole it first. + assert_eq!(22, rx.recv().unwrap()); +} + +#[test] +fn yield_local_to_spawn() { + let (tx, rx) = channel(); + + // Queue a regular spawn. + crate::spawn(move || tx.send(22).unwrap()); + + // The single-threaded fallback mode (for wasm etc.) won't + // get a chance to run the spawn if we never yield to it. + crate::registry::in_worker(move |_, _| { + crate::yield_local(); + }); + + // The spawn **must** have started by now, but we still might have to wait + // for it to finish if a different thread stole it first. + assert_eq!(22, rx.recv().unwrap()); +} diff --git a/compiler/rustc_thread_pool/src/tlv.rs b/compiler/rustc_thread_pool/src/tlv.rs new file mode 100644 index 000000000000..ce22f7aa0ce7 --- /dev/null +++ b/compiler/rustc_thread_pool/src/tlv.rs @@ -0,0 +1,31 @@ +//! Allows access to the Rayon's thread local value +//! which is preserved when moving jobs across threads + +use std::{cell::Cell, ptr}; + +thread_local!(pub static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) }); + +#[derive(Copy, Clone)] +pub(crate) struct Tlv(pub(crate) *const ()); + +impl Tlv { + #[inline] + pub(crate) fn null() -> Self { + Self(ptr::null()) + } +} + +unsafe impl Sync for Tlv {} +unsafe impl Send for Tlv {} + +/// Sets the current thread-local value +#[inline] +pub(crate) fn set(value: Tlv) { + TLV.with(|tlv| tlv.set(value.0)); +} + +/// Returns the current thread-local value +#[inline] +pub(crate) fn get() -> Tlv { + TLV.with(|tlv| Tlv(tlv.get())) +} diff --git a/compiler/rustc_thread_pool/src/unwind.rs b/compiler/rustc_thread_pool/src/unwind.rs new file mode 100644 index 000000000000..9671fa578214 --- /dev/null +++ b/compiler/rustc_thread_pool/src/unwind.rs @@ -0,0 +1,31 @@ +//! Package up unwind recovery. Note that if you are in some sensitive +//! place, you can use the `AbortIfPanic` helper to protect against +//! accidental panics in the rayon code itself. + +use std::any::Any; +use std::panic::{self, AssertUnwindSafe}; +use std::thread; + +/// Executes `f` and captures any panic, translating that panic into a +/// `Err` result. The assumption is that any panic will be propagated +/// later with `resume_unwinding`, and hence `f` can be treated as +/// exception safe. +pub(super) fn halt_unwinding(func: F) -> thread::Result +where + F: FnOnce() -> R, +{ + panic::catch_unwind(AssertUnwindSafe(func)) +} + +pub(super) fn resume_unwinding(payload: Box) -> ! { + panic::resume_unwind(payload) +} + +pub(super) struct AbortIfPanic; + +impl Drop for AbortIfPanic { + fn drop(&mut self) { + eprintln!("Rayon: detected unexpected panic; aborting"); + ::std::process::abort(); + } +} diff --git a/compiler/rustc_thread_pool/src/worker_local.rs b/compiler/rustc_thread_pool/src/worker_local.rs new file mode 100644 index 000000000000..85d51687c190 --- /dev/null +++ b/compiler/rustc_thread_pool/src/worker_local.rs @@ -0,0 +1,78 @@ +use crate::registry::{Registry, WorkerThread}; +use std::fmt; +use std::ops::Deref; +use std::sync::Arc; + +#[repr(align(64))] +#[derive(Debug)] +struct CacheAligned(T); + +/// Holds worker-locals values for each thread in a thread pool. +/// You can only access the worker local value through the Deref impl +/// on the thread pool it was constructed on. It will panic otherwise +pub struct WorkerLocal { + locals: Vec>, + registry: Arc, +} + +/// We prevent concurrent access to the underlying value in the +/// Deref impl, thus any values safe to send across threads can +/// be used with WorkerLocal. +unsafe impl Sync for WorkerLocal {} + +impl WorkerLocal { + /// Creates a new worker local where the `initial` closure computes the + /// value this worker local should take for each thread in the thread pool. + #[inline] + pub fn new T>(mut initial: F) -> WorkerLocal { + let registry = Registry::current(); + WorkerLocal { + locals: (0..registry.num_threads()) + .map(|i| CacheAligned(initial(i))) + .collect(), + registry, + } + } + + /// Returns the worker-local value for each thread + #[inline] + pub fn into_inner(self) -> Vec { + self.locals.into_iter().map(|c| c.0).collect() + } + + fn current(&self) -> &T { + unsafe { + let worker_thread = WorkerThread::current(); + if worker_thread.is_null() + || &*(*worker_thread).registry as *const _ != &*self.registry as *const _ + { + panic!("WorkerLocal can only be used on the thread pool it was created on") + } + &self.locals[(*worker_thread).index].0 + } + } +} + +impl WorkerLocal> { + /// Joins the elements of all the worker locals into one Vec + pub fn join(self) -> Vec { + self.into_inner().into_iter().flat_map(|v| v).collect() + } +} + +impl fmt::Debug for WorkerLocal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("WorkerLocal") + .field("registry", &self.registry.id()) + .finish() + } +} + +impl Deref for WorkerLocal { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + self.current() + } +} diff --git a/compiler/rustc_thread_pool/tests/double_init_fail.rs b/compiler/rustc_thread_pool/tests/double_init_fail.rs new file mode 100644 index 000000000000..15915304ddcc --- /dev/null +++ b/compiler/rustc_thread_pool/tests/double_init_fail.rs @@ -0,0 +1,15 @@ +use rayon_core::ThreadPoolBuilder; +use std::error::Error; + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn double_init_fail() { + let result1 = ThreadPoolBuilder::new().build_global(); + assert!(result1.is_ok()); + let err = ThreadPoolBuilder::new().build_global().unwrap_err(); + assert!(err.source().is_none()); + assert_eq!( + err.to_string(), + "The global thread pool has already been initialized.", + ); +} diff --git a/compiler/rustc_thread_pool/tests/init_zero_threads.rs b/compiler/rustc_thread_pool/tests/init_zero_threads.rs new file mode 100644 index 000000000000..3c1ad251c7e0 --- /dev/null +++ b/compiler/rustc_thread_pool/tests/init_zero_threads.rs @@ -0,0 +1,10 @@ +use rayon_core::ThreadPoolBuilder; + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn init_zero_threads() { + ThreadPoolBuilder::new() + .num_threads(0) + .build_global() + .unwrap(); +} diff --git a/compiler/rustc_thread_pool/tests/scope_join.rs b/compiler/rustc_thread_pool/tests/scope_join.rs new file mode 100644 index 000000000000..9d88133bc5b6 --- /dev/null +++ b/compiler/rustc_thread_pool/tests/scope_join.rs @@ -0,0 +1,45 @@ +/// Test that one can emulate join with `scope`: +fn pseudo_join(f: F, g: G) +where + F: FnOnce() + Send, + G: FnOnce() + Send, +{ + rayon_core::scope(|s| { + s.spawn(|_| g()); + f(); + }); +} + +fn quick_sort(v: &mut [T]) { + if v.len() <= 1 { + return; + } + + let mid = partition(v); + let (lo, hi) = v.split_at_mut(mid); + pseudo_join(|| quick_sort(lo), || quick_sort(hi)); +} + +fn partition(v: &mut [T]) -> usize { + let pivot = v.len() - 1; + let mut i = 0; + for j in 0..pivot { + if v[j] <= v[pivot] { + v.swap(i, j); + i += 1; + } + } + v.swap(i, pivot); + i +} + +fn is_sorted(v: &[T]) -> bool { + (1..v.len()).all(|i| v[i - 1] <= v[i]) +} + +#[test] +fn scope_join() { + let mut v: Vec = (0..256).rev().collect(); + quick_sort(&mut v); + assert!(is_sorted(&v)); +} diff --git a/compiler/rustc_thread_pool/tests/scoped_threadpool.rs b/compiler/rustc_thread_pool/tests/scoped_threadpool.rs new file mode 100644 index 000000000000..932147179f5c --- /dev/null +++ b/compiler/rustc_thread_pool/tests/scoped_threadpool.rs @@ -0,0 +1,99 @@ +use crossbeam_utils::thread; +use rayon_core::ThreadPoolBuilder; + +#[derive(PartialEq, Eq, Debug)] +struct Local(i32); + +scoped_tls::scoped_thread_local!(static LOCAL: Local); + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn missing_scoped_tls() { + LOCAL.set(&Local(42), || { + let pool = ThreadPoolBuilder::new() + .build() + .expect("thread pool created"); + + // `LOCAL` is not set in the pool. + pool.install(|| { + assert!(!LOCAL.is_set()); + }); + }); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn spawn_scoped_tls_threadpool() { + LOCAL.set(&Local(42), || { + LOCAL.with(|x| { + thread::scope(|scope| { + let pool = ThreadPoolBuilder::new() + .spawn_handler(move |thread| { + scope + .builder() + .spawn(move |_| { + // Borrow the same local value in the thread pool. + LOCAL.set(x, || thread.run()) + }) + .map(|_| ()) + }) + .build() + .expect("thread pool created"); + + // The pool matches our local value. + pool.install(|| { + assert!(LOCAL.is_set()); + LOCAL.with(|y| { + assert_eq!(x, y); + }); + }); + + // If we change our local value, the pool is not affected. + LOCAL.set(&Local(-1), || { + pool.install(|| { + assert!(LOCAL.is_set()); + LOCAL.with(|y| { + assert_eq!(x, y); + }); + }); + }); + }) + .expect("scope threads ok"); + // `thread::scope` will wait for the threads to exit before returning. + }); + }); +} + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] +fn build_scoped_tls_threadpool() { + LOCAL.set(&Local(42), || { + LOCAL.with(|x| { + ThreadPoolBuilder::new() + .build_scoped( + move |thread| LOCAL.set(x, || thread.run()), + |pool| { + // The pool matches our local value. + pool.install(|| { + assert!(LOCAL.is_set()); + LOCAL.with(|y| { + assert_eq!(x, y); + }); + }); + + // If we change our local value, the pool is not affected. + LOCAL.set(&Local(-1), || { + pool.install(|| { + assert!(LOCAL.is_set()); + LOCAL.with(|y| { + assert_eq!(x, y); + }); + }); + }); + }, + ) + .expect("thread pool created"); + // Internally, `std::thread::scope` will wait for the threads to exit before returning. + }); + }); +} diff --git a/compiler/rustc_thread_pool/tests/simple_panic.rs b/compiler/rustc_thread_pool/tests/simple_panic.rs new file mode 100644 index 000000000000..2564482a47e5 --- /dev/null +++ b/compiler/rustc_thread_pool/tests/simple_panic.rs @@ -0,0 +1,7 @@ +use rayon_core::join; + +#[test] +#[should_panic(expected = "should panic")] +fn simple_panic() { + join(|| {}, || panic!("should panic")); +} diff --git a/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs b/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs new file mode 100644 index 000000000000..a6494069212c --- /dev/null +++ b/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs @@ -0,0 +1,98 @@ +use rayon_core::ThreadPoolBuilder; + +use std::env; +use std::process::{Command, ExitStatus, Stdio}; + +#[cfg(target_os = "linux")] +use std::os::unix::process::ExitStatusExt; + +fn force_stack_overflow(depth: u32) { + let mut buffer = [0u8; 1024 * 1024]; + #[allow(clippy::incompatible_msrv)] + std::hint::black_box(&mut buffer); + if depth > 0 { + force_stack_overflow(depth - 1); + } +} + +#[cfg(unix)] +fn disable_core() { + unsafe { + libc::setrlimit( + libc::RLIMIT_CORE, + &libc::rlimit { + rlim_cur: 0, + rlim_max: 0, + }, + ); + } +} + +#[cfg(unix)] +fn overflow_code() -> Option { + None +} + +#[cfg(windows)] +fn overflow_code() -> Option { + use std::os::windows::process::ExitStatusExt; + + ExitStatus::from_raw(0xc00000fd /*STATUS_STACK_OVERFLOW*/).code() +} + +#[test] +#[cfg_attr(not(any(unix, windows)), ignore)] +fn stack_overflow_crash() { + // First check that the recursive call actually causes a stack overflow, + // and does not get optimized away. + let status = run_ignored("run_with_small_stack"); + assert!(!status.success()); + #[cfg(any(unix, windows))] + assert_eq!(status.code(), overflow_code()); + #[cfg(target_os = "linux")] + assert!(matches!( + status.signal(), + Some(libc::SIGABRT | libc::SIGSEGV) + )); + + // Now run with a larger stack and verify correct operation. + let status = run_ignored("run_with_large_stack"); + assert_eq!(status.code(), Some(0)); + #[cfg(target_os = "linux")] + assert_eq!(status.signal(), None); +} + +fn run_ignored(test: &str) -> ExitStatus { + Command::new(env::current_exe().unwrap()) + .arg("--ignored") + .arg("--exact") + .arg(test) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .unwrap() +} + +#[test] +#[ignore] +fn run_with_small_stack() { + run_with_stack(8); +} + +#[test] +#[ignore] +fn run_with_large_stack() { + run_with_stack(48); +} + +fn run_with_stack(stack_size_in_mb: usize) { + let pool = ThreadPoolBuilder::new() + .stack_size(stack_size_in_mb * 1024 * 1024) + .build() + .unwrap(); + pool.install(|| { + #[cfg(unix)] + disable_core(); + force_stack_overflow(32); + }); +} From 0b9b1df0064396708a5e5ca27fd010ae3ad3a305 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 11 Jun 2025 11:12:32 -0700 Subject: [PATCH 028/356] Fix format and tidy for code moved from rayon --- .../rustc_thread_pool/src/broadcast/mod.rs | 17 ++-- .../src/broadcast/{test.rs => tests.rs} | 5 +- compiler/rustc_thread_pool/src/job.rs | 26 +++-- compiler/rustc_thread_pool/src/join/mod.rs | 17 ++-- .../src/join/{test.rs => tests.rs} | 5 +- compiler/rustc_thread_pool/src/latch.rs | 54 +++-------- compiler/rustc_thread_pool/src/lib.rs | 56 ++++------- compiler/rustc_thread_pool/src/private.rs | 2 +- compiler/rustc_thread_pool/src/registry.rs | 95 +++++++------------ compiler/rustc_thread_pool/src/scope/mod.rs | 34 +++---- .../src/scope/{test.rs => tests.rs} | 35 ++----- .../rustc_thread_pool/src/sleep/README.md | 2 +- .../rustc_thread_pool/src/sleep/counters.rs | 8 +- compiler/rustc_thread_pool/src/sleep/mod.rs | 26 ++--- compiler/rustc_thread_pool/src/spawn/mod.rs | 17 ++-- .../src/spawn/{test.rs => tests.rs} | 19 +--- .../src/{test.rs => tests.rs} | 11 +-- .../rustc_thread_pool/src/thread_pool/mod.rs | 15 ++- .../src/thread_pool/{test.rs => tests.rs} | 12 +-- compiler/rustc_thread_pool/src/tlv.rs | 3 +- .../rustc_thread_pool/src/worker_local.rs | 11 +-- .../tests/double_init_fail.rs | 8 +- .../tests/init_zero_threads.rs | 5 +- .../tests/scoped_threadpool.rs | 4 +- .../tests/stack_overflow_crash.rs | 25 ++--- 25 files changed, 187 insertions(+), 325 deletions(-) rename compiler/rustc_thread_pool/src/broadcast/{test.rs => tests.rs} (99%) rename compiler/rustc_thread_pool/src/join/{test.rs => tests.rs} (99%) rename compiler/rustc_thread_pool/src/scope/{test.rs => tests.rs} (96%) rename compiler/rustc_thread_pool/src/spawn/{test.rs => tests.rs} (95%) rename compiler/rustc_thread_pool/src/{test.rs => tests.rs} (96%) rename compiler/rustc_thread_pool/src/thread_pool/{test.rs => tests.rs} (97%) diff --git a/compiler/rustc_thread_pool/src/broadcast/mod.rs b/compiler/rustc_thread_pool/src/broadcast/mod.rs index 442891f2d287..c2b0d47f8299 100644 --- a/compiler/rustc_thread_pool/src/broadcast/mod.rs +++ b/compiler/rustc_thread_pool/src/broadcast/mod.rs @@ -1,10 +1,11 @@ -use crate::job::{ArcJob, StackJob}; -use crate::latch::{CountLatch, LatchRef}; -use crate::registry::{Registry, WorkerThread}; use std::fmt; use std::marker::PhantomData; use std::sync::Arc; +use crate::job::{ArcJob, StackJob}; +use crate::latch::{CountLatch, LatchRef}; +use crate::registry::{Registry, WorkerThread}; + mod test; /// Executes `op` within every thread in the current threadpool. If this is @@ -53,10 +54,7 @@ impl<'a> BroadcastContext<'a> { pub(super) fn with(f: impl FnOnce(BroadcastContext<'_>) -> R) -> R { let worker_thread = WorkerThread::current(); assert!(!worker_thread.is_null()); - f(BroadcastContext { - worker: unsafe { &*worker_thread }, - _marker: PhantomData, - }) + f(BroadcastContext { worker: unsafe { &*worker_thread }, _marker: PhantomData }) } /// Our index amongst the broadcast threads (ranges from `0..self.num_threads()`). @@ -108,9 +106,8 @@ where let current_thread = WorkerThread::current().as_ref(); let tlv = crate::tlv::get(); let latch = CountLatch::with_count(n_threads, current_thread); - let jobs: Vec<_> = (0..n_threads) - .map(|_| StackJob::new(tlv, &f, LatchRef::new(&latch))) - .collect(); + let jobs: Vec<_> = + (0..n_threads).map(|_| StackJob::new(tlv, &f, LatchRef::new(&latch))).collect(); let job_refs = jobs.iter().map(|job| job.as_job_ref()); registry.inject_broadcast(job_refs); diff --git a/compiler/rustc_thread_pool/src/broadcast/test.rs b/compiler/rustc_thread_pool/src/broadcast/tests.rs similarity index 99% rename from compiler/rustc_thread_pool/src/broadcast/test.rs rename to compiler/rustc_thread_pool/src/broadcast/tests.rs index 00ab4ad7fe41..fac8b8ad4666 100644 --- a/compiler/rustc_thread_pool/src/broadcast/test.rs +++ b/compiler/rustc_thread_pool/src/broadcast/tests.rs @@ -1,11 +1,12 @@ #![cfg(test)] -use crate::ThreadPoolBuilder; +use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::channel; -use std::sync::Arc; use std::{thread, time}; +use crate::ThreadPoolBuilder; + #[test] fn broadcast_global() { let v = crate::broadcast(|ctx| ctx.index()); diff --git a/compiler/rustc_thread_pool/src/job.rs b/compiler/rustc_thread_pool/src/job.rs index 394c7576b2cb..3241914ba81c 100644 --- a/compiler/rustc_thread_pool/src/job.rs +++ b/compiler/rustc_thread_pool/src/job.rs @@ -1,13 +1,14 @@ -use crate::latch::Latch; -use crate::tlv; -use crate::tlv::Tlv; -use crate::unwind; -use crossbeam_deque::{Injector, Steal}; use std::any::Any; use std::cell::UnsafeCell; use std::mem; use std::sync::Arc; +use crossbeam_deque::{Injector, Steal}; + +use crate::latch::Latch; +use crate::tlv::Tlv; +use crate::{tlv, unwind}; + pub(super) enum JobResult { None, Ok(T), @@ -29,7 +30,7 @@ pub(super) trait Job { /// Effectively a Job trait object. Each JobRef **must** be executed /// exactly once, or else data may leak. /// -/// Internally, we store the job's data in a `*const ()` pointer. The +/// Internally, we store the job's data in a `*const ()` pointer. The /// true type is something like `*const StackJob<...>`, but we hide /// it. We also carry the "execute fn" from the `Job` trait. pub(super) struct JobRef { @@ -48,10 +49,7 @@ impl JobRef { T: Job, { // erase types: - JobRef { - pointer: data as *const (), - execute_fn: ::execute, - } + JobRef { pointer: data as *const (), execute_fn: ::execute } } /// Returns an opaque handle that can be saved and compared, @@ -69,7 +67,7 @@ impl JobRef { /// A job that will be owned by a stack slot. This means that when it /// executes it need not free any heap data, the cleanup occurs when -/// the stack frame is later popped. The function parameter indicates +/// the stack frame is later popped. The function parameter indicates /// `true` if the job was stolen -- executed on a different thread. pub(super) struct StackJob where @@ -248,13 +246,11 @@ pub(super) struct JobFifo { impl JobFifo { pub(super) fn new() -> Self { - JobFifo { - inner: Injector::new(), - } + JobFifo { inner: Injector::new() } } pub(super) unsafe fn push(&self, job_ref: JobRef) -> JobRef { - // A little indirection ensures that spawns are always prioritized in FIFO order. The + // A little indirection ensures that spawns are always prioritized in FIFO order. The // jobs in a thread's deque may be popped from the back (LIFO) or stolen from the front // (FIFO), but either way they will end up popping from the front of this queue. self.inner.push(job_ref); diff --git a/compiler/rustc_thread_pool/src/join/mod.rs b/compiler/rustc_thread_pool/src/join/mod.rs index 032eec9c4c84..798a8347d798 100644 --- a/compiler/rustc_thread_pool/src/join/mod.rs +++ b/compiler/rustc_thread_pool/src/join/mod.rs @@ -1,11 +1,10 @@ +use std::any::Any; + use crate::job::StackJob; use crate::latch::SpinLatch; use crate::registry::{self, WorkerThread}; use crate::tlv::{self, Tlv}; -use crate::unwind; -use std::any::Any; - -use crate::FnContext; +use crate::{FnContext, unwind}; #[cfg(test)] mod test; @@ -22,7 +21,7 @@ mod test; /// it. /// /// When `join` is called from outside the thread pool, the calling -/// thread will block while the closures execute in the pool. When +/// thread will block while the closures execute in the pool. When /// `join` is called within the pool, the calling thread still actively /// participates in the thread pool. It will begin by executing closure /// A (on the current thread). While it is doing that, it will advertise @@ -80,13 +79,13 @@ mod test; /// CPU-bound tasks that do not perform I/O or other blocking /// operations. If you do perform I/O, and that I/O should block /// (e.g., waiting for a network request), the overall performance may -/// be poor. Moreover, if you cause one closure to be blocked waiting +/// be poor. Moreover, if you cause one closure to be blocked waiting /// on another (for example, using a channel), that could lead to a /// deadlock. /// /// # Panics /// -/// No matter what happens, both closures will always be executed. If +/// No matter what happens, both closures will always be executed. If /// a single closure panics, whether it be the first or second /// closure, that panic will be propagated and hence `join()` will /// panic with the same panic value. If both closures panic, `join()` @@ -109,7 +108,7 @@ where /// Identical to `join`, except that the closures have a parameter /// that provides context for the way the closure has been called, /// especially indicating whether they're executing on a different -/// thread than where `join_context` was called. This will occur if +/// thread than where `join_context` was called. This will occur if /// the second job is stolen by a different thread, or if /// `join_context` was called from outside the thread pool to begin /// with. @@ -148,7 +147,7 @@ where }; // Now that task A has finished, try to pop job B from the - // local stack. It may already have been popped by job A; it + // local stack. It may already have been popped by job A; it // may also have been stolen. There may also be some tasks // pushed on top of it in the stack, and we will have to pop // those off to get to it. diff --git a/compiler/rustc_thread_pool/src/join/test.rs b/compiler/rustc_thread_pool/src/join/tests.rs similarity index 99% rename from compiler/rustc_thread_pool/src/join/test.rs rename to compiler/rustc_thread_pool/src/join/tests.rs index 03f4ab4478d4..9df99072c3a1 100644 --- a/compiler/rustc_thread_pool/src/join/test.rs +++ b/compiler/rustc_thread_pool/src/join/tests.rs @@ -1,11 +1,12 @@ //! Tests for the join code. -use super::*; -use crate::ThreadPoolBuilder; use rand::distr::StandardUniform; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; +use super::*; +use crate::ThreadPoolBuilder; + fn quick_sort(v: &mut [T]) { if v.len() <= 1 { return; diff --git a/compiler/rustc_thread_pool/src/latch.rs b/compiler/rustc_thread_pool/src/latch.rs index 8903942a8ce3..f2f806e01845 100644 --- a/compiler/rustc_thread_pool/src/latch.rs +++ b/compiler/rustc_thread_pool/src/latch.rs @@ -28,7 +28,7 @@ use crate::registry::{Registry, WorkerThread}; /// - Once `probe()` returns true, all memory effects from the `set()` /// are visible (in other words, the set should synchronize-with /// the probe). -/// - Once `set()` occurs, the next `probe()` *will* observe it. This +/// - Once `set()` occurs, the next `probe()` *will* observe it. This /// typically requires a seq-cst ordering. See [the "tickle-then-get-sleepy" scenario in the sleep /// README](/src/sleep/README.md#tickle-then-get-sleepy) for details. pub(super) trait Latch { @@ -78,9 +78,7 @@ pub(super) struct CoreLatch { impl CoreLatch { #[inline] fn new() -> Self { - Self { - state: AtomicUsize::new(0), - } + Self { state: AtomicUsize::new(0) } } /// Invoked by owning thread as it prepares to sleep. Returns true @@ -88,9 +86,7 @@ impl CoreLatch { /// latch was set in the meantime. #[inline] pub(super) fn get_sleepy(&self) -> bool { - self.state - .compare_exchange(UNSET, SLEEPY, Ordering::SeqCst, Ordering::Relaxed) - .is_ok() + self.state.compare_exchange(UNSET, SLEEPY, Ordering::SeqCst, Ordering::Relaxed).is_ok() } /// Invoked by owning thread as it falls asleep sleep. Returns @@ -98,9 +94,7 @@ impl CoreLatch { /// was set in the meantime. #[inline] pub(super) fn fall_asleep(&self) -> bool { - self.state - .compare_exchange(SLEEPY, SLEEPING, Ordering::SeqCst, Ordering::Relaxed) - .is_ok() + self.state.compare_exchange(SLEEPY, SLEEPING, Ordering::SeqCst, Ordering::Relaxed).is_ok() } /// Invoked by owning thread as it falls asleep sleep. Returns @@ -110,8 +104,7 @@ impl CoreLatch { pub(super) fn wake_up(&self) { if !self.probe() { let _ = - self.state - .compare_exchange(SLEEPING, UNSET, Ordering::SeqCst, Ordering::Relaxed); + self.state.compare_exchange(SLEEPING, UNSET, Ordering::SeqCst, Ordering::Relaxed); } } @@ -166,15 +159,12 @@ impl<'r> SpinLatch<'r> { } } - /// Creates a new spin latch for cross-threadpool blocking. Notably, we + /// Creates a new spin latch for cross-threadpool blocking. Notably, we /// need to make sure the registry is kept alive after setting, so we can /// safely call the notification. #[inline] pub(super) fn cross(thread: &'r WorkerThread) -> SpinLatch<'r> { - SpinLatch { - cross: true, - ..SpinLatch::new(thread) - } + SpinLatch { cross: true, ..SpinLatch::new(thread) } } #[inline] @@ -235,10 +225,7 @@ pub(super) struct LockLatch { impl LockLatch { #[inline] pub(super) fn new() -> LockLatch { - LockLatch { - m: Mutex::new(false), - v: Condvar::new(), - } + LockLatch { m: Mutex::new(false), v: Condvar::new() } } /// Block until latch is set, then resets this lock latch so it can be reused again. @@ -288,9 +275,7 @@ pub(super) struct OnceLatch { impl OnceLatch { #[inline] pub(super) fn new() -> OnceLatch { - Self { - core_latch: CoreLatch::new(), - } + Self { core_latch: CoreLatch::new() } } /// Set the latch, then tickle the specific worker thread, @@ -372,9 +357,7 @@ impl CountLatch { registry: Arc::clone(owner.registry()), worker_index: owner.index(), }, - None => CountLatchKind::Blocking { - latch: LockLatch::new(), - }, + None => CountLatchKind::Blocking { latch: LockLatch::new() }, }, } } @@ -387,11 +370,7 @@ impl CountLatch { pub(super) fn wait(&self, owner: Option<&WorkerThread>) { match &self.kind { - CountLatchKind::Stealing { - latch, - registry, - worker_index, - } => unsafe { + CountLatchKind::Stealing { latch, registry, worker_index } => unsafe { let owner = owner.expect("owner thread"); debug_assert_eq!(registry.id(), owner.registry().id()); debug_assert_eq!(*worker_index, owner.index()); @@ -409,11 +388,7 @@ impl Latch for CountLatch { // NOTE: Once we call `set` on the internal `latch`, // the target may proceed and invalidate `this`! match (*this).kind { - CountLatchKind::Stealing { - ref latch, - ref registry, - worker_index, - } => { + CountLatchKind::Stealing { ref latch, ref registry, worker_index } => { let registry = Arc::clone(registry); if CoreLatch::set(latch) { registry.notify_worker_latch_is_set(worker_index); @@ -433,10 +408,7 @@ pub(super) struct LatchRef<'a, L> { impl LatchRef<'_, L> { pub(super) fn new(inner: &L) -> LatchRef<'_, L> { - LatchRef { - inner, - marker: PhantomData, - } + LatchRef { inner, marker: PhantomData } } } diff --git a/compiler/rustc_thread_pool/src/lib.rs b/compiler/rustc_thread_pool/src/lib.rs index 72064547e526..179d63ed668a 100644 --- a/compiler/rustc_thread_pool/src/lib.rs +++ b/compiler/rustc_thread_pool/src/lib.rs @@ -57,20 +57,17 @@ //! //! While we strive to keep `rayon-core` semver-compatible, it's still //! possible to arrive at this situation if different crates have overly -//! restrictive tilde or inequality requirements for `rayon-core`. The +//! restrictive tilde or inequality requirements for `rayon-core`. The //! conflicting requirements will need to be resolved before the build will //! succeed. #![warn(rust_2018_idioms)] use std::any::Any; -use std::env; use std::error::Error; -use std::fmt; -use std::io; use std::marker::PhantomData; use std::str::FromStr; -use std::thread; +use std::{env, fmt, io, thread}; #[macro_use] mod private; @@ -92,20 +89,18 @@ mod test; pub mod tlv; -pub use self::broadcast::{broadcast, spawn_broadcast, BroadcastContext}; -pub use self::join::{join, join_context}; -pub use self::registry::ThreadBuilder; -pub use self::registry::{mark_blocked, mark_unblocked, Registry}; -pub use self::scope::{in_place_scope, scope, Scope}; -pub use self::scope::{in_place_scope_fifo, scope_fifo, ScopeFifo}; -pub use self::spawn::{spawn, spawn_fifo}; -pub use self::thread_pool::current_thread_has_pending_tasks; -pub use self::thread_pool::current_thread_index; -pub use self::thread_pool::ThreadPool; -pub use self::thread_pool::{yield_local, yield_now, Yield}; pub use worker_local::WorkerLocal; +pub use self::broadcast::{BroadcastContext, broadcast, spawn_broadcast}; +pub use self::join::{join, join_context}; use self::registry::{CustomSpawn, DefaultSpawn, ThreadSpawn}; +pub use self::registry::{Registry, ThreadBuilder, mark_blocked, mark_unblocked}; +pub use self::scope::{Scope, ScopeFifo, in_place_scope, in_place_scope_fifo, scope, scope_fifo}; +pub use self::spawn::{spawn, spawn_fifo}; +pub use self::thread_pool::{ + ThreadPool, Yield, current_thread_has_pending_tasks, current_thread_index, yield_local, + yield_now, +}; /// Returns the maximum number of threads that Rayon supports in a single thread-pool. /// @@ -282,7 +277,7 @@ where } /// Initializes the global thread pool. This initialization is - /// **optional**. If you do not call this function, the thread pool + /// **optional**. If you do not call this function, the thread pool /// will be automatically initialized with the default /// configuration. Calling `build_global` is not recommended, except /// in two scenarios: @@ -290,7 +285,7 @@ where /// - You wish to change the default configuration. /// - You are running a benchmark, in which case initializing may /// yield slightly more consistent results, since the worker threads - /// will already be ready to go even in the first iteration. But + /// will already be ready to go even in the first iteration. But /// this cost is minimal. /// /// Initialization of the global thread pool happens exactly @@ -490,26 +485,16 @@ impl ThreadPoolBuilder { if self.num_threads > 0 { self.num_threads } else { - let default = || { - thread::available_parallelism() - .map(|n| n.get()) - .unwrap_or(1) - }; + let default = || thread::available_parallelism().map(|n| n.get()).unwrap_or(1); - match env::var("RAYON_NUM_THREADS") - .ok() - .and_then(|s| usize::from_str(&s).ok()) - { + match env::var("RAYON_NUM_THREADS").ok().and_then(|s| usize::from_str(&s).ok()) { Some(x @ 1..) => return x, Some(0) => return default(), _ => {} } // Support for deprecated `RAYON_RS_NUM_CPUS`. - match env::var("RAYON_RS_NUM_CPUS") - .ok() - .and_then(|s| usize::from_str(&s).ok()) - { + match env::var("RAYON_RS_NUM_CPUS").ok().and_then(|s| usize::from_str(&s).ok()) { Some(x @ 1..) => x, _ => default(), } @@ -723,9 +708,7 @@ impl ThreadPoolBuilder { impl Configuration { /// Creates and return a valid rayon thread pool configuration, but does not initialize it. pub fn new() -> Configuration { - Configuration { - builder: ThreadPoolBuilder::new(), - } + Configuration { builder: ThreadPoolBuilder::new() } } /// Deprecated in favor of `ThreadPoolBuilder::build`. @@ -905,10 +888,7 @@ pub struct FnContext { impl FnContext { #[inline] fn new(migrated: bool) -> Self { - FnContext { - migrated, - _marker: PhantomData, - } + FnContext { migrated, _marker: PhantomData } } } diff --git a/compiler/rustc_thread_pool/src/private.rs b/compiler/rustc_thread_pool/src/private.rs index c85e77b9cbb7..5d4f4a8c2caf 100644 --- a/compiler/rustc_thread_pool/src/private.rs +++ b/compiler/rustc_thread_pool/src/private.rs @@ -1,5 +1,5 @@ //! The public parts of this private module are used to create traits -//! that cannot be implemented outside of our own crate. This way we +//! that cannot be implemented outside of our own crate. This way we //! can feel free to extend those traits without worrying about it //! being a breaking change for other implementations. diff --git a/compiler/rustc_thread_pool/src/registry.rs b/compiler/rustc_thread_pool/src/registry.rs index 781b6827b829..2848556aab6a 100644 --- a/compiler/rustc_thread_pool/src/registry.rs +++ b/compiler/rustc_thread_pool/src/registry.rs @@ -1,23 +1,20 @@ +use std::cell::Cell; +use std::collections::hash_map::DefaultHasher; +use std::hash::Hasher; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex, Once}; +use std::{fmt, io, mem, ptr, thread}; + +use crossbeam_deque::{Injector, Steal, Stealer, Worker}; + use crate::job::{JobFifo, JobRef, StackJob}; use crate::latch::{AsCoreLatch, CoreLatch, Latch, LatchRef, LockLatch, OnceLatch, SpinLatch}; use crate::sleep::Sleep; use crate::tlv::Tlv; -use crate::unwind; use crate::{ AcquireThreadHandler, DeadlockHandler, ErrorKind, ExitHandler, PanicHandler, - ReleaseThreadHandler, StartHandler, ThreadPoolBuildError, ThreadPoolBuilder, Yield, + ReleaseThreadHandler, StartHandler, ThreadPoolBuildError, ThreadPoolBuilder, Yield, unwind, }; -use crossbeam_deque::{Injector, Steal, Stealer, Worker}; -use std::cell::Cell; -use std::collections::hash_map::DefaultHasher; -use std::fmt; -use std::hash::Hasher; -use std::io; -use std::mem; -use std::ptr; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Mutex, Once}; -use std::thread; /// Thread builder used for customization via /// [`ThreadPoolBuilder::spawn_handler`](struct.ThreadPoolBuilder.html#method.spawn_handler). @@ -193,9 +190,7 @@ fn set_global_registry(registry: F) -> Result<&'static Arc, ThreadP where F: FnOnce() -> Result, ThreadPoolBuildError>, { - let mut result = Err(ThreadPoolBuildError::new( - ErrorKind::GlobalPoolAlreadyInitialized, - )); + let mut result = Err(ThreadPoolBuildError::new(ErrorKind::GlobalPoolAlreadyInitialized)); THE_REGISTRY_SET.call_once(|| { result = registry().map(|registry: Arc| { @@ -222,25 +217,23 @@ fn default_global_registry() -> Result, ThreadPoolBuildError> { // is stubbed out, and we won't have to change anything if they do add real threading. let unsupported = matches!(&result, Err(e) if e.is_unsupported()); if unsupported && WorkerThread::current().is_null() { - let builder = ThreadPoolBuilder::new() - .num_threads(1) - .spawn_handler(|thread| { - // Rather than starting a new thread, we're just taking over the current thread - // *without* running the main loop, so we can still return from here. - // The WorkerThread is leaked, but we never shutdown the global pool anyway. - let worker_thread = Box::leak(Box::new(WorkerThread::from(thread))); - let registry = &*worker_thread.registry; - let index = worker_thread.index; + let builder = ThreadPoolBuilder::new().num_threads(1).spawn_handler(|thread| { + // Rather than starting a new thread, we're just taking over the current thread + // *without* running the main loop, so we can still return from here. + // The WorkerThread is leaked, but we never shutdown the global pool anyway. + let worker_thread = Box::leak(Box::new(WorkerThread::from(thread))); + let registry = &*worker_thread.registry; + let index = worker_thread.index; - unsafe { - WorkerThread::set_current(worker_thread); + unsafe { + WorkerThread::set_current(worker_thread); - // let registry know we are ready to do work - Latch::set(®istry.thread_infos[index].primed); - } + // let registry know we are ready to do work + Latch::set(®istry.thread_infos[index].primed); + } - Ok(()) - }); + Ok(()) + }); let fallback_result = Registry::new(builder); if fallback_result.is_ok() { @@ -273,11 +266,7 @@ impl Registry { let (workers, stealers): (Vec<_>, Vec<_>) = (0..n_threads) .map(|_| { - let worker = if breadth_first { - Worker::new_fifo() - } else { - Worker::new_lifo() - }; + let worker = if breadth_first { Worker::new_fifo() } else { Worker::new_lifo() }; let stealer = worker.stealer(); (worker, stealer) @@ -341,7 +330,7 @@ impl Registry { } } - /// Returns the number of threads in the current registry. This + /// Returns the number of threads in the current registry. This /// is better than `Registry::current().num_threads()` because it /// avoids incrementing the `Arc`. pub(super) fn current_num_threads() -> usize { @@ -359,11 +348,7 @@ impl Registry { pub(super) fn current_thread(&self) -> Option<&WorkerThread> { unsafe { let worker = WorkerThread::current().as_ref()?; - if worker.registry().id() == self.id() { - Some(worker) - } else { - None - } + if worker.registry().id() == self.id() { Some(worker) } else { None } } } @@ -371,9 +356,7 @@ impl Registry { pub(super) fn id(&self) -> RegistryId { // We can rely on `self` not to change since we only ever create // registries that are boxed up in an `Arc` (see `new()` above). - RegistryId { - addr: self as *const Self as usize, - } + RegistryId { addr: self as *const Self as usize } } pub(super) fn num_threads(&self) -> usize { @@ -391,7 +374,7 @@ impl Registry { } } - /// Waits for the worker threads to get up and running. This is + /// Waits for the worker threads to get up and running. This is /// meant to be used for benchmarking purposes, primarily, so that /// you can get more consistent numbers by having everything /// "ready to go". @@ -512,7 +495,7 @@ impl Registry { /// If already in a worker-thread of this registry, just execute `op`. /// Otherwise, inject `op` in this thread-pool. Either way, block until `op` /// completes and return its return value. If `op` panics, that panic will - /// be propagated as well. The second argument indicates `true` if injection + /// be propagated as well. The second argument indicates `true` if injection /// was performed, `false` if executed directly. pub(super) fn in_worker(&self, op: OP) -> R where @@ -844,9 +827,7 @@ impl WorkerThread { // The job might have injected local work, so go back to the outer loop. continue 'outer; } else { - self.registry - .sleep - .no_work_found(&mut idle_state, latch, &self) + self.registry.sleep.no_work_found(&mut idle_state, latch, &self) } } @@ -880,9 +861,7 @@ impl WorkerThread { // deques, and finally to injected jobs from the // outside. The idea is to finish what we started before // we take on something new. - self.take_local_job() - .or_else(|| self.steal()) - .or_else(|| self.registry.pop_injected_job()) + self.take_local_job().or_else(|| self.steal()).or_else(|| self.registry.pop_injected_job()) } pub(super) fn yield_now(&self) -> Yield { @@ -984,10 +963,10 @@ unsafe fn main_loop(thread: ThreadBuilder) { registry.release_thread(); } -/// If already in a worker-thread, just execute `op`. Otherwise, +/// If already in a worker-thread, just execute `op`. Otherwise, /// execute `op` in the default thread-pool. Either way, block until /// `op` completes and return its return value. If `op` panics, that -/// panic will be propagated as well. The second argument indicates +/// panic will be propagated as well. The second argument indicates /// `true` if injection was performed, `false` if executed directly. pub(super) fn in_worker(op: OP) -> R where @@ -1026,9 +1005,7 @@ impl XorShift64Star { seed = hasher.finish(); } - XorShift64Star { - state: Cell::new(seed), - } + XorShift64Star { state: Cell::new(seed) } } fn next(&self) -> u64 { diff --git a/compiler/rustc_thread_pool/src/scope/mod.rs b/compiler/rustc_thread_pool/src/scope/mod.rs index 364b322baadf..95a4e0b7a18f 100644 --- a/compiler/rustc_thread_pool/src/scope/mod.rs +++ b/compiler/rustc_thread_pool/src/scope/mod.rs @@ -5,19 +5,19 @@ //! [`in_place_scope()`]: fn.in_place_scope.html //! [`join()`]: ../join/join.fn.html +use std::any::Any; +use std::marker::PhantomData; +use std::mem::ManuallyDrop; +use std::sync::Arc; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::{fmt, ptr}; + use crate::broadcast::BroadcastContext; use crate::job::{ArcJob, HeapJob, JobFifo, JobRef}; use crate::latch::{CountLatch, Latch}; -use crate::registry::{global_registry, in_worker, Registry, WorkerThread}; +use crate::registry::{Registry, WorkerThread, global_registry, in_worker}; use crate::tlv::{self, Tlv}; use crate::unwind; -use std::any::Any; -use std::fmt; -use std::marker::PhantomData; -use std::mem::ManuallyDrop; -use std::ptr; -use std::sync::atomic::{AtomicPtr, Ordering}; -use std::sync::Arc; #[cfg(test)] mod test; @@ -53,7 +53,7 @@ struct ScopeBase<'scope> { job_completed_latch: CountLatch, /// You can think of a scope as containing a list of closures to execute, - /// all of which outlive `'scope`. They're not actually required to be + /// all of which outlive `'scope`. They're not actually required to be /// `Sync`, but it's still safe to let the `Scope` implement `Sync` because /// the closures are only *moved* across threads to be executed. #[allow(clippy::type_complexity)] @@ -179,9 +179,9 @@ struct ScopeBase<'scope> { /// they were spawned. So in this example, absent any stealing, we can /// expect `s.2` to execute before `s.1`, and `t.2` before `t.1`. Other /// threads always steal from the other end of the deque, like FIFO -/// order. The idea is that "recent" tasks are most likely to be fresh +/// order. The idea is that "recent" tasks are most likely to be fresh /// in the local CPU's cache, while other threads can steal older -/// "stale" tasks. For an alternate approach, consider +/// "stale" tasks. For an alternate approach, consider /// [`scope_fifo()`] instead. /// /// [`scope_fifo()`]: fn.scope_fifo.html @@ -353,7 +353,7 @@ where /// /// Under `scope_fifo()`, the spawns are prioritized in a FIFO order on /// the thread from which they were spawned, as opposed to `scope()`'s -/// LIFO. So in this example, we can expect `s.1` to execute before +/// LIFO. So in this example, we can expect `s.1` to execute before /// `s.2`, and `t.1` before `t.2`. Other threads also steal tasks in /// FIFO order, as usual. Overall, this has roughly the same order as /// the now-deprecated [`breadth_first`] option, except the effect is @@ -469,7 +469,7 @@ impl<'scope> Scope<'scope> { } /// Spawns a job into the fork-join scope `self`. This job will - /// execute sometime before the fork-join scope completes. The + /// execute sometime before the fork-join scope completes. The /// job is specified as a closure, and this closure receives its /// own reference to the scope `self` as argument. This can be /// used to inject new jobs into `self`. @@ -539,7 +539,7 @@ impl<'scope> Scope<'scope> { } /// Spawns a job into every thread of the fork-join scope `self`. This job will - /// execute on each thread sometime before the fork-join scope completes. The + /// execute on each thread sometime before the fork-join scope completes. The /// job is specified as a closure, and this closure receives its own reference /// to the scope `self` as argument, as well as a `BroadcastContext`. pub fn spawn_broadcast(&self, body: BODY) @@ -567,7 +567,7 @@ impl<'scope> ScopeFifo<'scope> { } /// Spawns a job into the fork-join scope `self`. This job will - /// execute sometime before the fork-join scope completes. The + /// execute sometime before the fork-join scope completes. The /// job is specified as a closure, and this closure receives its /// own reference to the scope `self` as argument. This can be /// used to inject new jobs into `self`. @@ -575,7 +575,7 @@ impl<'scope> ScopeFifo<'scope> { /// # See also /// /// This method is akin to [`Scope::spawn()`], but with a FIFO - /// priority. The [`scope_fifo` function] has more details about + /// priority. The [`scope_fifo` function] has more details about /// this distinction. /// /// [`Scope::spawn()`]: struct.Scope.html#method.spawn @@ -605,7 +605,7 @@ impl<'scope> ScopeFifo<'scope> { } /// Spawns a job into every thread of the fork-join scope `self`. This job will - /// execute on each thread sometime before the fork-join scope completes. The + /// execute on each thread sometime before the fork-join scope completes. The /// job is specified as a closure, and this closure receives its own reference /// to the scope `self` as argument, as well as a `BroadcastContext`. pub fn spawn_broadcast(&self, body: BODY) diff --git a/compiler/rustc_thread_pool/src/scope/test.rs b/compiler/rustc_thread_pool/src/scope/tests.rs similarity index 96% rename from compiler/rustc_thread_pool/src/scope/test.rs rename to compiler/rustc_thread_pool/src/scope/tests.rs index 4505ba7c4fba..2df3bc67e298 100644 --- a/compiler/rustc_thread_pool/src/scope/test.rs +++ b/compiler/rustc_thread_pool/src/scope/tests.rs @@ -1,13 +1,13 @@ -use crate::unwind; -use crate::ThreadPoolBuilder; -use crate::{scope, scope_fifo, Scope, ScopeFifo}; -use rand::{Rng, SeedableRng}; -use rand_xorshift::XorShiftRng; use std::iter::once; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Barrier, Mutex}; use std::vec; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; + +use crate::{Scope, ScopeFifo, ThreadPoolBuilder, scope, scope_fifo, unwind}; + #[test] fn scope_empty() { scope(|_| {}); @@ -93,10 +93,7 @@ impl Tree { where OP: Fn(&mut T) + Sync, { - let Tree { - ref mut value, - ref mut children, - } = *self; + let Tree { ref mut value, ref mut children } = *self; scope.spawn(move |scope| { for child in children { scope.spawn(move |scope| child.update_in_scope(op, scope)); @@ -124,10 +121,7 @@ fn random_tree1(depth: usize, rng: &mut XorShiftRng) -> Tree { .collect() }; - Tree { - value: rng.random_range(0..1_000_000), - children, - } + Tree { value: rng.random_range(0..1_000_000), children } } #[test] @@ -161,11 +155,7 @@ fn linear_stack_growth() { let diff_when_500 = *max_diff.get_mut().unwrap() as f64; let ratio = diff_when_5 / diff_when_500; - assert!( - ratio > 0.9 && ratio < 1.1, - "stack usage ratio out of bounds: {}", - ratio - ); + assert!(ratio > 0.9 && ratio < 1.1, "stack usage ratio out of bounds: {}", ratio); }); } @@ -366,10 +356,7 @@ fn nested_fifo_order() { fn nested_lifo_fifo_order() { // LIFO on the outside, FIFO on the inside let vec = test_nested_order!(scope => spawn, scope_fifo => spawn_fifo); - let expected: Vec = (0..10) - .rev() - .flat_map(|i| (0..10).map(move |j| i * 10 + j)) - .collect(); + let expected: Vec = (0..10).rev().flat_map(|i| (0..10).map(move |j| i * 10 + j)).collect(); assert_eq!(vec, expected); } @@ -378,9 +365,7 @@ fn nested_lifo_fifo_order() { fn nested_fifo_lifo_order() { // FIFO on the outside, LIFO on the inside let vec = test_nested_order!(scope_fifo => spawn_fifo, scope => spawn); - let expected: Vec = (0..10) - .flat_map(|i| (0..10).rev().map(move |j| i * 10 + j)) - .collect(); + let expected: Vec = (0..10).flat_map(|i| (0..10).rev().map(move |j| i * 10 + j)).collect(); assert_eq!(vec, expected); } diff --git a/compiler/rustc_thread_pool/src/sleep/README.md b/compiler/rustc_thread_pool/src/sleep/README.md index e79efd15ca9b..1e11da55f4a4 100644 --- a/compiler/rustc_thread_pool/src/sleep/README.md +++ b/compiler/rustc_thread_pool/src/sleep/README.md @@ -182,7 +182,7 @@ This is possible because the C++ memory model typically offers guarantees of the form "if you see the access A, then you must see those other accesses" -- but it doesn't guarantee that you will see the access A (i.e., if you think of processors with independent caches, you may be operating on very out of date -cache state). +cache state). ## Using seq-cst fences to prevent deadlock diff --git a/compiler/rustc_thread_pool/src/sleep/counters.rs b/compiler/rustc_thread_pool/src/sleep/counters.rs index 05941becd1c6..f2682028b96a 100644 --- a/compiler/rustc_thread_pool/src/sleep/counters.rs +++ b/compiler/rustc_thread_pool/src/sleep/counters.rs @@ -89,9 +89,7 @@ const ONE_JEC: usize = 1 << JEC_SHIFT; impl AtomicCounters { #[inline] pub(super) fn new() -> AtomicCounters { - AtomicCounters { - value: AtomicUsize::new(0), - } + AtomicCounters { value: AtomicUsize::new(0) } } /// Load and return the current value of the various counters. @@ -230,9 +228,7 @@ impl Counters { fn increment_jobs_counter(self) -> Counters { // We can freely add to JEC because it occupies the most significant bits. // Thus it doesn't overflow into the other counters, just wraps itself. - Counters { - word: self.word.wrapping_add(ONE_JEC), - } + Counters { word: self.word.wrapping_add(ONE_JEC) } } #[inline] diff --git a/compiler/rustc_thread_pool/src/sleep/mod.rs b/compiler/rustc_thread_pool/src/sleep/mod.rs index 7d88ece21076..bee7c82c450c 100644 --- a/compiler/rustc_thread_pool/src/sleep/mod.rs +++ b/compiler/rustc_thread_pool/src/sleep/mod.rs @@ -1,14 +1,16 @@ //! Code that decides when workers should go to sleep. See README.md //! for an overview. -use crate::latch::CoreLatch; -use crate::registry::WorkerThread; -use crate::DeadlockHandler; -use crossbeam_utils::CachePadded; use std::sync::atomic::Ordering; use std::sync::{Condvar, Mutex}; use std::thread; +use crossbeam_utils::CachePadded; + +use crate::DeadlockHandler; +use crate::latch::CoreLatch; +use crate::registry::WorkerThread; + mod counters; pub(crate) use self::counters::THREADS_MAX; use self::counters::{AtomicCounters, JobsEventCounter}; @@ -125,11 +127,7 @@ impl Sleep { pub(super) fn start_looking(&self, worker_index: usize) -> IdleState { self.counters.add_inactive_thread(); - IdleState { - worker_index, - rounds: 0, - jobs_counter: JobsEventCounter::DUMMY, - } + IdleState { worker_index, rounds: 0, jobs_counter: JobsEventCounter::DUMMY } } #[inline] @@ -165,9 +163,7 @@ impl Sleep { #[cold] fn announce_sleepy(&self) -> JobsEventCounter { - self.counters - .increment_jobs_event_counter_if(JobsEventCounter::is_active) - .jobs_counter() + self.counters.increment_jobs_event_counter_if(JobsEventCounter::is_active).jobs_counter() } #[cold] @@ -258,7 +254,7 @@ impl Sleep { } /// Notify the given thread that it should wake up (if it is - /// sleeping). When this method is invoked, we typically know the + /// sleeping). When this method is invoked, we typically know the /// thread is asleep, though in rare cases it could have been /// awoken by (e.g.) new work having been posted. pub(super) fn notify_worker_latch_is_set(&self, target_worker_index: usize) { @@ -307,9 +303,7 @@ impl Sleep { // Read the counters and -- if sleepy workers have announced themselves // -- announce that there is now work available. The final value of `counters` // with which we exit the loop thus corresponds to a state when - let counters = self - .counters - .increment_jobs_event_counter_if(JobsEventCounter::is_sleepy); + let counters = self.counters.increment_jobs_event_counter_if(JobsEventCounter::is_sleepy); let num_awake_but_idle = counters.awake_but_idle_threads(); let num_sleepers = counters.sleeping_threads(); diff --git a/compiler/rustc_thread_pool/src/spawn/mod.rs b/compiler/rustc_thread_pool/src/spawn/mod.rs index 034df30dcfb3..f1679a982343 100644 --- a/compiler/rustc_thread_pool/src/spawn/mod.rs +++ b/compiler/rustc_thread_pool/src/spawn/mod.rs @@ -1,9 +1,10 @@ +use std::mem; +use std::sync::Arc; + use crate::job::*; use crate::registry::Registry; use crate::tlv::Tlv; use crate::unwind; -use std::mem; -use std::sync::Arc; /// Puts the task into the Rayon threadpool's job queue in the "static" /// or "global" scope. Just like a standard thread, this task is not @@ -28,9 +29,9 @@ use std::sync::Arc; /// other threads may steal tasks at any time. However, they are /// generally prioritized in a LIFO order on the thread from which /// they were spawned. Other threads always steal from the other end of -/// the deque, like FIFO order. The idea is that "recent" tasks are +/// the deque, like FIFO order. The idea is that "recent" tasks are /// most likely to be fresh in the local CPU's cache, while other -/// threads can steal older "stale" tasks. For an alternate approach, +/// threads can steal older "stale" tasks. For an alternate approach, /// consider [`spawn_fifo()`] instead. /// /// [`spawn_fifo()`]: fn.spawn_fifo.html @@ -39,7 +40,7 @@ use std::sync::Arc; /// /// If this closure should panic, the resulting panic will be /// propagated to the panic handler registered in the `ThreadPoolBuilder`, -/// if any. See [`ThreadPoolBuilder::panic_handler()`][ph] for more +/// if any. See [`ThreadPoolBuilder::panic_handler()`][ph] for more /// details. /// /// [ph]: struct.ThreadPoolBuilder.html#method.panic_handler @@ -103,7 +104,7 @@ where } /// Fires off a task into the Rayon threadpool in the "static" or -/// "global" scope. Just like a standard thread, this task is not +/// "global" scope. Just like a standard thread, this task is not /// tied to the current stack frame, and hence it cannot hold any /// references other than those with `'static` lifetime. If you want /// to spawn a task that references stack data, use [the `scope_fifo()` @@ -124,7 +125,7 @@ where /// /// If this closure should panic, the resulting panic will be /// propagated to the panic handler registered in the `ThreadPoolBuilder`, -/// if any. See [`ThreadPoolBuilder::panic_handler()`][ph] for more +/// if any. See [`ThreadPoolBuilder::panic_handler()`][ph] for more /// details. /// /// [ph]: struct.ThreadPoolBuilder.html#method.panic_handler @@ -152,7 +153,7 @@ where let job_ref = spawn_job(func, registry); // If we're in the pool, use our thread's private fifo for this thread to execute - // in a locally-FIFO order. Otherwise, just use the pool's global injector. + // in a locally-FIFO order. Otherwise, just use the pool's global injector. match registry.current_thread() { Some(worker) => worker.push_fifo(job_ref), None => registry.inject(job_ref), diff --git a/compiler/rustc_thread_pool/src/spawn/test.rs b/compiler/rustc_thread_pool/src/spawn/tests.rs similarity index 95% rename from compiler/rustc_thread_pool/src/spawn/test.rs rename to compiler/rustc_thread_pool/src/spawn/tests.rs index b7a0535aabf6..8a70d2faf9c6 100644 --- a/compiler/rustc_thread_pool/src/spawn/test.rs +++ b/compiler/rustc_thread_pool/src/spawn/tests.rs @@ -1,10 +1,9 @@ -use crate::scope; use std::any::Any; -use std::sync::mpsc::channel; use std::sync::Mutex; +use std::sync::mpsc::channel; use super::{spawn, spawn_fifo}; -use crate::ThreadPoolBuilder; +use crate::{ThreadPoolBuilder, scope}; #[test] #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] @@ -45,10 +44,7 @@ fn panic_fwd() { let builder = ThreadPoolBuilder::new().panic_handler(panic_handler); - builder - .build() - .unwrap() - .spawn(move || panic!("Hello, world!")); + builder.build().unwrap().spawn(move || panic!("Hello, world!")); assert_eq!(1, rx.recv().unwrap()); } @@ -193,10 +189,7 @@ fn fifo_order() { fn lifo_fifo_order() { // LIFO on the outside, FIFO on the inside let vec = test_order!(spawn, spawn_fifo); - let expected: Vec = (0..10) - .rev() - .flat_map(|i| (0..10).map(move |j| i * 10 + j)) - .collect(); + let expected: Vec = (0..10).rev().flat_map(|i| (0..10).map(move |j| i * 10 + j)).collect(); assert_eq!(vec, expected); } @@ -205,9 +198,7 @@ fn lifo_fifo_order() { fn fifo_lifo_order() { // FIFO on the outside, LIFO on the inside let vec = test_order!(spawn_fifo, spawn); - let expected: Vec = (0..10) - .flat_map(|i| (0..10).rev().map(move |j| i * 10 + j)) - .collect(); + let expected: Vec = (0..10).flat_map(|i| (0..10).rev().map(move |j| i * 10 + j)).collect(); assert_eq!(vec, expected); } diff --git a/compiler/rustc_thread_pool/src/test.rs b/compiler/rustc_thread_pool/src/tests.rs similarity index 96% rename from compiler/rustc_thread_pool/src/test.rs rename to compiler/rustc_thread_pool/src/tests.rs index 25b8487f73bc..3082f11a167a 100644 --- a/compiler/rustc_thread_pool/src/test.rs +++ b/compiler/rustc_thread_pool/src/tests.rs @@ -1,9 +1,10 @@ #![cfg(test)] -use crate::{ThreadPoolBuildError, ThreadPoolBuilder}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Barrier}; +use crate::{ThreadPoolBuildError, ThreadPoolBuilder}; + #[test] #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] fn worker_thread_index() { @@ -29,9 +30,7 @@ fn start_callback_called() { b.wait(); }; - let conf = ThreadPoolBuilder::new() - .num_threads(n_threads) - .start_handler(start_handler); + let conf = ThreadPoolBuilder::new().num_threads(n_threads).start_handler(start_handler); let _ = conf.build().unwrap(); // Wait for all the threads to have been scheduled to run. @@ -56,9 +55,7 @@ fn exit_callback_called() { b.wait(); }; - let conf = ThreadPoolBuilder::new() - .num_threads(n_threads) - .exit_handler(exit_handler); + let conf = ThreadPoolBuilder::new().num_threads(n_threads).exit_handler(exit_handler); { let _ = conf.build().unwrap(); // Drop the pool so it stops the running threads. diff --git a/compiler/rustc_thread_pool/src/thread_pool/mod.rs b/compiler/rustc_thread_pool/src/thread_pool/mod.rs index 65af6d7106e6..ce8783cf0d69 100644 --- a/compiler/rustc_thread_pool/src/thread_pool/mod.rs +++ b/compiler/rustc_thread_pool/src/thread_pool/mod.rs @@ -3,18 +3,17 @@ //! //! [`ThreadPool`]: struct.ThreadPool.html -use crate::broadcast::{self, BroadcastContext}; -use crate::join; -use crate::registry::{Registry, ThreadSpawn, WorkerThread}; -use crate::scope::{do_in_place_scope, do_in_place_scope_fifo}; -use crate::spawn; -use crate::{scope, Scope}; -use crate::{scope_fifo, ScopeFifo}; -use crate::{ThreadPoolBuildError, ThreadPoolBuilder}; use std::error::Error; use std::fmt; use std::sync::Arc; +use crate::broadcast::{self, BroadcastContext}; +use crate::registry::{Registry, ThreadSpawn, WorkerThread}; +use crate::scope::{do_in_place_scope, do_in_place_scope_fifo}; +use crate::{ + Scope, ScopeFifo, ThreadPoolBuildError, ThreadPoolBuilder, join, scope, scope_fifo, spawn, +}; + mod test; /// Represents a user created [thread-pool]. diff --git a/compiler/rustc_thread_pool/src/thread_pool/test.rs b/compiler/rustc_thread_pool/src/thread_pool/tests.rs similarity index 97% rename from compiler/rustc_thread_pool/src/thread_pool/test.rs rename to compiler/rustc_thread_pool/src/thread_pool/tests.rs index 88b36282d481..42c99565088a 100644 --- a/compiler/rustc_thread_pool/src/thread_pool/test.rs +++ b/compiler/rustc_thread_pool/src/thread_pool/tests.rs @@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::channel; use std::sync::{Arc, Mutex}; -use crate::{join, Scope, ScopeFifo, ThreadPool, ThreadPoolBuilder}; +use crate::{Scope, ScopeFifo, ThreadPool, ThreadPoolBuilder, join}; #[test] #[should_panic(expected = "Hello, world!")] @@ -296,9 +296,8 @@ fn nested_scopes() { } } - let pools: Vec<_> = (0..10) - .map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()) - .collect(); + let pools: Vec<_> = + (0..10).map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()).collect(); let counter = AtomicUsize::new(0); nest(&pools, vec![], |scopes| { @@ -333,9 +332,8 @@ fn nested_fifo_scopes() { } } - let pools: Vec<_> = (0..10) - .map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()) - .collect(); + let pools: Vec<_> = + (0..10).map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()).collect(); let counter = AtomicUsize::new(0); nest(&pools, vec![], |scopes| { diff --git a/compiler/rustc_thread_pool/src/tlv.rs b/compiler/rustc_thread_pool/src/tlv.rs index ce22f7aa0ce7..b5f63479e2fe 100644 --- a/compiler/rustc_thread_pool/src/tlv.rs +++ b/compiler/rustc_thread_pool/src/tlv.rs @@ -1,7 +1,8 @@ //! Allows access to the Rayon's thread local value //! which is preserved when moving jobs across threads -use std::{cell::Cell, ptr}; +use std::cell::Cell; +use std::ptr; thread_local!(pub static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) }); diff --git a/compiler/rustc_thread_pool/src/worker_local.rs b/compiler/rustc_thread_pool/src/worker_local.rs index 85d51687c190..d108c91f9ee5 100644 --- a/compiler/rustc_thread_pool/src/worker_local.rs +++ b/compiler/rustc_thread_pool/src/worker_local.rs @@ -1,8 +1,9 @@ -use crate::registry::{Registry, WorkerThread}; use std::fmt; use std::ops::Deref; use std::sync::Arc; +use crate::registry::{Registry, WorkerThread}; + #[repr(align(64))] #[derive(Debug)] struct CacheAligned(T); @@ -27,9 +28,7 @@ impl WorkerLocal { pub fn new T>(mut initial: F) -> WorkerLocal { let registry = Registry::current(); WorkerLocal { - locals: (0..registry.num_threads()) - .map(|i| CacheAligned(initial(i))) - .collect(), + locals: (0..registry.num_threads()).map(|i| CacheAligned(initial(i))).collect(), registry, } } @@ -62,9 +61,7 @@ impl WorkerLocal> { impl fmt::Debug for WorkerLocal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("WorkerLocal") - .field("registry", &self.registry.id()) - .finish() + f.debug_struct("WorkerLocal").field("registry", &self.registry.id()).finish() } } diff --git a/compiler/rustc_thread_pool/tests/double_init_fail.rs b/compiler/rustc_thread_pool/tests/double_init_fail.rs index 15915304ddcc..71ed425bb32c 100644 --- a/compiler/rustc_thread_pool/tests/double_init_fail.rs +++ b/compiler/rustc_thread_pool/tests/double_init_fail.rs @@ -1,6 +1,7 @@ -use rayon_core::ThreadPoolBuilder; use std::error::Error; +use rayon_core::ThreadPoolBuilder; + #[test] #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] fn double_init_fail() { @@ -8,8 +9,5 @@ fn double_init_fail() { assert!(result1.is_ok()); let err = ThreadPoolBuilder::new().build_global().unwrap_err(); assert!(err.source().is_none()); - assert_eq!( - err.to_string(), - "The global thread pool has already been initialized.", - ); + assert_eq!(err.to_string(), "The global thread pool has already been initialized.",); } diff --git a/compiler/rustc_thread_pool/tests/init_zero_threads.rs b/compiler/rustc_thread_pool/tests/init_zero_threads.rs index 3c1ad251c7e0..c1770e57f3c8 100644 --- a/compiler/rustc_thread_pool/tests/init_zero_threads.rs +++ b/compiler/rustc_thread_pool/tests/init_zero_threads.rs @@ -3,8 +3,5 @@ use rayon_core::ThreadPoolBuilder; #[test] #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] fn init_zero_threads() { - ThreadPoolBuilder::new() - .num_threads(0) - .build_global() - .unwrap(); + ThreadPoolBuilder::new().num_threads(0).build_global().unwrap(); } diff --git a/compiler/rustc_thread_pool/tests/scoped_threadpool.rs b/compiler/rustc_thread_pool/tests/scoped_threadpool.rs index 932147179f5c..8cc2c859c0c6 100644 --- a/compiler/rustc_thread_pool/tests/scoped_threadpool.rs +++ b/compiler/rustc_thread_pool/tests/scoped_threadpool.rs @@ -10,9 +10,7 @@ scoped_tls::scoped_thread_local!(static LOCAL: Local); #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] fn missing_scoped_tls() { LOCAL.set(&Local(42), || { - let pool = ThreadPoolBuilder::new() - .build() - .expect("thread pool created"); + let pool = ThreadPoolBuilder::new().build().expect("thread pool created"); // `LOCAL` is not set in the pool. pool.install(|| { diff --git a/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs b/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs index a6494069212c..c7a880de8bb4 100644 --- a/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs +++ b/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs @@ -1,10 +1,9 @@ -use rayon_core::ThreadPoolBuilder; - use std::env; -use std::process::{Command, ExitStatus, Stdio}; - #[cfg(target_os = "linux")] use std::os::unix::process::ExitStatusExt; +use std::process::{Command, ExitStatus, Stdio}; + +use rayon_core::ThreadPoolBuilder; fn force_stack_overflow(depth: u32) { let mut buffer = [0u8; 1024 * 1024]; @@ -18,13 +17,7 @@ fn force_stack_overflow(depth: u32) { #[cfg(unix)] fn disable_core() { unsafe { - libc::setrlimit( - libc::RLIMIT_CORE, - &libc::rlimit { - rlim_cur: 0, - rlim_max: 0, - }, - ); + libc::setrlimit(libc::RLIMIT_CORE, &libc::rlimit { rlim_cur: 0, rlim_max: 0 }); } } @@ -50,10 +43,7 @@ fn stack_overflow_crash() { #[cfg(any(unix, windows))] assert_eq!(status.code(), overflow_code()); #[cfg(target_os = "linux")] - assert!(matches!( - status.signal(), - Some(libc::SIGABRT | libc::SIGSEGV) - )); + assert!(matches!(status.signal(), Some(libc::SIGABRT | libc::SIGSEGV))); // Now run with a larger stack and verify correct operation. let status = run_ignored("run_with_large_stack"); @@ -86,10 +76,7 @@ fn run_with_large_stack() { } fn run_with_stack(stack_size_in_mb: usize) { - let pool = ThreadPoolBuilder::new() - .stack_size(stack_size_in_mb * 1024 * 1024) - .build() - .unwrap(); + let pool = ThreadPoolBuilder::new().stack_size(stack_size_in_mb * 1024 * 1024).build().unwrap(); pool.install(|| { #[cfg(unix)] disable_core(); From 4aa62ea9e9015621969a0f505abf7a6894e99e9e Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 11 Jun 2025 11:45:06 -0700 Subject: [PATCH 029/356] Use `rustc_thread_pool` instead of `rustc-rayon-core` --- Cargo.lock | 39 ++++++++++++------- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_data_structures/src/sync.rs | 2 +- .../src/sync/parallel.rs | 12 +++--- compiler/rustc_interface/Cargo.toml | 2 +- compiler/rustc_interface/src/util.rs | 8 ++-- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_middle/src/ty/context/tls.rs | 2 +- compiler/rustc_query_system/Cargo.toml | 2 +- compiler/rustc_query_system/src/query/job.rs | 10 ++--- compiler/rustc_thread_pool/Cargo.toml | 14 ++----- .../src/compile_fail/quicksort_race1.rs | 2 +- .../src/compile_fail/quicksort_race2.rs | 2 +- .../src/compile_fail/quicksort_race3.rs | 2 +- .../src/compile_fail/rc_return.rs | 4 +- .../src/compile_fail/rc_upvar.rs | 2 +- .../src/compile_fail/scope_join_bad.rs | 4 +- compiler/rustc_thread_pool/src/join/mod.rs | 2 +- compiler/rustc_thread_pool/src/lib.rs | 12 +++--- compiler/rustc_thread_pool/src/scope/mod.rs | 16 ++++---- compiler/rustc_thread_pool/src/spawn/mod.rs | 2 +- .../rustc_thread_pool/src/thread_pool/mod.rs | 10 ++--- .../tests/double_init_fail.rs | 2 +- .../tests/init_zero_threads.rs | 2 +- .../rustc_thread_pool/tests/scope_join.rs | 2 +- .../tests/scoped_threadpool.rs | 2 +- .../rustc_thread_pool/tests/simple_panic.rs | 2 +- .../tests/stack_overflow_crash.rs | 2 +- src/tools/tidy/src/deps.rs | 2 +- 29 files changed, 86 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93abab8469a7..ba3a10bad95e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2977,6 +2977,15 @@ dependencies = [ "getrandom 0.3.3", ] +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.3", +] + [[package]] name = "rand_xoshiro" version = "0.7.0" @@ -3176,16 +3185,6 @@ dependencies = [ "tikv-jemalloc-sys", ] -[[package]] -name = "rustc-rayon-core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f42932dcd3bcbe484b38a3ccf79b7906fac41c02d408b5b1bac26da3416efdb" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "rustc-semver" version = "1.1.0" @@ -3554,7 +3553,6 @@ dependencies = [ "parking_lot", "portable-atomic", "rustc-hash 2.1.1", - "rustc-rayon-core", "rustc-stable-hash", "rustc_arena", "rustc_graphviz", @@ -3562,6 +3560,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_serialize", + "rustc_thread_pool", "smallvec", "stacker", "tempfile", @@ -3908,7 +3907,6 @@ dependencies = [ name = "rustc_interface" version = "0.0.0" dependencies = [ - "rustc-rayon-core", "rustc_abi", "rustc_ast", "rustc_ast_lowering", @@ -3947,6 +3945,7 @@ dependencies = [ "rustc_span", "rustc_symbol_mangling", "rustc_target", + "rustc_thread_pool", "rustc_trait_selection", "rustc_traits", "rustc_ty_utils", @@ -4074,7 +4073,6 @@ dependencies = [ "either", "gsgdt", "polonius-engine", - "rustc-rayon-core", "rustc_abi", "rustc_apfloat", "rustc_arena", @@ -4098,6 +4096,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_thread_pool", "rustc_type_ir", "smallvec", "thin-vec", @@ -4344,7 +4343,6 @@ version = "0.0.0" dependencies = [ "hashbrown", "parking_lot", - "rustc-rayon-core", "rustc_abi", "rustc_ast", "rustc_attr_data_structures", @@ -4359,6 +4357,7 @@ dependencies = [ "rustc_serialize", "rustc_session", "rustc_span", + "rustc_thread_pool", "smallvec", "tracing", ] @@ -4520,6 +4519,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "rustc_thread_pool" +version = "0.0.0" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", + "libc", + "rand 0.9.1", + "rand_xorshift", + "scoped-tls", +] + [[package]] name = "rustc_tools_util" version = "0.4.2" diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index f6a020116185..17204883fb03 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -14,7 +14,6 @@ indexmap = "2.4.0" jobserver_crate = { version = "0.1.28", package = "jobserver" } measureme = "12.0.1" rustc-hash = "2.0.0" -rustc-rayon-core = { version = "0.5.0" } rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } @@ -22,6 +21,7 @@ rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index", package = "rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } +rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] } stacker = "0.1.17" tempfile = "3.2" diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index b28c333d860c..68527dde1f3c 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -23,7 +23,7 @@ //! | `RwLock` | `RefCell` | `parking_lot::RwLock` | //! | `MTLock` [^1] | `T` | `Lock` | //! | | | | -//! | `ParallelIterator` | `Iterator` | `rayon::iter::ParallelIterator` | +//! | `ParallelIterator` | `Iterator` | `rustc_thread_pool::iter::ParallelIterator` | //! //! [^1]: `MTLock` is similar to `Lock`, but the serial version avoids the cost //! of a `RefCell`. This is appropriate when interior mutability is not diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index ab65c7f3a6b5..ff4b60a1031b 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -96,7 +96,7 @@ macro_rules! parallel { pub fn spawn(func: impl FnOnce() + DynSend + 'static) { if mode::is_dyn_thread_safe() { let func = FromDyn::from(func); - rayon_core::spawn(|| { + rustc_thread_pool::spawn(|| { (func.into_inner())(); }); } else { @@ -107,11 +107,11 @@ pub fn spawn(func: impl FnOnce() + DynSend + 'static) { // This function only works when `mode::is_dyn_thread_safe()`. pub fn scope<'scope, OP, R>(op: OP) -> R where - OP: FnOnce(&rayon_core::Scope<'scope>) -> R + DynSend, + OP: FnOnce(&rustc_thread_pool::Scope<'scope>) -> R + DynSend, R: DynSend, { let op = FromDyn::from(op); - rayon_core::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() + rustc_thread_pool::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() } #[inline] @@ -124,7 +124,7 @@ where let oper_a = FromDyn::from(oper_a); let oper_b = FromDyn::from(oper_b); let (a, b) = parallel_guard(|guard| { - rayon_core::join( + rustc_thread_pool::join( move || guard.run(move || FromDyn::from(oper_a.into_inner()())), move || guard.run(move || FromDyn::from(oper_b.into_inner()())), ) @@ -158,7 +158,7 @@ fn par_slice( let (left, right) = items.split_at_mut(items.len() / 2); let mut left = state.for_each.derive(left); let mut right = state.for_each.derive(right); - rayon_core::join(move || par_rec(*left, state), move || par_rec(*right, state)); + rustc_thread_pool::join(move || par_rec(*left, state), move || par_rec(*right, state)); } } @@ -241,7 +241,7 @@ pub fn par_map, R: DynSend, C: FromIterato pub fn broadcast(op: impl Fn(usize) -> R + DynSync) -> Vec { if mode::is_dyn_thread_safe() { let op = FromDyn::from(op); - let results = rayon_core::broadcast(|context| op.derive(op(context.index()))); + let results = rustc_thread_pool::broadcast(|context| op.derive(op(context.index()))); results.into_iter().map(|r| r.into_inner()).collect() } else { vec![op(0)] diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index ff28dbeaee69..a72a79587878 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-rayon-core = { version = "0.5.0" } rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_passes = { path = "../rustc_ast_passes" } @@ -43,6 +42,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } +rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_traits = { path = "../rustc_traits" } rustc_ty_utils = { path = "../rustc_ty_utils" } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 8bdc24d47d98..8a7d61172655 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -208,7 +208,7 @@ pub(crate) fn run_in_thread_pool_with_globals< let proxy_ = Arc::clone(&proxy); let proxy__ = Arc::clone(&proxy); - let builder = rayon_core::ThreadPoolBuilder::new() + let builder = rustc_thread_pool::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) .acquire_thread_handler(move || proxy_.acquire_thread()) .release_thread_handler(move || proxy__.release_thread()) @@ -218,7 +218,7 @@ pub(crate) fn run_in_thread_pool_with_globals< // locals to it. The new thread runs the deadlock handler. let current_gcx2 = current_gcx2.clone(); - let registry = rayon_core::Registry::current(); + let registry = rustc_thread_pool::Registry::current(); let session_globals = rustc_span::with_session_globals(|session_globals| { session_globals as *const SessionGlobals as usize }); @@ -265,7 +265,7 @@ pub(crate) fn run_in_thread_pool_with_globals< builder .build_scoped( // Initialize each new worker thread when created. - move |thread: rayon_core::ThreadBuilder| { + move |thread: rustc_thread_pool::ThreadBuilder| { // Register the thread for use with the `WorkerLocal` type. registry.register(); @@ -274,7 +274,7 @@ pub(crate) fn run_in_thread_pool_with_globals< }) }, // Run `f` on the first thread in the thread pool. - move |pool: &rayon_core::ThreadPool| { + move |pool: &rustc_thread_pool::ThreadPool| { pool.install(|| f(current_gcx.into_inner(), proxy)) }, ) diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 43c1af642dd5..edd0af6e4f53 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -9,7 +9,6 @@ bitflags = "2.4.1" either = "1.5.0" gsgdt = "0.1.2" polonius-engine = "0.13.0" -rustc-rayon-core = { version = "0.5.0" } rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } @@ -33,6 +32,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index 5fc80bc79367..fa9995898ac2 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { } // Import the thread-local variable from Rayon, which is preserved for Rayon jobs. -use rayon_core::tlv::TLV; +use rustc_thread_pool::tlv::TLV; #[inline] fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () { diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 7db06953aeb6..3d2d879a7644 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start parking_lot = "0.12" -rustc-rayon-core = { version = "0.5.0" } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } @@ -21,6 +20,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 1e79bd461d2a..7e61f5026da4 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -236,7 +236,7 @@ impl QueryLatch { // If this detects a deadlock and the deadlock handler wants to resume this thread // we have to be in the `wait` call. This is ensured by the deadlock handler // getting the self.info lock. - rayon_core::mark_blocked(); + rustc_thread_pool::mark_blocked(); let proxy = qcx.jobserver_proxy(); proxy.release_thread(); waiter.condvar.wait(&mut info); @@ -251,9 +251,9 @@ impl QueryLatch { let mut info = self.info.lock(); debug_assert!(!info.complete); info.complete = true; - let registry = rayon_core::Registry::current(); + let registry = rustc_thread_pool::Registry::current(); for waiter in info.waiters.drain(..) { - rayon_core::mark_unblocked(®istry); + rustc_thread_pool::mark_unblocked(®istry); waiter.condvar.notify_one(); } } @@ -507,7 +507,7 @@ fn remove_cycle( /// all active queries for cycles before finally resuming all the waiters at once. pub fn break_query_cycles( query_map: QueryMap, - registry: &rayon_core::Registry, + registry: &rustc_thread_pool::Registry, ) { let mut wakelist = Vec::new(); // It is OK per the comments: @@ -543,7 +543,7 @@ pub fn break_query_cycles( // we wake the threads up as otherwise Rayon could detect a deadlock if a thread we // resumed fell asleep and this thread had yet to mark the remaining threads as unblocked. for _ in 0..wakelist.len() { - rayon_core::mark_unblocked(registry); + rustc_thread_pool::mark_unblocked(registry); } for waiter in wakelist.into_iter() { diff --git a/compiler/rustc_thread_pool/Cargo.toml b/compiler/rustc_thread_pool/Cargo.toml index f7a3d1306b43..d0bd065c4578 100644 --- a/compiler/rustc_thread_pool/Cargo.toml +++ b/compiler/rustc_thread_pool/Cargo.toml @@ -1,25 +1,19 @@ [package] -name = "rustc-rayon-core" -version = "0.5.1" +name = "rustc_thread_pool" +version = "0.0.0" authors = ["Niko Matsakis ", "Josh Stone "] description = "Core APIs for Rayon - fork for rustc" license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-lang/rustc-rayon" -documentation = "https://docs.rs/rustc-rayon-core/" rust-version = "1.63" edition = "2021" readme = "README.md" keywords = ["parallel", "thread", "concurrency", "join", "performance"] categories = ["concurrency"] -[lib] -name = "rayon_core" - -# Some dependencies may not be their latest version, in order to support older rustc. [dependencies] -crossbeam-deque = "0.8.1" -crossbeam-utils = "0.8.0" +crossbeam-deque = "0.8" +crossbeam-utils = "0.8" [dev-dependencies] rand = "0.9" diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs index 5615033895a0..1f7a7b0b429b 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs @@ -7,7 +7,7 @@ fn quick_sort(v: &mut [T]) { let mid = partition(v); let (lo, _hi) = v.split_at_mut(mid); - rayon_core::join(|| quick_sort(lo), || quick_sort(lo)); //~ ERROR + rustc_thred_pool::join(|| quick_sort(lo), || quick_sort(lo)); //~ ERROR } fn partition(v: &mut [T]) -> usize { diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs index 020589c29a84..71b695dd8551 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs @@ -7,7 +7,7 @@ fn quick_sort(v: &mut [T]) { let mid = partition(v); let (lo, _hi) = v.split_at_mut(mid); - rayon_core::join(|| quick_sort(lo), || quick_sort(v)); //~ ERROR + rustc_thred_pool::join(|| quick_sort(lo), || quick_sort(v)); //~ ERROR } fn partition(v: &mut [T]) -> usize { diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs index 16fbf3b824d3..8484cebaae80 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs @@ -7,7 +7,7 @@ fn quick_sort(v: &mut [T]) { let mid = partition(v); let (_lo, hi) = v.split_at_mut(mid); - rayon_core::join(|| quick_sort(hi), || quick_sort(hi)); //~ ERROR + rustc_thred_pool::join(|| quick_sort(hi), || quick_sort(hi)); //~ ERROR } fn partition(v: &mut [T]) -> usize { diff --git a/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs b/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs index 93e3a603849a..509c8d62ad11 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs @@ -2,7 +2,7 @@ use std::rc::Rc; -rayon_core::join(|| Rc::new(22), || ()); //~ ERROR +rustc_thred_pool::join(|| Rc::new(22), || ()); //~ ERROR ``` */ mod left {} @@ -11,7 +11,7 @@ mod left {} use std::rc::Rc; -rayon_core::join(|| (), || Rc::new(23)); //~ ERROR +rustc_thred_pool::join(|| (), || Rc::new(23)); //~ ERROR ``` */ mod right {} diff --git a/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs b/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs index d8aebcfcbf24..a27b3c8c39fc 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs @@ -3,7 +3,7 @@ use std::rc::Rc; let r = Rc::new(22); -rayon_core::join(|| r.clone(), || r.clone()); +rustc_thred_pool::join(|| r.clone(), || r.clone()); //~^ ERROR ``` */ diff --git a/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs b/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs index 75e4c5ca6c0d..6e700a483b10 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs @@ -3,7 +3,7 @@ fn bad_scope(f: F) where F: FnOnce(&i32) + Send, { - rayon_core::scope(|s| { + rustc_thred_pool::scope(|s| { let x = 22; s.spawn(|_| f(&x)); //~ ERROR `x` does not live long enough }); @@ -13,7 +13,7 @@ fn good_scope(f: F) where F: FnOnce(&i32) + Send, { let x = 22; - rayon_core::scope(|s| { + rustc_thred_pool::scope(|s| { s.spawn(|_| f(&x)); }); } diff --git a/compiler/rustc_thread_pool/src/join/mod.rs b/compiler/rustc_thread_pool/src/join/mod.rs index 798a8347d798..e48d17f16a3a 100644 --- a/compiler/rustc_thread_pool/src/join/mod.rs +++ b/compiler/rustc_thread_pool/src/join/mod.rs @@ -41,7 +41,7 @@ mod test; /// [the `par_sort` method]: ../rayon/slice/trait.ParallelSliceMut.html#method.par_sort /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// let mut v = vec![5, 1, 8, 22, 0, 44]; /// quick_sort(&mut v); /// assert_eq!(v, vec![0, 1, 5, 8, 22, 44]); diff --git a/compiler/rustc_thread_pool/src/lib.rs b/compiler/rustc_thread_pool/src/lib.rs index 179d63ed668a..f1d466b49487 100644 --- a/compiler/rustc_thread_pool/src/lib.rs +++ b/compiler/rustc_thread_pool/src/lib.rs @@ -152,14 +152,14 @@ enum ErrorKind { /// The following creates a thread pool with 22 threads. /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// let pool = rayon::ThreadPoolBuilder::new().num_threads(22).build().unwrap(); /// ``` /// /// To instead configure the global thread pool, use [`build_global()`]: /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// rayon::ThreadPoolBuilder::new().num_threads(22).build_global().unwrap(); /// ``` /// @@ -315,7 +315,7 @@ impl ThreadPoolBuilder { /// A scoped pool may be useful in combination with scoped thread-local variables. /// /// ``` - /// # use rayon_core as rayon; + /// # use rustc_thred_pool as rayon; /// /// scoped_tls::scoped_thread_local!(static POOL_DATA: Vec); /// @@ -382,7 +382,7 @@ impl ThreadPoolBuilder { /// A minimal spawn handler just needs to call `run()` from an independent thread. /// /// ``` - /// # use rayon_core as rayon; + /// # use rustc_thred_pool as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// let pool = rayon::ThreadPoolBuilder::new() /// .spawn_handler(|thread| { @@ -400,7 +400,7 @@ impl ThreadPoolBuilder { /// any errors from the thread builder. /// /// ``` - /// # use rayon_core as rayon; + /// # use rustc_thred_pool as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// let pool = rayon::ThreadPoolBuilder::new() /// .spawn_handler(|thread| { @@ -429,7 +429,7 @@ impl ThreadPoolBuilder { /// [`std::thread::scope`]: https://doc.rust-lang.org/std/thread/fn.scope.html /// /// ``` - /// # use rayon_core as rayon; + /// # use rustc_thred_pool as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// std::thread::scope(|scope| { /// let pool = rayon::ThreadPoolBuilder::new() diff --git a/compiler/rustc_thread_pool/src/scope/mod.rs b/compiler/rustc_thread_pool/src/scope/mod.rs index 95a4e0b7a18f..82b3d053dcb8 100644 --- a/compiler/rustc_thread_pool/src/scope/mod.rs +++ b/compiler/rustc_thread_pool/src/scope/mod.rs @@ -84,7 +84,7 @@ struct ScopeBase<'scope> { /// it would be less efficient than the real implementation: /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// pub fn join(oper_a: A, oper_b: B) -> (RA, RB) /// where A: FnOnce() -> RA + Send, /// B: FnOnce() -> RB + Send, @@ -125,7 +125,7 @@ struct ScopeBase<'scope> { /// To see how and when tasks are joined, consider this example: /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// // point start /// rayon::scope(|s| { /// s.spawn(|s| { // task s.1 @@ -193,7 +193,7 @@ struct ScopeBase<'scope> { /// spawned task. /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// let ok: Vec = vec![1, 2, 3]; /// rayon::scope(|s| { /// let bad: Vec = vec![4, 5, 6]; @@ -217,7 +217,7 @@ struct ScopeBase<'scope> { /// in this case including both `ok` *and* `bad`: /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// let ok: Vec = vec![1, 2, 3]; /// rayon::scope(|s| { /// let bad: Vec = vec![4, 5, 6]; @@ -238,7 +238,7 @@ struct ScopeBase<'scope> { /// is a borrow of `ok` and capture *that*: /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// let ok: Vec = vec![1, 2, 3]; /// rayon::scope(|s| { /// let bad: Vec = vec![4, 5, 6]; @@ -260,7 +260,7 @@ struct ScopeBase<'scope> { /// of individual variables: /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// let ok: Vec = vec![1, 2, 3]; /// rayon::scope(|s| { /// let bad: Vec = vec![4, 5, 6]; @@ -312,7 +312,7 @@ where /// [`scope()`]: fn.scope.html /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// // point start /// rayon::scope_fifo(|s| { /// s.spawn_fifo(|s| { // task s.1 @@ -487,7 +487,7 @@ impl<'scope> Scope<'scope> { /// # Examples /// /// ```rust - /// # use rayon_core as rayon; + /// # use rustc_thred_pool as rayon; /// let mut value_a = None; /// let mut value_b = None; /// let mut value_c = None; diff --git a/compiler/rustc_thread_pool/src/spawn/mod.rs b/compiler/rustc_thread_pool/src/spawn/mod.rs index f1679a982343..92b89ed59480 100644 --- a/compiler/rustc_thread_pool/src/spawn/mod.rs +++ b/compiler/rustc_thread_pool/src/spawn/mod.rs @@ -50,7 +50,7 @@ use crate::unwind; /// This code creates a Rayon task that increments a global counter. /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; /// /// static GLOBAL_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; diff --git a/compiler/rustc_thread_pool/src/thread_pool/mod.rs b/compiler/rustc_thread_pool/src/thread_pool/mod.rs index ce8783cf0d69..c8644ecf9a9d 100644 --- a/compiler/rustc_thread_pool/src/thread_pool/mod.rs +++ b/compiler/rustc_thread_pool/src/thread_pool/mod.rs @@ -28,7 +28,7 @@ mod test; /// ## Creating a ThreadPool /// /// ```rust -/// # use rayon_core as rayon; +/// # use rustc_thred_pool as rayon; /// let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap(); /// ``` /// @@ -88,10 +88,10 @@ impl ThreadPool { /// meantime. For example /// /// ```rust - /// # use rayon_core as rayon; + /// # use rustc_thred_pool as rayon; /// fn main() { /// rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap(); - /// let pool = rayon_core::ThreadPoolBuilder::default().build().unwrap(); + /// let pool = rustc_thred_pool::ThreadPoolBuilder::default().build().unwrap(); /// let do_it = || { /// print!("one "); /// pool.install(||{}); @@ -123,7 +123,7 @@ impl ThreadPool { /// ## Using `install()` /// /// ```rust - /// # use rayon_core as rayon; + /// # use rustc_thred_pool as rayon; /// fn main() { /// let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap(); /// let n = pool.install(|| fib(20)); @@ -172,7 +172,7 @@ impl ThreadPool { /// # Examples /// /// ``` - /// # use rayon_core as rayon; + /// # use rustc_thred_pool as rayon; /// use std::sync::atomic::{AtomicUsize, Ordering}; /// /// fn main() { diff --git a/compiler/rustc_thread_pool/tests/double_init_fail.rs b/compiler/rustc_thread_pool/tests/double_init_fail.rs index 71ed425bb32c..ef190099293e 100644 --- a/compiler/rustc_thread_pool/tests/double_init_fail.rs +++ b/compiler/rustc_thread_pool/tests/double_init_fail.rs @@ -1,6 +1,6 @@ use std::error::Error; -use rayon_core::ThreadPoolBuilder; +use rustc_thred_pool::ThreadPoolBuilder; #[test] #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] diff --git a/compiler/rustc_thread_pool/tests/init_zero_threads.rs b/compiler/rustc_thread_pool/tests/init_zero_threads.rs index c1770e57f3c8..1f7e299e3e9c 100644 --- a/compiler/rustc_thread_pool/tests/init_zero_threads.rs +++ b/compiler/rustc_thread_pool/tests/init_zero_threads.rs @@ -1,4 +1,4 @@ -use rayon_core::ThreadPoolBuilder; +use rustc_thred_pool::ThreadPoolBuilder; #[test] #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] diff --git a/compiler/rustc_thread_pool/tests/scope_join.rs b/compiler/rustc_thread_pool/tests/scope_join.rs index 9d88133bc5b6..0bd33d086cf1 100644 --- a/compiler/rustc_thread_pool/tests/scope_join.rs +++ b/compiler/rustc_thread_pool/tests/scope_join.rs @@ -4,7 +4,7 @@ where F: FnOnce() + Send, G: FnOnce() + Send, { - rayon_core::scope(|s| { + rustc_thred_pool::scope(|s| { s.spawn(|_| g()); f(); }); diff --git a/compiler/rustc_thread_pool/tests/scoped_threadpool.rs b/compiler/rustc_thread_pool/tests/scoped_threadpool.rs index 8cc2c859c0c6..e4b0f6c41e1f 100644 --- a/compiler/rustc_thread_pool/tests/scoped_threadpool.rs +++ b/compiler/rustc_thread_pool/tests/scoped_threadpool.rs @@ -1,5 +1,5 @@ use crossbeam_utils::thread; -use rayon_core::ThreadPoolBuilder; +use rustc_thred_pool::ThreadPoolBuilder; #[derive(PartialEq, Eq, Debug)] struct Local(i32); diff --git a/compiler/rustc_thread_pool/tests/simple_panic.rs b/compiler/rustc_thread_pool/tests/simple_panic.rs index 2564482a47e5..16896e36fa04 100644 --- a/compiler/rustc_thread_pool/tests/simple_panic.rs +++ b/compiler/rustc_thread_pool/tests/simple_panic.rs @@ -1,4 +1,4 @@ -use rayon_core::join; +use rustc_thred_pool::join; #[test] #[should_panic(expected = "should panic")] diff --git a/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs b/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs index c7a880de8bb4..49c9ca1d75e9 100644 --- a/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs +++ b/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs @@ -3,7 +3,7 @@ use std::env; use std::os::unix::process::ExitStatusExt; use std::process::{Command, ExitStatus, Stdio}; -use rayon_core::ThreadPoolBuilder; +use rustc_thred_pool::ThreadPoolBuilder; fn force_stack_overflow(depth: u32) { let mut buffer = [0u8; 1024 * 1024]; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index fdca7a7a40e2..7cdfe79a40b7 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -356,6 +356,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rand", "rand_chacha", "rand_core", + "rand_xorshift", // dependency for doc-tests in rustc_thread_pool "rand_xoshiro", "redox_syscall", "regex", @@ -364,7 +365,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustc-demangle", "rustc-hash", "rustc-literal-escaper", - "rustc-rayon-core", "rustc-stable-hash", "rustc_apfloat", "rustix", From 2457bb2cfbda090a0a688351ab9b480ead129879 Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 12 Jun 2025 00:47:01 +0100 Subject: [PATCH 030/356] Apply ABI attributes on return types in `rustc_codegen_cranelift` --- src/abi/pass_mode.rs | 59 +++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 6d8614aca693..9a0a5b510397 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -1,6 +1,6 @@ //! Argument passing -use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose}; +use cranelift_codegen::ir::ArgumentPurpose; use rustc_abi::{Reg, RegKind}; use rustc_target::callconv::{ ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, @@ -32,13 +32,12 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam { AbiParam::new(clif_ty) } -fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam { +fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam { match arg_attrs.arg_ext { - RustcArgExtension::None => {} - RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext, - RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext, + RustcArgExtension::None => param, + RustcArgExtension::Zext => param.uext(), + RustcArgExtension::Sext => param.sext(), } - param } fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> { @@ -82,7 +81,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { match self.mode { PassMode::Ignore => smallvec![], PassMode::Direct(attrs) => match self.layout.backend_repr { - BackendRepr::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param( + BackendRepr::Scalar(scalar) => smallvec![apply_attrs_to_abi_param( AbiParam::new(scalar_to_clif_type(tcx, scalar)), attrs )], @@ -97,8 +96,8 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); smallvec![ - apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a), - apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b), + apply_attrs_to_abi_param(AbiParam::new(a), attrs_a), + apply_attrs_to_abi_param(AbiParam::new(b), attrs_b), ] } _ => unreachable!("{:?}", self.layout.backend_repr), @@ -112,19 +111,19 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { // Abi requires aligning struct size to pointer size let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi); let size = u32::try_from(size.bytes()).unwrap(); - smallvec![apply_arg_attrs_to_abi_param( + smallvec![apply_attrs_to_abi_param( AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),), attrs )] } else { - smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)] + smallvec![apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)] } } PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { assert!(!on_stack); smallvec![ - apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), - apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs), + apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), + apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs), ] } } @@ -133,30 +132,46 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option, Vec) { match self.mode { PassMode::Ignore => (None, vec![]), - PassMode::Direct(_) => match self.layout.backend_repr { - BackendRepr::Scalar(scalar) => { - (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))]) - } + PassMode::Direct(attrs) => match self.layout.backend_repr { + BackendRepr::Scalar(scalar) => ( + None, + vec![apply_attrs_to_abi_param( + AbiParam::new(scalar_to_clif_type(tcx, scalar)), + attrs, + )], + ), BackendRepr::SimdVector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); - (None, vec![AbiParam::new(vector_ty)]) + (None, vec![apply_attrs_to_abi_param(AbiParam::new(vector_ty), attrs)]) } _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Pair(_, _) => match self.layout.backend_repr { + PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr { BackendRepr::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); - (None, vec![AbiParam::new(a), AbiParam::new(b)]) + ( + None, + vec![ + apply_attrs_to_abi_param(AbiParam::new(a), attrs_a), + apply_attrs_to_abi_param(AbiParam::new(b), attrs_b), + ], + ) } _ => unreachable!("{:?}", self.layout.backend_repr), }, PassMode::Cast { ref cast, .. } => { (None, cast_target_to_abi_params(cast).into_iter().collect()) } - PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => { + PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { assert!(!on_stack); - (Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![]) + ( + Some(apply_attrs_to_abi_param( + AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn), + attrs, + )), + vec![], + ) } PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") From f52c6eee02fb9a9cfe203ce95c4968c2835c034b Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 11 Jun 2025 12:32:09 -0700 Subject: [PATCH 031/356] Another round of tidy / warning fixes --- Cargo.toml | 2 +- compiler/rustc_data_structures/src/sync.rs | 2 -- .../rustc_thread_pool/src/broadcast/mod.rs | 8 ++--- .../src/compile_fail/quicksort_race1.rs | 2 +- .../src/compile_fail/quicksort_race2.rs | 2 +- .../src/compile_fail/quicksort_race3.rs | 2 +- .../src/compile_fail/rc_return.rs | 4 +-- .../src/compile_fail/rc_upvar.rs | 2 +- .../src/compile_fail/scope_join_bad.rs | 4 +-- compiler/rustc_thread_pool/src/job.rs | 30 +++++++++------- compiler/rustc_thread_pool/src/join/mod.rs | 6 ++-- compiler/rustc_thread_pool/src/latch.rs | 32 ++++++++--------- compiler/rustc_thread_pool/src/lib.rs | 15 ++++---- compiler/rustc_thread_pool/src/registry.rs | 34 +++++++++---------- compiler/rustc_thread_pool/src/scope/mod.rs | 26 +++++++------- compiler/rustc_thread_pool/src/sleep/mod.rs | 6 ++-- compiler/rustc_thread_pool/src/spawn/mod.rs | 10 +++--- .../rustc_thread_pool/src/thread_pool/mod.rs | 14 ++++---- .../tests/double_init_fail.rs | 4 ++- .../tests/init_zero_threads.rs | 4 ++- .../rustc_thread_pool/tests/scope_join.rs | 4 ++- .../tests/scoped_threadpool.rs | 4 ++- .../rustc_thread_pool/tests/simple_panic.rs | 4 ++- .../tests/stack_overflow_crash.rs | 4 ++- 24 files changed, 120 insertions(+), 105 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c4d2a06f4cb1..e08f14d21016 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ exclude = [ "obj", ] -[profile.release.package.rustc-rayon-core] +[profile.release.package.rustc_thread_pool] # The rustc fork of Rayon has deadlock detection code which intermittently # causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227) # so we turn overflow checks off for now. diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 68527dde1f3c..3881f3c2aa84 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -22,8 +22,6 @@ //! | | | `parking_lot::Mutex` | //! | `RwLock` | `RefCell` | `parking_lot::RwLock` | //! | `MTLock` [^1] | `T` | `Lock` | -//! | | | | -//! | `ParallelIterator` | `Iterator` | `rustc_thread_pool::iter::ParallelIterator` | //! //! [^1]: `MTLock` is similar to `Lock`, but the serial version avoids the cost //! of a `RefCell`. This is appropriate when interior mutability is not diff --git a/compiler/rustc_thread_pool/src/broadcast/mod.rs b/compiler/rustc_thread_pool/src/broadcast/mod.rs index c2b0d47f8299..9545c4b15d8f 100644 --- a/compiler/rustc_thread_pool/src/broadcast/mod.rs +++ b/compiler/rustc_thread_pool/src/broadcast/mod.rs @@ -6,7 +6,7 @@ use crate::job::{ArcJob, StackJob}; use crate::latch::{CountLatch, LatchRef}; use crate::registry::{Registry, WorkerThread}; -mod test; +mod tests; /// Executes `op` within every thread in the current threadpool. If this is /// called from a non-Rayon thread, it will execute in the global threadpool. @@ -103,18 +103,18 @@ where }; let n_threads = registry.num_threads(); - let current_thread = WorkerThread::current().as_ref(); + let current_thread = unsafe { WorkerThread::current().as_ref() }; let tlv = crate::tlv::get(); let latch = CountLatch::with_count(n_threads, current_thread); let jobs: Vec<_> = (0..n_threads).map(|_| StackJob::new(tlv, &f, LatchRef::new(&latch))).collect(); - let job_refs = jobs.iter().map(|job| job.as_job_ref()); + let job_refs = jobs.iter().map(|job| unsafe { job.as_job_ref() }); registry.inject_broadcast(job_refs); // Wait for all jobs to complete, then collect the results, maybe propagating a panic. latch.wait(current_thread); - jobs.into_iter().map(|job| job.into_result()).collect() + jobs.into_iter().map(|job| unsafe { job.into_result() }).collect() } /// Execute `op` on every thread in the pool. It will be executed on each diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs index 1f7a7b0b429b..f6dbc7696993 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race1.rs @@ -7,7 +7,7 @@ fn quick_sort(v: &mut [T]) { let mid = partition(v); let (lo, _hi) = v.split_at_mut(mid); - rustc_thred_pool::join(|| quick_sort(lo), || quick_sort(lo)); //~ ERROR + rustc_thread_pool::join(|| quick_sort(lo), || quick_sort(lo)); //~ ERROR } fn partition(v: &mut [T]) -> usize { diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs index 71b695dd8551..ccd737a700d8 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race2.rs @@ -7,7 +7,7 @@ fn quick_sort(v: &mut [T]) { let mid = partition(v); let (lo, _hi) = v.split_at_mut(mid); - rustc_thred_pool::join(|| quick_sort(lo), || quick_sort(v)); //~ ERROR + rustc_thread_pool::join(|| quick_sort(lo), || quick_sort(v)); //~ ERROR } fn partition(v: &mut [T]) -> usize { diff --git a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs index 8484cebaae80..6acdf0844337 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/quicksort_race3.rs @@ -7,7 +7,7 @@ fn quick_sort(v: &mut [T]) { let mid = partition(v); let (_lo, hi) = v.split_at_mut(mid); - rustc_thred_pool::join(|| quick_sort(hi), || quick_sort(hi)); //~ ERROR + rustc_thread_pool::join(|| quick_sort(hi), || quick_sort(hi)); //~ ERROR } fn partition(v: &mut [T]) -> usize { diff --git a/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs b/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs index 509c8d62ad11..165c685aba10 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/rc_return.rs @@ -2,7 +2,7 @@ use std::rc::Rc; -rustc_thred_pool::join(|| Rc::new(22), || ()); //~ ERROR +rustc_thread_pool::join(|| Rc::new(22), || ()); //~ ERROR ``` */ mod left {} @@ -11,7 +11,7 @@ mod left {} use std::rc::Rc; -rustc_thred_pool::join(|| (), || Rc::new(23)); //~ ERROR +rustc_thread_pool::join(|| (), || Rc::new(23)); //~ ERROR ``` */ mod right {} diff --git a/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs b/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs index a27b3c8c39fc..6dc9ead48a09 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/rc_upvar.rs @@ -3,7 +3,7 @@ use std::rc::Rc; let r = Rc::new(22); -rustc_thred_pool::join(|| r.clone(), || r.clone()); +rustc_thread_pool::join(|| r.clone(), || r.clone()); //~^ ERROR ``` */ diff --git a/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs b/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs index 6e700a483b10..e65abfc3c1e8 100644 --- a/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs +++ b/compiler/rustc_thread_pool/src/compile_fail/scope_join_bad.rs @@ -3,7 +3,7 @@ fn bad_scope(f: F) where F: FnOnce(&i32) + Send, { - rustc_thred_pool::scope(|s| { + rustc_thread_pool::scope(|s| { let x = 22; s.spawn(|_| f(&x)); //~ ERROR `x` does not live long enough }); @@ -13,7 +13,7 @@ fn good_scope(f: F) where F: FnOnce(&i32) + Send, { let x = 22; - rustc_thred_pool::scope(|s| { + rustc_thread_pool::scope(|s| { s.spawn(|_| f(&x)); }); } diff --git a/compiler/rustc_thread_pool/src/job.rs b/compiler/rustc_thread_pool/src/job.rs index 3241914ba81c..e6e84ac2320b 100644 --- a/compiler/rustc_thread_pool/src/job.rs +++ b/compiler/rustc_thread_pool/src/job.rs @@ -61,7 +61,7 @@ impl JobRef { #[inline] pub(super) unsafe fn execute(self) { - (self.execute_fn)(self.pointer) + unsafe { (self.execute_fn)(self.pointer) } } } @@ -97,7 +97,7 @@ where } pub(super) unsafe fn as_job_ref(&self) -> JobRef { - JobRef::new(self) + unsafe { JobRef::new(self) } } pub(super) unsafe fn run_inline(self, stolen: bool) -> R { @@ -116,12 +116,16 @@ where R: Send, { unsafe fn execute(this: *const ()) { - let this = &*(this as *const Self); + let this = unsafe { &*(this as *const Self) }; tlv::set(this.tlv); let abort = unwind::AbortIfPanic; - let func = (*this.func.get()).take().unwrap(); - (*this.result.get()) = JobResult::call(func); - Latch::set(&this.latch); + let func = unsafe { (*this.func.get()).take().unwrap() }; + unsafe { + (*this.result.get()) = JobResult::call(func); + } + unsafe { + Latch::set(&this.latch); + } mem::forget(abort); } } @@ -152,7 +156,7 @@ where /// lifetimes, so it is up to you to ensure that this JobRef /// doesn't outlive any data that it closes over. pub(super) unsafe fn into_job_ref(self: Box) -> JobRef { - JobRef::new(Box::into_raw(self)) + unsafe { JobRef::new(Box::into_raw(self)) } } /// Creates a static `JobRef` from this job. @@ -169,7 +173,7 @@ where BODY: FnOnce() + Send, { unsafe fn execute(this: *const ()) { - let this = Box::from_raw(this as *mut Self); + let this = unsafe { Box::from_raw(this as *mut Self) }; tlv::set(this.tlv); (this.job)(); } @@ -196,7 +200,7 @@ where /// lifetimes, so it is up to you to ensure that this JobRef /// doesn't outlive any data that it closes over. pub(super) unsafe fn as_job_ref(this: &Arc) -> JobRef { - JobRef::new(Arc::into_raw(Arc::clone(this))) + unsafe { JobRef::new(Arc::into_raw(Arc::clone(this))) } } /// Creates a static `JobRef` from this job. @@ -213,7 +217,7 @@ where BODY: Fn() + Send + Sync, { unsafe fn execute(this: *const ()) { - let this = Arc::from_raw(this as *mut Self); + let this = unsafe { Arc::from_raw(this as *mut Self) }; (this.job)(); } } @@ -254,17 +258,17 @@ impl JobFifo { // jobs in a thread's deque may be popped from the back (LIFO) or stolen from the front // (FIFO), but either way they will end up popping from the front of this queue. self.inner.push(job_ref); - JobRef::new(self) + unsafe { JobRef::new(self) } } } impl Job for JobFifo { unsafe fn execute(this: *const ()) { // We "execute" a queue by executing its first job, FIFO. - let this = &*(this as *const Self); + let this = unsafe { &*(this as *const Self) }; loop { match this.inner.steal() { - Steal::Success(job_ref) => break job_ref.execute(), + Steal::Success(job_ref) => break unsafe { job_ref.execute() }, Steal::Empty => panic!("FIFO is empty"), Steal::Retry => {} } diff --git a/compiler/rustc_thread_pool/src/join/mod.rs b/compiler/rustc_thread_pool/src/join/mod.rs index e48d17f16a3a..f285362c19b1 100644 --- a/compiler/rustc_thread_pool/src/join/mod.rs +++ b/compiler/rustc_thread_pool/src/join/mod.rs @@ -7,7 +7,7 @@ use crate::tlv::{self, Tlv}; use crate::{FnContext, unwind}; #[cfg(test)] -mod test; +mod tests; /// Takes two closures and *potentially* runs them in parallel. It /// returns a pair of the results from those closures. @@ -41,7 +41,7 @@ mod test; /// [the `par_sort` method]: ../rayon/slice/trait.ParallelSliceMut.html#method.par_sort /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// let mut v = vec![5, 1, 8, 22, 0, 44]; /// quick_sort(&mut v); /// assert_eq!(v, vec![0, 1, 5, 8, 22, 44]); @@ -192,7 +192,7 @@ unsafe fn join_recover_from_panic( err: Box, tlv: Tlv, ) -> ! { - worker_thread.wait_until(job_b_latch); + unsafe { worker_thread.wait_until(job_b_latch) }; // Restore the TLV since we might have run some jobs overwriting it when waiting for job b. tlv::set(tlv); diff --git a/compiler/rustc_thread_pool/src/latch.rs b/compiler/rustc_thread_pool/src/latch.rs index f2f806e01845..49ba62d3bea3 100644 --- a/compiler/rustc_thread_pool/src/latch.rs +++ b/compiler/rustc_thread_pool/src/latch.rs @@ -116,7 +116,7 @@ impl CoreLatch { /// latch code. #[inline] unsafe fn set(this: *const Self) -> bool { - let old_state = (*this).state.swap(SET, Ordering::AcqRel); + let old_state = unsafe { (*this).state.swap(SET, Ordering::AcqRel) }; old_state == SLEEPING } @@ -185,13 +185,13 @@ impl<'r> Latch for SpinLatch<'r> { unsafe fn set(this: *const Self) { let cross_registry; - let registry: &Registry = if (*this).cross { + let registry: &Registry = if unsafe { (*this).cross } { // Ensure the registry stays alive while we notify it. // Otherwise, it would be possible that we set the spin // latch and the other thread sees it and exits, causing // the registry to be deallocated, all before we get a // chance to invoke `registry.notify_worker_latch_is_set`. - cross_registry = Arc::clone((*this).registry); + cross_registry = Arc::clone(unsafe { (*this).registry }); &cross_registry } else { // If this is not a "cross-registry" spin-latch, then the @@ -199,12 +199,12 @@ impl<'r> Latch for SpinLatch<'r> { // that the registry stays alive. However, that doesn't // include this *particular* `Arc` handle if the waiting // thread then exits, so we must completely dereference it. - (*this).registry + unsafe { (*this).registry } }; - let target_worker_index = (*this).target_worker_index; + let target_worker_index = unsafe { (*this).target_worker_index }; // NOTE: Once we `set`, the target may proceed and invalidate `this`! - if CoreLatch::set(&(*this).core_latch) { + if unsafe { CoreLatch::set(&(*this).core_latch) } { // Subtle: at this point, we can no longer read from // `self`, because the thread owning this spin latch may // have awoken and deallocated the latch. Therefore, we @@ -249,9 +249,9 @@ impl LockLatch { impl Latch for LockLatch { #[inline] unsafe fn set(this: *const Self) { - let mut guard = (*this).m.lock().unwrap(); + let mut guard = unsafe { (*this).m.lock().unwrap() }; *guard = true; - (*this).v.notify_all(); + unsafe { (*this).v.notify_all() }; } } @@ -286,7 +286,7 @@ impl OnceLatch { registry: &Registry, target_worker_index: usize, ) { - if CoreLatch::set(&(*this).core_latch) { + if unsafe { CoreLatch::set(&(*this).core_latch) } { registry.notify_worker_latch_is_set(target_worker_index); } } @@ -384,17 +384,17 @@ impl CountLatch { impl Latch for CountLatch { #[inline] unsafe fn set(this: *const Self) { - if (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 { + if unsafe { (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 } { // NOTE: Once we call `set` on the internal `latch`, // the target may proceed and invalidate `this`! - match (*this).kind { - CountLatchKind::Stealing { ref latch, ref registry, worker_index } => { + match unsafe { &(*this).kind } { + CountLatchKind::Stealing { latch, registry, worker_index } => { let registry = Arc::clone(registry); - if CoreLatch::set(latch) { - registry.notify_worker_latch_is_set(worker_index); + if unsafe { CoreLatch::set(latch) } { + registry.notify_worker_latch_is_set(*worker_index); } } - CountLatchKind::Blocking { ref latch } => LockLatch::set(latch), + CountLatchKind::Blocking { latch } => unsafe { LockLatch::set(latch) }, } } } @@ -426,6 +426,6 @@ impl Deref for LatchRef<'_, L> { impl Latch for LatchRef<'_, L> { #[inline] unsafe fn set(this: *const Self) { - L::set((*this).inner); + unsafe { L::set((*this).inner) }; } } diff --git a/compiler/rustc_thread_pool/src/lib.rs b/compiler/rustc_thread_pool/src/lib.rs index f1d466b49487..34252d919e38 100644 --- a/compiler/rustc_thread_pool/src/lib.rs +++ b/compiler/rustc_thread_pool/src/lib.rs @@ -61,6 +61,7 @@ //! conflicting requirements will need to be resolved before the build will //! succeed. +#![cfg_attr(test, allow(unused_crate_dependencies))] #![warn(rust_2018_idioms)] use std::any::Any; @@ -85,7 +86,7 @@ mod unwind; mod worker_local; mod compile_fail; -mod test; +mod tests; pub mod tlv; @@ -152,14 +153,14 @@ enum ErrorKind { /// The following creates a thread pool with 22 threads. /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// let pool = rayon::ThreadPoolBuilder::new().num_threads(22).build().unwrap(); /// ``` /// /// To instead configure the global thread pool, use [`build_global()`]: /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// rayon::ThreadPoolBuilder::new().num_threads(22).build_global().unwrap(); /// ``` /// @@ -315,7 +316,7 @@ impl ThreadPoolBuilder { /// A scoped pool may be useful in combination with scoped thread-local variables. /// /// ``` - /// # use rustc_thred_pool as rayon; + /// # use rustc_thread_pool as rayon; /// /// scoped_tls::scoped_thread_local!(static POOL_DATA: Vec); /// @@ -382,7 +383,7 @@ impl ThreadPoolBuilder { /// A minimal spawn handler just needs to call `run()` from an independent thread. /// /// ``` - /// # use rustc_thred_pool as rayon; + /// # use rustc_thread_pool as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// let pool = rayon::ThreadPoolBuilder::new() /// .spawn_handler(|thread| { @@ -400,7 +401,7 @@ impl ThreadPoolBuilder { /// any errors from the thread builder. /// /// ``` - /// # use rustc_thred_pool as rayon; + /// # use rustc_thread_pool as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// let pool = rayon::ThreadPoolBuilder::new() /// .spawn_handler(|thread| { @@ -429,7 +430,7 @@ impl ThreadPoolBuilder { /// [`std::thread::scope`]: https://doc.rust-lang.org/std/thread/fn.scope.html /// /// ``` - /// # use rustc_thred_pool as rayon; + /// # use rustc_thread_pool as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// std::thread::scope(|scope| { /// let pool = rayon::ThreadPoolBuilder::new() diff --git a/compiler/rustc_thread_pool/src/registry.rs b/compiler/rustc_thread_pool/src/registry.rs index 2848556aab6a..03a01aa29d2a 100644 --- a/compiler/rustc_thread_pool/src/registry.rs +++ b/compiler/rustc_thread_pool/src/registry.rs @@ -533,16 +533,16 @@ impl Registry { |injected| { let worker_thread = WorkerThread::current(); assert!(injected && !worker_thread.is_null()); - op(&*worker_thread, true) + op(unsafe { &*worker_thread }, true) }, LatchRef::new(l), ); - self.inject(job.as_job_ref()); + self.inject(unsafe { job.as_job_ref() }); self.release_thread(); job.latch.wait_and_reset(); // Make sure we can use the same latch again next time. self.acquire_thread(); - job.into_result() + unsafe { job.into_result() } }) } @@ -561,13 +561,13 @@ impl Registry { |injected| { let worker_thread = WorkerThread::current(); assert!(injected && !worker_thread.is_null()); - op(&*worker_thread, true) + op(unsafe { &*worker_thread }, true) }, latch, ); - self.inject(job.as_job_ref()); - current_thread.wait_until(&job.latch); - job.into_result() + self.inject(unsafe { job.as_job_ref() }); + unsafe { current_thread.wait_until(&job.latch) }; + unsafe { job.into_result() } } /// Increments the terminate counter. This increment should be @@ -759,7 +759,7 @@ impl WorkerThread { #[inline] pub(super) unsafe fn push_fifo(&self, job: JobRef) { - self.push(self.fifo.push(job)); + unsafe { self.push(self.fifo.push(job)) }; } #[inline] @@ -798,7 +798,7 @@ impl WorkerThread { pub(super) unsafe fn wait_until(&self, latch: &L) { let latch = latch.as_core_latch(); if !latch.probe() { - self.wait_until_cold(latch); + unsafe { self.wait_until_cold(latch) }; } } @@ -815,7 +815,7 @@ impl WorkerThread { // Check for local work *before* we start marking ourself idle, // especially to avoid modifying shared sleep state. if let Some(job) = self.take_local_job() { - self.execute(job); + unsafe { self.execute(job) }; continue; } @@ -823,7 +823,7 @@ impl WorkerThread { while !latch.probe() { if let Some(job) = self.find_work() { self.registry.sleep.work_found(); - self.execute(job); + unsafe { self.execute(job) }; // The job might have injected local work, so go back to the outer loop. continue 'outer; } else { @@ -846,13 +846,13 @@ impl WorkerThread { let index = self.index; registry.acquire_thread(); - self.wait_until(®istry.thread_infos[index].terminate); + unsafe { self.wait_until(®istry.thread_infos[index].terminate) }; // Should not be any work left in our queue. debug_assert!(self.take_local_job().is_none()); // Let registry know we are done - Latch::set(®istry.thread_infos[index].stopped); + unsafe { Latch::set(®istry.thread_infos[index].stopped) }; } fn find_work(&self) -> Option { @@ -886,7 +886,7 @@ impl WorkerThread { #[inline] pub(super) unsafe fn execute(&self, job: JobRef) { - job.execute(); + unsafe { job.execute() }; } /// Try to steal a single job and return it. @@ -932,12 +932,12 @@ impl WorkerThread { unsafe fn main_loop(thread: ThreadBuilder) { let worker_thread = &WorkerThread::from(thread); - WorkerThread::set_current(worker_thread); + unsafe { WorkerThread::set_current(worker_thread) }; let registry = &*worker_thread.registry; let index = worker_thread.index; // let registry know we are ready to do work - Latch::set(®istry.thread_infos[index].primed); + unsafe { Latch::set(®istry.thread_infos[index].primed) }; // Worker threads should not panic. If they do, just abort, as the // internal state of the threadpool is corrupted. Note that if @@ -949,7 +949,7 @@ unsafe fn main_loop(thread: ThreadBuilder) { registry.catch_unwind(|| handler(index)); } - worker_thread.wait_until_out_of_work(); + unsafe { worker_thread.wait_until_out_of_work() }; // Normal termination, do not abort. mem::forget(abort_guard); diff --git a/compiler/rustc_thread_pool/src/scope/mod.rs b/compiler/rustc_thread_pool/src/scope/mod.rs index 82b3d053dcb8..55e58b3509d7 100644 --- a/compiler/rustc_thread_pool/src/scope/mod.rs +++ b/compiler/rustc_thread_pool/src/scope/mod.rs @@ -20,7 +20,7 @@ use crate::tlv::{self, Tlv}; use crate::unwind; #[cfg(test)] -mod test; +mod tests; /// Represents a fork-join scope which can be used to spawn any number of tasks. /// See [`scope()`] for more information. @@ -84,7 +84,7 @@ struct ScopeBase<'scope> { /// it would be less efficient than the real implementation: /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// pub fn join(oper_a: A, oper_b: B) -> (RA, RB) /// where A: FnOnce() -> RA + Send, /// B: FnOnce() -> RB + Send, @@ -125,7 +125,7 @@ struct ScopeBase<'scope> { /// To see how and when tasks are joined, consider this example: /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// // point start /// rayon::scope(|s| { /// s.spawn(|s| { // task s.1 @@ -193,7 +193,7 @@ struct ScopeBase<'scope> { /// spawned task. /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// let ok: Vec = vec![1, 2, 3]; /// rayon::scope(|s| { /// let bad: Vec = vec![4, 5, 6]; @@ -217,7 +217,7 @@ struct ScopeBase<'scope> { /// in this case including both `ok` *and* `bad`: /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// let ok: Vec = vec![1, 2, 3]; /// rayon::scope(|s| { /// let bad: Vec = vec![4, 5, 6]; @@ -238,7 +238,7 @@ struct ScopeBase<'scope> { /// is a borrow of `ok` and capture *that*: /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// let ok: Vec = vec![1, 2, 3]; /// rayon::scope(|s| { /// let bad: Vec = vec![4, 5, 6]; @@ -260,7 +260,7 @@ struct ScopeBase<'scope> { /// of individual variables: /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// let ok: Vec = vec![1, 2, 3]; /// rayon::scope(|s| { /// let bad: Vec = vec![4, 5, 6]; @@ -312,7 +312,7 @@ where /// [`scope()`]: fn.scope.html /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// // point start /// rayon::scope_fifo(|s| { /// s.spawn_fifo(|s| { // task s.1 @@ -487,7 +487,7 @@ impl<'scope> Scope<'scope> { /// # Examples /// /// ```rust - /// # use rustc_thred_pool as rayon; + /// # use rustc_thread_pool as rayon; /// let mut value_a = None; /// let mut value_b = None; /// let mut value_c = None; @@ -686,7 +686,7 @@ impl<'scope> ScopeBase<'scope> { where FUNC: FnOnce(), { - let _: Option<()> = Self::execute_job_closure(this, func); + let _: Option<()> = unsafe { Self::execute_job_closure(this, func) }; } /// Executes `func` as a job in scope. Adjusts the "job completed" @@ -699,11 +699,11 @@ impl<'scope> ScopeBase<'scope> { let result = match unwind::halt_unwinding(func) { Ok(r) => Some(r), Err(err) => { - (*this).job_panicked(err); + unsafe { (*this).job_panicked(err) }; None } }; - Latch::set(&(*this).job_completed_latch); + unsafe { Latch::set(&(*this).job_completed_latch) }; result } @@ -778,6 +778,6 @@ unsafe impl Sync for ScopePtr {} impl ScopePtr { // Helper to avoid disjoint captures of `scope_ptr.0` unsafe fn as_ref(&self) -> &T { - &*self.0 + unsafe { &*self.0 } } } diff --git a/compiler/rustc_thread_pool/src/sleep/mod.rs b/compiler/rustc_thread_pool/src/sleep/mod.rs index bee7c82c450c..a9cdf68cc7eb 100644 --- a/compiler/rustc_thread_pool/src/sleep/mod.rs +++ b/compiler/rustc_thread_pool/src/sleep/mod.rs @@ -31,7 +31,7 @@ struct SleepData { impl SleepData { /// Checks if the conditions for a deadlock holds and if so calls the deadlock handler #[inline] - pub fn deadlock_check(&self, deadlock_handler: &Option>) { + pub(super) fn deadlock_check(&self, deadlock_handler: &Option>) { if self.active_threads == 0 && self.blocked_threads > 0 { (deadlock_handler.as_ref().unwrap())(); } @@ -102,7 +102,7 @@ impl Sleep { /// Mark a Rayon worker thread as blocked. This triggers the deadlock handler /// if no other worker thread is active #[inline] - pub fn mark_blocked(&self, deadlock_handler: &Option>) { + pub(super) fn mark_blocked(&self, deadlock_handler: &Option>) { let mut data = self.data.lock().unwrap(); debug_assert!(data.active_threads > 0); debug_assert!(data.blocked_threads < data.worker_count); @@ -115,7 +115,7 @@ impl Sleep { /// Mark a previously blocked Rayon worker thread as unblocked #[inline] - pub fn mark_unblocked(&self) { + pub(super) fn mark_unblocked(&self) { let mut data = self.data.lock().unwrap(); debug_assert!(data.active_threads < data.worker_count); debug_assert!(data.blocked_threads > 0); diff --git a/compiler/rustc_thread_pool/src/spawn/mod.rs b/compiler/rustc_thread_pool/src/spawn/mod.rs index 92b89ed59480..040a02bfa676 100644 --- a/compiler/rustc_thread_pool/src/spawn/mod.rs +++ b/compiler/rustc_thread_pool/src/spawn/mod.rs @@ -50,7 +50,7 @@ use crate::unwind; /// This code creates a Rayon task that increments a global counter. /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; /// /// static GLOBAL_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; @@ -80,7 +80,7 @@ where // be able to panic, and hence the data won't leak but will be // enqueued into some deque for later execution. let abort_guard = unwind::AbortIfPanic; // just in case we are wrong, and code CAN panic - let job_ref = spawn_job(func, registry); + let job_ref = unsafe { spawn_job(func, registry) }; registry.inject_or_push(job_ref); mem::forget(abort_guard); } @@ -150,16 +150,16 @@ where // be able to panic, and hence the data won't leak but will be // enqueued into some deque for later execution. let abort_guard = unwind::AbortIfPanic; // just in case we are wrong, and code CAN panic - let job_ref = spawn_job(func, registry); + let job_ref = unsafe { spawn_job(func, registry) }; // If we're in the pool, use our thread's private fifo for this thread to execute // in a locally-FIFO order. Otherwise, just use the pool's global injector. match registry.current_thread() { - Some(worker) => worker.push_fifo(job_ref), + Some(worker) => unsafe { worker.push_fifo(job_ref) }, None => registry.inject(job_ref), } mem::forget(abort_guard); } #[cfg(test)] -mod test; +mod tests; diff --git a/compiler/rustc_thread_pool/src/thread_pool/mod.rs b/compiler/rustc_thread_pool/src/thread_pool/mod.rs index c8644ecf9a9d..3294e2a77cbe 100644 --- a/compiler/rustc_thread_pool/src/thread_pool/mod.rs +++ b/compiler/rustc_thread_pool/src/thread_pool/mod.rs @@ -14,7 +14,7 @@ use crate::{ Scope, ScopeFifo, ThreadPoolBuildError, ThreadPoolBuilder, join, scope, scope_fifo, spawn, }; -mod test; +mod tests; /// Represents a user created [thread-pool]. /// @@ -28,7 +28,7 @@ mod test; /// ## Creating a ThreadPool /// /// ```rust -/// # use rustc_thred_pool as rayon; +/// # use rustc_thread_pool as rayon; /// let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap(); /// ``` /// @@ -88,10 +88,10 @@ impl ThreadPool { /// meantime. For example /// /// ```rust - /// # use rustc_thred_pool as rayon; + /// # use rustc_thread_pool as rayon; /// fn main() { /// rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap(); - /// let pool = rustc_thred_pool::ThreadPoolBuilder::default().build().unwrap(); + /// let pool = rustc_thread_pool::ThreadPoolBuilder::default().build().unwrap(); /// let do_it = || { /// print!("one "); /// pool.install(||{}); @@ -123,7 +123,7 @@ impl ThreadPool { /// ## Using `install()` /// /// ```rust - /// # use rustc_thred_pool as rayon; + /// # use rustc_thread_pool as rayon; /// fn main() { /// let pool = rayon::ThreadPoolBuilder::new().num_threads(8).build().unwrap(); /// let n = pool.install(|| fib(20)); @@ -172,7 +172,7 @@ impl ThreadPool { /// # Examples /// /// ``` - /// # use rustc_thred_pool as rayon; + /// # use rustc_thread_pool as rayon; /// use std::sync::atomic::{AtomicUsize, Ordering}; /// /// fn main() { @@ -401,7 +401,7 @@ impl ThreadPool { } pub(crate) fn wait_until_stopped(self) { - let registry = self.registry.clone(); + let registry = Arc::clone(&self.registry); drop(self); registry.wait_until_stopped(); } diff --git a/compiler/rustc_thread_pool/tests/double_init_fail.rs b/compiler/rustc_thread_pool/tests/double_init_fail.rs index ef190099293e..85e509518d43 100644 --- a/compiler/rustc_thread_pool/tests/double_init_fail.rs +++ b/compiler/rustc_thread_pool/tests/double_init_fail.rs @@ -1,6 +1,8 @@ +#![allow(unused_crate_dependencies)] + use std::error::Error; -use rustc_thred_pool::ThreadPoolBuilder; +use rustc_thread_pool::ThreadPoolBuilder; #[test] #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] diff --git a/compiler/rustc_thread_pool/tests/init_zero_threads.rs b/compiler/rustc_thread_pool/tests/init_zero_threads.rs index 1f7e299e3e9c..261493fcb7b7 100644 --- a/compiler/rustc_thread_pool/tests/init_zero_threads.rs +++ b/compiler/rustc_thread_pool/tests/init_zero_threads.rs @@ -1,4 +1,6 @@ -use rustc_thred_pool::ThreadPoolBuilder; +#![allow(unused_crate_dependencies)] + +use rustc_thread_pool::ThreadPoolBuilder; #[test] #[cfg_attr(any(target_os = "emscripten", target_family = "wasm"), ignore)] diff --git a/compiler/rustc_thread_pool/tests/scope_join.rs b/compiler/rustc_thread_pool/tests/scope_join.rs index 0bd33d086cf1..83468da81c01 100644 --- a/compiler/rustc_thread_pool/tests/scope_join.rs +++ b/compiler/rustc_thread_pool/tests/scope_join.rs @@ -1,10 +1,12 @@ +#![allow(unused_crate_dependencies)] + /// Test that one can emulate join with `scope`: fn pseudo_join(f: F, g: G) where F: FnOnce() + Send, G: FnOnce() + Send, { - rustc_thred_pool::scope(|s| { + rustc_thread_pool::scope(|s| { s.spawn(|_| g()); f(); }); diff --git a/compiler/rustc_thread_pool/tests/scoped_threadpool.rs b/compiler/rustc_thread_pool/tests/scoped_threadpool.rs index e4b0f6c41e1f..295da650e880 100644 --- a/compiler/rustc_thread_pool/tests/scoped_threadpool.rs +++ b/compiler/rustc_thread_pool/tests/scoped_threadpool.rs @@ -1,5 +1,7 @@ +#![allow(unused_crate_dependencies)] + use crossbeam_utils::thread; -use rustc_thred_pool::ThreadPoolBuilder; +use rustc_thread_pool::ThreadPoolBuilder; #[derive(PartialEq, Eq, Debug)] struct Local(i32); diff --git a/compiler/rustc_thread_pool/tests/simple_panic.rs b/compiler/rustc_thread_pool/tests/simple_panic.rs index 16896e36fa04..b35b4d632d2b 100644 --- a/compiler/rustc_thread_pool/tests/simple_panic.rs +++ b/compiler/rustc_thread_pool/tests/simple_panic.rs @@ -1,4 +1,6 @@ -use rustc_thred_pool::join; +#![allow(unused_crate_dependencies)] + +use rustc_thread_pool::join; #[test] #[should_panic(expected = "should panic")] diff --git a/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs b/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs index 49c9ca1d75e9..805b6d8ee3f2 100644 --- a/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs +++ b/compiler/rustc_thread_pool/tests/stack_overflow_crash.rs @@ -1,9 +1,11 @@ +#![allow(unused_crate_dependencies)] + use std::env; #[cfg(target_os = "linux")] use std::os::unix::process::ExitStatusExt; use std::process::{Command, ExitStatus, Stdio}; -use rustc_thred_pool::ThreadPoolBuilder; +use rustc_thread_pool::ThreadPoolBuilder; fn force_stack_overflow(depth: u32) { let mut buffer = [0u8; 1024 * 1024]; From a9fd42e53627e53d32d1df6819e9958b7d3ee8f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jun 2025 13:44:19 +0200 Subject: [PATCH 032/356] intrinsics: rename min_align_of to align_of --- example/mini_core.rs | 4 ++-- example/mini_core_hello_world.rs | 7 ++----- src/intrinsics/mod.rs | 4 ++-- src/unsize.rs | 2 +- src/vtable.rs | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 1dc799c0aeea..012e4dbc3ec9 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -644,9 +644,9 @@ pub mod intrinsics { #[rustc_intrinsic] pub unsafe fn size_of_val(val: *const T) -> usize; #[rustc_intrinsic] - pub fn min_align_of() -> usize; + pub fn align_of() -> usize; #[rustc_intrinsic] - pub unsafe fn min_align_of_val(val: *const T) -> usize; + pub unsafe fn align_of_val(val: *const T) -> usize; #[rustc_intrinsic] pub unsafe fn copy(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic] diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 93ca2e0e4218..1499f948deb3 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -204,11 +204,8 @@ fn main() { assert_eq!(intrinsics::size_of_val(a) as u8, 16); assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); - assert_eq!(intrinsics::min_align_of::() as u8, 2); - assert_eq!( - intrinsics::min_align_of_val(&a) as u8, - intrinsics::min_align_of::<&str>() as u8 - ); + assert_eq!(intrinsics::align_of::() as u8, 2); + assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); assert!(!intrinsics::needs_drop::()); assert!(!intrinsics::needs_drop::<[u8]>()); diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 1d1cf884e48b..df5748c34d11 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta); ret.write_cvalue(fx, CValue::by_val(size, usize_layout)); } - sym::min_align_of_val => { + sym::align_of_val => { intrinsic_args!(fx, args => (ptr); intrinsic); let layout = fx.layout_of(generic_args.type_at(0)); @@ -613,7 +613,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (vtable); intrinsic); let vtable = vtable.load_scalar(fx); - let align = crate::vtable::min_align_of_obj(fx, vtable); + let align = crate::vtable::align_of_obj(fx, vtable); ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); } diff --git a/src/unsize.rs b/src/unsize.rs index 662546e49998..df60b05c4636 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -212,7 +212,7 @@ pub(crate) fn size_and_align_of<'tcx>( // load size/align from vtable ( crate::vtable::size_of_obj(fx, info.unwrap()), - crate::vtable::min_align_of_obj(fx, info.unwrap()), + crate::vtable::align_of_obj(fx, info.unwrap()), ) } ty::Slice(_) | ty::Str => { diff --git a/src/vtable.rs b/src/vtable.rs index 05a8e3c33421..1fae56949bc0 100644 --- a/src/vtable.rs +++ b/src/vtable.rs @@ -31,7 +31,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val ) } -pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { +pub(crate) fn align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; fx.bcx.ins().load( fx.pointer_type, From 9594d67bcf88c82546f8fae1382a06a239cddbe9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Jun 2025 16:48:29 +0000 Subject: [PATCH 033/356] Rustup to rustc 1.89.0-nightly (e703dff8f 2025-06-11) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 1e867bd76580..fc8f892fb1e0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-08" +channel = "nightly-2025-06-12" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From dcc48749e21d24b45b22f37734f0058138d71efc Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 7 May 2025 20:02:29 +0200 Subject: [PATCH 034/356] add `extern "custom"` functions --- src/abi/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index fe5b220117f3..4c6fd9078154 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv( CanonAbi::Rust | CanonAbi::C => default_call_conv, CanonAbi::RustCold => CallConv::Cold, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => default_call_conv, + CanonAbi::X86(x86_call) => match x86_call { X86Call::SysV64 => CallConv::SystemV, X86Call::Win64 => CallConv::WindowsFastcall, From a6ecde32b94f4155587c97d69f07c3d3cd174203 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Fri, 13 Jun 2025 01:16:36 +0200 Subject: [PATCH 035/356] Unimplement unsized_locals --- example/arbitrary_self_types_pointers_and_wrappers.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/example/arbitrary_self_types_pointers_and_wrappers.rs b/example/arbitrary_self_types_pointers_and_wrappers.rs index 5479b0c617bf..f0d1f6e22157 100644 --- a/example/arbitrary_self_types_pointers_and_wrappers.rs +++ b/example/arbitrary_self_types_pointers_and_wrappers.rs @@ -32,10 +32,6 @@ impl, U> CoerceUnsized> for Wrapper {} impl, U> DispatchFromDyn> for Wrapper {} trait Trait { - // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable - // without unsized_locals), but wrappers around `Self` currently are not. - // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented - // fn wrapper(self: Wrapper) -> i32; fn ptr_wrapper(self: Ptr>) -> i32; fn wrapper_ptr(self: Wrapper>) -> i32; fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; From 595e88ae7d3cca6b05b1dfb4c3cd3ed74a1a7861 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 13 Jun 2025 09:49:48 +0000 Subject: [PATCH 036/356] Windows: make read_dir stop iterating on error --- library/std/src/sys/fs/windows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index a95709b48914..9b674a251652 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -132,6 +132,7 @@ impl Iterator for ReadDir { let mut wfd = mem::zeroed(); loop { if c::FindNextFileW(handle.0, &mut wfd) == 0 { + self.handle = None; match api::get_last_error() { WinError::NO_MORE_FILES => return None, WinError { code } => { From 1d41c2c01c9d32b22b1b702cfe04e2f7aae477af Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 13 Jun 2025 10:57:00 +0000 Subject: [PATCH 037/356] Merge unboxed trait object error suggestion into regular dyn incompat error --- .../rustc_hir_analysis/src/check/wfcheck.rs | 66 ------------------- .../rustc_hir_analysis/src/hir_wf_check.rs | 14 +++- compiler/rustc_middle/src/traits/mod.rs | 2 + .../src/error_reporting/traits/suggestions.rs | 7 ++ .../src/traits/dyn_compatibility.rs | 2 +- .../avoid-ice-on-warning-3.old.stderr | 10 +++ .../supertrait-mentions-GAT.rs | 3 +- .../supertrait-mentions-GAT.stderr | 21 ++---- ...-trait-should-use-self-2021-without-dyn.rs | 3 - ...it-should-use-self-2021-without-dyn.stderr | 52 ++------------- ...incompatible-trait-should-use-self-2021.rs | 6 +- ...mpatible-trait-should-use-self-2021.stderr | 38 +++-------- .../dyn-incompatible-trait-should-use-self.rs | 6 +- ...-incompatible-trait-should-use-self.stderr | 38 +++-------- tests/ui/suggestions/issue-116434-2015.rs | 2 + tests/ui/suggestions/issue-116434-2015.stderr | 18 +++-- ...ce-hir-wf-check-anon-const-issue-122199.rs | 1 - ...ir-wf-check-anon-const-issue-122199.stderr | 19 +----- tests/ui/wf/issue-87495.stderr | 5 ++ 19 files changed, 92 insertions(+), 221 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b8dc01cbc03c..35cdf4c6d1fe 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -382,8 +382,6 @@ fn check_trait_item<'tcx>( _ => (None, trait_item.span), }; - check_dyn_incompatible_self_trait_by_name(tcx, trait_item); - // Check that an item definition in a subtrait is shadowing a supertrait item. lint_item_shadowing_supertrait_item(tcx, def_id); @@ -832,70 +830,6 @@ impl<'tcx> TypeVisitor> for GATArgsCollector<'tcx> { } } -fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { - match ty.kind { - hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments { - [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), - _ => false, - }, - _ => false, - } -} - -/// Detect when a dyn-incompatible trait is referring to itself in one of its associated items. -/// -/// In such cases, suggest using `Self` instead. -fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) { - let (trait_ident, trait_def_id) = - match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(item.hir_id()).def_id) { - hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, ident, ..) => (ident, item.owner_id), - _ => return, - }, - _ => return, - }; - let mut trait_should_be_self = vec![]; - match &item.kind { - hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty)) - if could_be_self(trait_def_id.def_id, ty) => - { - trait_should_be_self.push(ty.span) - } - hir::TraitItemKind::Fn(sig, _) => { - for ty in sig.decl.inputs { - if could_be_self(trait_def_id.def_id, ty) { - trait_should_be_self.push(ty.span); - } - } - match sig.decl.output { - hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => { - trait_should_be_self.push(ty.span); - } - _ => {} - } - } - _ => {} - } - if !trait_should_be_self.is_empty() { - if tcx.is_dyn_compatible(trait_def_id) { - return; - } - let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); - tcx.dcx() - .struct_span_err( - trait_should_be_self, - "associated item referring to unboxed trait object for its own trait", - ) - .with_span_label(trait_ident.span, "in this trait") - .with_multipart_suggestion( - "you might have meant to use `Self` to refer to the implementing type", - sugg, - Applicability::MachineApplicable, - ) - .emit(); - } -} - fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_id: LocalDefId) { let item_name = tcx.item_name(trait_item_def_id.to_def_id()); let trait_def_id = tcx.local_parent(trait_item_def_id); diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 4633f3951a78..fef0dbf2ece9 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -1,7 +1,8 @@ +use rustc_hir::def::DefKind; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_hir::{self as hir, AmbigArg, ForeignItem, ForeignItemKind}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{ObligationCause, WellFormedLoc}; +use rustc_infer::traits::{ObligationCause, ObligationCauseCode, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions}; @@ -107,6 +108,17 @@ fn diagnostic_hir_wf_check<'tcx>( // over less-specific types (e.g. `Option>`) if self.depth >= self.cause_depth { self.cause = Some(error.obligation.cause); + if let hir::TyKind::TraitObject(..) = ty.kind { + if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn = + self.tcx.def_kind(self.def_id) + { + self.cause = Some(ObligationCause::new( + ty.span, + self.def_id, + ObligationCauseCode::DynCompatible(ty.span), + )); + } + } self.cause_depth = self.depth } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 27079af06fcd..d877bd5c626c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -397,6 +397,8 @@ pub enum ObligationCauseCode<'tcx> { RustCall, + DynCompatible(Span), + /// Obligations to prove that a `Drop` or negative auto trait impl is not stronger than /// the ADT it's being implemented for. AlwaysApplicableImpl, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 68bd9440538f..505ac5eee25d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2721,6 +2721,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ObligationCauseCode::TupleElem => { err.note("only the last element of a tuple may have a dynamically sized type"); } + ObligationCauseCode::DynCompatible(span) => { + err.multipart_suggestion( + "you might have meant to use `Self` to refer to the implementing type", + vec![(span, "Self".into())], + Applicability::MachineApplicable, + ); + } ObligationCauseCode::WhereClause(item_def_id, span) | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..) | ObligationCauseCode::HostEffectInExpr(item_def_id, span, ..) diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 220a847cc230..2502a30930e0 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -31,7 +31,7 @@ use crate::traits::{ /// /// Currently that is `Self` in supertraits. This is needed /// because `dyn_compatibility_violations` can't be used during -/// type collection. +/// type collection, as type collection is needed for `dyn_compatiblity_violations` itself. #[instrument(level = "debug", skip(tcx), ret)] pub fn hir_ty_lowering_dyn_compatibility_violations( tcx: TyCtxt<'_>, diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr index d8935be56094..8b4f3f52ee93 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr @@ -87,6 +87,11 @@ help: alternatively, consider constraining `g` so it does not apply to trait obj | LL | trait A { fn g(b: B) -> B where Self: Sized; } | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - trait B { fn f(a: A) -> A; } +LL + trait B { fn f(a: Self) -> A; } + | warning: trait objects without an explicit `dyn` are deprecated --> $DIR/avoid-ice-on-warning-3.rs:14:19 @@ -124,6 +129,11 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj | LL | trait B { fn f(a: A) -> A where Self: Sized; } | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - trait A { fn g(b: B) -> B; } +LL + trait A { fn g(b: Self) -> B; } + | error: aborting due to 2 previous errors; 6 warnings emitted diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs index 9e5c1bfe4160..b866dab9dba2 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs @@ -8,8 +8,7 @@ trait GatTrait { trait SuperTrait: for<'a> GatTrait = T> { fn c(&self) -> dyn SuperTrait; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `SuperTrait` is not dyn compatible + //~^ ERROR the trait `SuperTrait` is not dyn compatible } fn main() {} diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr index 582cf1af0546..ba4ce4753995 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr @@ -7,20 +7,6 @@ LL | Self: 'a; | ^^ = help: consider adding an explicit lifetime bound `Self: 'a`... -error: associated item referring to unboxed trait object for its own trait - --> $DIR/supertrait-mentions-GAT.rs:10:20 - | -LL | trait SuperTrait: for<'a> GatTrait = T> { - | ---------- in this trait -LL | fn c(&self) -> dyn SuperTrait; - | ^^^^^^^^^^^^^^^^^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn c(&self) -> dyn SuperTrait; -LL + fn c(&self) -> Self; - | - error[E0038]: the trait `SuperTrait` is not dyn compatible --> $DIR/supertrait-mentions-GAT.rs:10:20 | @@ -37,8 +23,13 @@ LL | type Gat<'a> LL | trait SuperTrait: for<'a> GatTrait = T> { | ---------- this trait is not dyn compatible... = help: consider moving `Gat` to another trait +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn c(&self) -> dyn SuperTrait; +LL + fn c(&self) -> Self; + | -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0038, E0311. For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs index 10b4781eb049..97a0e005f86a 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs @@ -4,19 +4,16 @@ trait A: Sized { fn f(a: A) -> A; //~^ ERROR expected a type, found a trait //~| ERROR expected a type, found a trait - //~| ERROR associated item referring to unboxed trait object for its own trait } trait B { fn f(b: B) -> B; //~^ ERROR expected a type, found a trait //~| ERROR expected a type, found a trait - //~| ERROR associated item referring to unboxed trait object for its own trait } trait C { fn f(&self, c: C) -> C; //~^ ERROR expected a type, found a trait //~| ERROR expected a type, found a trait - //~| ERROR associated item referring to unboxed trait object for its own trait } fn main() {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr index e189012d15c9..c4dab4691f49 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr @@ -26,22 +26,8 @@ help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as LL | fn f(a: A) -> impl A; | ++++ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13 - | -LL | trait A: Sized { - | - in this trait -LL | fn f(a: A) -> A; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(a: A) -> A; -LL + fn f(a: Self) -> Self; - | - error[E0782]: expected a type, found a trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:9:13 | LL | fn f(b: B) -> B; | ^ @@ -58,7 +44,7 @@ LL | fn f(b: impl B) -> B; | ++++ error[E0782]: expected a type, found a trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:19 + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:9:19 | LL | fn f(b: B) -> B; | ^ @@ -68,22 +54,8 @@ help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as LL | fn f(b: B) -> impl B; | ++++ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13 - | -LL | trait B { - | - in this trait -LL | fn f(b: B) -> B; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(b: B) -> B; -LL + fn f(b: Self) -> Self; - | - error[E0782]: expected a type, found a trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20 + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:14:20 | LL | fn f(&self, c: C) -> C; | ^ @@ -100,7 +72,7 @@ LL | fn f(&self, c: impl C) -> C; | ++++ error[E0782]: expected a type, found a trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:26 + --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:14:26 | LL | fn f(&self, c: C) -> C; | ^ @@ -110,20 +82,6 @@ help: `C` is dyn-incompatible, use `impl C` to return an opaque type, as long as LL | fn f(&self, c: C) -> impl C; | ++++ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20 - | -LL | trait C { - | - in this trait -LL | fn f(&self, c: C) -> C; - | ^ ^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(&self, c: C) -> C; -LL + fn f(&self, c: Self) -> Self; - | - -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs index 747926c400ae..a798b1bd5787 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs @@ -2,13 +2,11 @@ #![allow(bare_trait_objects)] trait A: Sized { fn f(a: dyn A) -> dyn A; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `A` is not dyn compatible + //~^ ERROR the trait `A` is not dyn compatible } trait B { fn f(a: dyn B) -> dyn B; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `B` is not dyn compatible + //~^ ERROR the trait `B` is not dyn compatible } trait C { fn f(&self, a: dyn C) -> dyn C; diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr index 2e3919db1b75..4ccf65b68bf7 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr @@ -1,17 +1,3 @@ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13 - | -LL | trait A: Sized { - | - in this trait -LL | fn f(a: dyn A) -> dyn A; - | ^^^^^ ^^^^^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(a: dyn A) -> dyn A; -LL + fn f(a: Self) -> Self; - | - error[E0038]: the trait `A` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13 | @@ -26,30 +12,21 @@ LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` | | | this trait is not dyn compatible... - -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13 - | -LL | trait B { - | - in this trait -LL | fn f(a: dyn B) -> dyn B; - | ^^^^^ ^^^^^ - | help: you might have meant to use `Self` to refer to the implementing type | -LL - fn f(a: dyn B) -> dyn B; -LL + fn f(a: Self) -> Self; +LL - fn f(a: dyn A) -> dyn A; +LL + fn f(a: Self) -> dyn A; | error[E0038]: the trait `B` is not dyn compatible - --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:8:13 | LL | fn f(a: dyn B) -> dyn B; | ^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:8 + --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:8:8 | LL | trait B { | - this trait is not dyn compatible... @@ -63,7 +40,12 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj | LL | fn f(a: dyn B) -> dyn B where Self: Sized; | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn f(a: dyn B) -> dyn B; +LL + fn f(a: Self) -> dyn B; + | -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs index 63fe5ebaea49..d8e9d381dbda 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs @@ -1,12 +1,10 @@ trait A: Sized { fn f(a: dyn A) -> dyn A; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `A` is not dyn compatible + //~^ ERROR the trait `A` is not dyn compatible } trait B { fn f(a: dyn B) -> dyn B; - //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `B` is not dyn compatible + //~^ ERROR the trait `B` is not dyn compatible } trait C { fn f(&self, a: dyn C) -> dyn C; diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr index e8384afed7a1..bda1d01e23ff 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr @@ -1,17 +1,3 @@ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13 - | -LL | trait A: Sized { - | - in this trait -LL | fn f(a: dyn A) -> dyn A; - | ^^^^^ ^^^^^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn f(a: dyn A) -> dyn A; -LL + fn f(a: Self) -> Self; - | - error[E0038]: the trait `A` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13 | @@ -26,30 +12,21 @@ LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` | | | this trait is not dyn compatible... - -error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13 - | -LL | trait B { - | - in this trait -LL | fn f(a: dyn B) -> dyn B; - | ^^^^^ ^^^^^ - | help: you might have meant to use `Self` to refer to the implementing type | -LL - fn f(a: dyn B) -> dyn B; -LL + fn f(a: Self) -> Self; +LL - fn f(a: dyn A) -> dyn A; +LL + fn f(a: Self) -> dyn A; | error[E0038]: the trait `B` is not dyn compatible - --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:6:13 | LL | fn f(a: dyn B) -> dyn B; | ^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:8 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:6:8 | LL | trait B { | - this trait is not dyn compatible... @@ -63,7 +40,12 @@ help: alternatively, consider constraining `f` so it does not apply to trait obj | LL | fn f(a: dyn B) -> dyn B where Self: Sized; | +++++++++++++++++ +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn f(a: dyn B) -> dyn B; +LL + fn f(a: Self) -> dyn B; + | -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/suggestions/issue-116434-2015.rs b/tests/ui/suggestions/issue-116434-2015.rs index bad9d02321cf..e0438cdef253 100644 --- a/tests/ui/suggestions/issue-116434-2015.rs +++ b/tests/ui/suggestions/issue-116434-2015.rs @@ -11,6 +11,7 @@ trait Foo { //~| HELP if this is a dyn-compatible trait, use `dyn` //~| ERROR the trait `Clone` is not dyn compatible [E0038] //~| HELP there is an associated type with the same name + //~| HELP use `Self` to refer to the implementing type } trait DbHandle: Sized {} @@ -26,6 +27,7 @@ trait DbInterface { //~| HELP if this is a dyn-compatible trait, use `dyn` //~| ERROR the trait `DbHandle` is not dyn compatible [E0038] //~| HELP there is an associated type with the same name + //~| HELP use `Self` to refer to the implementing type } fn main() {} diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr index a0a99cc560db..cad5812da663 100644 --- a/tests/ui/suggestions/issue-116434-2015.stderr +++ b/tests/ui/suggestions/issue-116434-2015.stderr @@ -35,13 +35,18 @@ LL | fn foo() -> Clone; = note: the trait is not dyn compatible because it requires `Self: Sized` = note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn foo() -> Clone; +LL + fn foo() -> Self; + | help: there is an associated type with the same name | LL | fn foo() -> Self::Clone; | ++++++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:20:20 + --> $DIR/issue-116434-2015.rs:21:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ @@ -54,7 +59,7 @@ LL | fn handle() -> dyn DbHandle; | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:20:20 + --> $DIR/issue-116434-2015.rs:21:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ @@ -68,19 +73,24 @@ LL | fn handle() -> dyn DbHandle; | +++ error[E0038]: the trait `DbHandle` is not dyn compatible - --> $DIR/issue-116434-2015.rs:20:20 + --> $DIR/issue-116434-2015.rs:21:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ `DbHandle` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/issue-116434-2015.rs:16:17 + --> $DIR/issue-116434-2015.rs:17:17 | LL | trait DbHandle: Sized {} | -------- ^^^^^ ...because it requires `Self: Sized` | | | this trait is not dyn compatible... +help: you might have meant to use `Self` to refer to the implementing type + | +LL - fn handle() -> DbHandle; +LL + fn handle() -> Self; + | help: there is an associated type with the same name | LL | fn handle() -> Self::DbHandle; diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs index 53f07a94fd15..ad7d972879ff 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs @@ -5,7 +5,6 @@ trait Trait { //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters //~| ERROR expected value, found builtin type `u32` //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - //~| ERROR associated item referring to unboxed trait object for its own trait bar //~^ ERROR cannot find value `bar` in this scope } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index a085dd6ac576..e10bb98c1349 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -20,7 +20,7 @@ LL | fn fnc(&self) -> dyn Trait { | ^^^ not a value error[E0425]: cannot find value `bar` in this scope - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:9:9 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:8:9 | LL | bar | ^^^ not found in this scope @@ -45,22 +45,7 @@ error: defaults for const parameters are only allowed in `struct`, `enum`, `type LL | fn fnc(&self) -> dyn Trait { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: associated item referring to unboxed trait object for its own trait - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:48 - | -LL | trait Trait { - | ----- in this trait -... -LL | fn fnc(&self) -> dyn Trait { - | ^^^^^^^^^ - | -help: you might have meant to use `Self` to refer to the implementing type - | -LL - fn fnc(&self) -> dyn Trait { -LL + fn fnc(&self) -> Self { - | - -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0391, E0403, E0423, E0425. For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index 0c293e3576d6..bf79535df116 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -13,6 +13,11 @@ LL | trait T { LL | const CONST: (bool, dyn T); | ^^^^^ ...because it contains this associated `const` = help: consider moving `CONST` to another trait +help: you might have meant to use `Self` to refer to the implementing type + | +LL - const CONST: (bool, dyn T); +LL + const CONST: (bool, Self); + | error: aborting due to 1 previous error From 52167e04e62a84fe5073c4074733c72f96961ace Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Sat, 14 Jun 2025 12:05:19 +0800 Subject: [PATCH 038/356] Marks ADT live if it appears in pattern --- compiler/rustc_passes/src/dead.rs | 78 +++++++------------ library/core/src/default.rs | 1 - tests/incremental/track-deps-in-new-solver.rs | 2 + .../ui/const-generics/issues/issue-86535-2.rs | 2 +- .../issues/issue-86535-2.stderr | 10 +++ tests/ui/const-generics/issues/issue-86535.rs | 2 +- .../const-generics/issues/issue-86535.stderr | 10 +++ tests/ui/derives/clone-debug-dead-code.stderr | 2 +- .../impl-trait/extra-impl-in-trait-impl.fixed | 1 + .../ui/impl-trait/extra-impl-in-trait-impl.rs | 1 + .../extra-impl-in-trait-impl.stderr | 8 +- tests/ui/lint/dead-code/issue-41883.stderr | 2 - tests/ui/lint/dead-code/issue-59003.rs | 2 +- .../lint-unused-adt-appeared-in-pattern.rs | 37 +++++++++ ...lint-unused-adt-appeared-in-pattern.stderr | 20 +++++ ...tiple-dead-codes-in-the-same-struct.stderr | 2 - ...nt-adt-appeared-in-pattern-issue-120770.rs | 32 ++++++++ ...sed-adt-impl-pub-trait-with-assoc-const.rs | 2 +- ...adt-impl-pub-trait-with-assoc-const.stderr | 8 +- .../dead-code/unused-struct-derive-default.rs | 1 + .../unused-struct-derive-default.stderr | 1 - tests/ui/parser/issues/issue-105366.fixed | 1 + tests/ui/parser/issues/issue-105366.rs | 1 + tests/ui/parser/issues/issue-105366.stderr | 2 +- 24 files changed, 161 insertions(+), 67 deletions(-) create mode 100644 tests/ui/const-generics/issues/issue-86535-2.stderr create mode 100644 tests/ui/const-generics/issues/issue-86535.stderr create mode 100644 tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs create mode 100644 tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr create mode 100644 tests/ui/lint/dead-code/not-lint-adt-appeared-in-pattern-issue-120770.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 4257d8e8d16b..4738036318d3 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -234,7 +234,14 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { pats: &[hir::PatField<'_>], ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { - ty::Adt(adt, _) => adt.variant_of_res(res), + ty::Adt(adt, _) => { + // Marks the ADT live if its variant appears as the pattern, + // considering cases when we have `let T(x) = foo()` and `fn foo() -> T;`, + // we will lose the liveness info of `T` cause we cannot mark it live when visiting `foo`. + // Related issue: https://github.com/rust-lang/rust/issues/120770 + self.check_def_id(adt.did()); + adt.variant_of_res(res) + } _ => span_bug!(lhs.span, "non-ADT in struct pattern"), }; for pat in pats { @@ -254,7 +261,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { dotdot: hir::DotDotPos, ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { - ty::Adt(adt, _) => adt.variant_of_res(res), + ty::Adt(adt, _) => { + // Marks the ADT live if its variant appears as the pattern + self.check_def_id(adt.did()); + adt.variant_of_res(res) + } _ => { self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern"); return; @@ -359,31 +370,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { return false; } - // don't ignore impls for Enums and pub Structs whose methods don't have self receiver, - // cause external crate may call such methods to construct values of these types - if let Some(local_impl_of) = impl_of.as_local() - && let Some(local_def_id) = def_id.as_local() - && let Some(fn_sig) = - self.tcx.hir_fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id)) - && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None) - && let TyKind::Path(QPath::Resolved(_, path)) = - self.tcx.hir_expect_item(local_impl_of).expect_impl().self_ty.kind - && let Res::Def(def_kind, did) = path.res - { - match def_kind { - // for example, #[derive(Default)] pub struct T(i32); - // external crate can call T::default() to construct T, - // so that don't ignore impl Default for pub Enum and Structs - DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => { - return false; - } - // don't ignore impl Default for Enums, - // cause we don't know which variant is constructed - DefKind::Enum => return false, - _ => (), - }; - } - if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { @@ -494,38 +480,25 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { impl_id: hir::ItemId, local_def_id: LocalDefId, ) -> bool { - if self.should_ignore_item(local_def_id.to_def_id()) { - return false; - } - let trait_def_id = match self.tcx.def_kind(local_def_id) { // assoc impl items of traits are live if the corresponding trait items are live - DefKind::AssocFn => self.tcx.associated_item(local_def_id).trait_item_def_id, + DefKind::AssocFn => self + .tcx + .associated_item(local_def_id) + .trait_item_def_id + .and_then(|def_id| def_id.as_local()), // impl items are live if the corresponding traits are live DefKind::Impl { of_trait: true } => self .tcx .impl_trait_ref(impl_id.owner_id.def_id) - .and_then(|trait_ref| Some(trait_ref.skip_binder().def_id)), + .and_then(|trait_ref| trait_ref.skip_binder().def_id.as_local()), _ => None, }; - if let Some(trait_def_id) = trait_def_id { - if let Some(trait_def_id) = trait_def_id.as_local() - && !self.live_symbols.contains(&trait_def_id) - { - return false; - } - - // FIXME: legacy logic to check whether the function may construct `Self`, - // this can be removed after supporting marking ADTs appearing in patterns - // as live, then we can check private impls of public traits directly - if let Some(fn_sig) = - self.tcx.hir_fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id)) - && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None) - && self.tcx.visibility(trait_def_id).is_public() - { - return true; - } + if let Some(trait_def_id) = trait_def_id + && !self.live_symbols.contains(&trait_def_id) + { + return false; } // The impl or impl item is used if the corresponding trait or trait item is used and the ty is used. @@ -635,6 +608,11 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) { match &expr.kind { rustc_hir::PatExprKind::Path(qpath) => { + // mark the type of variant live when meeting E::V in expr + if let ty::Adt(adt, _) = self.typeck_results().node_type(expr.hir_id).kind() { + self.check_def_id(adt.did()); + } + let res = self.typeck_results().qpath_res(qpath, expr.hir_id); self.handle_res(res); } diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 044997a81a9a..0a15cedfb552 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -103,7 +103,6 @@ use crate::ascii::Char as AsciiChar; /// ``` #[rustc_diagnostic_item = "Default"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_trivial_field_reads] pub trait Default: Sized { /// Returns the "default value" for a type. /// diff --git a/tests/incremental/track-deps-in-new-solver.rs b/tests/incremental/track-deps-in-new-solver.rs index fb013b2b24a7..51cd6b89e37e 100644 --- a/tests/incremental/track-deps-in-new-solver.rs +++ b/tests/incremental/track-deps-in-new-solver.rs @@ -3,6 +3,8 @@ //@ compile-flags: -Znext-solver //@ check-pass +#![allow(dead_code)] + pub trait Future { type Error; fn poll() -> Self::Error; diff --git a/tests/ui/const-generics/issues/issue-86535-2.rs b/tests/ui/const-generics/issues/issue-86535-2.rs index 8d064f3eeb1b..5c9132fe54d3 100644 --- a/tests/ui/const-generics/issues/issue-86535-2.rs +++ b/tests/ui/const-generics/issues/issue-86535-2.rs @@ -9,7 +9,7 @@ pub trait Foo { [(); Self::ASSOC_C]:; } -struct Bar; +struct Bar; //~ WARN struct `Bar` is never constructed impl Foo for Bar { const ASSOC_C: usize = 3; diff --git a/tests/ui/const-generics/issues/issue-86535-2.stderr b/tests/ui/const-generics/issues/issue-86535-2.stderr new file mode 100644 index 000000000000..0ba748365754 --- /dev/null +++ b/tests/ui/const-generics/issues/issue-86535-2.stderr @@ -0,0 +1,10 @@ +warning: struct `Bar` is never constructed + --> $DIR/issue-86535-2.rs:12:8 + | +LL | struct Bar; + | ^^^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/const-generics/issues/issue-86535.rs b/tests/ui/const-generics/issues/issue-86535.rs index 62454f4a388a..2cdf801c1561 100644 --- a/tests/ui/const-generics/issues/issue-86535.rs +++ b/tests/ui/const-generics/issues/issue-86535.rs @@ -2,7 +2,7 @@ #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(incomplete_features, unused_variables)] -struct F; +struct F; //~ WARN struct `F` is never constructed impl X for F<{ S }> { const W: usize = 3; diff --git a/tests/ui/const-generics/issues/issue-86535.stderr b/tests/ui/const-generics/issues/issue-86535.stderr new file mode 100644 index 000000000000..84d6c1c11ff6 --- /dev/null +++ b/tests/ui/const-generics/issues/issue-86535.stderr @@ -0,0 +1,10 @@ +warning: struct `F` is never constructed + --> $DIR/issue-86535.rs:5:8 + | +LL | struct F; + | ^ + | + = note: `#[warn(dead_code)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/derives/clone-debug-dead-code.stderr b/tests/ui/derives/clone-debug-dead-code.stderr index 34b7f929ec5e..38be486e3320 100644 --- a/tests/ui/derives/clone-debug-dead-code.stderr +++ b/tests/ui/derives/clone-debug-dead-code.stderr @@ -40,7 +40,7 @@ LL | struct D { f: () } | | | field in this struct | - = note: `D` has derived impls for the traits `Debug` and `Clone`, but these are intentionally ignored during dead code analysis + = note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis error: field `f` is never read --> $DIR/clone-debug-dead-code.rs:21:12 diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed index 886fc1d00580..d8eceeff6788 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed @@ -1,5 +1,6 @@ //@ run-rustfix +#![allow(dead_code)] struct S(T); struct S2; diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs index f3271993867c..c2e511c0d055 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs @@ -1,5 +1,6 @@ //@ run-rustfix +#![allow(dead_code)] struct S(T); struct S2; diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr index 5aafc8b64d4f..22e68463a8cf 100644 --- a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr @@ -1,23 +1,23 @@ error: unexpected `impl` keyword - --> $DIR/extra-impl-in-trait-impl.rs:6:18 + --> $DIR/extra-impl-in-trait-impl.rs:7:18 | LL | impl impl Default for S { | ^^^^^ help: remove the extra `impl` | note: this is parsed as an `impl Trait` type, but a trait is expected at this position - --> $DIR/extra-impl-in-trait-impl.rs:6:18 + --> $DIR/extra-impl-in-trait-impl.rs:7:18 | LL | impl impl Default for S { | ^^^^^^^^^^^^ error: unexpected `impl` keyword - --> $DIR/extra-impl-in-trait-impl.rs:12:6 + --> $DIR/extra-impl-in-trait-impl.rs:13:6 | LL | impl impl Default for S2 { | ^^^^^ help: remove the extra `impl` | note: this is parsed as an `impl Trait` type, but a trait is expected at this position - --> $DIR/extra-impl-in-trait-impl.rs:12:6 + --> $DIR/extra-impl-in-trait-impl.rs:13:6 | LL | impl impl Default for S2 { | ^^^^^^^^^^^^ diff --git a/tests/ui/lint/dead-code/issue-41883.stderr b/tests/ui/lint/dead-code/issue-41883.stderr index cf079e4dda33..47ccef9a5306 100644 --- a/tests/ui/lint/dead-code/issue-41883.stderr +++ b/tests/ui/lint/dead-code/issue-41883.stderr @@ -29,8 +29,6 @@ error: struct `UnusedStruct` is never constructed | LL | struct UnusedStruct; | ^^^^^^^^^^^^ - | - = note: `UnusedStruct` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis error: aborting due to 4 previous errors diff --git a/tests/ui/lint/dead-code/issue-59003.rs b/tests/ui/lint/dead-code/issue-59003.rs index e3dcaca57788..319cf2db1495 100644 --- a/tests/ui/lint/dead-code/issue-59003.rs +++ b/tests/ui/lint/dead-code/issue-59003.rs @@ -4,8 +4,8 @@ #![deny(dead_code)] +#[allow(dead_code)] struct Foo { - #[allow(dead_code)] inner: u32, } diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs new file mode 100644 index 000000000000..25777438456b --- /dev/null +++ b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.rs @@ -0,0 +1,37 @@ +#![deny(dead_code)] + +struct Foo(u8); //~ ERROR struct `Foo` is never constructed + +enum Bar { //~ ERROR enum `Bar` is never used + Var1(u8), + Var2(u8), +} + +pub trait Tr1 { + fn f1() -> Self; +} + +impl Tr1 for Foo { + fn f1() -> Foo { + let f = Foo(0); + let Foo(tag) = f; + Foo(tag) + } +} + +impl Tr1 for Bar { + fn f1() -> Bar { + let b = Bar::Var1(0); + let b = if let Bar::Var1(_) = b { + Bar::Var1(0) + } else { + Bar::Var2(0) + }; + match b { + Bar::Var1(_) => Bar::Var2(0), + Bar::Var2(_) => Bar::Var1(0), + } + } +} + +fn main() {} diff --git a/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr new file mode 100644 index 000000000000..7c1a4b459775 --- /dev/null +++ b/tests/ui/lint/dead-code/lint-unused-adt-appeared-in-pattern.stderr @@ -0,0 +1,20 @@ +error: struct `Foo` is never constructed + --> $DIR/lint-unused-adt-appeared-in-pattern.rs:3:8 + | +LL | struct Foo(u8); + | ^^^ + | +note: the lint level is defined here + --> $DIR/lint-unused-adt-appeared-in-pattern.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: enum `Bar` is never used + --> $DIR/lint-unused-adt-appeared-in-pattern.rs:5:6 + | +LL | enum Bar { + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr index b992005318f2..25a7d96cb897 100644 --- a/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr +++ b/tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr @@ -56,8 +56,6 @@ warning: struct `Foo` is never constructed | LL | struct Foo(usize, #[allow(unused)] usize); | ^^^ - | - = note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis error: aborting due to 2 previous errors; 2 warnings emitted diff --git a/tests/ui/lint/dead-code/not-lint-adt-appeared-in-pattern-issue-120770.rs b/tests/ui/lint/dead-code/not-lint-adt-appeared-in-pattern-issue-120770.rs new file mode 100644 index 000000000000..43a2e4319043 --- /dev/null +++ b/tests/ui/lint/dead-code/not-lint-adt-appeared-in-pattern-issue-120770.rs @@ -0,0 +1,32 @@ +//@ check-pass + +#![deny(dead_code)] + +#[repr(u8)] +#[derive(Copy, Clone, Debug)] +pub enum RecordField { + Target = 1, + Level, + Module, + File, + Line, + NumArgs, +} + +unsafe trait Pod {} + +#[repr(transparent)] +struct RecordFieldWrapper(RecordField); + +unsafe impl Pod for RecordFieldWrapper {} + +fn try_read(buf: &[u8]) -> T { + unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const T) } +} + +pub fn foo(buf: &[u8]) -> RecordField { + let RecordFieldWrapper(tag) = try_read(buf); + tag +} + +fn main() {} diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs index 5b755d62a059..415eb4138def 100644 --- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs +++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs @@ -2,7 +2,7 @@ struct T1; //~ ERROR struct `T1` is never constructed pub struct T2(i32); //~ ERROR field `0` is never read -struct T3; +struct T3; //~ ERROR struct `T3` is never constructed trait Trait1 { //~ ERROR trait `Trait1` is never used const UNUSED: i32; diff --git a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr index 2441a3f868dc..778dadee153f 100644 --- a/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr +++ b/tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr @@ -20,11 +20,17 @@ LL | pub struct T2(i32); | = help: consider removing this field +error: struct `T3` is never constructed + --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:5:8 + | +LL | struct T3; + | ^^ + error: trait `Trait1` is never used --> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7 | LL | trait Trait1 { | ^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.rs b/tests/ui/lint/dead-code/unused-struct-derive-default.rs index 330ad32dd570..f20b7cb66ee5 100644 --- a/tests/ui/lint/dead-code/unused-struct-derive-default.rs +++ b/tests/ui/lint/dead-code/unused-struct-derive-default.rs @@ -22,4 +22,5 @@ pub struct T2 { fn main() { let _x: Used = Default::default(); + let _e: E = Default::default(); } diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr index bbb0bd7be706..7422f9a39f31 100644 --- a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr +++ b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr @@ -4,7 +4,6 @@ error: struct `T` is never constructed LL | struct T; | ^ | - = note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis note: the lint level is defined here --> $DIR/unused-struct-derive-default.rs:1:9 | diff --git a/tests/ui/parser/issues/issue-105366.fixed b/tests/ui/parser/issues/issue-105366.fixed index 7157b647524d..95419dc07f2c 100644 --- a/tests/ui/parser/issues/issue-105366.fixed +++ b/tests/ui/parser/issues/issue-105366.fixed @@ -1,5 +1,6 @@ //@ run-rustfix +#[allow(dead_code)] struct Foo; impl From for Foo { diff --git a/tests/ui/parser/issues/issue-105366.rs b/tests/ui/parser/issues/issue-105366.rs index dc3cb8b343d3..3278b7379912 100644 --- a/tests/ui/parser/issues/issue-105366.rs +++ b/tests/ui/parser/issues/issue-105366.rs @@ -1,5 +1,6 @@ //@ run-rustfix +#[allow(dead_code)] struct Foo; fn From for Foo { diff --git a/tests/ui/parser/issues/issue-105366.stderr b/tests/ui/parser/issues/issue-105366.stderr index d8c79a0e0eaf..225e436b4aa8 100644 --- a/tests/ui/parser/issues/issue-105366.stderr +++ b/tests/ui/parser/issues/issue-105366.stderr @@ -1,5 +1,5 @@ error: you might have meant to write `impl` instead of `fn` - --> $DIR/issue-105366.rs:5:1 + --> $DIR/issue-105366.rs:6:1 | LL | fn From for Foo { | ^^ From 600a8a7f63f2935ac4ad67637c03df83b99c1eca Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 14 Jun 2025 09:42:41 +0000 Subject: [PATCH 039/356] Rustup to rustc 1.89.0-nightly (8da623945 2025-06-13) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index fc8f892fb1e0..5114d3686a43 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-12" +channel = "nightly-2025-06-14" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 6ca4639d6a0131097bb10e30b516abc2632cf32e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 14 Jun 2025 11:58:47 +0200 Subject: [PATCH 040/356] Fix random failure when JS code is executed when the whole file was not read yet --- src/librustdoc/html/static/js/search.js | 74 ++++++++++++------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index dce5fddb3177..126da46ab773 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -5393,43 +5393,6 @@ function updateCrate(ev) { search(true); } -// @ts-expect-error -function initSearch(searchIndx) { - rawSearchIndex = searchIndx; - if (typeof window !== "undefined") { - // @ts-expect-error - docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState); - registerSearchEvents(); - // If there's a search term in the URL, execute the search now. - if (window.searchState.getQueryStringParams().search) { - search(); - } - } else if (typeof exports !== "undefined") { - // @ts-expect-error - docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState); - exports.docSearch = docSearch; - exports.parseQuery = DocSearch.parseQuery; - } -} - -if (typeof exports !== "undefined") { - exports.initSearch = initSearch; -} - -if (typeof window !== "undefined") { - // @ts-expect-error - window.initSearch = initSearch; - // @ts-expect-error - if (window.searchIndex !== undefined) { - // @ts-expect-error - initSearch(window.searchIndex); - } -} else { - // Running in Node, not a browser. Run initSearch just to produce the - // exports. - initSearch(new Map()); -} - // Parts of this code are based on Lucene, which is licensed under the // Apache/2.0 license. // More information found here: @@ -5908,3 +5871,40 @@ Lev1TParametricDescription.prototype.toStates3 = /*3 bits per value */ new Int32 Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new Int32Array([ 0xa0fc0000,0x5555ba08,0x55555555, ]); + +// @ts-expect-error +function initSearch(searchIndx) { + rawSearchIndex = searchIndx; + if (typeof window !== "undefined") { + // @ts-expect-error + docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState); + registerSearchEvents(); + // If there's a search term in the URL, execute the search now. + if (window.searchState.getQueryStringParams().search) { + search(); + } + } else if (typeof exports !== "undefined") { + // @ts-expect-error + docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState); + exports.docSearch = docSearch; + exports.parseQuery = DocSearch.parseQuery; + } +} + +if (typeof exports !== "undefined") { + exports.initSearch = initSearch; +} + +if (typeof window !== "undefined") { + // @ts-expect-error + window.initSearch = initSearch; + // @ts-expect-error + if (window.searchIndex !== undefined) { + // @ts-expect-error + initSearch(window.searchIndex); + } +} else { + // Running in Node, not a browser. Run initSearch just to produce the + // exports. + initSearch(new Map()); +} From 870e5a26ee465a935050ee04f8edbb520d5278e6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 15 Jun 2025 00:26:43 +0000 Subject: [PATCH 041/356] cargo update compiler & tools dependencies: Locking 31 packages to latest compatible versions Updating adler2 v2.0.0 -> v2.0.1 Updating cfg-if v1.0.0 -> v1.0.1 Updating clap v4.5.39 -> v4.5.40 Updating clap_builder v4.5.39 -> v4.5.40 Updating clap_derive v4.5.32 -> v4.5.40 Updating clap_lex v0.7.4 -> v0.7.5 Updating getopts v0.2.21 -> v0.2.23 Updating hermit-abi v0.5.1 -> v0.5.2 Updating jiff v0.2.14 -> v0.2.15 Updating jiff-static v0.2.14 -> v0.2.15 Updating libc v0.2.172 -> v0.2.173 Updating memchr v2.7.4 -> v2.7.5 Updating minifier v0.3.5 -> v0.3.6 Updating miniz_oxide v0.8.8 -> v0.8.9 Updating object v0.37.0 -> v0.37.1 Updating redox_syscall v0.5.12 -> v0.5.13 Updating rustc-demangle v0.1.24 -> v0.1.25 Updating syn v2.0.101 -> v2.0.103 Updating thread_local v1.1.8 -> v1.1.9 Updating unicode-width v0.2.0 -> v0.2.1 Updating wasi v0.11.0+wasi-snapshot-preview1 -> v0.11.1+wasi-snapshot-preview1 Updating wasm-encoder v0.233.0 -> v0.235.0 Removing wasmparser v0.232.0 Removing wasmparser v0.233.0 Adding wasmparser v0.234.0 Adding wasmparser v0.235.0 Updating wast v233.0.0 -> v235.0.0 Updating wat v1.233.0 -> v1.235.0 Updating windows v0.61.1 -> v0.61.3 Updating windows-link v0.1.1 -> v0.1.3 Adding windows-sys v0.60.2 Updating windows-targets v0.53.0 -> v0.53.2 Updating winnow v0.7.10 -> v0.7.11 note: pass `--verbose` to see 39 unchanged dependencies behind latest library dependencies: Locking 1 package to latest compatible version Updating libc v0.2.172 -> v0.2.173 note: pass `--verbose` to see 4 unchanged dependencies behind latest rustbook dependencies: Locking 19 packages to latest compatible versions Updating adler2 v2.0.0 -> v2.0.1 Updating cc v1.2.26 -> v1.2.27 Updating cfg-if v1.0.0 -> v1.0.1 Updating clap v4.5.39 -> v4.5.40 Updating clap_builder v4.5.39 -> v4.5.40 Updating clap_complete v4.5.52 -> v4.5.54 Updating clap_derive v4.5.32 -> v4.5.40 Updating clap_lex v0.7.4 -> v0.7.5 Updating getopts v0.2.21 -> v0.2.23 Updating jiff v0.2.14 -> v0.2.15 Updating jiff-static v0.2.14 -> v0.2.15 Updating libc v0.2.172 -> v0.2.173 Updating memchr v2.7.4 -> v2.7.5 Updating miniz_oxide v0.8.8 -> v0.8.9 Updating redox_syscall v0.5.12 -> v0.5.13 Updating syn v2.0.101 -> v2.0.103 Removing unicode-width v0.1.14 Removing unicode-width v0.2.0 Adding unicode-width v0.2.1 Updating windows-link v0.1.1 -> v0.1.3 Updating winnow v0.7.10 -> v0.7.11 --- Cargo.lock | 240 ++++++++++++++++++---------------- library/Cargo.lock | 4 +- src/tools/rustbook/Cargo.lock | 86 ++++++------ 3 files changed, 166 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df2842bddb38..2b107b11cff8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aes" @@ -75,7 +75,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" dependencies = [ "anstyle", - "unicode-width 0.2.0", + "unicode-width 0.2.1", ] [[package]] @@ -136,7 +136,7 @@ dependencies = [ "anstyle-lossy", "anstyle-parse", "html-escape", - "unicode-width 0.2.0", + "unicode-width 0.2.1", ] [[package]] @@ -204,7 +204,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_derive", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -216,7 +216,7 @@ dependencies = [ "memchr", "serde", "serde_derive", - "winnow 0.7.10", + "winnow 0.7.11", ] [[package]] @@ -431,9 +431,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -487,9 +487,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -507,9 +507,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -519,21 +519,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "clippy" @@ -558,7 +558,7 @@ dependencies = [ "rustc_tools_util 0.4.2", "serde", "serde_json", - "syn 2.0.101", + "syn 2.0.103", "tempfile", "termize", "tokio", @@ -673,7 +673,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -748,7 +748,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.0", + "unicode-width 0.2.1", "windows-sys 0.59.0", ] @@ -900,7 +900,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -911,7 +911,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -939,7 +939,7 @@ checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -960,7 +960,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -970,7 +970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -982,7 +982,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1050,7 +1050,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.0", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1072,7 +1072,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1352,7 +1352,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1416,11 +1416,11 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" dependencies = [ - "unicode-width 0.1.14", + "unicode-width 0.2.1", ] [[package]] @@ -1431,7 +1431,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] @@ -1511,9 +1511,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -1775,7 +1775,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -1859,7 +1859,7 @@ dependencies = [ "console", "number_prefix", "portable-atomic", - "unicode-width 0.2.0", + "unicode-width 0.2.1", "web-time", ] @@ -1933,9 +1933,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ "jiff-static", "log", @@ -1946,13 +1946,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -2045,9 +2045,9 @@ checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" [[package]] name = "libdbus-sys" @@ -2085,7 +2085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.53.2", ] [[package]] @@ -2223,7 +2223,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -2261,9 +2261,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -2276,9 +2276,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfdc64e2f805f3d12965f10522000bae36e88d2cfea44112331f467d4f4bf68" +checksum = "14f1541610994bba178cb36757e102d06a52a2d9612aa6d34c64b3b377c5d943" [[package]] name = "minimal-lexical" @@ -2288,9 +2288,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] @@ -2512,15 +2512,15 @@ dependencies = [ [[package]] name = "object" -version = "0.37.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6273adb7096cf9ab4335f258e627d8230e69d40d45567d678f552dcec6245215" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" dependencies = [ "crc32fast", "hashbrown", "indexmap", "memchr", - "wasmparser 0.232.0", + "wasmparser 0.234.0", ] [[package]] @@ -2725,7 +2725,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -3014,9 +3014,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags", ] @@ -3148,9 +3148,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -3440,7 +3440,7 @@ dependencies = [ "itertools", "libc", "measureme", - "object 0.37.0", + "object 0.37.1", "rustc-demangle", "rustc_abi", "rustc_ast", @@ -3481,7 +3481,7 @@ dependencies = [ "either", "itertools", "libc", - "object 0.37.0", + "object 0.37.1", "pathdiff", "regex", "rustc_abi", @@ -3741,7 +3741,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "unic-langid", ] @@ -3890,7 +3890,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -4037,7 +4037,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "synstructure", ] @@ -4242,7 +4242,7 @@ dependencies = [ "thin-vec", "tracing", "unicode-normalization", - "unicode-width 0.2.0", + "unicode-width 0.2.1", ] [[package]] @@ -4491,7 +4491,7 @@ dependencies = [ "sha1", "sha2", "tracing", - "unicode-width 0.2.0", + "unicode-width 0.2.1", ] [[package]] @@ -4516,7 +4516,7 @@ name = "rustc_target" version = "0.0.0" dependencies = [ "bitflags", - "object 0.37.0", + "object 0.37.1", "rustc_abi", "rustc_data_structures", "rustc_fs_util", @@ -4637,7 +4637,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "synstructure", ] @@ -4728,7 +4728,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -4856,7 +4856,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5096,9 +5096,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", @@ -5113,7 +5113,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5246,7 +5246,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5257,7 +5257,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5274,12 +5274,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -5433,7 +5432,7 @@ checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -5604,7 +5603,7 @@ checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.101", + "syn 2.0.103", "unic-langid-impl", ] @@ -5672,9 +5671,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "unicode-xid" @@ -5775,9 +5774,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -5816,7 +5815,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "wasm-bindgen-shared", ] @@ -5838,7 +5837,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5901,12 +5900,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.233.0" +version = "0.235.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9679ae3cf7cfa2ca3a327f7fab97f27f3294d402fd1a76ca8ab514e17973e4d3" +checksum = "b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a" dependencies = [ "leb128fmt", - "wasmparser 0.233.0", + "wasmparser 0.235.0", ] [[package]] @@ -5946,18 +5945,18 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.232.0" +version = "0.234.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917739b33bb1eb0e9a49bcd2637a351931be4578d0cc4d37b908d7a797784fbb" +checksum = "be22e5a8f600afce671dd53c8d2dd26b4b7aa810fd18ae27dfc49737f3e02fc5" dependencies = [ "bitflags", ] [[package]] name = "wasmparser" -version = "0.233.0" +version = "0.235.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51cb03afce7964bbfce46602d6cb358726f36430b6ba084ac6020d8ce5bc102" +checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ "bitflags", "indexmap", @@ -5966,22 +5965,22 @@ dependencies = [ [[package]] name = "wast" -version = "233.0.0" +version = "235.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eaf4099d8d0c922b83bf3c90663f5666f0769db9e525184284ebbbdb1dd2180" +checksum = "1eda4293f626c99021bb3a6fbe4fbbe90c0e31a5ace89b5f620af8925de72e13" dependencies = [ "bumpalo", "leb128fmt", "memchr", - "unicode-width 0.2.0", - "wasm-encoder 0.233.0", + "unicode-width 0.2.1", + "wasm-encoder 0.235.0", ] [[package]] name = "wat" -version = "1.233.0" +version = "1.235.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d9bc80f5e4b25ea086ef41b91ccd244adde45d931c384d94a8ff64ab8bd7d87" +checksum = "e777e0327115793cb96ab220b98f85327ec3d11f34ec9e8d723264522ef206aa" dependencies = [ "wast", ] @@ -6029,9 +6028,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.61.1" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", "windows-core", @@ -6092,7 +6091,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6103,14 +6102,14 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-numerics" @@ -6167,6 +6166,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -6200,9 +6208,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", @@ -6372,9 +6380,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -6507,7 +6515,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "synstructure", ] @@ -6519,7 +6527,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "synstructure", ] @@ -6540,7 +6548,7 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6560,7 +6568,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", "synstructure", ] @@ -6605,7 +6613,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] [[package]] @@ -6616,5 +6624,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.103", ] diff --git a/library/Cargo.lock b/library/Cargo.lock index 1bd97e7b5273..c7d59655ea46 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -141,9 +141,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" dependencies = [ "rustc-std-workspace-core", ] diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index ed67fa7d1a9e..3e83a2168ff1 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -156,18 +156,18 @@ checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "cc" -version = "1.2.26" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "chrono" @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -208,18 +208,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.52" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a554639e42d0c838336fc4fbedb9e2df3ad1fa4acda149f9126b4ccfcd7900f" +checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", @@ -229,9 +229,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" @@ -527,11 +527,11 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" dependencies = [ - "unicode-width 0.1.14", + "unicode-width", ] [[package]] @@ -768,9 +768,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ "jiff-static", "log", @@ -781,9 +781,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", @@ -808,9 +808,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" [[package]] name = "linereader" @@ -966,15 +966,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] @@ -1325,7 +1325,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5b8e8a7c20c600f9b98cbf46b64e63d5c9e69deb98cee1ff264de9f1dda5d" dependencies = [ - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -1345,9 +1345,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "redox_syscall" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.1", ] @@ -1548,9 +1548,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", @@ -1760,15 +1760,9 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-width" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "url" @@ -1940,9 +1934,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-result" @@ -2037,9 +2031,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] From e627f88f88de85cc52ff1c99a076909084806c98 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sun, 19 Jan 2025 22:01:11 +0800 Subject: [PATCH 042/356] Implement pinned borrows, part of `pin_ergonomics` --- compiler/rustc_ast/src/ast.rs | 4 + .../rustc_ast_pretty/src/pprust/state/expr.rs | 4 + .../rustc_const_eval/src/check_consts/ops.rs | 12 +- compiler/rustc_hir_pretty/src/lib.rs | 4 + compiler/rustc_hir_typeck/src/expr.rs | 8 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 25 ++++ compiler/rustc_parse/src/parser/expr.rs | 7 +- src/tools/rustfmt/src/expr.rs | 2 + src/tools/rustfmt/tests/source/pin_sugar.rs | 10 ++ src/tools/rustfmt/tests/target/pin_sugar.rs | 7 + tests/pretty/pin-ergonomics-hir.pp | 43 +++++++ tests/pretty/pin-ergonomics-hir.rs | 40 ++++++ tests/pretty/pin-ergonomics.rs | 14 ++ .../pin-ergonomics/borrow-mut-xor-share.rs | 59 +++++++++ .../borrow-mut-xor-share.stderr | 121 ++++++++++++++++++ tests/ui/async-await/pin-ergonomics/borrow.rs | 31 +++++ .../feature-gate-pin_ergonomics.rs | 28 ++++ .../feature-gate-pin_ergonomics.stderr | 70 ++++++++-- 18 files changed, 471 insertions(+), 18 deletions(-) create mode 100644 tests/pretty/pin-ergonomics-hir.pp create mode 100644 tests/pretty/pin-ergonomics-hir.rs create mode 100644 tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs create mode 100644 tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr create mode 100644 tests/ui/async-await/pin-ergonomics/borrow.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 6b51cbd7fbeb..40f0ac6dea34 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -898,6 +898,10 @@ pub enum BorrowKind { /// The resulting type is either `*const T` or `*mut T` /// where `T = typeof($expr)`. Raw, + /// A pinned borrow, `&pin const $expr` or `&pin mut $expr`. + /// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>` + /// where `T = typeof($expr)` and `'a` is some lifetime. + Pin, } #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ee49246a4bbf..32c14e5fe157 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -357,6 +357,10 @@ impl<'a> State<'a> { self.word_nbsp("raw"); self.print_mutability(mutability, true); } + ast::BorrowKind::Pin => { + self.word_nbsp("pin"); + self.print_mutability(mutability, true); + } } self.print_expr_cond_paren( expr, diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 9c30dbff99eb..1bba3fe7ec30 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -616,11 +616,13 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow { kind: ccx.const_kind(), teach: ccx.tcx.sess.teach(E0764), }), - hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping { - span, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764), - }), + hir::BorrowKind::Ref | hir::BorrowKind::Pin => { + ccx.dcx().create_err(errors::MutableRefEscaping { + span, + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(E0764), + }) + } } } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b23b3125c59a..23d37facaa34 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1339,6 +1339,10 @@ impl<'a> State<'a> { self.word_nbsp("raw"); self.print_mutability(mutability, true); } + hir::BorrowKind::Pin => { + self.word_nbsp("pin"); + self.print_mutability(mutability, true); + } } self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix); } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 30bf557dc93a..b87907f84601 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -664,7 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_named_place_expr(oprnd); Ty::new_ptr(self.tcx, ty, mutbl) } - hir::BorrowKind::Ref => { + hir::BorrowKind::Ref | hir::BorrowKind::Pin => { // Note: at this point, we cannot say what the best lifetime // is to use for resulting pointer. We want to use the // shortest lifetime possible so as to avoid spurious borrowck @@ -680,7 +680,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // whose address was taken can actually be made to live as long // as it needs to live. let region = self.next_region_var(infer::BorrowRegion(expr.span)); - Ty::new_ref(self.tcx, region, ty, mutbl) + match kind { + hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl), + hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl), + _ => unreachable!(), + } } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 3baeccf64094..52de0395ab64 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -479,6 +479,31 @@ impl<'tcx> ThirBuildCx<'tcx> { ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) } } + // Make `&pin mut $expr` and `&pin const $expr` into + // `Pin { __pointer: &mut $expr }` and `Pin { __pointer: &$expr }`. + hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg) => match expr_ty.kind() { + &ty::Adt(adt_def, args) + if tcx.is_lang_item(adt_def.did(), rustc_hir::LangItem::Pin) => + { + let arg = self.mirror_expr(arg); + let expr = self.thir.exprs.push(Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: args.type_at(0), + span: expr.span, + kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg }, + }); + ExprKind::Adt(Box::new(AdtExpr { + adt_def, + variant_index: FIRST_VARIANT, + args, + fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]), + user_ty: None, + base: AdtExprBase::None, + })) + } + _ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty), + }, + hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) }, hir::ExprKind::Assign(lhs, rhs, _) => { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93489aa8ee94..b64b50cf1873 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -847,7 +847,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span }); } - /// Parse `mut?` or `raw [ const | mut ]`. + /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`. fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) { if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) { // `raw [ const | mut ]`. @@ -855,6 +855,11 @@ impl<'a> Parser<'a> { assert!(found_raw); let mutability = self.parse_const_or_mut().unwrap(); (ast::BorrowKind::Raw, mutability) + } else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() { + // `pin [ const | mut ]`. + // `pin` has been gated in `self.parse_pin_and_mut()` so we don't + // need to gate it here. + (ast::BorrowKind::Pin, mutbl) } else { // `mut?` (ast::BorrowKind::Ref, self.parse_mutability()) diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index be6b483bfff1..08aedff2b20d 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -2289,8 +2289,10 @@ fn rewrite_expr_addrof( ) -> RewriteResult { let operator_str = match (mutability, borrow_kind) { (ast::Mutability::Not, ast::BorrowKind::Ref) => "&", + (ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ", (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ", (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ", + (ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ", (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ", }; rewrite_unary_prefix(context, operator_str, expr, shape) diff --git a/src/tools/rustfmt/tests/source/pin_sugar.rs b/src/tools/rustfmt/tests/source/pin_sugar.rs index 370dfbc196ae..e5b47339b928 100644 --- a/src/tools/rustfmt/tests/source/pin_sugar.rs +++ b/src/tools/rustfmt/tests/source/pin_sugar.rs @@ -18,3 +18,13 @@ impl Foo { mut self) {} fn i(&pin mut self) {} } + +fn borrows() { + let mut foo = 0_i32; + let x: Pin<&mut _> = & pin + mut foo; + + let x: Pin<&_> = & + pin const + foo; +} diff --git a/src/tools/rustfmt/tests/target/pin_sugar.rs b/src/tools/rustfmt/tests/target/pin_sugar.rs index 7d04efb1b326..09ad23a5807f 100644 --- a/src/tools/rustfmt/tests/target/pin_sugar.rs +++ b/src/tools/rustfmt/tests/target/pin_sugar.rs @@ -16,3 +16,10 @@ impl Foo { fn h<'a>(&'a pin mut self) {} fn i(&pin mut self) {} } + +fn borrows() { + let mut foo = 0_i32; + let x: Pin<&mut _> = &pin mut foo; + + let x: Pin<&_> = &pin const foo; +} diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp new file mode 100644 index 000000000000..42405982f92c --- /dev/null +++ b/tests/pretty/pin-ergonomics-hir.pp @@ -0,0 +1,43 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:pin-ergonomics-hir.pp + +#![feature(pin_ergonomics)]#![allow(dead_code, incomplete_features)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; + +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn baz(&mut self) { } + + fn baz_const(&self) { } + + fn baz_lt<'a>(&mut self) { } + + fn baz_const_lt(&self) { } +} + +fn foo(_: Pin<&'_ mut Foo>) { } +fn foo_lt<'a>(_: Pin<&'a mut Foo>) { } + +fn foo_const(_: Pin<&'_ Foo>) { } +fn foo_const_lt(_: Pin<&'_ Foo>) { } + +fn bar() { + let mut x: Pin<&mut _> = &pin mut Foo; + foo(x.as_mut()); + foo(x.as_mut()); + foo_const(x); + + let x: Pin<&_> = &pin const Foo; + + foo_const(x); + foo_const(x); +} + +fn main() { } diff --git a/tests/pretty/pin-ergonomics-hir.rs b/tests/pretty/pin-ergonomics-hir.rs new file mode 100644 index 000000000000..5f2158258f07 --- /dev/null +++ b/tests/pretty/pin-ergonomics-hir.rs @@ -0,0 +1,40 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:pin-ergonomics-hir.pp + +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn baz(&mut self) { } + + fn baz_const(&self) { } + + fn baz_lt<'a>(&mut self) { } + + fn baz_const_lt(&self) { } +} + +fn foo(_: Pin<&'_ mut Foo>) { } +fn foo_lt<'a>(_: Pin<&'a mut Foo>) { } + +fn foo_const(_: Pin<&'_ Foo>) { } +fn foo_const_lt(_: Pin<&'_ Foo>) { } + +fn bar() { + let mut x: Pin<&mut _> = &pin mut Foo; + foo(x.as_mut()); + foo(x.as_mut()); + foo_const(x); + + let x: Pin<&_> = &pin const Foo; + + foo_const(x); + foo_const(x); +} + +fn main() { } diff --git a/tests/pretty/pin-ergonomics.rs b/tests/pretty/pin-ergonomics.rs index 47ffc97b1183..54a57545c553 100644 --- a/tests/pretty/pin-ergonomics.rs +++ b/tests/pretty/pin-ergonomics.rs @@ -3,6 +3,8 @@ #![feature(pin_ergonomics)] #![allow(dead_code, incomplete_features)] +use std::pin::Pin; + struct Foo; impl Foo { @@ -21,4 +23,16 @@ fn foo_lt<'a>(_: &'a pin mut Foo) {} fn foo_const(_: &pin const Foo) {} fn foo_const_lt(_: &'_ pin const Foo) {} +fn bar() { + let mut x: Pin<&mut _> = &pin mut Foo; + foo(x.as_mut()); + foo(x.as_mut()); + foo_const(x); + + let x: Pin<&_> = &pin const Foo; + + foo_const(x); + foo_const(x); +} + fn main() {} diff --git a/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs b/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs new file mode 100644 index 000000000000..c5363eafef5a --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs @@ -0,0 +1,59 @@ +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// Makes sure `&pin mut place` and `&pin const place` cannot violate the mut-xor-share rules. + +use std::pin::Pin; + +struct Foo; + +fn foo_mut(_: &mut Foo) { +} + +fn foo_ref(_: &Foo) { +} + +fn foo_pin_mut(_: Pin<&mut Foo>) { +} + +fn foo_pin_ref(_: Pin<&Foo>) { +} + +fn bar() { + let foo = Foo; + foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable + + let mut foo = Foo; + let x = &pin mut foo; + foo_pin_ref(&pin const foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time + foo_ref(&foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time + + foo_pin_mut(x); + + let mut foo = Foo; + let x = &pin const foo; + foo_pin_ref(&pin const foo); // ok + foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable + foo_ref(&foo); // ok + foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable + + foo_pin_ref(x); + + let mut foo = Foo; + let x = &mut foo; + foo_pin_ref(&pin const foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time + + foo_mut(x); + + let mut foo = Foo; + let x = &foo; + foo_pin_ref(&pin const foo); // ok + foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable + + foo_ref(x); +} + +fn main() {} diff --git a/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr b/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr new file mode 100644 index 000000000000..47d990b2ec91 --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr @@ -0,0 +1,121 @@ +error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable + --> $DIR/borrow-mut-xor-share.rs:24:17 + | +LL | foo_pin_mut(&pin mut foo); + | ^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut foo = Foo; + | +++ + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/borrow-mut-xor-share.rs:28:17 + | +LL | let x = &pin mut foo; + | ------------ mutable borrow occurs here +LL | foo_pin_ref(&pin const foo); + | ^^^^^^^^^^^^^^ immutable borrow occurs here +... +LL | foo_pin_mut(x); + | - mutable borrow later used here + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/borrow-mut-xor-share.rs:29:17 + | +LL | let x = &pin mut foo; + | ------------ first mutable borrow occurs here +LL | foo_pin_ref(&pin const foo); +LL | foo_pin_mut(&pin mut foo); + | ^^^^^^^^^^^^ second mutable borrow occurs here +... +LL | foo_pin_mut(x); + | - first borrow later used here + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/borrow-mut-xor-share.rs:30:13 + | +LL | let x = &pin mut foo; + | ------------ mutable borrow occurs here +... +LL | foo_ref(&foo); + | ^^^^ immutable borrow occurs here +... +LL | foo_pin_mut(x); + | - mutable borrow later used here + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/borrow-mut-xor-share.rs:31:13 + | +LL | let x = &pin mut foo; + | ------------ first mutable borrow occurs here +... +LL | foo_mut(&mut foo); + | ^^^^^^^^ second mutable borrow occurs here +LL | +LL | foo_pin_mut(x); + | - first borrow later used here + +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrow-mut-xor-share.rs:38:17 + | +LL | let x = &pin const foo; + | -------------- immutable borrow occurs here +LL | foo_pin_ref(&pin const foo); // ok +LL | foo_pin_mut(&pin mut foo); + | ^^^^^^^^^^^^ mutable borrow occurs here +... +LL | foo_pin_ref(x); + | - immutable borrow later used here + +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrow-mut-xor-share.rs:40:13 + | +LL | let x = &pin const foo; + | -------------- immutable borrow occurs here +... +LL | foo_mut(&mut foo); + | ^^^^^^^^ mutable borrow occurs here +LL | +LL | foo_pin_ref(x); + | - immutable borrow later used here + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/borrow-mut-xor-share.rs:46:17 + | +LL | let x = &mut foo; + | -------- mutable borrow occurs here +LL | foo_pin_ref(&pin const foo); + | ^^^^^^^^^^^^^^ immutable borrow occurs here +... +LL | foo_mut(x); + | - mutable borrow later used here + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/borrow-mut-xor-share.rs:47:17 + | +LL | let x = &mut foo; + | -------- first mutable borrow occurs here +LL | foo_pin_ref(&pin const foo); +LL | foo_pin_mut(&pin mut foo); + | ^^^^^^^^^^^^ second mutable borrow occurs here +LL | +LL | foo_mut(x); + | - first borrow later used here + +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrow-mut-xor-share.rs:54:17 + | +LL | let x = &foo; + | ---- immutable borrow occurs here +LL | foo_pin_ref(&pin const foo); // ok +LL | foo_pin_mut(&pin mut foo); + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | foo_ref(x); + | - immutable borrow later used here + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0499, E0502, E0596. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/async-await/pin-ergonomics/borrow.rs b/tests/ui/async-await/pin-ergonomics/borrow.rs new file mode 100644 index 000000000000..e33f3c1fa26f --- /dev/null +++ b/tests/ui/async-await/pin-ergonomics/borrow.rs @@ -0,0 +1,31 @@ +//@ check-pass + +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// Makes sure we can handle `&pin mut place` and `&pin const place` as sugar for +// `unsafe { Pin::new_unchecked(&mut place) }` and `Pin::new(&place)`. + +use std::pin::Pin; + +struct Foo; + +fn foo_pin_mut(_: Pin<&mut Foo>) { +} + +fn foo_pin_ref(_: Pin<&Foo>) { +} + +fn bar() { + let mut x: Pin<&mut _> = &pin mut Foo; + foo_pin_mut(x.as_mut()); + foo_pin_mut(x.as_mut()); + foo_pin_ref(x); + + let x: Pin<&_> = &pin const Foo; + + foo_pin_ref(x); + foo_pin_ref(x); +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 663a83a665c4..7746654555dd 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -17,6 +17,10 @@ fn foo(mut x: Pin<&mut Foo>) { let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental } +fn foo_const(x: Pin<&Foo>) { + let _y: &pin const Foo = x; //~ ERROR pinned reference syntax is experimental +} + fn foo_sugar(_: &pin mut Foo) {} //~ ERROR pinned reference syntax is experimental fn bar(x: Pin<&mut Foo>) { @@ -31,6 +35,18 @@ fn baz(mut x: Pin<&mut Foo>) { fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental +fn borrows() { + let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental + foo(x.as_mut()); + foo(x.as_mut()); + foo_const(x.as_ref()); + + let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental + + foo_const(x); + foo_const(x); +} + #[cfg(any())] mod not_compiled { use std::pin::Pin; @@ -63,6 +79,18 @@ mod not_compiled { } fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental + + fn borrows() { + let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental + foo(x.as_mut()); + foo(x.as_mut()); + foo_const(x.as_ref()); + + let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental + + foo_const(x); + foo_const(x); + } } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index 8ed7543d86e3..a8890254face 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -29,7 +29,17 @@ LL | let _y: &pin mut Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:20:18 + --> $DIR/feature-gate-pin_ergonomics.rs:21:14 + | +LL | let _y: &pin const Foo = x; + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` 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]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:24:18 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -39,7 +49,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:32:18 + --> $DIR/feature-gate-pin_ergonomics.rs:36:18 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -49,7 +59,27 @@ LL | fn baz_sugar(_: &pin const Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:43:23 + --> $DIR/feature-gate-pin_ergonomics.rs:39:31 + | +LL | let mut x: Pin<&mut _> = &pin mut Foo; + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` 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]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:44:23 + | +LL | let x: Pin<&_> = &pin const Foo; + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` 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]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:59:23 | LL | fn foo_sugar(&pin mut self) {} | ^^^ @@ -59,7 +89,7 @@ LL | fn foo_sugar(&pin mut self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:44:29 + --> $DIR/feature-gate-pin_ergonomics.rs:60:29 | LL | fn foo_sugar_const(&pin const self) {} | ^^^ @@ -69,7 +99,7 @@ LL | fn foo_sugar_const(&pin const self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:50:18 + --> $DIR/feature-gate-pin_ergonomics.rs:66:18 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -79,7 +109,7 @@ LL | let _y: &pin mut Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:53:22 + --> $DIR/feature-gate-pin_ergonomics.rs:69:22 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -89,7 +119,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:65:22 + --> $DIR/feature-gate-pin_ergonomics.rs:81:22 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -98,8 +128,28 @@ LL | fn baz_sugar(_: &pin const Foo) {} = help: add `#![feature(pin_ergonomics)]` 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]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:84:35 + | +LL | let mut x: Pin<&mut _> = &pin mut Foo; + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` 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]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:89:27 + | +LL | let x: Pin<&_> = &pin const Foo; + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` 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[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:24:9 + --> $DIR/feature-gate-pin_ergonomics.rs:28:9 | LL | fn bar(x: Pin<&mut Foo>) { | - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -117,7 +167,7 @@ LL | fn foo(mut x: Pin<&mut Foo>) { | in this function error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:29:5 + --> $DIR/feature-gate-pin_ergonomics.rs:33:5 | LL | fn baz(mut x: Pin<&mut Foo>) { | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -136,7 +186,7 @@ help: consider reborrowing the `Pin` instead of moving it LL | x.as_mut().foo(); | +++++++++ -error: aborting due to 12 previous errors +error: aborting due to 17 previous errors Some errors have detailed explanations: E0382, E0658. For more information about an error, try `rustc --explain E0382`. From 2090f40770c37b78af02c4db3ee8fdbefd438dcf Mon Sep 17 00:00:00 2001 From: Frank King Date: Sun, 16 Mar 2025 21:19:57 +0800 Subject: [PATCH 043/356] Move `tests/ui/async-await/pin-ergonomics` to `tests/ui` --- tests/ui/{async-await => }/pin-ergonomics/borrow-mut-xor-share.rs | 0 .../{async-await => }/pin-ergonomics/borrow-mut-xor-share.stderr | 0 tests/ui/{async-await => }/pin-ergonomics/borrow.rs | 0 .../ui/{async-await => }/pin-ergonomics/coerce-non-pointer-pin.rs | 0 .../pin-ergonomics/coerce-non-pointer-pin.stderr | 0 tests/ui/{async-await => }/pin-ergonomics/reborrow-arg.rs | 0 .../ui/{async-await => }/pin-ergonomics/reborrow-const-as-mut.rs | 0 .../{async-await => }/pin-ergonomics/reborrow-const-as-mut.stderr | 0 tests/ui/{async-await => }/pin-ergonomics/reborrow-once.rs | 0 tests/ui/{async-await => }/pin-ergonomics/reborrow-once.stderr | 0 tests/ui/{async-await => }/pin-ergonomics/reborrow-self.rs | 0 tests/ui/{async-await => }/pin-ergonomics/reborrow-shorter.rs | 0 tests/ui/{async-await => }/pin-ergonomics/sugar-ambiguity.rs | 0 tests/ui/{async-await => }/pin-ergonomics/sugar-no-const.rs | 0 tests/ui/{async-await => }/pin-ergonomics/sugar-no-const.stderr | 0 tests/ui/{async-await => }/pin-ergonomics/sugar-self.rs | 0 tests/ui/{async-await => }/pin-ergonomics/sugar.rs | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{async-await => }/pin-ergonomics/borrow-mut-xor-share.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/borrow-mut-xor-share.stderr (100%) rename tests/ui/{async-await => }/pin-ergonomics/borrow.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/coerce-non-pointer-pin.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/coerce-non-pointer-pin.stderr (100%) rename tests/ui/{async-await => }/pin-ergonomics/reborrow-arg.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/reborrow-const-as-mut.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/reborrow-const-as-mut.stderr (100%) rename tests/ui/{async-await => }/pin-ergonomics/reborrow-once.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/reborrow-once.stderr (100%) rename tests/ui/{async-await => }/pin-ergonomics/reborrow-self.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/reborrow-shorter.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/sugar-ambiguity.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/sugar-no-const.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/sugar-no-const.stderr (100%) rename tests/ui/{async-await => }/pin-ergonomics/sugar-self.rs (100%) rename tests/ui/{async-await => }/pin-ergonomics/sugar.rs (100%) diff --git a/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs b/tests/ui/pin-ergonomics/borrow-mut-xor-share.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs rename to tests/ui/pin-ergonomics/borrow-mut-xor-share.rs diff --git a/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr b/tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr similarity index 100% rename from tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr rename to tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr diff --git a/tests/ui/async-await/pin-ergonomics/borrow.rs b/tests/ui/pin-ergonomics/borrow.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/borrow.rs rename to tests/ui/pin-ergonomics/borrow.rs diff --git a/tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.rs b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.rs rename to tests/ui/pin-ergonomics/coerce-non-pointer-pin.rs diff --git a/tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.stderr b/tests/ui/pin-ergonomics/coerce-non-pointer-pin.stderr similarity index 100% rename from tests/ui/async-await/pin-ergonomics/coerce-non-pointer-pin.stderr rename to tests/ui/pin-ergonomics/coerce-non-pointer-pin.stderr diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-arg.rs b/tests/ui/pin-ergonomics/reborrow-arg.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/reborrow-arg.rs rename to tests/ui/pin-ergonomics/reborrow-arg.rs diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.rs b/tests/ui/pin-ergonomics/reborrow-const-as-mut.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.rs rename to tests/ui/pin-ergonomics/reborrow-const-as-mut.rs diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.stderr b/tests/ui/pin-ergonomics/reborrow-const-as-mut.stderr similarity index 100% rename from tests/ui/async-await/pin-ergonomics/reborrow-const-as-mut.stderr rename to tests/ui/pin-ergonomics/reborrow-const-as-mut.stderr diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-once.rs b/tests/ui/pin-ergonomics/reborrow-once.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/reborrow-once.rs rename to tests/ui/pin-ergonomics/reborrow-once.rs diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr b/tests/ui/pin-ergonomics/reborrow-once.stderr similarity index 100% rename from tests/ui/async-await/pin-ergonomics/reborrow-once.stderr rename to tests/ui/pin-ergonomics/reborrow-once.stderr diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-self.rs b/tests/ui/pin-ergonomics/reborrow-self.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/reborrow-self.rs rename to tests/ui/pin-ergonomics/reborrow-self.rs diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-shorter.rs b/tests/ui/pin-ergonomics/reborrow-shorter.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/reborrow-shorter.rs rename to tests/ui/pin-ergonomics/reborrow-shorter.rs diff --git a/tests/ui/async-await/pin-ergonomics/sugar-ambiguity.rs b/tests/ui/pin-ergonomics/sugar-ambiguity.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/sugar-ambiguity.rs rename to tests/ui/pin-ergonomics/sugar-ambiguity.rs diff --git a/tests/ui/async-await/pin-ergonomics/sugar-no-const.rs b/tests/ui/pin-ergonomics/sugar-no-const.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/sugar-no-const.rs rename to tests/ui/pin-ergonomics/sugar-no-const.rs diff --git a/tests/ui/async-await/pin-ergonomics/sugar-no-const.stderr b/tests/ui/pin-ergonomics/sugar-no-const.stderr similarity index 100% rename from tests/ui/async-await/pin-ergonomics/sugar-no-const.stderr rename to tests/ui/pin-ergonomics/sugar-no-const.stderr diff --git a/tests/ui/async-await/pin-ergonomics/sugar-self.rs b/tests/ui/pin-ergonomics/sugar-self.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/sugar-self.rs rename to tests/ui/pin-ergonomics/sugar-self.rs diff --git a/tests/ui/async-await/pin-ergonomics/sugar.rs b/tests/ui/pin-ergonomics/sugar.rs similarity index 100% rename from tests/ui/async-await/pin-ergonomics/sugar.rs rename to tests/ui/pin-ergonomics/sugar.rs From afdb54a673243c83660417b540af888f7690f0fb Mon Sep 17 00:00:00 2001 From: Frank King Date: Fri, 4 Apr 2025 12:15:23 +0800 Subject: [PATCH 044/356] Move the place in `&pin mut $place` when `!Unpin` to ensure soundness --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 38 ++- tests/pretty/pin-ergonomics-hir.pp | 3 +- tests/pretty/pin-ergonomics.rs | 1 - .../ui/pin-ergonomics/borrow-mut-xor-share.rs | 59 ----- .../borrow-mut-xor-share.stderr | 121 --------- .../pin-ergonomics/borrow-unpin.pinned.stderr | 238 ++++++++++++++++++ tests/ui/pin-ergonomics/borrow-unpin.rs | 143 +++++++++++ .../pin-ergonomics/borrow-unpin.unpin.stderr | 136 ++++++++++ tests/ui/pin-ergonomics/borrow.rs | 11 +- 9 files changed, 559 insertions(+), 191 deletions(-) delete mode 100644 tests/ui/pin-ergonomics/borrow-mut-xor-share.rs delete mode 100644 tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr create mode 100644 tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr create mode 100644 tests/ui/pin-ergonomics/borrow-unpin.rs create mode 100644 tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 52de0395ab64..764b7efe2a3e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -480,15 +480,39 @@ impl<'tcx> ThirBuildCx<'tcx> { } // Make `&pin mut $expr` and `&pin const $expr` into - // `Pin { __pointer: &mut $expr }` and `Pin { __pointer: &$expr }`. - hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg) => match expr_ty.kind() { - &ty::Adt(adt_def, args) - if tcx.is_lang_item(adt_def.did(), rustc_hir::LangItem::Pin) => - { - let arg = self.mirror_expr(arg); + // `Pin { __pointer: &mut { $expr } }` and `Pin { __pointer: &$expr }`. + hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg_expr) => match expr_ty.kind() { + &ty::Adt(adt_def, args) if tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) => { + let ty = args.type_at(0); + let arg_ty = self.typeck_results.expr_ty(arg_expr); + let mut arg = self.mirror_expr(arg_expr); + // For `&pin mut $place` where `$place` is not `Unpin`, move the place + // `$place` to ensure it will not be used afterwards. + if mutbl.is_mut() && !arg_ty.is_unpin(self.tcx, self.typing_env) { + let block = self.thir.blocks.push(Block { + targeted_by_break: false, + region_scope: region::Scope { + local_id: arg_expr.hir_id.local_id, + data: region::ScopeData::Node, + }, + span: arg_expr.span, + stmts: Box::new([]), + expr: Some(arg), + safety_mode: BlockSafety::Safe, + }); + let (temp_lifetime, backwards_incompatible) = self + .rvalue_scopes + .temporary_scope(self.region_scope_tree, arg_expr.hir_id.local_id); + arg = self.thir.exprs.push(Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: arg_ty, + span: arg_expr.span, + kind: ExprKind::Block { block }, + }); + } let expr = self.thir.exprs.push(Expr { temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, - ty: args.type_at(0), + ty, span: expr.span, kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg }, }); diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp index 42405982f92c..212e0e174dae 100644 --- a/tests/pretty/pin-ergonomics-hir.pp +++ b/tests/pretty/pin-ergonomics-hir.pp @@ -2,7 +2,8 @@ //@ pretty-mode:hir //@ pp-exact:pin-ergonomics-hir.pp -#![feature(pin_ergonomics)]#![allow(dead_code, incomplete_features)] +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] diff --git a/tests/pretty/pin-ergonomics.rs b/tests/pretty/pin-ergonomics.rs index 54a57545c553..8e8ced791b13 100644 --- a/tests/pretty/pin-ergonomics.rs +++ b/tests/pretty/pin-ergonomics.rs @@ -30,7 +30,6 @@ fn bar() { foo_const(x); let x: Pin<&_> = &pin const Foo; - foo_const(x); foo_const(x); } diff --git a/tests/ui/pin-ergonomics/borrow-mut-xor-share.rs b/tests/ui/pin-ergonomics/borrow-mut-xor-share.rs deleted file mode 100644 index c5363eafef5a..000000000000 --- a/tests/ui/pin-ergonomics/borrow-mut-xor-share.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![feature(pin_ergonomics)] -#![allow(dead_code, incomplete_features)] - -// Makes sure `&pin mut place` and `&pin const place` cannot violate the mut-xor-share rules. - -use std::pin::Pin; - -struct Foo; - -fn foo_mut(_: &mut Foo) { -} - -fn foo_ref(_: &Foo) { -} - -fn foo_pin_mut(_: Pin<&mut Foo>) { -} - -fn foo_pin_ref(_: Pin<&Foo>) { -} - -fn bar() { - let foo = Foo; - foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable - - let mut foo = Foo; - let x = &pin mut foo; - foo_pin_ref(&pin const foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable - foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time - foo_ref(&foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable - foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time - - foo_pin_mut(x); - - let mut foo = Foo; - let x = &pin const foo; - foo_pin_ref(&pin const foo); // ok - foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable - foo_ref(&foo); // ok - foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable - - foo_pin_ref(x); - - let mut foo = Foo; - let x = &mut foo; - foo_pin_ref(&pin const foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable - foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time - - foo_mut(x); - - let mut foo = Foo; - let x = &foo; - foo_pin_ref(&pin const foo); // ok - foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable - - foo_ref(x); -} - -fn main() {} diff --git a/tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr b/tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr deleted file mode 100644 index 47d990b2ec91..000000000000 --- a/tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr +++ /dev/null @@ -1,121 +0,0 @@ -error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable - --> $DIR/borrow-mut-xor-share.rs:24:17 - | -LL | foo_pin_mut(&pin mut foo); - | ^^^^^^^^^^^^ cannot borrow as mutable - | -help: consider changing this to be mutable - | -LL | let mut foo = Foo; - | +++ - -error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrow-mut-xor-share.rs:28:17 - | -LL | let x = &pin mut foo; - | ------------ mutable borrow occurs here -LL | foo_pin_ref(&pin const foo); - | ^^^^^^^^^^^^^^ immutable borrow occurs here -... -LL | foo_pin_mut(x); - | - mutable borrow later used here - -error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/borrow-mut-xor-share.rs:29:17 - | -LL | let x = &pin mut foo; - | ------------ first mutable borrow occurs here -LL | foo_pin_ref(&pin const foo); -LL | foo_pin_mut(&pin mut foo); - | ^^^^^^^^^^^^ second mutable borrow occurs here -... -LL | foo_pin_mut(x); - | - first borrow later used here - -error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrow-mut-xor-share.rs:30:13 - | -LL | let x = &pin mut foo; - | ------------ mutable borrow occurs here -... -LL | foo_ref(&foo); - | ^^^^ immutable borrow occurs here -... -LL | foo_pin_mut(x); - | - mutable borrow later used here - -error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/borrow-mut-xor-share.rs:31:13 - | -LL | let x = &pin mut foo; - | ------------ first mutable borrow occurs here -... -LL | foo_mut(&mut foo); - | ^^^^^^^^ second mutable borrow occurs here -LL | -LL | foo_pin_mut(x); - | - first borrow later used here - -error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable - --> $DIR/borrow-mut-xor-share.rs:38:17 - | -LL | let x = &pin const foo; - | -------------- immutable borrow occurs here -LL | foo_pin_ref(&pin const foo); // ok -LL | foo_pin_mut(&pin mut foo); - | ^^^^^^^^^^^^ mutable borrow occurs here -... -LL | foo_pin_ref(x); - | - immutable borrow later used here - -error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable - --> $DIR/borrow-mut-xor-share.rs:40:13 - | -LL | let x = &pin const foo; - | -------------- immutable borrow occurs here -... -LL | foo_mut(&mut foo); - | ^^^^^^^^ mutable borrow occurs here -LL | -LL | foo_pin_ref(x); - | - immutable borrow later used here - -error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrow-mut-xor-share.rs:46:17 - | -LL | let x = &mut foo; - | -------- mutable borrow occurs here -LL | foo_pin_ref(&pin const foo); - | ^^^^^^^^^^^^^^ immutable borrow occurs here -... -LL | foo_mut(x); - | - mutable borrow later used here - -error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/borrow-mut-xor-share.rs:47:17 - | -LL | let x = &mut foo; - | -------- first mutable borrow occurs here -LL | foo_pin_ref(&pin const foo); -LL | foo_pin_mut(&pin mut foo); - | ^^^^^^^^^^^^ second mutable borrow occurs here -LL | -LL | foo_mut(x); - | - first borrow later used here - -error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable - --> $DIR/borrow-mut-xor-share.rs:54:17 - | -LL | let x = &foo; - | ---- immutable borrow occurs here -LL | foo_pin_ref(&pin const foo); // ok -LL | foo_pin_mut(&pin mut foo); - | ^^^^^^^^^^^^ mutable borrow occurs here -LL | -LL | foo_ref(x); - | - immutable borrow later used here - -error: aborting due to 10 previous errors - -Some errors have detailed explanations: E0499, E0502, E0596. -For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr b/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr new file mode 100644 index 000000000000..cc438461a5d1 --- /dev/null +++ b/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr @@ -0,0 +1,238 @@ +error[E0382]: use of moved value: `foo` + --> $DIR/borrow-unpin.rs:39:14 + | +LL | let foo = Foo::default(); + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | foo_pin_mut(&pin mut foo); + | --- value moved here +LL | foo_move(foo); + | ^^^ value used here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | foo_pin_mut(&pin mut foo); + | --- you could clone this value + +error[E0382]: use of moved value: `foo` + --> $DIR/borrow-unpin.rs:43:14 + | +LL | let foo = Foo::default(); + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | let x = &pin mut foo; + | --- value moved here +LL | foo_move(foo); + | ^^^ value used here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin mut foo; + | --- you could clone this value + +error[E0382]: use of moved value: `foo` + --> $DIR/borrow-unpin.rs:52:14 + | +LL | let mut foo = Foo::default(); + | ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | foo_pin_mut(&pin mut foo); // ok + | --- value moved here +LL | foo_move(foo); + | ^^^ value used here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | foo_pin_mut(&pin mut foo); // ok + | --- you could clone this value + +error[E0382]: use of moved value: `foo` + --> $DIR/borrow-unpin.rs:56:14 + | +LL | let mut foo = Foo::default(); + | ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | let x = &pin mut foo; // ok + | --- value moved here +LL | foo_move(foo); + | ^^^ value used here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin mut foo; // ok + | --- you could clone this value + +error[E0505]: cannot move out of `foo` because it is borrowed + --> $DIR/borrow-unpin.rs:68:14 + | +LL | let foo = Foo::default(); + | --- binding `foo` declared here +LL | let x = &pin const foo; // ok + | -------------- borrow of `foo` occurs here +LL | foo_move(foo); + | ^^^ move out of `foo` occurs here +LL | +LL | foo_pin_ref(x); + | - borrow later used here + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin const foo; // ok + | --- you could clone this value + +error[E0382]: borrow of moved value: `foo` + --> $DIR/borrow-unpin.rs:76:13 + | +LL | let mut foo = Foo::default(); + | ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | foo_pin_mut(&pin mut foo); // ok + | --- value moved here +LL | foo_ref(&foo); + | ^^^^ value borrowed here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | foo_pin_mut(&pin mut foo); // ok + | --- you could clone this value + +error[E0382]: borrow of moved value: `foo` + --> $DIR/borrow-unpin.rs:80:13 + | +LL | let mut foo = Foo::default(); + | ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | let x = &pin mut foo; // ok + | --- value moved here +LL | foo_ref(&foo); + | ^^^^ value borrowed here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin mut foo; // ok + | --- you could clone this value + +error[E0382]: use of moved value: `foo` + --> $DIR/borrow-unpin.rs:99:26 + | +LL | let mut foo = Foo::default(); + | ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | foo_pin_mut(&pin mut foo); // ok + | --- value moved here +LL | foo_pin_mut(&pin mut foo); + | ^^^ value used here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | foo_pin_mut(&pin mut foo); // ok + | --- you could clone this value + +error[E0382]: use of moved value: `foo` + --> $DIR/borrow-unpin.rs:103:26 + | +LL | let mut foo = Foo::default(); + | ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | let x = &pin mut foo; // ok + | --- value moved here +LL | foo_pin_mut(&pin mut foo); + | ^^^ value used here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin mut foo; // ok + | --- you could clone this value + +error[E0505]: cannot move out of `foo` because it is borrowed + --> $DIR/borrow-unpin.rs:115:26 + | +LL | let mut foo = Foo::default(); + | ------- binding `foo` declared here +LL | let x = &pin const foo; // ok + | -------------- borrow of `foo` occurs here +LL | foo_pin_mut(&pin mut foo); + | ^^^ move out of `foo` occurs here +LL | +LL | foo_pin_ref(x); + | - borrow later used here + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin const foo; // ok + | --- you could clone this value + +error[E0382]: borrow of moved value: `foo` + --> $DIR/borrow-unpin.rs:123:17 + | +LL | let mut foo = Foo::default(); + | ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | foo_pin_mut(&pin mut foo); // ok + | --- value moved here +LL | foo_pin_ref(&pin const foo); + | ^^^^^^^^^^^^^^ value borrowed here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | foo_pin_mut(&pin mut foo); // ok + | --- you could clone this value + +error[E0382]: borrow of moved value: `foo` + --> $DIR/borrow-unpin.rs:127:17 + | +LL | let mut foo = Foo::default(); + | ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | let x = &pin mut foo; // ok + | --- value moved here +LL | foo_pin_ref(&pin const foo); + | ^^^^^^^^^^^^^^ value borrowed here after move + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:16:1 + | +LL | struct Foo(PhantomPinned); + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin mut foo; // ok + | --- you could clone this value + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/pin-ergonomics/borrow-unpin.rs b/tests/ui/pin-ergonomics/borrow-unpin.rs new file mode 100644 index 000000000000..61e69bab12bc --- /dev/null +++ b/tests/ui/pin-ergonomics/borrow-unpin.rs @@ -0,0 +1,143 @@ +//@ revisions: unpin pinned +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// For now, in order to ensure soundness, we move the place in `&pin mut place` +// if `place` is not `Unpin`. +// In the next step, we borrow the place instead of moving it, after that we +// have to makes sure `&pin mut place` and `&pin const place` cannot violate +// the mut-xor-share rules. + +use std::pin::Pin; +use std::marker::PhantomPinned; + +#[cfg(pinned)] +#[derive(Default)] +struct Foo(PhantomPinned); + +#[cfg(unpin)] +#[derive(Default)] +struct Foo; + +fn foo_mut(_: &mut Foo) { +} + +fn foo_ref(_: &Foo) { +} + +fn foo_pin_mut(_: Pin<&mut Foo>) { +} + +fn foo_pin_ref(_: Pin<&Foo>) { +} + +fn foo_move(_: Foo) {} + +fn immutable_pin_mut_then_move() { + let foo = Foo::default(); + foo_pin_mut(&pin mut foo); //[unpin]~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable + foo_move(foo); //[pinned]~ ERROR use of moved value: `foo` + + let foo = Foo::default(); + let x = &pin mut foo; //[unpin]~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable + foo_move(foo); //[pinned]~ ERROR use of moved value: `foo` + //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed + foo_pin_mut(x); // +} + + +fn pin_mut_then_move() { + let mut foo = Foo::default(); + foo_pin_mut(&pin mut foo); // ok + foo_move(foo); //[pinned]~ ERROR use of moved value: `foo` + + let mut foo = Foo::default(); + let x = &pin mut foo; // ok + foo_move(foo); //[pinned]~ ERROR use of moved value: `foo` + //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed + foo_pin_mut(x); // +} + +fn pin_ref_then_move() { + let foo = Foo::default(); + foo_pin_ref(&pin const foo); // ok + foo_move(foo); // ok + + let foo = Foo::default(); + let x = &pin const foo; // ok + foo_move(foo); //[pinned]~ ERROR cannot move out of `foo` because it is borrowed + //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed + foo_pin_ref(x); +} + +fn pin_mut_then_ref() { + let mut foo = Foo::default(); + foo_pin_mut(&pin mut foo); // ok + foo_ref(&foo); //[pinned]~ ERROR borrow of moved value: `foo` + + let mut foo = Foo::default(); + let x = &pin mut foo; // ok + foo_ref(&foo); //[pinned]~ ERROR borrow of moved value: `foo` + //[unpin]~^ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + foo_pin_mut(x); +} + +fn pin_ref_then_ref() { + let mut foo = Foo::default(); + foo_pin_ref(&pin const foo); // ok + foo_ref(&foo); // ok + + let mut foo = Foo::default(); + let x = &pin const foo; // ok + foo_ref(&foo); // ok + foo_pin_ref(x); +} + +fn pin_mut_then_pin_mut() { + let mut foo = Foo::default(); + foo_pin_mut(&pin mut foo); // ok + foo_pin_mut(&pin mut foo); //[pinned]~ ERROR use of moved value: `foo` + + let mut foo = Foo::default(); + let x = &pin mut foo; // ok + foo_pin_mut(&pin mut foo); //[pinned]~ ERROR use of moved value: `foo` + //[unpin]~^ ERROR cannot borrow `foo` as mutable more than once at a time + foo_pin_mut(x); +} + +fn pin_ref_then_pin_mut() { + let mut foo = Foo::default(); + foo_pin_ref(&pin const foo); // ok + foo_pin_mut(&pin mut foo); // ok + + let mut foo = Foo::default(); + let x = &pin const foo; // ok + foo_pin_mut(&pin mut foo); //[pinned]~ ERROR cannot move out of `foo` because it is borrowed + //[unpin]~^ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable + foo_pin_ref(x); +} + +fn pin_mut_then_pin_ref() { + let mut foo = Foo::default(); + foo_pin_mut(&pin mut foo); // ok + foo_pin_ref(&pin const foo); //[pinned]~ ERROR borrow of moved value: `foo` + + let mut foo = Foo::default(); + let x = &pin mut foo; // ok + foo_pin_ref(&pin const foo); //[pinned]~ ERROR borrow of moved value: `foo` + //[unpin]~^ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable + foo_pin_mut(x); +} + +fn pin_ref_then_pin_ref() { + let mut foo = Foo::default(); + foo_pin_ref(&pin const foo); // ok + foo_pin_ref(&pin const foo); // ok + + let mut foo = Foo::default(); + let x = &pin const foo; // ok + foo_pin_ref(&pin const foo); // ok + foo_pin_ref(x); +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr new file mode 100644 index 000000000000..bf9921343ee7 --- /dev/null +++ b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr @@ -0,0 +1,136 @@ +error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable + --> $DIR/borrow-unpin.rs:38:17 + | +LL | foo_pin_mut(&pin mut foo); + | ^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut foo = Foo::default(); + | +++ + +error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable + --> $DIR/borrow-unpin.rs:42:13 + | +LL | let x = &pin mut foo; + | ^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut foo = Foo::default(); + | +++ + +error[E0505]: cannot move out of `foo` because it is borrowed + --> $DIR/borrow-unpin.rs:43:14 + | +LL | let foo = Foo::default(); + | --- binding `foo` declared here +LL | let x = &pin mut foo; + | ------------ borrow of `foo` occurs here +LL | foo_move(foo); + | ^^^ move out of `foo` occurs here +LL | +LL | foo_pin_mut(x); // + | - borrow later used here + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:20:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin mut foo; + | --- you could clone this value + +error[E0505]: cannot move out of `foo` because it is borrowed + --> $DIR/borrow-unpin.rs:56:14 + | +LL | let mut foo = Foo::default(); + | ------- binding `foo` declared here +LL | let x = &pin mut foo; // ok + | ------------ borrow of `foo` occurs here +LL | foo_move(foo); + | ^^^ move out of `foo` occurs here +LL | +LL | foo_pin_mut(x); // + | - borrow later used here + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:20:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin mut foo; // ok + | --- you could clone this value + +error[E0505]: cannot move out of `foo` because it is borrowed + --> $DIR/borrow-unpin.rs:68:14 + | +LL | let foo = Foo::default(); + | --- binding `foo` declared here +LL | let x = &pin const foo; // ok + | -------------- borrow of `foo` occurs here +LL | foo_move(foo); + | ^^^ move out of `foo` occurs here +LL | +LL | foo_pin_ref(x); + | - borrow later used here + | +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/borrow-unpin.rs:20:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | let x = &pin const foo; // ok + | --- you could clone this value + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/borrow-unpin.rs:80:13 + | +LL | let x = &pin mut foo; // ok + | ------------ mutable borrow occurs here +LL | foo_ref(&foo); + | ^^^^ immutable borrow occurs here +LL | +LL | foo_pin_mut(x); + | - mutable borrow later used here + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/borrow-unpin.rs:103:17 + | +LL | let x = &pin mut foo; // ok + | ------------ first mutable borrow occurs here +LL | foo_pin_mut(&pin mut foo); + | ^^^^^^^^^^^^ second mutable borrow occurs here +LL | +LL | foo_pin_mut(x); + | - first borrow later used here + +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrow-unpin.rs:115:17 + | +LL | let x = &pin const foo; // ok + | -------------- immutable borrow occurs here +LL | foo_pin_mut(&pin mut foo); + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | foo_pin_ref(x); + | - immutable borrow later used here + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/borrow-unpin.rs:127:17 + | +LL | let x = &pin mut foo; // ok + | ------------ mutable borrow occurs here +LL | foo_pin_ref(&pin const foo); + | ^^^^^^^^^^^^^^ immutable borrow occurs here +LL | +LL | foo_pin_mut(x); + | - mutable borrow later used here + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0499, E0502, E0505, E0596. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/pin-ergonomics/borrow.rs b/tests/ui/pin-ergonomics/borrow.rs index e33f3c1fa26f..f221165848ba 100644 --- a/tests/ui/pin-ergonomics/borrow.rs +++ b/tests/ui/pin-ergonomics/borrow.rs @@ -1,10 +1,9 @@ //@ check-pass - #![feature(pin_ergonomics)] #![allow(dead_code, incomplete_features)] // Makes sure we can handle `&pin mut place` and `&pin const place` as sugar for -// `unsafe { Pin::new_unchecked(&mut place) }` and `Pin::new(&place)`. +// `std::pin::pin!(place)` and `Pin::new(&place)`. use std::pin::Pin; @@ -28,4 +27,12 @@ fn bar() { foo_pin_ref(x); } +fn baz(mut x: Foo, y: Foo) { + let _x = &pin mut x; + let _x = x; // ok because `Foo: Unpin` and thus `&pin mut x` doesn't move `x` + + let _y = &pin const y; + let _y = y; // ok because `&pin const y` dosn't move `y` +} + fn main() {} From 3e59f14fb286859e01f467e17aa3fb251802e670 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 15 Jun 2025 11:19:04 +0000 Subject: [PATCH 045/356] Update to abi-cafe 1.0 --- build_system/abi_cafe.rs | 4 +- .../0002-abi-cafe-Disable-broken-tests.patch | 70 +++++++++---------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index 674acfbd3097..bee59b2b9560 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -6,8 +6,8 @@ use crate::{CodegenBackend, SysrootKind, build_sysroot}; static ABI_CAFE_REPO: GitRepo = GitRepo::github( "Gankra", "abi-cafe", - "f1220cfd13b57f5c0082c26529163865ee25e115", - "fe93a9acd461425d", + "49efdca14e9d48c34e50552d1f620615a87637bb", + "21fed1b4ca4cd439", "abi-cafe", ); diff --git a/patches/0002-abi-cafe-Disable-broken-tests.patch b/patches/0002-abi-cafe-Disable-broken-tests.patch index 01b6a990b720..708bef0edcf8 100644 --- a/patches/0002-abi-cafe-Disable-broken-tests.patch +++ b/patches/0002-abi-cafe-Disable-broken-tests.patch @@ -4,7 +4,7 @@ Date: Tue, 9 Jul 2024 11:25:14 +0000 Subject: [PATCH] Disable broken tests --- - src/report.rs | 36 ++++++++++++++++++++++++++++++++++++ + src/harness/report.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/toolchains/rust.rs b/src/toolchains/rust.rs @@ -14,56 +14,56 @@ index 0c50f7a..bfde2b1 100644 @@ -83,6 +83,7 @@ impl Toolchain for RustcToolchain { .arg(out_dir) .arg("--target") - .arg(built_info::TARGET) + .arg(&self.platform_info.target) + .arg("-g") .arg(format!("-Cmetadata={lib_name}")) .arg(src_path); if let Some(codegen_backend) = &self.codegen_backend { -diff --git a/src/report.rs b/src/report.rs +diff --git a/src/harness/report.rs b/src/harness/report.rs index 958ab43..dcf1044 100644 ---- a/src/report.rs -+++ b/src/report.rs +--- a/src/harness/report.rs ++++ b/src/harness/report.rs @@ -48,6 +48,40 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn Toolchain, callee: &dyn Toolc - // - // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES + // + // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES -+ if cfg!(all(target_arch = "aarch64", target_os = "linux")) { -+ if test.test == "F32Array" && test.options.convention == CallingConvention::C { -+ result.check = Busted(Check); -+ } -+ } -+ -+ if cfg!(all(target_arch = "aarch64", target_os = "macos")) { -+ if test.test == "SingleVariantUnion" && test.options.convention == CallingConvention::C && test.options.repr == LangRepr::C { -+ result.check = Busted(Check); ++ if cfg!(all(target_arch = "aarch64", target_os = "linux")) { ++ if key.test == "F32Array" && key.options.convention == CallingConvention::C { ++ result.check = Busted(Check); ++ } + } + -+ if test.test == "OptionU128" && test.caller == "rustc" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C { -+ result.check = Busted(Run); ++ if cfg!(all(target_arch = "aarch64", target_os = "macos")) { ++ if key.test == "SingleVariantUnion" && key.options.convention == CallingConvention::C && key.options.repr == LangRepr::C { ++ result.check = Busted(Check); ++ } ++ ++ if key.test == "OptionU128" && key.caller == "rustc" && key.options.convention == CallingConvention::Rust && key.options.repr == LangRepr::C { ++ result.check = Busted(Run); ++ } ++ ++ if key.test == "OptionU128" && key.caller == "cgclif" && key.options.convention == CallingConvention::Rust && key.options.repr == LangRepr::C { ++ result.check = Busted(Check); ++ } + } + -+ if test.test == "OptionU128" && test.caller == "cgclif" && test.options.convention == CallingConvention::Rust && test.options.repr == LangRepr::C { -+ result.check = Busted(Check); -+ } -+ } ++ if cfg!(all(target_arch = "x86_64", windows)) { ++ if key.test == "simple" && key.options.convention == CallingConvention::Rust { ++ result.check = Busted(Check); ++ } + -+ if cfg!(all(target_arch = "x86_64", windows)) { -+ if test.test == "simple" && test.options.convention == CallingConvention::Rust { -+ result.check = Busted(Check); ++ if key.test == "simple" && key.options.convention == CallingConvention::Rust && key.caller == "rustc" { ++ result.check = Busted(Run); ++ } + } + -+ if test.test == "simple" && test.options.convention == CallingConvention::Rust && test.caller == "rustc" { -+ result.check = Busted(Run); ++ if key.test == "f16" || key.test == "f128" { ++ result.run = Skip; + } -+ } + -+ if test.test == "f16" || test.test == "f128" { -+ result.run = Skip; -+ } -+ - // END OF VENDOR RESERVED AREA - // - // + // END OF VENDOR RESERVED AREA + // + // -- 2.34.1 From 8a396193432f4a9cb25ab76f6fdeefe08484edf8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 15 Jun 2025 12:09:50 +0000 Subject: [PATCH 046/356] Use the new abi-cafe-rules.toml support --- build_system/abi_cafe.rs | 2 + .../0002-abi-cafe-Disable-broken-tests.patch | 69 ------------------- patches/0002-abi-cafe-Enable-debuginfo.patch | 24 +++++++ scripts/abi-cafe-rules.toml | 17 +++++ 4 files changed, 43 insertions(+), 69 deletions(-) delete mode 100644 patches/0002-abi-cafe-Disable-broken-tests.patch create mode 100644 patches/0002-abi-cafe-Enable-debuginfo.patch create mode 100644 scripts/abi-cafe-rules.toml diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index bee59b2b9560..8f8884d2ac94 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -46,6 +46,8 @@ pub(crate) fn run( let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs); cmd.arg("--"); + cmd.arg("--rules").arg(dirs.source_dir.join("scripts/abi-cafe-rules.toml")); + // stdcall, vectorcall and such don't work yet cmd.arg("--conventions").arg("c").arg("--conventions").arg("rust"); diff --git a/patches/0002-abi-cafe-Disable-broken-tests.patch b/patches/0002-abi-cafe-Disable-broken-tests.patch deleted file mode 100644 index 708bef0edcf8..000000000000 --- a/patches/0002-abi-cafe-Disable-broken-tests.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 236df390f3bc4ed69c26f4d51d584bea246da886 Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Tue, 9 Jul 2024 11:25:14 +0000 -Subject: [PATCH] Disable broken tests - ---- - src/harness/report.rs | 36 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/src/toolchains/rust.rs b/src/toolchains/rust.rs -index 0c50f7a..bfde2b1 100644 ---- a/src/toolchains/rust.rs -+++ b/src/toolchains/rust.rs -@@ -83,6 +83,7 @@ impl Toolchain for RustcToolchain { - .arg(out_dir) - .arg("--target") - .arg(&self.platform_info.target) -+ .arg("-g") - .arg(format!("-Cmetadata={lib_name}")) - .arg(src_path); - if let Some(codegen_backend) = &self.codegen_backend { -diff --git a/src/harness/report.rs b/src/harness/report.rs -index 958ab43..dcf1044 100644 ---- a/src/harness/report.rs -+++ b/src/harness/report.rs -@@ -48,6 +48,40 @@ pub fn get_test_rules(test: &TestKey, caller: &dyn Toolchain, callee: &dyn Toolc - // - // THIS AREA RESERVED FOR VENDORS TO APPLY PATCHES - -+ if cfg!(all(target_arch = "aarch64", target_os = "linux")) { -+ if key.test == "F32Array" && key.options.convention == CallingConvention::C { -+ result.check = Busted(Check); -+ } -+ } -+ -+ if cfg!(all(target_arch = "aarch64", target_os = "macos")) { -+ if key.test == "SingleVariantUnion" && key.options.convention == CallingConvention::C && key.options.repr == LangRepr::C { -+ result.check = Busted(Check); -+ } -+ -+ if key.test == "OptionU128" && key.caller == "rustc" && key.options.convention == CallingConvention::Rust && key.options.repr == LangRepr::C { -+ result.check = Busted(Run); -+ } -+ -+ if key.test == "OptionU128" && key.caller == "cgclif" && key.options.convention == CallingConvention::Rust && key.options.repr == LangRepr::C { -+ result.check = Busted(Check); -+ } -+ } -+ -+ if cfg!(all(target_arch = "x86_64", windows)) { -+ if key.test == "simple" && key.options.convention == CallingConvention::Rust { -+ result.check = Busted(Check); -+ } -+ -+ if key.test == "simple" && key.options.convention == CallingConvention::Rust && key.caller == "rustc" { -+ result.check = Busted(Run); -+ } -+ } -+ -+ if key.test == "f16" || key.test == "f128" { -+ result.run = Skip; -+ } -+ - // END OF VENDOR RESERVED AREA - // - // --- -2.34.1 - diff --git a/patches/0002-abi-cafe-Enable-debuginfo.patch b/patches/0002-abi-cafe-Enable-debuginfo.patch new file mode 100644 index 000000000000..6f5c588f2b2f --- /dev/null +++ b/patches/0002-abi-cafe-Enable-debuginfo.patch @@ -0,0 +1,24 @@ +From 236df390f3bc4ed69c26f4d51d584bea246da886 Mon Sep 17 00:00:00 2001 +From: bjorn3 <17426603+bjorn3@users.noreply.github.com> +Date: Tue, 9 Jul 2024 11:25:14 +0000 +Subject: [PATCH] Enable debuginfo + +--- + src/toolchains/rust.rs | 1 + + 1 file changed, 1 insertions(+) + +diff --git a/src/toolchains/rust.rs b/src/toolchains/rust.rs +index 0c50f7a..bfde2b1 100644 +--- a/src/toolchains/rust.rs ++++ b/src/toolchains/rust.rs +@@ -83,6 +83,7 @@ impl Toolchain for RustcToolchain { + .arg(out_dir) + .arg("--target") + .arg(&self.platform_info.target) ++ .arg("-g") + .arg(format!("-Cmetadata={lib_name}")) + .arg(src_path); + if let Some(codegen_backend) = &self.codegen_backend { +-- +2.34.1 + diff --git a/scripts/abi-cafe-rules.toml b/scripts/abi-cafe-rules.toml new file mode 100644 index 000000000000..54f9445c8e52 --- /dev/null +++ b/scripts/abi-cafe-rules.toml @@ -0,0 +1,17 @@ +[target.'cfg(all(target_arch = "aarch64", target_os = "linux"))'] +'F32Array::conv_c'.busted = "check" + +[target.'cfg(all(target_arch = "aarch64", target_os = "macos"))'] +'SingleVariantUnion::conv_c::repr_c'.busted = "check" +'OptionU128::conv_rust::repr_c::rustc_caller'.busted = "run" +'OptionU128::conv_rust::repr_c::cgclif_caller'.busted = "check" + +[target.'cfg(all(target_arch = "x86_64", windows))'] +'simple::conv_rust'.busted = "check" +'simple::conv_rust::rustc_caller'.busted = "run" + +[target.'*'.'f16'] +run = "skip" + +[target.'*'.'f128'] +run = "skip" From 89b079d844454d0288fbce1160dab129987a4921 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 15 Jun 2025 18:48:03 +0000 Subject: [PATCH 047/356] Only traverse reachable blocks in JumpThreading. --- compiler/rustc_mir_transform/src/jump_threading.rs | 2 +- .../mir/unreachable-loop-jump-threading.rs} | 3 ++- tests/ui/mir/unreachable-loop-jump-threading.stderr | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) rename tests/{crashes/131451.rs => ui/mir/unreachable-loop-jump-threading.rs} (74%) create mode 100644 tests/ui/mir/unreachable-loop-jump-threading.stderr diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 48db536c122e..b45bff2af447 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -89,7 +89,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { opportunities: Vec::new(), }; - for bb in body.basic_blocks.indices() { + for (bb, _) in traversal::preorder(body) { finder.start_from_switch(bb); } diff --git a/tests/crashes/131451.rs b/tests/ui/mir/unreachable-loop-jump-threading.rs similarity index 74% rename from tests/crashes/131451.rs rename to tests/ui/mir/unreachable-loop-jump-threading.rs index cd5b44bad8a5..8403906bb5c0 100644 --- a/tests/crashes/131451.rs +++ b/tests/ui/mir/unreachable-loop-jump-threading.rs @@ -1,9 +1,10 @@ -//@ known-bug: #131451 +//@ build-pass //@ needs-rustc-debug-assertions //@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+JumpThreading --crate-type=lib pub fn fun(terminate: bool) { while true {} + //~^ WARN denote infinite loops with `loop { ... }` while !terminate {} } diff --git a/tests/ui/mir/unreachable-loop-jump-threading.stderr b/tests/ui/mir/unreachable-loop-jump-threading.stderr new file mode 100644 index 000000000000..21b174c80218 --- /dev/null +++ b/tests/ui/mir/unreachable-loop-jump-threading.stderr @@ -0,0 +1,10 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/unreachable-loop-jump-threading.rs:6:5 + | +LL | while true {} + | ^^^^^^^^^^ help: use `loop` + | + = note: `#[warn(while_true)]` on by default + +warning: 1 warning emitted + From 3cb0cba054d9d1871f3a10345d5c30cfc7ac214c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Sun, 1 Jun 2025 23:12:35 +0800 Subject: [PATCH 048/356] Handle win32 separator & prefixes for cygwin paths --- library/std/src/path.rs | 17 +- library/std/src/sys/path/cygwin.rs | 92 ++++ library/std/src/sys/path/mod.rs | 5 + library/std/src/sys/path/windows.rs | 175 +------- library/std/src/sys/path/windows/tests.rs | 2 + library/std/src/sys/path/windows_prefix.rs | 182 ++++++++ library/std/tests/path.rs | 472 +++++++++++++++++++++ 7 files changed, 772 insertions(+), 173 deletions(-) create mode 100644 library/std/src/sys/path/cygwin.rs create mode 100644 library/std/src/sys/path/windows_prefix.rs diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 826d9f0f39dc..be8d9f1b0541 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1316,8 +1316,17 @@ impl PathBuf { need_sep = false } + let need_clear = if cfg!(target_os = "cygwin") { + // If path is absolute and its prefix is none, it is like `/foo`, + // and will be handled below. + path.prefix().is_some() + } else { + // On Unix: prefix is always None. + path.is_absolute() || path.prefix().is_some() + }; + // absolute `path` replaces `self` - if path.is_absolute() || path.prefix().is_some() { + if need_clear { self.inner.truncate(0); // verbatim paths need . and .. removed @@ -3616,6 +3625,11 @@ impl Error for NormalizeError {} /// paths, this is currently equivalent to calling /// [`GetFullPathNameW`][windows-path]. /// +/// On Cygwin, this is currently equivalent to calling [`cygwin_conv_path`][cygwin-path] +/// with mode `CCP_WIN_A_TO_POSIX`, and then being processed like other POSIX platforms. +/// If a Windows path is given, it will be converted to an absolute POSIX path without +/// keeping `..`. +/// /// Note that these [may change in the future][changes]. /// /// # Errors @@ -3673,6 +3687,7 @@ impl Error for NormalizeError {} /// [changes]: io#platform-specific-behavior /// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 /// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew +/// [cygwin-path]: https://cygwin.com/cygwin-api/func-cygwin-conv-path.html #[stable(feature = "absolute_path", since = "1.79.0")] pub fn absolute>(path: P) -> io::Result { let path = path.as_ref(); diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs new file mode 100644 index 000000000000..e90372805bbf --- /dev/null +++ b/library/std/src/sys/path/cygwin.rs @@ -0,0 +1,92 @@ +use crate::ffi::OsString; +use crate::os::unix::ffi::OsStringExt; +use crate::path::{Path, PathBuf}; +use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::cvt; +use crate::{io, ptr}; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'/' || b == b'\\' +} + +/// Cygwin allways prefers `/` over `\`, and it always converts all `/` to `\` +/// internally when calling Win32 APIs. Therefore, the server component of path +/// `\\?\UNC\localhost/share` is `localhost/share` on Win32, but `localhost` +/// on Cygwin. +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'/' || b == b'\\' +} + +pub use super::windows_prefix::parse_prefix; + +pub const MAIN_SEP_STR: &str = "/"; +pub const MAIN_SEP: char = '/'; + +unsafe extern "C" { + // Doc: https://cygwin.com/cygwin-api/func-cygwin-conv-path.html + // Src: https://github.com/cygwin/cygwin/blob/718a15ba50e0d01c79800bd658c2477f9a603540/winsup/cygwin/path.cc#L3902 + // Safety: + // * `what` should be `CCP_WIN_A_TO_POSIX` here + // * `from` is null-terminated UTF-8 path + // * `to` is buffer, the buffer size is `size`. + // + // Converts a path to an absolute POSIX path, no matter the input is Win32 path or POSIX path. + fn cygwin_conv_path( + what: libc::c_uint, + from: *const libc::c_char, + to: *mut u8, + size: libc::size_t, + ) -> libc::ssize_t; +} + +const CCP_WIN_A_TO_POSIX: libc::c_uint = 2; + +/// Make a POSIX path absolute. +pub(crate) fn absolute(path: &Path) -> io::Result { + run_path_with_cstr(path, &|path| { + let conv = CCP_WIN_A_TO_POSIX; + let size = cvt(unsafe { cygwin_conv_path(conv, path.as_ptr(), ptr::null_mut(), 0) })?; + // If success, size should not be 0. + debug_assert!(size >= 1); + let size = size as usize; + let mut buffer = Vec::with_capacity(size); + cvt(unsafe { cygwin_conv_path(conv, path.as_ptr(), buffer.as_mut_ptr(), size) })?; + unsafe { + buffer.set_len(size - 1); + } + Ok(PathBuf::from(OsString::from_vec(buffer))) + }) + .map(|path| { + if path.prefix().is_some() { + return path; + } + + // From unix.rs + let mut components = path.components(); + let path_os = path.as_os_str().as_encoded_bytes(); + + let mut normalized = if path_os.starts_with(b"//") && !path_os.starts_with(b"///") { + components.next(); + PathBuf::from("//") + } else { + PathBuf::new() + }; + normalized.extend(components); + + if path_os.ends_with(b"/") { + normalized.push(""); + } + + normalized + }) +} + +pub(crate) fn is_absolute(path: &Path) -> bool { + if path.as_os_str().as_encoded_bytes().starts_with(b"\\") { + path.has_root() && path.prefix().is_some() + } else { + path.has_root() + } +} diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs index 1fa4e80d6780..a4ff4338cf5f 100644 --- a/library/std/src/sys/path/mod.rs +++ b/library/std/src/sys/path/mod.rs @@ -1,6 +1,7 @@ cfg_if::cfg_if! { if #[cfg(target_os = "windows")] { mod windows; + mod windows_prefix; pub use windows::*; } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; @@ -11,6 +12,10 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "uefi")] { mod uefi; pub use uefi::*; + } else if #[cfg(target_os = "cygwin")] { + mod cygwin; + mod windows_prefix; + pub use cygwin::*; } else { mod unix; pub use unix::*; diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index e0e003f6a819..f124e1e5a71c 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -1,5 +1,5 @@ use crate::ffi::{OsStr, OsString}; -use crate::path::{Path, PathBuf, Prefix}; +use crate::path::{Path, PathBuf}; use crate::sys::api::utf16; use crate::sys::pal::{c, fill_utf16_buf, os2path, to_u16s}; use crate::{io, ptr}; @@ -7,6 +7,8 @@ use crate::{io, ptr}; #[cfg(test)] mod tests; +pub use super::windows_prefix::parse_prefix; + pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP: char = '\\'; @@ -77,177 +79,6 @@ pub(crate) fn append_suffix(path: PathBuf, suffix: &OsStr) -> PathBuf { path.into() } -struct PrefixParser<'a, const LEN: usize> { - path: &'a OsStr, - prefix: [u8; LEN], -} - -impl<'a, const LEN: usize> PrefixParser<'a, LEN> { - #[inline] - fn get_prefix(path: &OsStr) -> [u8; LEN] { - let mut prefix = [0; LEN]; - // SAFETY: Only ASCII characters are modified. - for (i, &ch) in path.as_encoded_bytes().iter().take(LEN).enumerate() { - prefix[i] = if ch == b'/' { b'\\' } else { ch }; - } - prefix - } - - fn new(path: &'a OsStr) -> Self { - Self { path, prefix: Self::get_prefix(path) } - } - - fn as_slice(&self) -> PrefixParserSlice<'a, '_> { - PrefixParserSlice { - path: self.path, - prefix: &self.prefix[..LEN.min(self.path.len())], - index: 0, - } - } -} - -struct PrefixParserSlice<'a, 'b> { - path: &'a OsStr, - prefix: &'b [u8], - index: usize, -} - -impl<'a> PrefixParserSlice<'a, '_> { - fn strip_prefix(&self, prefix: &str) -> Option { - self.prefix[self.index..] - .starts_with(prefix.as_bytes()) - .then_some(Self { index: self.index + prefix.len(), ..*self }) - } - - fn prefix_bytes(&self) -> &'a [u8] { - &self.path.as_encoded_bytes()[..self.index] - } - - fn finish(self) -> &'a OsStr { - // SAFETY: The unsafety here stems from converting between &OsStr and - // &[u8] and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced only - // from ASCII-bounded slices of existing &OsStr values. - unsafe { OsStr::from_encoded_bytes_unchecked(&self.path.as_encoded_bytes()[self.index..]) } - } -} - -pub fn parse_prefix(path: &OsStr) -> Option> { - use Prefix::{DeviceNS, Disk, UNC, Verbatim, VerbatimDisk, VerbatimUNC}; - - let parser = PrefixParser::<8>::new(path); - let parser = parser.as_slice(); - if let Some(parser) = parser.strip_prefix(r"\\") { - // \\ - - // The meaning of verbatim paths can change when they use a different - // separator. - if let Some(parser) = parser.strip_prefix(r"?\") - && !parser.prefix_bytes().iter().any(|&x| x == b'/') - { - // \\?\ - if let Some(parser) = parser.strip_prefix(r"UNC\") { - // \\?\UNC\server\share - - let path = parser.finish(); - let (server, path) = parse_next_component(path, true); - let (share, _) = parse_next_component(path, true); - - Some(VerbatimUNC(server, share)) - } else { - let path = parser.finish(); - - // in verbatim paths only recognize an exact drive prefix - if let Some(drive) = parse_drive_exact(path) { - // \\?\C: - Some(VerbatimDisk(drive)) - } else { - // \\?\prefix - let (prefix, _) = parse_next_component(path, true); - Some(Verbatim(prefix)) - } - } - } else if let Some(parser) = parser.strip_prefix(r".\") { - // \\.\COM42 - let path = parser.finish(); - let (prefix, _) = parse_next_component(path, false); - Some(DeviceNS(prefix)) - } else { - let path = parser.finish(); - let (server, path) = parse_next_component(path, false); - let (share, _) = parse_next_component(path, false); - - if !server.is_empty() && !share.is_empty() { - // \\server\share - Some(UNC(server, share)) - } else { - // no valid prefix beginning with "\\" recognized - None - } - } - } else { - // If it has a drive like `C:` then it's a disk. - // Otherwise there is no prefix. - parse_drive(path).map(Disk) - } -} - -// Parses a drive prefix, e.g. "C:" and "C:\whatever" -fn parse_drive(path: &OsStr) -> Option { - // In most DOS systems, it is not possible to have more than 26 drive letters. - // See . - fn is_valid_drive_letter(drive: &u8) -> bool { - drive.is_ascii_alphabetic() - } - - match path.as_encoded_bytes() { - [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()), - _ => None, - } -} - -// Parses a drive prefix exactly, e.g. "C:" -fn parse_drive_exact(path: &OsStr) -> Option { - // only parse two bytes: the drive letter and the drive separator - if path.as_encoded_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { - parse_drive(path) - } else { - None - } -} - -// Parse the next path component. -// -// Returns the next component and the rest of the path excluding the component and separator. -// Does not recognize `/` as a separator character if `verbatim` is true. -fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { - let separator = if verbatim { is_verbatim_sep } else { is_sep_byte }; - - match path.as_encoded_bytes().iter().position(|&x| separator(x)) { - Some(separator_start) => { - let separator_end = separator_start + 1; - - let component = &path.as_encoded_bytes()[..separator_start]; - - // Panic safe - // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. - let path = &path.as_encoded_bytes()[separator_end..]; - - // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') - // is encoded in a single byte, therefore `bytes[separator_start]` and - // `bytes[separator_end]` must be code point boundaries and thus - // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. - unsafe { - ( - OsStr::from_encoded_bytes_unchecked(component), - OsStr::from_encoded_bytes_unchecked(path), - ) - } - } - None => (path, OsStr::new("")), - } -} - /// Returns a UTF-16 encoded path capable of bypassing the legacy `MAX_PATH` limits. /// /// This path may or may not have a verbatim prefix. diff --git a/library/std/src/sys/path/windows/tests.rs b/library/std/src/sys/path/windows/tests.rs index 9eb79203dcac..830f48d7bfc9 100644 --- a/library/std/src/sys/path/windows/tests.rs +++ b/library/std/src/sys/path/windows/tests.rs @@ -1,4 +1,6 @@ +use super::super::windows_prefix::*; use super::*; +use crate::path::Prefix; #[test] fn test_parse_next_component() { diff --git a/library/std/src/sys/path/windows_prefix.rs b/library/std/src/sys/path/windows_prefix.rs new file mode 100644 index 000000000000..b9dfe754485a --- /dev/null +++ b/library/std/src/sys/path/windows_prefix.rs @@ -0,0 +1,182 @@ +//! Parse Windows prefixes, for both Windows and Cygwin. + +use super::{is_sep_byte, is_verbatim_sep}; +use crate::ffi::OsStr; +use crate::path::Prefix; + +struct PrefixParser<'a, const LEN: usize> { + path: &'a OsStr, + prefix: [u8; LEN], +} + +impl<'a, const LEN: usize> PrefixParser<'a, LEN> { + #[inline] + fn get_prefix(path: &OsStr) -> [u8; LEN] { + let mut prefix = [0; LEN]; + // SAFETY: Only ASCII characters are modified. + for (i, &ch) in path.as_encoded_bytes().iter().take(LEN).enumerate() { + prefix[i] = if ch == b'/' { b'\\' } else { ch }; + } + prefix + } + + fn new(path: &'a OsStr) -> Self { + Self { path, prefix: Self::get_prefix(path) } + } + + fn as_slice(&self) -> PrefixParserSlice<'a, '_> { + PrefixParserSlice { + path: self.path, + prefix: &self.prefix[..LEN.min(self.path.len())], + index: 0, + } + } +} + +struct PrefixParserSlice<'a, 'b> { + path: &'a OsStr, + prefix: &'b [u8], + index: usize, +} + +impl<'a> PrefixParserSlice<'a, '_> { + fn strip_prefix(&self, prefix: &str) -> Option { + self.prefix[self.index..] + .starts_with(prefix.as_bytes()) + .then_some(Self { index: self.index + prefix.len(), ..*self }) + } + + fn prefix_bytes(&self) -> &'a [u8] { + &self.path.as_encoded_bytes()[..self.index] + } + + fn finish(self) -> &'a OsStr { + // SAFETY: The unsafety here stems from converting between &OsStr and + // &[u8] and back. This is safe to do because (1) we only look at ASCII + // contents of the encoding and (2) new &OsStr values are produced only + // from ASCII-bounded slices of existing &OsStr values. + unsafe { OsStr::from_encoded_bytes_unchecked(&self.path.as_encoded_bytes()[self.index..]) } + } +} + +pub fn parse_prefix(path: &OsStr) -> Option> { + use Prefix::{DeviceNS, Disk, UNC, Verbatim, VerbatimDisk, VerbatimUNC}; + + let parser = PrefixParser::<8>::new(path); + let parser = parser.as_slice(); + if let Some(parser) = parser.strip_prefix(r"\\") { + // \\ + + // It's a POSIX path. + if cfg!(target_os = "cygwin") && !path.as_encoded_bytes().iter().any(|&x| x == b'\\') { + return None; + } + + // The meaning of verbatim paths can change when they use a different + // separator. + if let Some(parser) = parser.strip_prefix(r"?\") + // Cygwin allows `/` in verbatim paths. + && (cfg!(target_os = "cygwin") || !parser.prefix_bytes().iter().any(|&x| x == b'/')) + { + // \\?\ + if let Some(parser) = parser.strip_prefix(r"UNC\") { + // \\?\UNC\server\share + + let path = parser.finish(); + let (server, path) = parse_next_component(path, true); + let (share, _) = parse_next_component(path, true); + + Some(VerbatimUNC(server, share)) + } else { + let path = parser.finish(); + + // in verbatim paths only recognize an exact drive prefix + if let Some(drive) = parse_drive_exact(path) { + // \\?\C: + Some(VerbatimDisk(drive)) + } else { + // \\?\prefix + let (prefix, _) = parse_next_component(path, true); + Some(Verbatim(prefix)) + } + } + } else if let Some(parser) = parser.strip_prefix(r".\") { + // \\.\COM42 + let path = parser.finish(); + let (prefix, _) = parse_next_component(path, false); + Some(DeviceNS(prefix)) + } else { + let path = parser.finish(); + let (server, path) = parse_next_component(path, false); + let (share, _) = parse_next_component(path, false); + + if !server.is_empty() && !share.is_empty() { + // \\server\share + Some(UNC(server, share)) + } else { + // no valid prefix beginning with "\\" recognized + None + } + } + } else { + // If it has a drive like `C:` then it's a disk. + // Otherwise there is no prefix. + Some(Disk(parse_drive(path)?)) + } +} + +// Parses a drive prefix, e.g. "C:" and "C:\whatever" +fn parse_drive(path: &OsStr) -> Option { + // In most DOS systems, it is not possible to have more than 26 drive letters. + // See . + fn is_valid_drive_letter(drive: &u8) -> bool { + drive.is_ascii_alphabetic() + } + + match path.as_encoded_bytes() { + [drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()), + _ => None, + } +} + +// Parses a drive prefix exactly, e.g. "C:" +fn parse_drive_exact(path: &OsStr) -> Option { + // only parse two bytes: the drive letter and the drive separator + if path.as_encoded_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) { + parse_drive(path) + } else { + None + } +} + +// Parse the next path component. +// +// Returns the next component and the rest of the path excluding the component and separator. +// Does not recognize `/` as a separator character on Windows if `verbatim` is true. +pub(crate) fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { + let separator = if verbatim { is_verbatim_sep } else { is_sep_byte }; + + match path.as_encoded_bytes().iter().position(|&x| separator(x)) { + Some(separator_start) => { + let separator_end = separator_start + 1; + + let component = &path.as_encoded_bytes()[..separator_start]; + + // Panic safe + // The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index. + let path = &path.as_encoded_bytes()[separator_end..]; + + // SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\') + // is encoded in a single byte, therefore `bytes[separator_start]` and + // `bytes[separator_end]` must be code point boundaries and thus + // `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices. + unsafe { + ( + OsStr::from_encoded_bytes_unchecked(component), + OsStr::from_encoded_bytes_unchecked(path), + ) + } + } + None => (path, OsStr::new("")), + } +} diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index be0dda1d426f..901d2770f203 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -1112,6 +1112,473 @@ pub fn test_decompositions_windows() { ); } +// Unix paths are tested in `test_decompositions_unix` above. +#[test] +#[cfg(target_os = "cygwin")] +pub fn test_decompositions_cygwin() { + t!("\\", + iter: ["/"], + has_root: true, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("c:", + iter: ["c:"], + has_root: false, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("c:\\", + iter: ["c:", "/"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("c:/", + iter: ["c:", "/"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("a\\b\\c", + iter: ["a", "b", "c"], + has_root: false, + is_absolute: false, + parent: Some("a\\b"), + file_name: Some("c"), + file_stem: Some("c"), + extension: None, + file_prefix: Some("c") + ); + + t!("\\a", + iter: ["/", "a"], + has_root: true, + is_absolute: false, + parent: Some("\\"), + file_name: Some("a"), + file_stem: Some("a"), + extension: None, + file_prefix: Some("a") + ); + + t!("c:\\foo.txt", + iter: ["c:", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("c:\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("\\\\server\\share\\foo.txt", + iter: ["\\\\server\\share", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\server\\share\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("//server/share\\foo.txt", + iter: ["//server/share", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("//server/share\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("//server/share/foo.txt", + iter: ["/", "server", "share", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("//server/share"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("\\\\server\\share", + iter: ["\\\\server\\share", "/"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("\\\\server", + iter: ["/", "server"], + has_root: true, + is_absolute: false, + parent: Some("\\"), + file_name: Some("server"), + file_stem: Some("server"), + extension: None, + file_prefix: Some("server") + ); + + t!("\\\\?\\bar\\foo.txt", + iter: ["\\\\?\\bar", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\bar\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("\\\\?\\bar", + iter: ["\\\\?\\bar"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("\\\\?\\", + iter: ["\\\\?\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("\\\\?\\UNC\\server\\share\\foo.txt", + iter: ["\\\\?\\UNC\\server\\share", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\UNC\\server\\share\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("\\\\?\\UNC\\server/share\\foo.txt", + iter: ["\\\\?\\UNC\\server/share", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\UNC\\server/share\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("//?/UNC/server\\share/foo.txt", + iter: ["//?/UNC/server\\share", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("//?/UNC/server\\share/"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("//?/UNC/server/share/foo.txt", + iter: ["/", "?", "UNC", "server", "share", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("//?/UNC/server/share"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("\\\\?\\UNC\\server", + iter: ["\\\\?\\UNC\\server"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("\\\\?\\UNC\\", + iter: ["\\\\?\\UNC\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("\\\\?\\C:\\foo.txt", + iter: ["\\\\?\\C:", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\C:\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("//?/C:\\foo.txt", + iter: ["//?/C:", "/", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("//?/C:\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("//?/C:/foo.txt", + iter: ["/", "?", "C:", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("//?/C:"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt"), + file_prefix: Some("foo") + ); + + t!("\\\\?\\C:\\", + iter: ["\\\\?\\C:", "/"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("\\\\?\\C:", + iter: ["\\\\?\\C:"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("\\\\?\\foo/bar", + iter: ["\\\\?\\foo", "/", "bar"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\foo/"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("\\\\?\\C:/foo/bar", + iter: ["\\\\?\\C:", "/", "foo", "bar"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\C:/foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("\\\\.\\foo\\bar", + iter: ["\\\\.\\foo", "/", "bar"], + has_root: true, + is_absolute: true, + parent: Some("\\\\.\\foo\\"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("\\\\.\\foo", + iter: ["\\\\.\\foo", "/"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("\\\\.\\foo/bar", + iter: ["\\\\.\\foo", "/", "bar"], + has_root: true, + is_absolute: true, + parent: Some("\\\\.\\foo/"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("\\\\.\\foo\\bar/baz", + iter: ["\\\\.\\foo", "/", "bar", "baz"], + has_root: true, + is_absolute: true, + parent: Some("\\\\.\\foo\\bar"), + file_name: Some("baz"), + file_stem: Some("baz"), + extension: None, + file_prefix: Some("baz") + ); + + t!("\\\\.\\", + iter: ["\\\\.\\", "/"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None, + file_prefix: None + ); + + t!("//.\\foo/bar", + iter: ["//.\\foo", "/", "bar"], + has_root: true, + is_absolute: true, + parent: Some("//.\\foo/"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("\\\\./foo/bar", + iter: ["\\\\./foo", "/", "bar"], + has_root: true, + is_absolute: true, + parent: Some("\\\\./foo/"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("//./foo\\bar", + iter: ["//./foo", "/", "bar"], + has_root: true, + is_absolute: true, + parent: Some("//./foo\\"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("//./?/C:/foo/bar", + iter: ["/", "?", "C:", "foo", "bar"], + has_root: true, + is_absolute: true, + parent: Some("//./?/C:/foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("//././../././../?/C:/foo/bar", + iter: ["/", "..", "..", "?", "C:", "foo", "bar"], + has_root: true, + is_absolute: true, + parent: Some("//././../././../?/C:/foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None, + file_prefix: Some("bar") + ); + + t!("\\\\?\\a\\b\\", + iter: ["\\\\?\\a", "/", "b"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\a\\"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None, + file_prefix: Some("b") + ); + + t!("\\\\?\\C:\\foo.txt.zip", + iter: ["\\\\?\\C:", "/", "foo.txt.zip"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\C:\\"), + file_name: Some("foo.txt.zip"), + file_stem: Some("foo.txt"), + extension: Some("zip"), + file_prefix: Some("foo") + ); + + t!("\\\\?\\C:\\.foo.txt.zip", + iter: ["\\\\?\\C:", "/", ".foo.txt.zip"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\C:\\"), + file_name: Some(".foo.txt.zip"), + file_stem: Some(".foo.txt"), + extension: Some("zip"), + file_prefix: Some(".foo") + ); + + t!("\\\\?\\C:\\.foo", + iter: ["\\\\?\\C:", "/", ".foo"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\C:\\"), + file_name: Some(".foo"), + file_stem: Some(".foo"), + extension: None, + file_prefix: Some(".foo") + ); +} + #[test] pub fn test_stem_ext() { t!("foo", @@ -1227,6 +1694,11 @@ pub fn test_push() { tp!("/foo/bar", "/", "/"); tp!("/foo/bar", "/baz", "/baz"); tp!("/foo/bar", "./baz", "/foo/bar/./baz"); + + if cfg!(target_os = "cygwin") { + tp!("c:\\", "windows", "c:\\windows"); + tp!("c:", "windows", "c:windows"); + } } else { tp!("", "foo", "foo"); tp!("foo", "bar", r"foo\bar"); From 426ab142507fca8704d934da556f1c96b0fd61b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=81owicki?= Date: Fri, 18 Apr 2025 10:38:17 +0200 Subject: [PATCH 049/356] Set MSG_NOSIGNAL for UnixSteam https://github.com/rust-lang/rust/issues/139956 fix --- library/std/src/net/tcp.rs | 6 +++++ library/std/src/os/unix/net/stream.rs | 23 ++++++++++++++++++- .../std/src/sys/net/connection/socket/unix.rs | 8 +++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 6a9514264072..10685b493194 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -53,6 +53,12 @@ use crate::time::Duration; /// Ok(()) /// } // the stream is closed here /// ``` +/// +/// # Platform-specific Behavior +/// +/// On Unix, writes to the underlying socket in `SOCK_STREAM` mode are made with +/// `MSG_NOSIGNAL` flag. This suppresses the emission of the `SIGPIPE` signal when writing +/// to disconnected socket. In some cases, getting a `SIGPIPE` would trigger process termination. #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpStream(net_imp::TcpStream); diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 1bd3bab5e373..035768a6fab7 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -1,3 +1,18 @@ +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "linux", target_os = "android", + target_os = "hurd", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "solaris", target_os = "illumos", + target_os = "haiku", target_os = "nto", + target_os = "cygwin"))] { + use libc::MSG_NOSIGNAL; + } else { + const MSG_NOSIGNAL: core::ffi::c_int = 0x0; + } +} + use super::{SocketAddr, sockaddr_un}; #[cfg(any(doc, target_os = "android", target_os = "linux"))] use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to}; @@ -41,6 +56,12 @@ use crate::time::Duration; /// Ok(()) /// } /// ``` +/// +/// # `SIGPIPE` +/// +/// Writes to the underlying socket in `SOCK_STREAM` mode are made with `MSG_NOSIGNAL` flag. +/// This suppresses the emission of the `SIGPIPE` signal when writing to disconnected socket. +/// In some cases getting a `SIGPIPE` would trigger process termination. #[stable(feature = "unix_socket", since = "1.10.0")] pub struct UnixStream(pub(super) Socket); @@ -633,7 +654,7 @@ impl io::Write for UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) + self.0.send_with_flags(buf, MSG_NOSIGNAL) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index b35d5d2aa841..b2a4961c3c53 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -281,6 +281,14 @@ impl Socket { self.0.duplicate().map(Socket) } + pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result { + let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; + let ret = cvt(unsafe { + libc::send(self.as_raw_fd(), buf.as_ptr() as *const c_void, len, flags) + })?; + Ok(ret as usize) + } + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { let ret = cvt(unsafe { libc::recv( From 1ade48fde9faeb4e161119619aaa4f940acab79b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 16 Jun 2025 08:15:58 +0000 Subject: [PATCH 050/356] Rustup to rustc 1.89.0-nightly (586ad391f 2025-06-15) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 5114d3686a43..d92c80a3d934 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-14" +channel = "nightly-2025-06-16" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From b7cfe2f4db9e7740f6302a1627d1c087054e64b4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 16 Jun 2025 08:23:24 +0000 Subject: [PATCH 051/356] Use the new --debug flag of abi-cafe As opposed to patching abi-cafe itself. --- build_system/abi_cafe.rs | 6 +++-- patches/0002-abi-cafe-Enable-debuginfo.patch | 24 -------------------- 2 files changed, 4 insertions(+), 26 deletions(-) delete mode 100644 patches/0002-abi-cafe-Enable-debuginfo.patch diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index 8f8884d2ac94..43025137bc6b 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -6,8 +6,8 @@ use crate::{CodegenBackend, SysrootKind, build_sysroot}; static ABI_CAFE_REPO: GitRepo = GitRepo::github( "Gankra", "abi-cafe", - "49efdca14e9d48c34e50552d1f620615a87637bb", - "21fed1b4ca4cd439", + "94d38030419eb00a1ba80e5e2b4d763dcee58db4", + "6efb4457893c8670", "abi-cafe", ); @@ -46,6 +46,8 @@ pub(crate) fn run( let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs); cmd.arg("--"); + cmd.arg("--debug"); + cmd.arg("--rules").arg(dirs.source_dir.join("scripts/abi-cafe-rules.toml")); // stdcall, vectorcall and such don't work yet diff --git a/patches/0002-abi-cafe-Enable-debuginfo.patch b/patches/0002-abi-cafe-Enable-debuginfo.patch deleted file mode 100644 index 6f5c588f2b2f..000000000000 --- a/patches/0002-abi-cafe-Enable-debuginfo.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 236df390f3bc4ed69c26f4d51d584bea246da886 Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Tue, 9 Jul 2024 11:25:14 +0000 -Subject: [PATCH] Enable debuginfo - ---- - src/toolchains/rust.rs | 1 + - 1 file changed, 1 insertions(+) - -diff --git a/src/toolchains/rust.rs b/src/toolchains/rust.rs -index 0c50f7a..bfde2b1 100644 ---- a/src/toolchains/rust.rs -+++ b/src/toolchains/rust.rs -@@ -83,6 +83,7 @@ impl Toolchain for RustcToolchain { - .arg(out_dir) - .arg("--target") - .arg(&self.platform_info.target) -+ .arg("-g") - .arg(format!("-Cmetadata={lib_name}")) - .arg(src_path); - if let Some(codegen_backend) = &self.codegen_backend { --- -2.34.1 - From e3916036f927e2bfc2ff356df08ef2e1d1b29378 Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 3 Apr 2025 23:53:06 +0100 Subject: [PATCH 052/356] Fix RISC-V C function ABI when passing/returning structs containing floats --- src/abi/pass_mode.rs | 66 ++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index 9a0a5b510397..cd0afee0cfb2 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -40,7 +40,18 @@ fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiPar } } -fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> { +fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2]> { + if let Some(offset_from_start) = cast.rest_offset { + assert!(cast.prefix[1..].iter().all(|p| p.is_none())); + assert_eq!(cast.rest.unit.size, cast.rest.total); + let first = cast.prefix[0].unwrap(); + let second = cast.rest.unit; + return smallvec![ + (Size::ZERO, reg_to_abi_param(first)), + (offset_from_start, reg_to_abi_param(second)) + ]; + } + let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 { (0, 0) } else { @@ -55,25 +66,32 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> { // different types in Cranelift IR. Instead a single array of primitive types is used. // Create list of fields in the main structure - let mut args = cast + let args = cast .prefix .iter() .flatten() .map(|®| reg_to_abi_param(reg)) - .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit))) - .collect::>(); + .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit))); + + let mut res = SmallVec::new(); + let mut offset = Size::ZERO; + + for arg in args { + res.push((offset, arg)); + offset += Size::from_bytes(arg.value_type.bytes()); + } // Append final integer if rem_bytes != 0 { // Only integers can be really split further. assert_eq!(cast.rest.unit.kind, RegKind::Integer); - args.push(reg_to_abi_param(Reg { - kind: RegKind::Integer, - size: Size::from_bytes(rem_bytes), - })); + res.push(( + offset, + reg_to_abi_param(Reg { kind: RegKind::Integer, size: Size::from_bytes(rem_bytes) }), + )); } - args + res } impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { @@ -104,7 +122,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { }, PassMode::Cast { ref cast, pad_i32 } => { assert!(!pad_i32, "padding support not yet implemented"); - cast_target_to_abi_params(cast) + cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect() } PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { if on_stack { @@ -160,9 +178,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Cast { ref cast, .. } => { - (None, cast_target_to_abi_params(cast).into_iter().collect()) - } + PassMode::Cast { ref cast, .. } => ( + None, + cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(), + ), PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { assert!(!on_stack); ( @@ -187,12 +206,14 @@ pub(super) fn to_casted_value<'tcx>( ) -> SmallVec<[Value; 2]> { let (ptr, meta) = arg.force_stack(fx); assert!(meta.is_none()); - let mut offset = 0; cast_target_to_abi_params(cast) .into_iter() - .map(|param| { - let val = ptr.offset_i64(fx, offset).load(fx, param.value_type, MemFlags::new()); - offset += i64::from(param.value_type.bytes()); + .map(|(offset, param)| { + let val = ptr.offset_i64(fx, offset.bytes() as i64).load( + fx, + param.value_type, + MemFlags::new(), + ); val }) .collect() @@ -205,7 +226,7 @@ pub(super) fn from_casted_value<'tcx>( cast: &CastTarget, ) -> CValue<'tcx> { let abi_params = cast_target_to_abi_params(cast); - let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum(); + let abi_param_size: u32 = abi_params.iter().map(|(_, param)| param.value_type.bytes()).sum(); let layout_size = u32::try_from(layout.size.bytes()).unwrap(); let ptr = fx.create_stack_slot( // Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`. @@ -214,16 +235,13 @@ pub(super) fn from_casted_value<'tcx>( std::cmp::max(abi_param_size, layout_size), u32::try_from(layout.align.abi.bytes()).unwrap(), ); - let mut offset = 0; let mut block_params_iter = block_params.iter().copied(); - for param in abi_params { - let val = ptr.offset_i64(fx, offset).store( + for (offset, _) in abi_params { + ptr.offset_i64(fx, offset.bytes() as i64).store( fx, block_params_iter.next().unwrap(), MemFlags::new(), - ); - offset += i64::from(param.value_type.bytes()); - val + ) } assert_eq!(block_params_iter.next(), None, "Leftover block param"); CValue::by_ref(ptr, layout) From 0e141a2be1796c4bab82484fac507166667c687b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 10 Jun 2025 15:41:02 +0200 Subject: [PATCH 053/356] Implement `_fmt` on `u128` --- library/core/src/fmt/num.rs | 205 +++++++++++++++++++----------------- 1 file changed, 109 insertions(+), 96 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index ce878f2da4bd..eb56e47bfafe 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -568,120 +568,133 @@ impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128); #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for u128 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_u128(*self, true, f) + const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; + let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + + f.pad_integral(true, "", self._fmt(&mut buf)) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for i128 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_u128(self.unsigned_abs(), *self >= 0, f) + // This is not a typo, we use the maximum number of digits of `u128`, hence why we use + // `u128::MAX`. + const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; + let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + + let is_nonnegative = *self >= 0; + f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf)) } } -/// Format optimized for u128. Computation of 128 bits is limited by proccessing -/// in batches of 16 decimals at a time. -fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Optimize common-case zero, which would also need special treatment due to - // its "leading" zero. - if n == 0 { - return f.pad_integral(true, "", "0"); - } +impl u128 { + /// Format optimized for u128. Computation of 128 bits is limited by proccessing + /// in batches of 16 decimals at a time. + #[doc(hidden)] + #[unstable( + feature = "fmt_internals", + reason = "specialized method meant to only be used by `SpecToString` implementation", + issue = "none" + )] + pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit]) -> &'a str { + const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; - // U128::MAX has 39 significant-decimals. - const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; - // Buffer decimals with right alignment. - let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; - - // Take the 16 least-significant decimals. - let (quot_1e16, mod_1e16) = div_rem_1e16(n); - let (mut remain, mut offset) = if quot_1e16 == 0 { - (mod_1e16, MAX_DEC_N) - } else { - // Write digits at buf[23..39]. - enc_16lsd::<{ MAX_DEC_N - 16 }>(&mut buf, mod_1e16); - - // Take another 16 decimals. - let (quot2, mod2) = div_rem_1e16(quot_1e16); - if quot2 == 0 { - (mod2, MAX_DEC_N - 16) - } else { - // Write digits at buf[7..23]. - enc_16lsd::<{ MAX_DEC_N - 32 }>(&mut buf, mod2); - // Quot2 has at most 7 decimals remaining after two 1e16 divisions. - (quot2 as u64, MAX_DEC_N - 32) + // Optimize common-case zero, which would also need special treatment due to + // its "leading" zero. + if self == 0 { + return "0"; } - }; - // Format per four digits from the lookup table. - while remain > 999 { - // SAFETY: All of the decimals fit in buf due to MAX_DEC_N - // and the while condition ensures at least 4 more decimals. - unsafe { core::hint::assert_unchecked(offset >= 4) } - // SAFETY: The offset counts down from its initial buf.len() - // without underflow due to the previous precondition. - unsafe { core::hint::assert_unchecked(offset <= buf.len()) } - offset -= 4; + // Take the 16 least-significant decimals. + let (quot_1e16, mod_1e16) = div_rem_1e16(self); + let (mut remain, mut offset) = if quot_1e16 == 0 { + (mod_1e16, MAX_DEC_N) + } else { + // Write digits at buf[23..39]. + enc_16lsd::<{ MAX_DEC_N - 16 }>(buf, mod_1e16); - // pull two pairs - let quad = remain % 1_00_00; - remain /= 1_00_00; - let pair1 = (quad / 100) as usize; - let pair2 = (quad % 100) as usize; - buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]); - buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]); - buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]); - buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]); + // Take another 16 decimals. + let (quot2, mod2) = div_rem_1e16(quot_1e16); + if quot2 == 0 { + (mod2, MAX_DEC_N - 16) + } else { + // Write digits at buf[7..23]. + enc_16lsd::<{ MAX_DEC_N - 32 }>(buf, mod2); + // Quot2 has at most 7 decimals remaining after two 1e16 divisions. + (quot2 as u64, MAX_DEC_N - 32) + } + }; + + // Format per four digits from the lookup table. + while remain > 999 { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the while condition ensures at least 4 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 4) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 4; + + // pull two pairs + let quad = remain % 1_00_00; + remain /= 1_00_00; + let pair1 = (quad / 100) as usize; + let pair2 = (quad % 100) as usize; + buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]); + buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]); + buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]); + buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]); + } + + // Format per two digits from the lookup table. + if remain > 9 { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the if condition ensures at least 2 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 2) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 2; + + let pair = (remain % 100) as usize; + remain /= 100; + buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]); + buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]); + } + + // Format the last remaining digit, if any. + if remain != 0 { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the if condition ensures (at least) 1 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 1) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 1; + + // Either the compiler sees that remain < 10, or it prevents + // a boundary check up next. + let last = (remain & 15) as usize; + buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]); + // not used: remain = 0; + } + + // SAFETY: All buf content since offset is set. + let written = unsafe { buf.get_unchecked(offset..) }; + // SAFETY: Writes use ASCII from the lookup table exclusively. + unsafe { + str::from_utf8_unchecked(slice::from_raw_parts( + MaybeUninit::slice_as_ptr(written), + written.len(), + )) + } } - - // Format per two digits from the lookup table. - if remain > 9 { - // SAFETY: All of the decimals fit in buf due to MAX_DEC_N - // and the if condition ensures at least 2 more decimals. - unsafe { core::hint::assert_unchecked(offset >= 2) } - // SAFETY: The offset counts down from its initial buf.len() - // without underflow due to the previous precondition. - unsafe { core::hint::assert_unchecked(offset <= buf.len()) } - offset -= 2; - - let pair = (remain % 100) as usize; - remain /= 100; - buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]); - buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]); - } - - // Format the last remaining digit, if any. - if remain != 0 { - // SAFETY: All of the decimals fit in buf due to MAX_DEC_N - // and the if condition ensures (at least) 1 more decimals. - unsafe { core::hint::assert_unchecked(offset >= 1) } - // SAFETY: The offset counts down from its initial buf.len() - // without underflow due to the previous precondition. - unsafe { core::hint::assert_unchecked(offset <= buf.len()) } - offset -= 1; - - // Either the compiler sees that remain < 10, or it prevents - // a boundary check up next. - let last = (remain & 15) as usize; - buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]); - // not used: remain = 0; - } - - // SAFETY: All buf content since offset is set. - let written = unsafe { buf.get_unchecked(offset..) }; - // SAFETY: Writes use ASCII from the lookup table exclusively. - let as_str = unsafe { - str::from_utf8_unchecked(slice::from_raw_parts( - MaybeUninit::slice_as_ptr(written), - written.len(), - )) - }; - f.pad_integral(is_nonnegative, "", as_str) } /// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET + /// 16 ]`. -fn enc_16lsd(buf: &mut [MaybeUninit; 39], n: u64) { +fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { // Consume the least-significant decimals from a working copy. let mut remain = n; From aec32486a8d018b398fc9499898d6ab7dbe93741 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 10 Jun 2025 15:40:49 +0200 Subject: [PATCH 054/356] Specialize `ToString` implementation on `u128` and `i128` --- library/alloc/src/string.rs | 1 + library/core/src/fmt/num.rs | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 37614a7ca457..a3174d74e18c 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2870,6 +2870,7 @@ impl_to_string! { i32, u32, i64, u64, isize, usize, + i128, u128, } #[cfg(not(no_global_oom_handling))] diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index eb56e47bfafe..13cd7f710943 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -565,11 +565,12 @@ mod imp { } impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128); +const U128_MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for u128 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; - let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + let mut buf = [MaybeUninit::::uninit(); U128_MAX_DEC_N]; f.pad_integral(true, "", self._fmt(&mut buf)) } @@ -579,9 +580,8 @@ impl fmt::Display for u128 { impl fmt::Display for i128 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // This is not a typo, we use the maximum number of digits of `u128`, hence why we use - // `u128::MAX`. - const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; - let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; + // `U128_MAX_DEC_N`. + let mut buf = [MaybeUninit::::uninit(); U128_MAX_DEC_N]; let is_nonnegative = *self >= 0; f.pad_integral(is_nonnegative, "", self.unsigned_abs()._fmt(&mut buf)) @@ -598,8 +598,6 @@ impl u128 { issue = "none" )] pub fn _fmt<'a>(self, buf: &'a mut [MaybeUninit]) -> &'a str { - const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; - // Optimize common-case zero, which would also need special treatment due to // its "leading" zero. if self == 0 { @@ -609,26 +607,26 @@ impl u128 { // Take the 16 least-significant decimals. let (quot_1e16, mod_1e16) = div_rem_1e16(self); let (mut remain, mut offset) = if quot_1e16 == 0 { - (mod_1e16, MAX_DEC_N) + (mod_1e16, U128_MAX_DEC_N) } else { // Write digits at buf[23..39]. - enc_16lsd::<{ MAX_DEC_N - 16 }>(buf, mod_1e16); + enc_16lsd::<{ U128_MAX_DEC_N - 16 }>(buf, mod_1e16); // Take another 16 decimals. let (quot2, mod2) = div_rem_1e16(quot_1e16); if quot2 == 0 { - (mod2, MAX_DEC_N - 16) + (mod2, U128_MAX_DEC_N - 16) } else { // Write digits at buf[7..23]. - enc_16lsd::<{ MAX_DEC_N - 32 }>(buf, mod2); + enc_16lsd::<{ U128_MAX_DEC_N - 32 }>(buf, mod2); // Quot2 has at most 7 decimals remaining after two 1e16 divisions. - (quot2 as u64, MAX_DEC_N - 32) + (quot2 as u64, U128_MAX_DEC_N - 32) } }; // Format per four digits from the lookup table. while remain > 999 { - // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N // and the while condition ensures at least 4 more decimals. unsafe { core::hint::assert_unchecked(offset >= 4) } // SAFETY: The offset counts down from its initial buf.len() @@ -649,7 +647,7 @@ impl u128 { // Format per two digits from the lookup table. if remain > 9 { - // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N // and the if condition ensures at least 2 more decimals. unsafe { core::hint::assert_unchecked(offset >= 2) } // SAFETY: The offset counts down from its initial buf.len() @@ -665,7 +663,7 @@ impl u128 { // Format the last remaining digit, if any. if remain != 0 { - // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // SAFETY: All of the decimals fit in buf due to U128_MAX_DEC_N // and the if condition ensures (at least) 1 more decimals. unsafe { core::hint::assert_unchecked(offset >= 1) } // SAFETY: The offset counts down from its initial buf.len() From 9b09948897886541bc4f31a9d07bf4a2e1680171 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 10 Jun 2025 15:41:16 +0200 Subject: [PATCH 055/356] Extend num tests on `usize` and `isize` as well --- library/alloctests/tests/num.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/alloctests/tests/num.rs b/library/alloctests/tests/num.rs index 3c76e68c6064..a169bbec8e0c 100644 --- a/library/alloctests/tests/num.rs +++ b/library/alloctests/tests/num.rs @@ -52,6 +52,8 @@ int_to_s!( i32, test_i64_to_string, i64, + test_isize_to_string, + isize, test_i128_to_string, i128, ); @@ -64,6 +66,8 @@ uint_to_s!( u32, test_u64_to_string, u64, + test_usize_to_string, + usize, test_u128_to_string, u128, ); From 7c1553c85bf0c6566bffa5a22e91a9c517458ab9 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 16 Jun 2025 07:30:09 -0400 Subject: [PATCH 056/356] Bless unicode test Most likely caused by updating unicode-width v0.2.0 -> v0.2.1, the change seems reasonable enough. --- .../ui/diagnostic-width/non-whitespace-trimming-unicode.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr b/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr index 5408825d8cd6..18d80810ab0c 100644 --- a/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr +++ b/tests/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/non-whitespace-trimming-unicode.rs:4:415 | -LL | ...♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼... +LL | ...♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽ ... | -- ^^ expected `()`, found integer | | | expected due to this From 71afc6f463f141965c3a7aff70be3e4fe55c15ce Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 16 Jun 2025 14:07:25 +0000 Subject: [PATCH 057/356] Add test. --- .../write_to_borrowed.main.CopyProp.diff | 31 +++++++++++++ tests/mir-opt/copy-prop/write_to_borrowed.rs | 45 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff create mode 100644 tests/mir-opt/copy-prop/write_to_borrowed.rs diff --git a/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff b/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff new file mode 100644 index 000000000000..eb73f8c17558 --- /dev/null +++ b/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff @@ -0,0 +1,31 @@ +- // MIR for `main` before CopyProp ++ // MIR for `main` after CopyProp + + fn main() -> () { + let mut _0: (); + let mut _1: *const char; + let mut _2: char; + let mut _3: char; + let mut _4: char; + let mut _5: char; + let mut _6: &char; + let mut _7: (); + + bb0: { + _1 = &raw const _2; + _3 = const 'b'; + _5 = copy _3; + _6 = &_3; +- _4 = copy _5; ++ _3 = copy _5; + (*_1) = copy (*_6); + _6 = &_5; +- _7 = dump_var::(copy _4) -> [return: bb1, unwind unreachable]; ++ _7 = dump_var::(copy _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/copy-prop/write_to_borrowed.rs b/tests/mir-opt/copy-prop/write_to_borrowed.rs new file mode 100644 index 000000000000..dba504fe970d --- /dev/null +++ b/tests/mir-opt/copy-prop/write_to_borrowed.rs @@ -0,0 +1,45 @@ +//@ test-mir-pass: CopyProp + +#![feature(custom_mir, core_intrinsics)] +#![allow(internal_features)] + +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime")] +fn main() { + mir! { + // Both _3 and _5 are borrowed, check that we do not unify them, and that we do not + // introduce a write to any of them. + let _1; + let _2; + let _3; + let _4; + let _5; + let _6; + let _7; + // CHECK: bb0: { + { + // CHECK-NEXT: _1 = &raw const _2; + _1 = core::ptr::addr_of!(_2); + // CHECK-NEXT: _3 = const 'b'; + _3 = 'b'; + // CHECK-NEXT: _5 = copy _3; + _5 = _3; + // CHECK-NEXT: _6 = &_3; + _6 = &_3; + // CHECK-NEXT: _3 = copy _5 + _4 = _5; + // CHECK-NEXT: (*_1) = copy (*_6); + *_1 = *_6; + // CHECK-NEXT: _6 = &_5; + _6 = &_5; + // CHECK-NEXT: _7 = dump_var::(copy _3) + Call(_7 = dump_var(_4), ReturnTo(bb1), UnwindUnreachable()) + } + bb1 = { Return() } + } +} + +fn dump_var(_: T) {} + +// EMIT_MIR write_to_borrowed.main.CopyProp.diff From c4b67c6d873866d4b2c687306bf2f558a8659246 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 16 Jun 2025 10:05:54 +0000 Subject: [PATCH 058/356] Reason about borrowed classes in CopyProp. --- compiler/rustc_mir_transform/src/copy_prop.rs | 34 ++++--------------- compiler/rustc_mir_transform/src/ssa.rs | 23 +++++++++++++ .../write_to_borrowed.main.CopyProp.diff | 3 +- tests/mir-opt/copy-prop/write_to_borrowed.rs | 4 +-- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 27af5818982d..fe78a104fa0b 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -30,6 +30,8 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp { let typing_env = body.typing_env(tcx); let ssa = SsaLocals::new(tcx, body, typing_env); + debug!(borrowed_locals = ?ssa.borrowed_locals()); + debug!(copy_classes = ?ssa.copy_classes()); let fully_moved = fully_moved_locals(&ssa, body); debug!(?fully_moved); @@ -43,14 +45,8 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp { let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h); - Replacer { - tcx, - copy_classes: ssa.copy_classes(), - fully_moved, - borrowed_locals: ssa.borrowed_locals(), - storage_to_remove, - } - .visit_body_preserves_cfg(body); + Replacer { tcx, copy_classes: ssa.copy_classes(), fully_moved, storage_to_remove } + .visit_body_preserves_cfg(body); if any_replacement { crate::simplify::remove_unused_definitions(body); @@ -102,7 +98,6 @@ struct Replacer<'a, 'tcx> { tcx: TyCtxt<'tcx>, fully_moved: DenseBitSet, storage_to_remove: DenseBitSet, - borrowed_locals: &'a DenseBitSet, copy_classes: &'a IndexSlice, } @@ -111,34 +106,18 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { self.tcx } + #[tracing::instrument(level = "trace", skip(self))] fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) { let new_local = self.copy_classes[*local]; - // We must not unify two locals that are borrowed. But this is fine if one is borrowed and - // the other is not. We chose to check the original local, and not the target. That way, if - // the original local is borrowed and the target is not, we do not pessimize the whole class. - if self.borrowed_locals.contains(*local) { - return; - } match ctxt { // Do not modify the local in storage statements. PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {} - // The local should have been marked as non-SSA. - PlaceContext::MutatingUse(_) => assert_eq!(*local, new_local), // We access the value. _ => *local = new_local, } } - fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) { - if let Some(new_projection) = self.process_projection(place.projection, loc) { - place.projection = self.tcx().mk_place_elems(&new_projection); - } - - // Any non-mutating use context is ok. - let ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); - self.visit_local(&mut place.local, ctxt, loc) - } - + #[tracing::instrument(level = "trace", skip(self))] fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { if let Operand::Move(place) = *operand // A move out of a projection of a copy is equivalent to a copy of the original @@ -151,6 +130,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { self.super_operand(operand, loc); } + #[tracing::instrument(level = "trace", skip(self))] fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) { // When removing storage statements, we need to remove both (#107511). if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index edd0cabca49a..03b6f9b7ff3b 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -293,6 +293,10 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_, 'tcx> { fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) { let mut direct_uses = std::mem::take(&mut ssa.direct_uses); let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len()); + // We must not unify two locals that are borrowed. But this is fine if one is borrowed and + // the other is not. This bitset is keyed by *class head* and contains whether any member of + // the class is borrowed. + let mut borrowed_classes = ssa.borrowed_locals().clone(); for (local, rvalue, _) in ssa.assignments(body) { let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) @@ -318,6 +322,11 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) { // visited before `local`, and we just have to copy the representing local. let head = copies[rhs]; + // Do not unify two borrowed locals. + if borrowed_classes.contains(local) && borrowed_classes.contains(head) { + continue; + } + if local == RETURN_PLACE { // `_0` is special, we cannot rename it. Instead, rename the class of `rhs` to // `RETURN_PLACE`. This is only possible if the class head is a temporary, not an @@ -330,14 +339,21 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) { *h = RETURN_PLACE; } } + if borrowed_classes.contains(head) { + borrowed_classes.insert(RETURN_PLACE); + } } else { copies[local] = head; + if borrowed_classes.contains(local) { + borrowed_classes.insert(head); + } } direct_uses[rhs] -= 1; } debug!(?copies); debug!(?direct_uses); + debug!(?borrowed_classes); // Invariant: `copies` must point to the head of an equivalence class. #[cfg(debug_assertions)] @@ -346,6 +362,13 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) { } debug_assert_eq!(copies[RETURN_PLACE], RETURN_PLACE); + // Invariant: `borrowed_classes` must be true if any member of the class is borrowed. + #[cfg(debug_assertions)] + for &head in copies.iter() { + let any_borrowed = ssa.borrowed_locals.iter().any(|l| copies[l] == head); + assert_eq!(borrowed_classes.contains(head), any_borrowed); + } + ssa.direct_uses = direct_uses; ssa.copy_classes = copies; } diff --git a/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff b/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff index eb73f8c17558..eab06b1ba1e7 100644 --- a/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff +++ b/tests/mir-opt/copy-prop/write_to_borrowed.main.CopyProp.diff @@ -17,11 +17,10 @@ _5 = copy _3; _6 = &_3; - _4 = copy _5; -+ _3 = copy _5; (*_1) = copy (*_6); _6 = &_5; - _7 = dump_var::(copy _4) -> [return: bb1, unwind unreachable]; -+ _7 = dump_var::(copy _3) -> [return: bb1, unwind unreachable]; ++ _7 = dump_var::(copy _5) -> [return: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/copy-prop/write_to_borrowed.rs b/tests/mir-opt/copy-prop/write_to_borrowed.rs index dba504fe970d..58809749103e 100644 --- a/tests/mir-opt/copy-prop/write_to_borrowed.rs +++ b/tests/mir-opt/copy-prop/write_to_borrowed.rs @@ -27,13 +27,13 @@ fn main() { _5 = _3; // CHECK-NEXT: _6 = &_3; _6 = &_3; - // CHECK-NEXT: _3 = copy _5 + // CHECK-NOT: {{_.*}} = {{_.*}}; _4 = _5; // CHECK-NEXT: (*_1) = copy (*_6); *_1 = *_6; // CHECK-NEXT: _6 = &_5; _6 = &_5; - // CHECK-NEXT: _7 = dump_var::(copy _3) + // CHECK-NEXT: _7 = dump_var::(copy _5) Call(_7 = dump_var(_4), ReturnTo(bb1), UnwindUnreachable()) } bb1 = { Return() } From 13f5866e96eb0347c278b40fa73a926dfe1546d3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 16 Jun 2025 18:05:44 +0200 Subject: [PATCH 059/356] feat: Show what cargo metadata is doing in status --- .../crates/load-cargo/src/lib.rs | 2 +- .../project-model/src/cargo_workspace.rs | 21 +++++++-- .../crates/project-model/src/sysroot.rs | 6 ++- .../crates/project-model/src/tests.rs | 3 +- .../crates/project-model/src/workspace.rs | 46 ++++++++++++------- .../rust-analyzer/src/cli/rustc_tests.rs | 3 +- 6 files changed, 56 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 89b8631cd25f..52f59679b587 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -42,7 +42,7 @@ pub fn load_workspace_at( root: &Path, cargo_config: &CargoConfig, load_config: &LoadCargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option)> { let root = AbsPathBuf::assert_utf8(std::env::current_dir()?.join(root)); let root = ProjectManifest::discover_single(&root)?; diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 1fade7b33233..392650e1504a 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -12,6 +12,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use serde_derive::Deserialize; use serde_json::from_value; use span::Edition; +use stdx::process::spawn_with_streaming_output; use toolchain::Tool; use crate::{CfgOverrides, InvocationStrategy}; @@ -399,11 +400,21 @@ impl CargoWorkspace { // FIXME: Fetching metadata is a slow process, as it might require // calling crates.io. We should be reporting progress here, but it's // unclear whether cargo itself supports it. - progress("metadata".to_owned()); + progress("cargo metadata: started".to_owned()); - (|| -> anyhow::Result<(_, _)> { - let output = meta.cargo_command().output()?; + let res = (|| -> anyhow::Result<(_, _)> { + let mut errored = false; + let output = + spawn_with_streaming_output(meta.cargo_command(), &mut |_| (), &mut |line| { + errored = errored || line.starts_with("error") || line.starts_with("warning"); + if errored { + progress("cargo metadata: ?".to_owned()); + return; + } + progress(format!("cargo metadata: {line}")); + })?; if !output.status.success() { + progress(format!("cargo metadata: failed {}", output.status)); let error = cargo_metadata::Error::CargoMetadata { stderr: String::from_utf8(output.stderr)?, } @@ -431,7 +442,9 @@ impl CargoWorkspace { .ok_or(cargo_metadata::Error::NoJson)?; Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None)) })() - .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command())) + .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command())); + progress("cargo metadata: finished".to_owned()); + res } pub fn new( diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs index ebd86e3dc48a..29818acd32ef 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs @@ -195,6 +195,7 @@ impl Sysroot { pub fn load_workspace( &self, sysroot_source_config: &RustSourceWorkspaceConfig, + progress: &dyn Fn(String), ) -> Option { assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded"); let Self { root: _, rust_lib_src_root: Some(src_root), workspace: _, error: _ } = self @@ -205,7 +206,7 @@ impl Sysroot { let library_manifest = ManifestPath::try_from(src_root.join("Cargo.toml")).unwrap(); if fs::metadata(&library_manifest).is_ok() { if let Some(loaded) = - self.load_library_via_cargo(library_manifest, src_root, cargo_config) + self.load_library_via_cargo(library_manifest, src_root, cargo_config, progress) { return Some(loaded); } @@ -296,6 +297,7 @@ impl Sysroot { library_manifest: ManifestPath, rust_lib_src_dir: &AbsPathBuf, cargo_config: &CargoMetadataConfig, + progress: &dyn Fn(String), ) -> Option { tracing::debug!("Loading library metadata: {library_manifest}"); let mut cargo_config = cargo_config.clone(); @@ -313,7 +315,7 @@ impl Sysroot { false, // Make sure we never attempt to write to the sysroot true, - &|_| (), + progress, ) { Ok(it) => it, Err(e) => { diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index c69891b7463d..426aa5813729 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -235,7 +235,8 @@ fn smoke_test_real_sysroot_cargo() { AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))), &Default::default(), ); - let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo()); + let loaded_sysroot = + sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &|_| ()); if let Some(loaded_sysroot) = loaded_sysroot { sysroot.set_workspace(loaded_sysroot); } diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index eec0077ea6e2..9366c0a8b411 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -170,7 +170,7 @@ impl ProjectWorkspace { pub fn load( manifest: ProjectManifest, config: &CargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> anyhow::Result { ProjectWorkspace::load_inner(&manifest, config, progress) .with_context(|| format!("Failed to load the project at {manifest}")) @@ -179,7 +179,7 @@ impl ProjectWorkspace { fn load_inner( manifest: &ProjectManifest, config: &CargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> anyhow::Result { let res = match manifest { ProjectManifest::ProjectJson(project_json) => { @@ -206,7 +206,7 @@ impl ProjectWorkspace { fn load_cargo( cargo_toml: &ManifestPath, config: &CargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> Result { progress("Discovering sysroot".to_owned()); let CargoConfig { @@ -304,7 +304,7 @@ impl ProjectWorkspace { &sysroot, *no_deps, false, - &|_| (), + progress, ) { Ok((meta, _error)) => { let workspace = CargoWorkspace::new( @@ -347,13 +347,16 @@ impl ProjectWorkspace { &sysroot, *no_deps, false, - &|_| (), + progress, ) }); let loaded_sysroot = s.spawn(|| { - sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( - sysroot_metadata_config(extra_env, &targets), - )) + sysroot.load_workspace( + &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( + extra_env, &targets, + )), + progress, + ) }); let cargo_config_extra_env = s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot)); @@ -411,7 +414,7 @@ impl ProjectWorkspace { pub fn load_inline( mut project_json: ProjectJson, config: &CargoConfig, - progress: &dyn Fn(String), + progress: &(dyn Fn(String) + Sync), ) -> ProjectWorkspace { progress("Discovering sysroot".to_owned()); let mut sysroot = @@ -443,11 +446,18 @@ impl ProjectWorkspace { }); let loaded_sysroot = s.spawn(|| { if let Some(sysroot_project) = sysroot_project { - sysroot.load_workspace(&RustSourceWorkspaceConfig::Json(*sysroot_project)) + sysroot.load_workspace( + &RustSourceWorkspaceConfig::Json(*sysroot_project), + progress, + ) } else { - sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( - sysroot_metadata_config(&config.extra_env, &targets), - )) + sysroot.load_workspace( + &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( + &config.extra_env, + &targets, + )), + progress, + ) } }); @@ -497,9 +507,13 @@ impl ProjectWorkspace { .unwrap_or_default(); let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env); let data_layout = target_data_layout::get(query_config, None, &config.extra_env); - let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::CargoMetadata( - sysroot_metadata_config(&config.extra_env, &targets), - )); + let loaded_sysroot = sysroot.load_workspace( + &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( + &config.extra_env, + &targets, + )), + &|_| (), + ); if let Some(loaded_sysroot) = loaded_sysroot { sysroot.set_workspace(loaded_sysroot); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index e3b372c91494..0e8b9185f600 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -76,7 +76,8 @@ impl Tester { }; let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env); - let loaded_sysroot = sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo()); + let loaded_sysroot = + sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &|_| ()); if let Some(loaded_sysroot) = loaded_sysroot { sysroot.set_workspace(loaded_sysroot); } From 2eccf18075893f7ea2226f6d7d7df818606835cb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 16 Jun 2025 18:06:28 +0200 Subject: [PATCH 060/356] Add comment to prevent having code other than `initSearch` at the end of `search.js` --- src/librustdoc/html/static/js/search.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 126da46ab773..bc9d8a102961 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -5872,6 +5872,10 @@ Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new In 0xa0fc0000,0x5555ba08,0x55555555, ]); +// ==================== +// WARNING: Nothing should be added below this comment: we need the `initSearch` function to +// be called ONLY when the whole file has been parsed and loaded. + // @ts-expect-error function initSearch(searchIndx) { rawSearchIndex = searchIndx; From a38a9a626253c330e06ce2132ec8aa6ba7c5e1b7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 16 Jun 2025 18:30:40 +0200 Subject: [PATCH 061/356] feat: Insert required parentheses when typing `+` in trait type --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 4 +- .../rust-analyzer/crates/ide/src/typing.rs | 88 ++++++++++++++++++- .../crates/rust-analyzer/src/config.rs | 2 +- .../rust-analyzer/src/lsp/capabilities.rs | 2 +- .../docs/book/src/configuration_generated.md | 2 +- .../rust-analyzer/editors/code/package.json | 2 +- 6 files changed, 92 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 82dbcde4c06f..b3b8deb61fc0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -409,7 +409,7 @@ impl Analysis { self.with_db(|db| typing::on_enter(db, position)) } - pub const SUPPORTED_TRIGGER_CHARS: &'static str = typing::TRIGGER_CHARS; + pub const SUPPORTED_TRIGGER_CHARS: &[char] = typing::TRIGGER_CHARS; /// Returns an edit which should be applied after a character was typed. /// @@ -421,7 +421,7 @@ impl Analysis { char_typed: char, ) -> Cancellable> { // Fast path to not even parse the file. - if !typing::TRIGGER_CHARS.contains(char_typed) { + if !typing::TRIGGER_CHARS.contains(&char_typed) { return Ok(None); } diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index 4df7e25223d9..ed55ac5bf04b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -15,6 +15,7 @@ mod on_enter; +use either::Either; use hir::EditionedFileId; use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb}; use span::Edition; @@ -33,7 +34,7 @@ use crate::SourceChange; pub(crate) use on_enter::on_enter; // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. -pub(crate) const TRIGGER_CHARS: &str = ".=<>{(|"; +pub(crate) const TRIGGER_CHARS: &[char] = &['.', '=', '<', '>', '{', '(', '|', '+']; struct ExtendedTextEdit { edit: TextEdit, @@ -66,7 +67,7 @@ pub(crate) fn on_char_typed( position: FilePosition, char_typed: char, ) -> Option { - if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { + if !TRIGGER_CHARS.contains(&char_typed) { return None; } // FIXME: We need to figure out the edition of the file here, but that means hitting the @@ -101,6 +102,7 @@ fn on_char_typed_( '>' => on_right_angle_typed(&file.tree(), offset), '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition), '|' => on_pipe_typed(&file.tree(), offset), + '+' => on_plus_typed(&file.tree(), offset), _ => None, } .map(conv) @@ -402,6 +404,28 @@ fn on_pipe_typed(file: &SourceFile, offset: TextSize) -> Option { Some(TextEdit::insert(after_lpipe, "|".to_owned())) } +fn on_plus_typed(file: &SourceFile, offset: TextSize) -> Option { + let plus_token = file.syntax().token_at_offset(offset).right_biased()?; + if plus_token.kind() != SyntaxKind::PLUS { + return None; + } + let mut ancestors = plus_token.parent_ancestors(); + ancestors.next().and_then(ast::TypeBoundList::cast)?; + let trait_type = + ancestors.next().and_then(>::cast)?; + let kind = ancestors.next()?.kind(); + + if ast::RefType::can_cast(kind) || ast::PtrType::can_cast(kind) || ast::RetType::can_cast(kind) + { + let mut builder = TextEdit::builder(); + builder.insert(trait_type.syntax().text_range().start(), "(".to_owned()); + builder.insert(trait_type.syntax().text_range().end(), ")".to_owned()); + Some(builder.finish()) + } else { + None + } +} + /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option { let file_text = file.syntax().text(); @@ -1594,6 +1618,66 @@ fn foo() { fn foo() { let $0 } +"#, + ); + } + + #[test] + fn adds_parentheses_around_trait_object_in_ref_type() { + type_char( + '+', + r#" +fn foo(x: &dyn A$0) {} +"#, + r#" +fn foo(x: &(dyn A+)) {} +"#, + ); + type_char( + '+', + r#" +fn foo(x: &'static dyn A$0B) {} +"#, + r#" +fn foo(x: &'static (dyn A+B)) {} +"#, + ); + type_char_noop( + '+', + r#" +fn foo(x: &(dyn A$0)) {} +"#, + ); + type_char_noop( + '+', + r#" +fn foo(x: Box) {} +"#, + ); + } + + #[test] + fn adds_parentheses_around_trait_object_in_ptr_type() { + type_char( + '+', + r#" +fn foo(x: *const dyn A$0) {} +"#, + r#" +fn foo(x: *const (dyn A+)) {} +"#, + ); + } + + #[test] + fn adds_parentheses_around_trait_object_in_return_type() { + type_char( + '+', + r#" +fn foo(x: fn() -> dyn A$0) {} +"#, + r#" +fn foo(x: fn() -> (dyn A+)) {} "#, ); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 762b63f54b09..99d1a4d64ca8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -344,7 +344,7 @@ config_data! { /// - typing `{` in a use item adds a closing `}` in the right place /// - typing `>` to complete a return type `->` will insert a whitespace after it /// - typing `<` in a path or type position inserts a closing `>` after the path or type. - typing_triggerChars: Option = Some("=.".to_owned()), + typing_triggerChars: Option = Some("=.+".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index 418fe957590d..04e31f37fd2c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -77,7 +77,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { _ => Some(OneOf::Left(false)), }, document_on_type_formatting_provider: Some({ - let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.chars(); + let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.iter(); DocumentOnTypeFormattingOptions { first_trigger_character: chars.next().unwrap().to_string(), more_trigger_character: Some(chars.map(|c| c.to_string()).collect()), diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 4eb9cfc4e5bd..521edb068a07 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -1410,7 +1410,7 @@ Show documentation. ## rust-analyzer.typing.triggerChars {#typing.triggerChars} -Default: `"=."` +Default: `"=.+"` Specify the characters allowed to invoke special on typing triggers. - typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index dcdb4fe30ee8..0b86332d1a3b 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2836,7 +2836,7 @@ "properties": { "rust-analyzer.typing.triggerChars": { "markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.", - "default": "=.", + "default": "=.+", "type": [ "null", "string" From db5a427b3104a8597cca338ec0da3ab0243b7864 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 15 May 2025 16:38:46 -0700 Subject: [PATCH 062/356] Change __rust_no_alloc_shim_is_unstable to be a function --- src/allocator.rs | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 9cff8a84db3d..ffb932a3c38e 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,6 +1,7 @@ //! Allocator shim // Adapted from rustc +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, @@ -97,16 +98,31 @@ fn codegen_inner( data.define(Box::new([val])); module.define_data(data_id, &data).unwrap(); - let data_id = module - .declare_data( - &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - Linkage::Export, - false, - false, - ) - .unwrap(); - let mut data = DataDescription::new(); - data.set_align(1); - data.define(Box::new([0])); - module.define_data(data_id, &data).unwrap(); + { + let sig = Signature { + call_conv: module.target_config().default_call_conv, + params: vec![], + returns: vec![], + }; + let func_id = module + .declare_function( + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + Linkage::Export, + &sig, + ) + .unwrap(); + + let mut ctx = Context::new(); + ctx.func.signature = sig; + let mut func_ctx = FunctionBuilderContext::new(); + let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); + + let block = bcx.create_block(); + bcx.switch_to_block(block); + bcx.ins().return_(&[]); + bcx.seal_all_blocks(); + bcx.finalize(); + + module.define_function(func_id, &mut ctx).unwrap(); + } } From 6da3bf853e2a3a0417de7faa878e4d7907526a96 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Mon, 16 Jun 2025 12:25:25 -0700 Subject: [PATCH 063/356] Apply suggestions from code review Co-authored-by: Oli Scherer --- compiler/rustc_thread_pool/LICENSE-APACHE | 201 ---------------------- compiler/rustc_thread_pool/LICENSE-MIT | 25 --- compiler/rustc_thread_pool/README.md | 5 +- 3 files changed, 1 insertion(+), 230 deletions(-) delete mode 100644 compiler/rustc_thread_pool/LICENSE-APACHE delete mode 100644 compiler/rustc_thread_pool/LICENSE-MIT diff --git a/compiler/rustc_thread_pool/LICENSE-APACHE b/compiler/rustc_thread_pool/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e80..000000000000 --- a/compiler/rustc_thread_pool/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/compiler/rustc_thread_pool/LICENSE-MIT b/compiler/rustc_thread_pool/LICENSE-MIT deleted file mode 100644 index 25597d5838fa..000000000000 --- a/compiler/rustc_thread_pool/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2010 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/compiler/rustc_thread_pool/README.md b/compiler/rustc_thread_pool/README.md index 5b8714f5df48..a50cc1165b81 100644 --- a/compiler/rustc_thread_pool/README.md +++ b/compiler/rustc_thread_pool/README.md @@ -2,12 +2,9 @@ Note: This is an unstable fork made for use in rustc Rayon-core represents the "core, stable" APIs of Rayon: join, scope, and so forth, as well as the ability to create custom thread-pools with ThreadPool. -Maybe worth mentioning: users are not necessarily intended to directly access rayon-core; all its APIs are mirrored in the rayon crate. To that end, the examples in the docs use rayon::join and so forth rather than rayon_core::join. +Maybe worth mentioning: users are not necessarily intended to directly access rustc_thread_pool; all its APIs are mirrored in the rayon crate. To that end, the examples in the docs use rayon::join and so forth rather than rayon_core::join. -rayon-core aims to never, or almost never, have a breaking change to its API, because each revision of rayon-core also houses the global thread-pool (and hence if you have two simultaneous versions of rayon-core, you have two thread-pools). Please see [Rayon Docs] for details about using Rayon. [Rayon Docs]: https://docs.rs/rayon/ - -Rayon-core currently requires `rustc 1.63.0` or greater. From cfa4c8f473cbe5af1a6665add451ee0ec702f898 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 5 Mar 2025 04:31:12 +0000 Subject: [PATCH 064/356] cranelift/gcc: `{Meta,Pointee,}Sized` in minicore As in many previous commits, adding the new traits to minicore, but this time for cranelift and gcc. --- example/mini_core.rs | 66 ++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/example/mini_core.rs b/example/mini_core.rs index 012e4dbc3ec9..524ebde1c743 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -14,8 +14,14 @@ #![no_core] #![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)] +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + #[lang = "sized"] -pub trait Sized {} +pub trait Sized: MetaSized {} #[lang = "destruct"] pub trait Destruct {} @@ -24,35 +30,35 @@ pub trait Destruct {} pub trait Tuple {} #[lang = "unsize"] -pub trait Unsize {} +pub trait Unsize: PointeeSized {} #[lang = "coerce_unsized"] pub trait CoerceUnsized {} -impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} -impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} -impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} +impl<'a, 'b: 'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {} +impl<'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {} +impl, U: PointeeSized> CoerceUnsized<*const U> for *const T {} +impl, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {} #[lang = "dispatch_from_dyn"] pub trait DispatchFromDyn {} // &T -> &U -impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} +impl<'a, T: PointeeSized + Unsize, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {} // &mut T -> &mut U -impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} +impl<'a, T: PointeeSized + Unsize, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {} // *const T -> *const U -impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} +impl, U: PointeeSized> DispatchFromDyn<*const U> for *const T {} // *mut T -> *mut U -impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} -impl, U: ?Sized> DispatchFromDyn> for Box {} +impl, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {} +impl, U: MetaSized> DispatchFromDyn> for Box {} #[lang = "legacy_receiver"] pub trait LegacyReceiver {} -impl LegacyReceiver for &T {} -impl LegacyReceiver for &mut T {} -impl LegacyReceiver for Box {} +impl LegacyReceiver for &T {} +impl LegacyReceiver for &mut T {} +impl LegacyReceiver for Box {} #[lang = "copy"] pub trait Copy {} @@ -74,9 +80,9 @@ impl Copy for isize {} impl Copy for f32 {} impl Copy for f64 {} impl Copy for char {} -impl<'a, T: ?Sized> Copy for &'a T {} -impl Copy for *const T {} -impl Copy for *mut T {} +impl<'a, T: PointeeSized> Copy for &'a T {} +impl Copy for *const T {} +impl Copy for *mut T {} impl Copy for Option {} #[lang = "sync"] @@ -94,17 +100,17 @@ unsafe impl Sync for i32 {} unsafe impl Sync for isize {} unsafe impl Sync for char {} unsafe impl Sync for f32 {} -unsafe impl<'a, T: ?Sized> Sync for &'a T {} +unsafe impl<'a, T: PointeeSized> Sync for &'a T {} unsafe impl Sync for [T; N] {} #[lang = "freeze"] unsafe auto trait Freeze {} -unsafe impl Freeze for PhantomData {} -unsafe impl Freeze for *const T {} -unsafe impl Freeze for *mut T {} -unsafe impl Freeze for &T {} -unsafe impl Freeze for &mut T {} +unsafe impl Freeze for PhantomData {} +unsafe impl Freeze for *const T {} +unsafe impl Freeze for *mut T {} +unsafe impl Freeze for &T {} +unsafe impl Freeze for &mut T {} #[lang = "structural_peq"] pub trait StructuralPartialEq {} @@ -443,7 +449,7 @@ pub enum Option { pub use Option::*; #[lang = "phantom_data"] -pub struct PhantomData; +pub struct PhantomData; #[lang = "fn_once"] #[rustc_paren_sugar] @@ -564,18 +570,18 @@ pub trait Deref { #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] -pub struct NonNull(pub *const T); +pub struct NonNull(pub *const T); -impl CoerceUnsized> for NonNull where T: Unsize {} -impl DispatchFromDyn> for NonNull where T: Unsize {} +impl CoerceUnsized> for NonNull where T: Unsize {} +impl DispatchFromDyn> for NonNull where T: Unsize {} -pub struct Unique { +pub struct Unique { pub pointer: NonNull, pub _marker: PhantomData, } -impl CoerceUnsized> for Unique where T: Unsize {} -impl DispatchFromDyn> for Unique where T: Unsize {} +impl CoerceUnsized> for Unique where T: Unsize {} +impl DispatchFromDyn> for Unique where T: Unsize {} #[lang = "global_alloc_ty"] pub struct Global; From 6d040856df069e0345cc34047c4d21c66021cca9 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Mon, 16 Jun 2025 19:41:12 +0200 Subject: [PATCH 065/356] Add a warning to LateContext::get_def_path --- compiler/rustc_lint/src/context.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5679d4566dcd..c7d59fa283a7 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -710,6 +710,15 @@ impl<'tcx> LateContext<'tcx> { /// Gets the absolute path of `def_id` as a vector of `Symbol`. /// + /// Note that this is kinda expensive because it has to + /// travel the tree and pretty-print. Use sparingly. + /// + /// If you're trying to match for an item given by its path, use a + /// diagnostic item. If you're only interested in given sections, use more + /// specific functions, such as [`TyCtxt::crate_name`] + /// + /// FIXME: It would be great if this could be optimized. + /// /// # Examples /// /// ```rust,ignore (no context or def id available) From 703856f123ab1f7d77a7e7607ef1271aff2bba45 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 17 Jun 2025 07:40:50 +0200 Subject: [PATCH 066/356] fix: Copy lockfiles into target directory before invoking `cargo metadata` --- .../project-model/src/cargo_workspace.rs | 73 ++++++++++-- .../crates/project-model/src/manifest_path.rs | 8 +- .../crates/project-model/src/sysroot.rs | 54 ++++++--- .../crates/project-model/src/tests.rs | 12 +- .../crates/project-model/src/workspace.rs | 110 ++++++++++-------- .../rust-analyzer/src/cli/rustc_tests.rs | 9 +- 6 files changed, 179 insertions(+), 87 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 392650e1504a..58507418e4d3 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -7,7 +7,7 @@ use anyhow::Context; use base_db::Env; use cargo_metadata::{CargoOpt, MetadataCommand}; use la_arena::{Arena, Idx}; -use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; +use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use serde_derive::Deserialize; use serde_json::from_value; @@ -18,6 +18,14 @@ use toolchain::Tool; use crate::{CfgOverrides, InvocationStrategy}; use crate::{ManifestPath, Sysroot}; +const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH: semver::Version = semver::Version { + major: 1, + minor: 82, + patch: 0, + pre: semver::Prerelease::EMPTY, + build: semver::BuildMetadata::EMPTY, +}; + /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo /// workspace. It pretty closely mirrors `cargo metadata` output. /// @@ -291,6 +299,13 @@ pub struct CargoMetadataConfig { pub extra_args: Vec, /// Extra env vars to set when invoking the cargo command pub extra_env: FxHashMap>, + /// The target dir for this workspace load. + pub target_dir: Utf8PathBuf, + /// What kind of metadata are we fetching: workspace, rustc, or sysroot. + pub kind: &'static str, + /// The toolchain version, if known. + /// Used to conditionally enable unstable cargo features. + pub toolchain_version: Option, } // Deserialize helper for the cargo metadata @@ -383,18 +398,54 @@ impl CargoWorkspace { config.targets.iter().flat_map(|it| ["--filter-platform".to_owned(), it.clone()]), ); } - // The manifest is a rust file, so this means its a script manifest - if cargo_toml.is_rust_manifest() { - // Deliberately don't set up RUSTC_BOOTSTRAP or a nightly override here, the user should - // opt into it themselves. - other_options.push("-Zscript".to_owned()); - } - if locked { - other_options.push("--locked".to_owned()); - } if no_deps { other_options.push("--no-deps".to_owned()); } + + let mut using_lockfile_copy = false; + // The manifest is a rust file, so this means its a script manifest + if cargo_toml.is_rust_manifest() { + other_options.push("-Zscript".to_owned()); + } else if config + .toolchain_version + .as_ref() + .is_some_and(|v| *v >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH) + { + let lockfile = <_ as AsRef>::as_ref(cargo_toml).with_extension("lock"); + let target_lockfile = config + .target_dir + .join("rust-analyzer") + .join("metadata") + .join(config.kind) + .join("Cargo.lock"); + match std::fs::copy(&lockfile, &target_lockfile) { + Ok(_) => { + using_lockfile_copy = true; + other_options.push("--lockfile-path".to_owned()); + other_options.push(target_lockfile.to_string()); + } + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + // There exists no lockfile yet + using_lockfile_copy = true; + other_options.push("--lockfile-path".to_owned()); + other_options.push(target_lockfile.to_string()); + } + Err(e) => { + tracing::warn!( + "Failed to copy lock file from `{lockfile}` to `{target_lockfile}`: {e}", + ); + } + } + } + if using_lockfile_copy { + other_options.push("-Zunstable-options".to_owned()); + meta.env("RUSTC_BOOTSTRAP", "1"); + } + // No need to lock it if we copied the lockfile, we won't modify the original after all/ + // This way cargo cannot error out on us if the lockfile requires updating. + if !using_lockfile_copy && locked { + other_options.push("--locked".to_owned()); + } meta.other_options(other_options); // FIXME: Fetching metadata is a slow process, as it might require @@ -427,8 +478,8 @@ impl CargoWorkspace { current_dir, config, sysroot, - locked, true, + locked, progress, ) { return Ok((metadata, Some(error))); diff --git a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs index 4f43be2f38fd..fba8cc9709d1 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs @@ -1,7 +1,7 @@ //! See [`ManifestPath`]. use std::{borrow::Borrow, fmt, ops}; -use paths::{AbsPath, AbsPathBuf}; +use paths::{AbsPath, AbsPathBuf, Utf8Path}; /// More or less [`AbsPathBuf`] with non-None parent. /// @@ -78,6 +78,12 @@ impl AsRef for ManifestPath { } } +impl AsRef for ManifestPath { + fn as_ref(&self) -> &Utf8Path { + self.file.as_ref() + } +} + impl Borrow for ManifestPath { fn borrow(&self) -> &AbsPath { self.file.borrow() diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs index 29818acd32ef..4b34fc007112 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs @@ -4,6 +4,7 @@ //! but we can't process `.rlib` and need source code instead. The source code //! is typically installed with `rustup component add rust-src` command. +use core::fmt; use std::{env, fs, ops::Not, path::Path, process::Command}; use anyhow::{Result, format_err}; @@ -34,6 +35,19 @@ pub enum RustLibSrcWorkspace { Empty, } +impl fmt::Display for RustLibSrcWorkspace { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RustLibSrcWorkspace::Workspace(ws) => write!(f, "workspace {}", ws.workspace_root()), + RustLibSrcWorkspace::Json(json) => write!(f, "json {}", json.manifest_or_root()), + RustLibSrcWorkspace::Stitched(stitched) => { + write!(f, "stitched with {} crates", stitched.crates.len()) + } + RustLibSrcWorkspace::Empty => write!(f, "empty"), + } + } +} + impl Sysroot { pub const fn empty() -> Sysroot { Sysroot { @@ -195,6 +209,7 @@ impl Sysroot { pub fn load_workspace( &self, sysroot_source_config: &RustSourceWorkspaceConfig, + current_dir: &AbsPath, progress: &dyn Fn(String), ) -> Option { assert!(matches!(self.workspace, RustLibSrcWorkspace::Empty), "workspace already loaded"); @@ -205,10 +220,16 @@ impl Sysroot { if let RustSourceWorkspaceConfig::CargoMetadata(cargo_config) = sysroot_source_config { let library_manifest = ManifestPath::try_from(src_root.join("Cargo.toml")).unwrap(); if fs::metadata(&library_manifest).is_ok() { - if let Some(loaded) = - self.load_library_via_cargo(library_manifest, src_root, cargo_config, progress) - { - return Some(loaded); + match self.load_library_via_cargo( + &library_manifest, + current_dir, + cargo_config, + progress, + ) { + Ok(loaded) => return Some(loaded), + Err(e) => { + tracing::error!("`cargo metadata` failed on `{library_manifest}` : {e}") + } } } tracing::debug!("Stitching sysroot library: {src_root}"); @@ -294,11 +315,11 @@ impl Sysroot { fn load_library_via_cargo( &self, - library_manifest: ManifestPath, - rust_lib_src_dir: &AbsPathBuf, + library_manifest: &ManifestPath, + current_dir: &AbsPath, cargo_config: &CargoMetadataConfig, progress: &dyn Fn(String), - ) -> Option { + ) -> Result { tracing::debug!("Loading library metadata: {library_manifest}"); let mut cargo_config = cargo_config.clone(); // the sysroot uses `public-dependency`, so we make cargo think it's a nightly @@ -307,22 +328,16 @@ impl Sysroot { Some("nightly".to_owned()), ); - let (mut res, _) = match CargoWorkspace::fetch_metadata( - &library_manifest, - rust_lib_src_dir, + let (mut res, _) = CargoWorkspace::fetch_metadata( + library_manifest, + current_dir, &cargo_config, self, false, // Make sure we never attempt to write to the sysroot true, progress, - ) { - Ok(it) => it, - Err(e) => { - tracing::error!("`cargo metadata` failed on `{library_manifest}` : {e}"); - return None; - } - }; + )?; // Patch out `rustc-std-workspace-*` crates to point to the real crates. // This is done prior to `CrateGraph` construction to prevent de-duplication logic from failing. @@ -373,8 +388,9 @@ impl Sysroot { res.packages.remove(idx); }); - let cargo_workspace = CargoWorkspace::new(res, library_manifest, Default::default(), true); - Some(RustLibSrcWorkspace::Workspace(cargo_workspace)) + let cargo_workspace = + CargoWorkspace::new(res, library_manifest.clone(), Default::default(), true); + Ok(RustLibSrcWorkspace::Workspace(cargo_workspace)) } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 426aa5813729..4f11af2d06cf 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -1,3 +1,5 @@ +use std::env::temp_dir; + use base_db::{CrateGraphBuilder, ProcMacroPaths}; use cargo_metadata::Metadata; use cfg::{CfgAtom, CfgDiff}; @@ -235,12 +237,18 @@ fn smoke_test_real_sysroot_cargo() { AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))), &Default::default(), ); + let cwd = AbsPathBuf::assert_utf8(temp_dir().join("smoke_test_real_sysroot_cargo")); + std::fs::create_dir_all(&cwd).unwrap(); let loaded_sysroot = - sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &|_| ()); + sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &cwd, &|_| ()); if let Some(loaded_sysroot) = loaded_sysroot { sysroot.set_workspace(loaded_sysroot); } - assert!(matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_))); + assert!( + matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)), + "got {}", + sysroot.workspace() + ); let project_workspace = ProjectWorkspace { kind: ProjectWorkspaceKind::Cargo { cargo: cargo_workspace, diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 9366c0a8b411..a6743a32b142 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -12,7 +12,7 @@ use base_db::{ }; use cfg::{CfgAtom, CfgDiff, CfgOptions}; use intern::{Symbol, sym}; -use paths::{AbsPath, AbsPathBuf}; +use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use span::{Edition, FileId}; @@ -209,6 +209,7 @@ impl ProjectWorkspace { progress: &(dyn Fn(String) + Sync), ) -> Result { progress("Discovering sysroot".to_owned()); + let workspace_dir = cargo_toml.parent(); let CargoConfig { features, rustc_source, @@ -224,15 +225,9 @@ impl ProjectWorkspace { .. } = config; let mut sysroot = match (sysroot, sysroot_src) { - (Some(RustLibSource::Discover), None) => { - Sysroot::discover(cargo_toml.parent(), extra_env) - } + (Some(RustLibSource::Discover), None) => Sysroot::discover(workspace_dir, extra_env), (Some(RustLibSource::Discover), Some(sysroot_src)) => { - Sysroot::discover_with_src_override( - cargo_toml.parent(), - extra_env, - sysroot_src.clone(), - ) + Sysroot::discover_with_src_override(workspace_dir, extra_env, sysroot_src.clone()) } (Some(RustLibSource::Path(path)), None) => { Sysroot::discover_rust_lib_src_dir(path.clone()) @@ -248,24 +243,23 @@ impl ProjectWorkspace { let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml); let targets = target_tuple::get(toolchain_config, target.as_deref(), extra_env).unwrap_or_default(); + let toolchain = version::get(toolchain_config, extra_env) + .inspect_err(|e| { + tracing::error!(%e, + "failed fetching toolchain version for {cargo_toml:?} workspace" + ) + }) + .ok() + .flatten(); + + let target_dir = + config.target_dir.clone().unwrap_or_else(|| workspace_dir.join("target").into()); // We spawn a bunch of processes to query various information about the workspace's // toolchain and sysroot // We can speed up loading a bit by spawning all of these processes in parallel (especially // on systems were process spawning is delayed) let join = thread::scope(|s| { - let workspace_dir = cargo_toml.parent(); - let toolchain = s.spawn(|| { - version::get(toolchain_config, extra_env) - .inspect_err(|e| { - tracing::error!(%e, - "failed fetching toolchain version for {cargo_toml:?} workspace" - ) - }) - .ok() - .flatten() - }); - let rustc_cfg = s.spawn(|| { rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), extra_env) }); @@ -300,10 +294,13 @@ impl ProjectWorkspace { targets: targets.clone(), extra_args: extra_args.clone(), extra_env: extra_env.clone(), + target_dir: target_dir.clone(), + toolchain_version: toolchain.clone(), + kind: "rustc-dev" }, &sysroot, *no_deps, - false, + true, progress, ) { Ok((meta, _error)) => { @@ -343,6 +340,9 @@ impl ProjectWorkspace { targets: targets.clone(), extra_args: extra_args.clone(), extra_env: extra_env.clone(), + target_dir: target_dir.clone(), + toolchain_version: toolchain.clone(), + kind: "workspace", }, &sysroot, *no_deps, @@ -353,15 +353,18 @@ impl ProjectWorkspace { let loaded_sysroot = s.spawn(|| { sysroot.load_workspace( &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( - extra_env, &targets, + config, + &targets, + toolchain.clone(), + target_dir.clone(), )), + workspace_dir, progress, ) }); let cargo_config_extra_env = s.spawn(|| cargo_config_env(cargo_toml, extra_env, &sysroot)); thread::Result::Ok(( - toolchain.join()?, rustc_cfg.join()?, data_layout.join()?, rustc_dir.join()?, @@ -371,18 +374,11 @@ impl ProjectWorkspace { )) }); - let ( - toolchain, - rustc_cfg, - data_layout, - rustc, - loaded_sysroot, - cargo_metadata, - cargo_config_extra_env, - ) = match join { - Ok(it) => it, - Err(e) => std::panic::resume_unwind(e), - }; + let (rustc_cfg, data_layout, rustc, loaded_sysroot, cargo_metadata, cargo_config_extra_env) = + match join { + Ok(it) => it, + Err(e) => std::panic::resume_unwind(e), + }; let (meta, error) = cargo_metadata.with_context(|| { format!( @@ -391,6 +387,7 @@ impl ProjectWorkspace { })?; let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_config_extra_env, false); if let Some(loaded_sysroot) = loaded_sysroot { + tracing::info!(src_root = ?sysroot.rust_lib_src_root(), root = %loaded_sysroot, "Loaded sysroot"); sysroot.set_workspace(loaded_sysroot); } @@ -426,14 +423,13 @@ impl ProjectWorkspace { let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref()); let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env) .unwrap_or_default(); + let toolchain = version::get(query_config, &config.extra_env).ok().flatten(); // We spawn a bunch of processes to query various information about the workspace's // toolchain and sysroot // We can speed up loading a bit by spawning all of these processes in parallel (especially // on systems were process spawning is delayed) let join = thread::scope(|s| { - let toolchain = - s.spawn(|| version::get(query_config, &config.extra_env).ok().flatten()); let rustc_cfg = s.spawn(|| { rustc_cfg::get(query_config, targets.first().map(Deref::deref), &config.extra_env) }); @@ -445,31 +441,35 @@ impl ProjectWorkspace { ) }); let loaded_sysroot = s.spawn(|| { + let project_root = project_json.project_root(); if let Some(sysroot_project) = sysroot_project { sysroot.load_workspace( &RustSourceWorkspaceConfig::Json(*sysroot_project), + project_root, progress, ) } else { + let target_dir = config + .target_dir + .clone() + .unwrap_or_else(|| project_root.join("target").into()); sysroot.load_workspace( &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( - &config.extra_env, + config, &targets, + toolchain.clone(), + target_dir, )), + project_root, progress, ) } }); - thread::Result::Ok(( - toolchain.join()?, - rustc_cfg.join()?, - data_layout.join()?, - loaded_sysroot.join()?, - )) + thread::Result::Ok((rustc_cfg.join()?, data_layout.join()?, loaded_sysroot.join()?)) }); - let (toolchain, rustc_cfg, target_layout, loaded_sysroot) = match join { + let (rustc_cfg, target_layout, loaded_sysroot) = match join { Ok(it) => it, Err(e) => std::panic::resume_unwind(e), }; @@ -507,11 +507,15 @@ impl ProjectWorkspace { .unwrap_or_default(); let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env); let data_layout = target_data_layout::get(query_config, None, &config.extra_env); + let target_dir = config.target_dir.clone().unwrap_or_else(|| dir.join("target").into()); let loaded_sysroot = sysroot.load_workspace( &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( - &config.extra_env, + config, &targets, + toolchain.clone(), + target_dir.clone(), )), + dir, &|_| (), ); if let Some(loaded_sysroot) = loaded_sysroot { @@ -526,6 +530,9 @@ impl ProjectWorkspace { targets, extra_args: config.extra_args.clone(), extra_env: config.extra_env.clone(), + target_dir, + toolchain_version: toolchain.clone(), + kind: "detached-file", }, &sysroot, config.no_deps, @@ -1818,13 +1825,18 @@ fn add_dep_inner(graph: &mut CrateGraphBuilder, from: CrateBuilderId, dep: Depen } fn sysroot_metadata_config( - extra_env: &FxHashMap>, + config: &CargoConfig, targets: &[String], + toolchain_version: Option, + target_dir: Utf8PathBuf, ) -> CargoMetadataConfig { CargoMetadataConfig { features: Default::default(), targets: targets.to_vec(), extra_args: Default::default(), - extra_env: extra_env.clone(), + extra_env: config.extra_env.clone(), + target_dir, + toolchain_version, + kind: "sysroot", } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 0e8b9185f600..740fcd81ea98 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -9,7 +9,6 @@ use hir::{ChangeWithProcMacros, Crate}; use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig}; use ide_db::base_db; use itertools::Either; -use paths::Utf8PathBuf; use profile::StopWatch; use project_model::toolchain_info::{QueryConfig, target_data_layout}; use project_model::{ @@ -64,9 +63,9 @@ fn detect_errors_from_rustc_stderr_file(p: PathBuf) -> FxHashMap Result { - let mut path = std::env::temp_dir(); - path.push("ra-rustc-test.rs"); - let tmp_file = AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).unwrap()).unwrap(); + let mut path = AbsPathBuf::assert_utf8(std::env::temp_dir()); + path.push("ra-rustc-test"); + let tmp_file = path.join("ra-rustc-test.rs"); std::fs::write(&tmp_file, "")?; let cargo_config = CargoConfig { sysroot: Some(RustLibSource::Discover), @@ -77,7 +76,7 @@ impl Tester { let mut sysroot = Sysroot::discover(tmp_file.parent().unwrap(), &cargo_config.extra_env); let loaded_sysroot = - sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &|_| ()); + sysroot.load_workspace(&RustSourceWorkspaceConfig::default_cargo(), &path, &|_| ()); if let Some(loaded_sysroot) = loaded_sysroot { sysroot.set_workspace(loaded_sysroot); } From 8e86b84cd16388f7fac3b712fee66637c22182c6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 1 Apr 2025 11:29:46 +0200 Subject: [PATCH 067/356] chore: Start infesting ide crates with 'db lifetime --- .../rust-analyzer/crates/hir/src/attrs.rs | 12 +- .../crates/hir/src/diagnostics.rs | 80 ++-- .../rust-analyzer/crates/hir/src/display.rs | 4 +- .../crates/hir/src/has_source.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 444 ++++++++++-------- .../rust-analyzer/crates/hir/src/semantics.rs | 67 +-- .../crates/hir/src/source_analyzer.rs | 41 +- .../crates/hir/src/term_search.rs | 48 +- .../crates/hir/src/term_search/expr.rs | 33 +- .../crates/hir/src/term_search/tactics.rs | 98 ++-- .../crates/ide-assists/src/assist_context.rs | 2 +- .../src/handlers/add_missing_impl_members.rs | 2 +- .../src/handlers/add_missing_match_arms.rs | 10 +- .../ide-assists/src/handlers/auto_import.rs | 10 +- .../src/handlers/extract_function.rs | 149 +++--- .../src/handlers/generate_function.rs | 2 +- .../ide-assists/src/handlers/inline_call.rs | 8 +- .../src/handlers/inline_const_as_literal.rs | 2 +- .../src/handlers/merge_match_arms.rs | 16 +- .../ide-assists/src/handlers/qualify_path.rs | 4 +- .../ide-assists/src/handlers/term_search.rs | 2 +- .../crates/ide-assists/src/utils.rs | 37 +- .../src/utils/gen_trait_fn_body.rs | 6 +- .../crates/ide-completion/src/completions.rs | 38 +- .../src/completions/attribute.rs | 2 +- .../src/completions/attribute/derive.rs | 2 +- .../ide-completion/src/completions/dot.rs | 14 +- .../ide-completion/src/completions/expr.rs | 4 +- .../ide-completion/src/completions/field.rs | 2 +- .../src/completions/flyimport.rs | 20 +- .../src/completions/item_list.rs | 6 +- .../src/completions/item_list/trait_impl.rs | 2 +- .../ide-completion/src/completions/pattern.rs | 2 +- .../ide-completion/src/completions/postfix.rs | 2 +- .../ide-completion/src/completions/record.rs | 4 +- .../ide-completion/src/completions/snippet.rs | 6 +- .../ide-completion/src/completions/type.rs | 4 +- .../ide-completion/src/completions/use_.rs | 2 +- .../ide-completion/src/completions/vis.rs | 2 +- .../crates/ide-completion/src/context.rs | 50 +- .../ide-completion/src/context/analysis.rs | 33 +- .../crates/ide-completion/src/item.rs | 2 +- .../crates/ide-completion/src/render.rs | 32 +- .../ide-completion/src/render/function.rs | 24 +- .../ide-completion/src/render/literal.rs | 8 +- .../ide-completion/src/render/macro_.rs | 2 +- .../ide-completion/src/render/pattern.rs | 4 +- .../crates/ide-db/src/active_parameter.rs | 32 +- .../rust-analyzer/crates/ide-db/src/defs.rs | 59 +-- .../ide-db/src/imports/import_assets.rs | 60 +-- .../rust-analyzer/crates/ide-db/src/search.rs | 8 +- .../ide-db/src/syntax_helpers/suggest_name.rs | 18 +- .../crates/ide-db/src/ty_filter.rs | 2 +- .../ide-db/src/use_trivial_constructor.rs | 2 +- .../src/handlers/expected_function.rs | 2 +- .../src/handlers/invalid_cast.rs | 7 +- .../src/handlers/missing_fields.rs | 6 +- .../src/handlers/moved_out_of_ref.rs | 5 +- .../src/handlers/type_mismatch.rs | 14 +- .../src/handlers/typed_hole.rs | 6 +- .../src/handlers/unresolved_field.rs | 6 +- .../src/handlers/unresolved_method.rs | 13 +- .../rust-analyzer/crates/ide-ssr/src/lib.rs | 2 +- .../crates/ide-ssr/src/matching.rs | 22 +- .../crates/ide-ssr/src/replacing.rs | 28 +- .../crates/ide-ssr/src/resolving.rs | 26 +- .../crates/ide-ssr/src/search.rs | 16 +- .../crates/ide/src/goto_implementation.rs | 2 +- .../crates/ide/src/goto_type_definition.rs | 2 +- .../rust-analyzer/crates/ide/src/hover.rs | 16 +- .../crates/ide/src/hover/render.rs | 10 +- .../crates/ide/src/inlay_hints.rs | 16 +- .../crates/ide/src/inlay_hints/param_name.rs | 6 +- .../crates/ide/src/signature_help.rs | 14 +- .../crates/ide/src/view_memory_layout.rs | 2 +- .../crates/query-group-macro/src/queries.rs | 8 +- .../rust-analyzer/src/cli/analysis_stats.rs | 2 +- .../rust-analyzer/crates/stdx/src/lib.rs | 1 + .../rust-analyzer/crates/stdx/src/variance.rs | 270 +++++++++++ 79 files changed, 1214 insertions(+), 815 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/stdx/src/variance.rs diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index b1cf30b98f5b..0bce69a179b8 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -242,9 +242,9 @@ fn resolve_assoc_or_field( resolve_field(db, variant_def, name, ns) } -fn resolve_assoc_item( - db: &dyn HirDatabase, - ty: &Type, +fn resolve_assoc_item<'db>( + db: &'db dyn HirDatabase, + ty: &Type<'db>, name: &Name, ns: Option, ) -> Option { @@ -256,10 +256,10 @@ fn resolve_assoc_item( }) } -fn resolve_impl_trait_item( - db: &dyn HirDatabase, +fn resolve_impl_trait_item<'db>( + db: &'db dyn HirDatabase, resolver: Resolver<'_>, - ty: &Type, + ty: &Type<'db>, name: &Name, ns: Option, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index f7b140e03d43..074bde91fb69 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -36,15 +36,15 @@ pub use hir_ty::{ }; macro_rules! diagnostics { - ($($diag:ident,)*) => { + ($($diag:ident $(<$lt:lifetime>)?,)*) => { #[derive(Debug)] - pub enum AnyDiagnostic {$( - $diag(Box<$diag>), + pub enum AnyDiagnostic<'db> {$( + $diag(Box<$diag $(<$lt>)?>), )*} $( - impl From<$diag> for AnyDiagnostic { - fn from(d: $diag) -> AnyDiagnostic { + impl<'db> From<$diag $(<$lt>)?> for AnyDiagnostic<'db> { + fn from(d: $diag $(<$lt>)?) -> AnyDiagnostic<'db> { AnyDiagnostic::$diag(Box::new(d)) } } @@ -69,12 +69,12 @@ macro_rules! diagnostics { diagnostics![ AwaitOutsideOfAsync, BreakOutsideOfLoop, - CastToUnsized, - ExpectedFunction, + CastToUnsized<'db>, + ExpectedFunction<'db>, InactiveCode, IncoherentImpl, IncorrectCase, - InvalidCast, + InvalidCast<'db>, InvalidDeriveTarget, MacroDefError, MacroError, @@ -85,7 +85,7 @@ diagnostics![ MissingFields, MissingMatchArms, MissingUnsafe, - MovedOutOfRef, + MovedOutOfRef<'db>, NeedMut, NonExhaustiveLet, NoSuchField, @@ -98,17 +98,17 @@ diagnostics![ TraitImplMissingAssocItems, TraitImplOrphan, TraitImplRedundantAssocItems, - TypedHole, - TypeMismatch, + TypedHole<'db>, + TypeMismatch<'db>, UndeclaredLabel, UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedAssocItem, UnresolvedExternCrate, - UnresolvedField, + UnresolvedField<'db>, UnresolvedImport, UnresolvedMacroCall, - UnresolvedMethodCall, + UnresolvedMethodCall<'db>, UnresolvedModule, UnresolvedIdent, UnusedMut, @@ -130,9 +130,9 @@ pub struct BreakOutsideOfLoop { } #[derive(Debug)] -pub struct TypedHole { +pub struct TypedHole<'db> { pub expr: InFile, - pub expected: Type, + pub expected: Type<'db>, } #[derive(Debug)] @@ -242,25 +242,25 @@ pub struct MismatchedTupleStructPatArgCount { } #[derive(Debug)] -pub struct ExpectedFunction { +pub struct ExpectedFunction<'db> { pub call: InFile, - pub found: Type, + pub found: Type<'db>, } #[derive(Debug)] -pub struct UnresolvedField { +pub struct UnresolvedField<'db> { pub expr: InFile, - pub receiver: Type, + pub receiver: Type<'db>, pub name: Name, pub method_with_same_name_exists: bool, } #[derive(Debug)] -pub struct UnresolvedMethodCall { +pub struct UnresolvedMethodCall<'db> { pub expr: InFile, - pub receiver: Type, + pub receiver: Type<'db>, pub name: Name, - pub field_with_same_name: Option, + pub field_with_same_name: Option>, pub assoc_func_with_same_name: Option, } @@ -329,10 +329,10 @@ pub struct NonExhaustiveLet { } #[derive(Debug)] -pub struct TypeMismatch { +pub struct TypeMismatch<'db> { pub expr_or_pat: InFile, - pub expected: Type, - pub actual: Type, + pub expected: Type<'db>, + pub actual: Type<'db>, } #[derive(Debug)] @@ -352,8 +352,8 @@ pub struct UnusedVariable { } #[derive(Debug)] -pub struct MovedOutOfRef { - pub ty: Type, +pub struct MovedOutOfRef<'db> { + pub ty: Type<'db>, pub span: InFile, } @@ -403,17 +403,17 @@ pub struct RemoveUnnecessaryElse { } #[derive(Debug)] -pub struct CastToUnsized { +pub struct CastToUnsized<'db> { pub expr: InFile, - pub cast_ty: Type, + pub cast_ty: Type<'db>, } #[derive(Debug)] -pub struct InvalidCast { +pub struct InvalidCast<'db> { pub expr: InFile, pub error: CastError, - pub expr_ty: Type, - pub cast_ty: Type, + pub expr_ty: Type<'db>, + pub cast_ty: Type<'db>, } #[derive(Debug)] @@ -482,12 +482,12 @@ pub struct IncorrectGenericsOrder { pub expected_kind: GenericArgKind, } -impl AnyDiagnostic { +impl<'db> AnyDiagnostic<'db> { pub(crate) fn body_validation_diagnostic( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, diagnostic: BodyValidationDiagnostic, source_map: &hir_def::expr_store::BodySourceMap, - ) -> Option { + ) -> Option> { match diagnostic { BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => { let variant_data = variant.variant_data(db); @@ -618,12 +618,12 @@ impl AnyDiagnostic { } pub(crate) fn inference_diagnostic( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: DefWithBodyId, d: &InferenceDiagnostic, source_map: &hir_def::expr_store::BodySourceMap, sig_map: &hir_def::expr_store::ExpressionStoreSourceMap, - ) -> Option { + ) -> Option> { let expr_syntax = |expr| { source_map .expr_syntax(expr) @@ -819,7 +819,7 @@ impl AnyDiagnostic { fn path_diagnostic( diag: &PathLoweringDiagnostic, path: InFile, - ) -> Option { + ) -> Option> { Some(match *diag { PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => { let segment = hir_segment_to_ast_segment(&path.value, segment)?; @@ -912,8 +912,8 @@ impl AnyDiagnostic { pub(crate) fn ty_diagnostic( diag: &TyLoweringDiagnostic, source_map: &ExpressionStoreSourceMap, - db: &dyn HirDatabase, - ) -> Option { + db: &'db dyn HirDatabase, + ) -> Option> { let Ok(source) = source_map.type_syntax(diag.source) else { stdx::never!("error on synthetic type syntax"); return None; diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 124ab8e274af..112558bdd04a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -431,7 +431,7 @@ impl HirDisplay for Variant { } } -impl HirDisplay for Type { +impl HirDisplay for Type<'_> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { self.ty.hir_fmt(f) } @@ -743,7 +743,7 @@ impl HirDisplay for Static { } } -impl HirDisplay for TraitRef { +impl HirDisplay for TraitRef<'_> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { self.trait_ref.hir_fmt(f) } diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index fe7429c86725..4767d4792e71 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -225,7 +225,7 @@ impl HasSource for LocalSource { } } -impl HasSource for Param { +impl HasSource for Param<'_> { type Ast = Either; fn source(self, db: &dyn HirDatabase) -> Option> { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index adae335627ba..c4f5a7ef588b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -84,7 +84,7 @@ use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; use smallvec::SmallVec; use span::{AstIdNode, Edition, FileId}; -use stdx::{format_to, impl_from, never}; +use stdx::{format_to, impl_from, never, variance::PhantomCovariantLifetime}; use syntax::{ AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr, ast::{self, HasAttrs as _, HasName, HasVisibility as _}, @@ -400,7 +400,11 @@ impl ModuleDef { Some(name) } - pub fn diagnostics(self, db: &dyn HirDatabase, style_lints: bool) -> Vec { + pub fn diagnostics<'db>( + self, + db: &'db dyn HirDatabase, + style_lints: bool, + ) -> Vec> { let id = match self { ModuleDef::Adt(it) => match it { Adt::Struct(it) => it.id.into(), @@ -612,10 +616,10 @@ impl Module { } /// Fills `acc` with the module's diagnostics. - pub fn diagnostics( + pub fn diagnostics<'db>( self, - db: &dyn HirDatabase, - acc: &mut Vec, + db: &'db dyn HirDatabase, + acc: &mut Vec>, style_lints: bool, ) { let _p = tracing::info_span!("diagnostics", name = ?self.name(db)).entered(); @@ -970,10 +974,10 @@ impl Module { } } -fn macro_call_diagnostics( - db: &dyn HirDatabase, +fn macro_call_diagnostics<'db>( + db: &'db dyn HirDatabase, macro_call_id: MacroCallId, - acc: &mut Vec, + acc: &mut Vec>, ) { let Some(e) = db.parse_macro_expansion_error(macro_call_id) else { return; @@ -1010,7 +1014,11 @@ fn macro_call_diagnostics( } } -fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec, m: Macro) { +fn emit_macro_def_diagnostics<'db>( + db: &'db dyn HirDatabase, + acc: &mut Vec>, + m: Macro, +) { let id = db.macro_def(m.id); if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) { if let Some(e) = expander.mac.err() { @@ -1030,18 +1038,18 @@ fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec } } -fn emit_def_diagnostic( - db: &dyn HirDatabase, - acc: &mut Vec, +fn emit_def_diagnostic<'db>( + db: &'db dyn HirDatabase, + acc: &mut Vec>, diag: &DefDiagnostic, edition: Edition, ) { emit_def_diagnostic_(db, acc, &diag.kind, edition) } -fn emit_def_diagnostic_( - db: &dyn HirDatabase, - acc: &mut Vec, +fn emit_def_diagnostic_<'db>( + db: &'db dyn HirDatabase, + acc: &mut Vec>, diag: &DefDiagnosticKind, edition: Edition, ) { @@ -1251,14 +1259,18 @@ impl TupleField { Name::new_tuple_field(self.index as usize) } - pub fn ty(&self, db: &dyn HirDatabase) -> Type { + pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let ty = db.infer(self.owner).tuple_field_access_types[&self.tuple] .as_slice(Interner) .get(self.index as usize) .and_then(|arg| arg.ty(Interner)) .cloned() .unwrap_or_else(|| TyKind::Error.intern(Interner)); - Type { env: db.trait_environment_for_body(self.owner), ty } + Type { + env: db.trait_environment_for_body(self.owner), + ty, + _pd: PhantomCovariantLifetime::new(), + } } } @@ -1309,7 +1321,7 @@ impl Field { /// Returns the type as in the signature of the struct (i.e., with /// placeholder types for type parameters). Only use this in the context of /// the field definition. - pub fn ty(&self, db: &dyn HirDatabase) -> Type { + pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let var_id = self.parent.into(); let generic_def_id: GenericDefId = match self.parent { VariantDef::Struct(it) => it.id.into(), @@ -1322,7 +1334,11 @@ impl Field { } // FIXME: Find better API to also handle const generics - pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator) -> Type { + pub fn ty_with_args<'db>( + &self, + db: &'db dyn HirDatabase, + generics: impl Iterator>, + ) -> Type<'db> { let var_id = self.parent.into(); let def_id: AdtId = match self.parent { VariantDef::Struct(it) => it.id.into(), @@ -1394,15 +1410,15 @@ impl Struct { .collect() } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type { + pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_def_placeholders(db, self.id) } - pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_value_def(db, self.id) } @@ -1449,15 +1465,15 @@ impl Union { Module { id: self.id.lookup(db).container } } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type { + pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_def_placeholders(db, self.id) } - pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_value_def(db, self.id) } @@ -1515,16 +1531,16 @@ impl Enum { db.enum_signature(self.id).repr } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type { + pub fn ty_placeholders<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { Type::from_def_placeholders(db, self.id) } /// The type of the enum variant bodies. - pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type { + pub fn variant_body_ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { Type::new_for_crate( self.id.lookup(db).container.krate(), TyBuilder::builtin(match db.enum_signature(self.id).variant_body_type() { @@ -1599,7 +1615,7 @@ impl Variant { self.id.lookup(db).parent.into() } - pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_value_def(db, self.id) } @@ -1701,14 +1717,18 @@ impl Adt { /// Turns this ADT into a type. Any type parameters of the ADT will be /// turned into unknown types, which is good for e.g. finding the most /// general set of completions, but will not look very nice when printed. - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let id = AdtId::from(self); Type::from_def(db, id) } /// Turns this ADT into a type with the given type parameters. This isn't /// the greatest API, FIXME find a better one. - pub fn ty_with_args(self, db: &dyn HirDatabase, args: impl Iterator) -> Type { + pub fn ty_with_args<'db>( + self, + db: &'db dyn HirDatabase, + args: impl Iterator>, + ) -> Type<'db> { let id = AdtId::from(self); let mut it = args.map(|t| t.ty); let ty = TyBuilder::def_ty(db, id.into(), None) @@ -1841,7 +1861,7 @@ impl DefWithBody { } /// Returns the type this def's body has to evaluate to. - pub fn body_type(self, db: &dyn HirDatabase) -> Type { + pub fn body_type(self, db: &dyn HirDatabase) -> Type<'_> { match self { DefWithBody::Function(it) => it.ret_type(db), DefWithBody::Static(it) => it.ty(db), @@ -1874,10 +1894,10 @@ impl DefWithBody { } } - pub fn diagnostics( + pub fn diagnostics<'db>( self, - db: &dyn HirDatabase, - acc: &mut Vec, + db: &'db dyn HirDatabase, + acc: &mut Vec>, style_lints: bool, ) { let krate = self.module(db).id.krate(); @@ -2107,7 +2127,7 @@ impl DefWithBody { fn expr_store_diagnostics( db: &dyn HirDatabase, - acc: &mut Vec, + acc: &mut Vec>, source_map: &ExpressionStoreSourceMap, ) { for diag in source_map.diagnostics() { @@ -2172,11 +2192,11 @@ impl Function { db.function_signature(self.id).name.clone() } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_value_def(db, self.id) } - pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type { + pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); let substs = TyBuilder::placeholder_subst(db, self.id); let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); @@ -2185,7 +2205,7 @@ impl Function { } /// Get this function's return type - pub fn ret_type(self, db: &dyn HirDatabase) -> Type { + pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); let substs = TyBuilder::placeholder_subst(db, self.id); let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); @@ -2194,11 +2214,11 @@ impl Function { } // FIXME: Find better API to also handle const generics - pub fn ret_type_with_args( + pub fn ret_type_with_args<'db>( self, - db: &dyn HirDatabase, - generics: impl Iterator, - ) -> Type { + db: &'db dyn HirDatabase, + generics: impl Iterator>, + ) -> Type<'db> { let resolver = self.id.resolver(db); let parent_id: Option = match self.id.lookup(db).container { ItemContainerId::ImplId(it) => Some(it.into()), @@ -2223,7 +2243,7 @@ impl Function { Type::new_with_resolver_inner(db, &resolver, ty) } - pub fn async_ret_type(self, db: &dyn HirDatabase) -> Option { + pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option> { if !self.is_async(db) { return None; } @@ -2247,7 +2267,7 @@ impl Function { self.has_self_param(db).then_some(SelfParam { func: self.id }) } - pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec { + pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec> { let environment = db.trait_environment(self.id.into()); let substs = TyBuilder::placeholder_subst(db, self.id); let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); @@ -2256,7 +2276,11 @@ impl Function { .iter() .enumerate() .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty: ty.clone() }; + let ty = Type { + env: environment.clone(), + ty: ty.clone(), + _pd: PhantomCovariantLifetime::new(), + }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2266,12 +2290,12 @@ impl Function { db.function_signature(self.id).params.len() } - pub fn method_params(self, db: &dyn HirDatabase) -> Option> { + pub fn method_params(self, db: &dyn HirDatabase) -> Option>> { self.self_param(db)?; Some(self.params_without_self(db)) } - pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec { + pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec> { let environment = db.trait_environment(self.id.into()); let substs = TyBuilder::placeholder_subst(db, self.id); let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); @@ -2282,18 +2306,22 @@ impl Function { .enumerate() .skip(skip) .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty: ty.clone() }; + let ty = Type { + env: environment.clone(), + ty: ty.clone(), + _pd: PhantomCovariantLifetime::new(), + }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() } // FIXME: Find better API to also handle const generics - pub fn params_without_self_with_args( + pub fn params_without_self_with_args<'db>( self, - db: &dyn HirDatabase, - generics: impl Iterator, - ) -> Vec { + db: &'db dyn HirDatabase, + generics: impl Iterator>, + ) -> Vec> { let environment = db.trait_environment(self.id.into()); let parent_id: Option = match self.id.lookup(db).container { ItemContainerId::ImplId(it) => Some(it.into()), @@ -2328,7 +2356,11 @@ impl Function { .enumerate() .skip(skip) .map(|(idx, ty)| { - let ty = Type { env: environment.clone(), ty: ty.clone() }; + let ty = Type { + env: environment.clone(), + ty: ty.clone(), + _pd: PhantomCovariantLifetime::new(), + }; Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx } }) .collect() @@ -2358,7 +2390,8 @@ impl Function { return true; } - let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false }; + let ret_type = self.ret_type(db); + let Some(impl_traits) = ret_type.as_impl_traits(db) else { return false }; let Some(future_trait_id) = LangItem::Future.resolve_trait(db, self.ty(db).env.krate) else { return false; @@ -2501,14 +2534,14 @@ impl From for Access { } #[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct Param { +pub struct Param<'db> { func: Callee, /// The index in parameter list, including self parameter. idx: usize, - ty: Type, + ty: Type<'db>, } -impl Param { +impl<'db> Param<'db> { pub fn parent_fn(&self) -> Option { match self.func { Callee::Def(CallableDefId::FunctionId(f)) => Some(f.into()), @@ -2524,7 +2557,7 @@ impl Param { self.idx } - pub fn ty(&self) -> &Type { + pub fn ty(&self) -> &Type<'db> { &self.ty } @@ -2591,17 +2624,21 @@ impl SelfParam { Function::from(self.func) } - pub fn ty(&self, db: &dyn HirDatabase) -> Type { + pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let substs = TyBuilder::placeholder_subst(db, self.func); let callable_sig = db.callable_item_signature(self.func.into()).substitute(Interner, &substs); let environment = db.trait_environment(self.func.into()); let ty = callable_sig.params()[0].clone(); - Type { env: environment, ty } + Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } } // FIXME: Find better API to also handle const generics - pub fn ty_with_args(&self, db: &dyn HirDatabase, generics: impl Iterator) -> Type { + pub fn ty_with_args<'db>( + &self, + db: &'db dyn HirDatabase, + generics: impl Iterator>, + ) -> Type<'db> { let parent_id: GenericDefId = match self.func.lookup(db).container { ItemContainerId::ImplId(it) => it.into(), ItemContainerId::TraitId(it) => it.into(), @@ -2626,7 +2663,7 @@ impl SelfParam { db.callable_item_signature(self.func.into()).substitute(Interner, &substs); let environment = db.trait_environment(self.func.into()); let ty = callable_sig.params()[0].clone(); - Type { env: environment, ty } + Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } } } @@ -2714,7 +2751,7 @@ impl Const { self.source(db)?.value.body() } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_value_def(db, self.id) } @@ -2791,7 +2828,7 @@ impl Static { self.source(db)?.value.body() } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_value_def(db, self.id) } @@ -2961,11 +2998,11 @@ impl TypeAlias { Module { id: self.id.module(db) } } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_def(db, self.id) } - pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type { + pub fn ty_placeholders(self, db: &dyn HirDatabase) -> Type<'_> { Type::from_def_placeholders(db, self.id) } @@ -3010,7 +3047,7 @@ impl BuiltinType { BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str } } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]); Type::new_for_crate(core, TyBuilder::builtin(self.inner)) } @@ -3472,7 +3509,7 @@ impl AssocItem { } } - pub fn implementing_ty(self, db: &dyn HirDatabase) -> Option { + pub fn implementing_ty(self, db: &dyn HirDatabase) -> Option> { match self.container(db) { AssocItemContainer::Impl(i) => Some(i.self_ty(db)), _ => None, @@ -3500,10 +3537,10 @@ impl AssocItem { } } - pub fn diagnostics( + pub fn diagnostics<'db>( self, - db: &dyn HirDatabase, - acc: &mut Vec, + db: &'db dyn HirDatabase, + acc: &mut Vec>, style_lints: bool, ) { match self { @@ -3625,7 +3662,7 @@ impl GenericDef { } } - pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { + pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec>) { let def = self.id(); let generics = db.generic_params(def); @@ -3690,18 +3727,19 @@ impl GenericDef { // We cannot call this `Substitution` unfortunately... #[derive(Debug)] -pub struct GenericSubstitution { +pub struct GenericSubstitution<'db> { def: GenericDefId, subst: Substitution, env: Arc, + _pd: PhantomCovariantLifetime<'db>, } -impl GenericSubstitution { +impl<'db> GenericSubstitution<'db> { fn new(def: GenericDefId, subst: Substitution, env: Arc) -> Self { - Self { def, subst, env } + Self { def, subst, env, _pd: PhantomCovariantLifetime::new() } } - pub fn types(&self, db: &dyn HirDatabase) -> Vec<(Symbol, Type)> { + pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { let container = match self.def { GenericDefId::ConstId(id) => Some(id.lookup(db).container), GenericDefId::FunctionId(id) => Some(id.lookup(db).container), @@ -3744,7 +3782,10 @@ impl GenericSubstitution { container_params .chain(self_params) .filter_map(|(ty, name)| { - Some((name?.symbol().clone(), Type { ty, env: self.env.clone() })) + Some(( + name?.symbol().clone(), + Type { ty, env: self.env.clone(), _pd: PhantomCovariantLifetime::new() }, + )) }) .collect() } @@ -3847,7 +3888,7 @@ impl Local { self.parent(db).module(db) } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let def = self.parent; let infer = db.infer(def); let ty = infer[self.binding_id].clone(); @@ -4124,7 +4165,7 @@ impl TypeParam { } } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.parent().resolver(db); let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner); @@ -4146,7 +4187,7 @@ impl TypeParam { .collect() } - pub fn default(self, db: &dyn HirDatabase) -> Option { + pub fn default(self, db: &dyn HirDatabase) -> Option> { let ty = generic_arg_from_param(db, self.id.into())?; let resolver = self.id.parent().resolver(db); match ty.data(Interner) { @@ -4211,7 +4252,7 @@ impl ConstParam { self.id.parent().into() } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { Type::new(db, self.id.parent(), db.const_param_ty(self.id)) } @@ -4268,7 +4309,7 @@ impl TypeOrConstParam { } } - pub fn ty(self, db: &dyn HirDatabase) -> Type { + pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { match self.split(db) { Either::Left(it) => it.ty(db), Either::Right(it) => it.ty(db), @@ -4313,7 +4354,10 @@ impl Impl { module.id.def_map(db)[module.id.local_id].scope.impls().map(Into::into).collect() } - pub fn all_for_type(db: &dyn HirDatabase, Type { ty, env }: Type) -> Vec { + pub fn all_for_type<'db>( + db: &'db dyn HirDatabase, + Type { ty, env, _pd: _ }: Type<'db>, + ) -> Vec { let def_crates = match method_resolution::def_crates(db, &ty, env.krate) { Some(def_crates) => def_crates, None => return Vec::new(), @@ -4398,14 +4442,14 @@ impl Impl { Some(Trait { id }) } - pub fn trait_ref(self, db: &dyn HirDatabase) -> Option { + pub fn trait_ref(self, db: &dyn HirDatabase) -> Option> { let substs = TyBuilder::placeholder_subst(db, self.id); let trait_ref = db.impl_trait(self.id)?.substitute(Interner, &substs); let resolver = self.id.resolver(db); Some(TraitRef::new_with_resolver(db, &resolver, trait_ref)) } - pub fn self_ty(self, db: &dyn HirDatabase) -> Type { + pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> { let resolver = self.id.resolver(db); let substs = TyBuilder::placeholder_subst(db, self.id); let ty = db.impl_self_ty(self.id).substitute(Interner, &substs); @@ -4467,21 +4511,22 @@ impl Impl { } #[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TraitRef { +pub struct TraitRef<'db> { env: Arc, trait_ref: hir_ty::TraitRef, + _pd: PhantomCovariantLifetime<'db>, } -impl TraitRef { +impl<'db> TraitRef<'db> { pub(crate) fn new_with_resolver( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, resolver: &Resolver<'_>, trait_ref: hir_ty::TraitRef, - ) -> TraitRef { + ) -> Self { let env = resolver .generic_def() .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); - TraitRef { env, trait_ref } + TraitRef { env, trait_ref, _pd: PhantomCovariantLifetime::new() } } pub fn trait_(&self) -> Trait { @@ -4489,21 +4534,21 @@ impl TraitRef { Trait { id } } - pub fn self_ty(&self) -> Type { + pub fn self_ty(&self) -> Type<'_> { let ty = self.trait_ref.self_type_parameter(Interner); - Type { env: self.env.clone(), ty } + Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() } } /// Returns `idx`-th argument of this trait reference if it is a type argument. Note that the /// first argument is the `Self` type. - pub fn get_type_argument(&self, idx: usize) -> Option { + pub fn get_type_argument(&self, idx: usize) -> Option> { self.trait_ref .substitution .as_slice(Interner) .get(idx) .and_then(|arg| arg.ty(Interner)) .cloned() - .map(|ty| Type { env: self.env.clone(), ty }) + .map(|ty| Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() }) } } @@ -4551,7 +4596,7 @@ impl Closure { .collect() } - pub fn capture_types(&self, db: &dyn HirDatabase) -> Vec { + pub fn capture_types<'db>(&self, db: &'db dyn HirDatabase) -> Vec> { let owner = db.lookup_intern_closure((self.id).into()).0; let infer = &db.infer(owner); let (captures, _) = infer.closure_info(&self.id); @@ -4560,6 +4605,7 @@ impl Closure { .map(|capture| Type { env: db.trait_environment_for_body(owner), ty: capture.ty(&self.subst), + _pd: PhantomCovariantLifetime::new(), }) .collect() } @@ -4691,40 +4737,45 @@ impl CaptureUsageSource { } #[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct Type { +pub struct Type<'db> { env: Arc, ty: Ty, + _pd: PhantomCovariantLifetime<'db>, } -impl Type { - pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver<'_>, ty: Ty) -> Type { +impl<'db> Type<'db> { + pub(crate) fn new_with_resolver( + db: &'db dyn HirDatabase, + resolver: &Resolver<'_>, + ty: Ty, + ) -> Self { Type::new_with_resolver_inner(db, resolver, ty) } pub(crate) fn new_with_resolver_inner( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, resolver: &Resolver<'_>, ty: Ty, - ) -> Type { + ) -> Self { let environment = resolver .generic_def() .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); - Type { env: environment, ty } + Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } } - pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Type { - Type { env: TraitEnvironment::empty(krate), ty } + pub(crate) fn new_for_crate(krate: base_db::Crate, ty: Ty) -> Self { + Type { env: TraitEnvironment::empty(krate), ty, _pd: PhantomCovariantLifetime::new() } } - fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type { + fn new(db: &'db dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Self { let resolver = lexical_env.resolver(db); let environment = resolver .generic_def() .map_or_else(|| TraitEnvironment::empty(resolver.krate()), |d| db.trait_environment(d)); - Type { env: environment, ty } + Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() } } - fn from_def(db: &dyn HirDatabase, def: impl Into + HasResolver) -> Type { + fn from_def(db: &'db dyn HirDatabase, def: impl Into + HasResolver) -> Self { let ty = db.ty(def.into()); let substs = TyBuilder::unknown_subst( db, @@ -4737,7 +4788,10 @@ impl Type { Type::new(db, def, ty.substitute(Interner, &substs)) } - fn from_def_placeholders(db: &dyn HirDatabase, def: impl Into + HasResolver) -> Type { + fn from_def_placeholders( + db: &'db dyn HirDatabase, + def: impl Into + HasResolver, + ) -> Self { let ty = db.ty(def.into()); let substs = TyBuilder::placeholder_subst( db, @@ -4750,7 +4804,10 @@ impl Type { Type::new(db, def, ty.substitute(Interner, &substs)) } - fn from_value_def(db: &dyn HirDatabase, def: impl Into + HasResolver) -> Type { + fn from_value_def( + db: &'db dyn HirDatabase, + def: impl Into + HasResolver, + ) -> Self { let Some(ty) = db.value_ty(def.into()) else { return Type::new(db, def, TyKind::Error.intern(Interner)); }; @@ -4770,13 +4827,17 @@ impl Type { Type::new(db, def, ty.substitute(Interner, &substs)) } - pub fn new_slice(ty: Type) -> Type { - Type { env: ty.env, ty: TyBuilder::slice(ty.ty) } + pub fn new_slice(ty: Self) -> Self { + Type { env: ty.env, ty: TyBuilder::slice(ty.ty), _pd: PhantomCovariantLifetime::new() } } - pub fn new_tuple(krate: base_db::Crate, tys: &[Type]) -> Type { + pub fn new_tuple(krate: base_db::Crate, tys: &[Self]) -> Self { let tys = tys.iter().map(|it| it.ty.clone()); - Type { env: TraitEnvironment::empty(krate), ty: TyBuilder::tuple_with(tys) } + Type { + env: TraitEnvironment::empty(krate), + ty: TyBuilder::tuple_with(tys), + _pd: PhantomCovariantLifetime::new(), + } } pub fn is_unit(&self) -> bool { @@ -4803,7 +4864,7 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Ref(..)) } - pub fn contains_reference(&self, db: &dyn HirDatabase) -> bool { + pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool { return go(db, self.env.krate, &self.ty); fn go(db: &dyn HirDatabase, krate: base_db::Crate, ty: &Ty) -> bool { @@ -4847,13 +4908,13 @@ impl Type { } } - pub fn as_reference(&self) -> Option<(Type, Mutability)> { + pub fn as_reference(&self) -> Option<(Type<'db>, Mutability)> { let (ty, _lt, m) = self.ty.as_reference()?; let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut)); Some((self.derived(ty.clone()), m)) } - pub fn add_reference(&self, mutability: Mutability) -> Type { + pub fn add_reference(&self, mutability: Mutability) -> Self { let ty_mutability = match mutability { Mutability::Shared => hir_ty::Mutability::Not, Mutability::Mut => hir_ty::Mutability::Mut, @@ -4889,25 +4950,25 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Tuple(..)) } - pub fn remove_ref(&self) -> Option { + pub fn remove_ref(&self) -> Option> { match &self.ty.kind(Interner) { TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), _ => None, } } - pub fn as_slice(&self) -> Option { + pub fn as_slice(&self) -> Option> { match &self.ty.kind(Interner) { TyKind::Slice(ty) => Some(self.derived(ty.clone())), _ => None, } } - pub fn strip_references(&self) -> Type { + pub fn strip_references(&self) -> Self { self.derived(self.ty.strip_references().clone()) } - pub fn strip_reference(&self) -> Type { + pub fn strip_reference(&self) -> Self { self.derived(self.ty.strip_reference().clone()) } @@ -4918,7 +4979,7 @@ impl Type { /// Checks that particular type `ty` implements `std::future::IntoFuture` or /// `std::future::Future` and returns the `Output` associated type. /// This function is used in `.await` syntax completion. - pub fn into_future_output(&self, db: &dyn HirDatabase) -> Option { + pub fn into_future_output(&self, db: &'db dyn HirDatabase) -> Option> { let trait_ = LangItem::IntoFutureIntoFuture .resolve_function(db, self.env.krate) .and_then(|into_future_fn| { @@ -4940,13 +5001,13 @@ impl Type { } /// This does **not** resolve `IntoFuture`, only `Future`. - pub fn future_output(self, db: &dyn HirDatabase) -> Option { + pub fn future_output(self, db: &'db dyn HirDatabase) -> Option> { let future_output = LangItem::FutureOutput.resolve_type_alias(db, self.env.krate)?; self.normalize_trait_assoc_type(db, &[], future_output.into()) } /// This does **not** resolve `IntoIterator`, only `Iterator`. - pub fn iterator_item(self, db: &dyn HirDatabase) -> Option { + pub fn iterator_item(self, db: &'db dyn HirDatabase) -> Option> { let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?; let iterator_item = db .trait_items(iterator_trait) @@ -4954,7 +5015,7 @@ impl Type { self.normalize_trait_assoc_type(db, &[], iterator_item.into()) } - pub fn impls_iterator(self, db: &dyn HirDatabase) -> bool { + pub fn impls_iterator(self, db: &'db dyn HirDatabase) -> bool { let Some(iterator_trait) = LangItem::Iterator.resolve_trait(db, self.env.krate) else { return false; }; @@ -4964,7 +5025,7 @@ impl Type { } /// Resolves the projection `::IntoIter` and returns the resulting type - pub fn into_iterator_iter(self, db: &dyn HirDatabase) -> Option { + pub fn into_iterator_iter(self, db: &'db dyn HirDatabase) -> Option> { let trait_ = LangItem::IntoIterIntoIter.resolve_function(db, self.env.krate).and_then( |into_iter_fn| { let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?; @@ -4989,7 +5050,7 @@ impl Type { /// /// This function can be used to check if a particular type is callable, since FnOnce is a /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce. - pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool { + pub fn impls_fnonce(&self, db: &'db dyn HirDatabase) -> bool { let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.env.krate) { Some(it) => it, None => return false, @@ -5001,7 +5062,7 @@ impl Type { } // FIXME: Find better API that also handles const generics - pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { + pub fn impls_trait(&self, db: &'db dyn HirDatabase, trait_: Trait, args: &[Type<'db>]) -> bool { let mut it = args.iter().map(|t| t.ty.clone()); let trait_ref = TyBuilder::trait_ref(db, trait_.id) .push(self.ty.clone()) @@ -5029,10 +5090,10 @@ impl Type { pub fn normalize_trait_assoc_type( &self, - db: &dyn HirDatabase, - args: &[Type], + db: &'db dyn HirDatabase, + args: &[Type<'db>], alias: TypeAlias, - ) -> Option { + ) -> Option> { let mut args = args.iter(); let trait_id = match alias.id.lookup(db).container { ItemContainerId::TraitId(id) => id, @@ -5056,14 +5117,14 @@ impl Type { if ty.is_unknown() { None } else { Some(self.derived(ty)) } } - pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { + pub fn is_copy(&self, db: &'db dyn HirDatabase) -> bool { let Some(copy_trait) = LangItem::Copy.resolve_trait(db, self.env.krate) else { return false; }; self.impls_trait(db, copy_trait.into(), &[]) } - pub fn as_callable(&self, db: &dyn HirDatabase) -> Option { + pub fn as_callable(&self, db: &'db dyn HirDatabase) -> Option> { let callee = match self.ty.kind(Interner) { TyKind::Closure(id, subst) => Callee::Closure(*id, subst.clone()), TyKind::Function(_) => Callee::FnPtr, @@ -5117,7 +5178,7 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Array(..)) } - pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { + pub fn is_packed(&self, db: &'db dyn HirDatabase) -> bool { let adt_id = match *self.ty.kind(Interner) { TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, _ => return false, @@ -5134,7 +5195,7 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Raw(..)) } - pub fn remove_raw_ptr(&self) -> Option { + pub fn remove_raw_ptr(&self) -> Option> { if let TyKind::Raw(_, ty) = self.ty.kind(Interner) { Some(self.derived(ty.clone())) } else { @@ -5182,7 +5243,7 @@ impl Type { } } - pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { + pub fn fields(&self, db: &'db dyn HirDatabase) -> Vec<(Field, Self)> { let (variant_id, substs) = match self.ty.kind(Interner) { TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs), TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs), @@ -5199,7 +5260,7 @@ impl Type { .collect() } - pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec { + pub fn tuple_fields(&self, _db: &'db dyn HirDatabase) -> Vec { if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) { substs .iter(Interner) @@ -5210,7 +5271,7 @@ impl Type { } } - pub fn as_array(&self, db: &dyn HirDatabase) -> Option<(Type, usize)> { + pub fn as_array(&self, db: &'db dyn HirDatabase) -> Option<(Self, usize)> { if let TyKind::Array(ty, len) = &self.ty.kind(Interner) { try_const_usize(db, len).map(|it| (self.derived(ty.clone()), it as usize)) } else { @@ -5228,14 +5289,14 @@ impl Type { /// Returns types that this type dereferences to (including this type itself). The returned /// iterator won't yield the same type more than once even if the deref chain contains a cycle. - pub fn autoderef<'db>( + pub fn autoderef( &self, db: &'db dyn HirDatabase, - ) -> impl Iterator + use<'_, 'db> { + ) -> impl Iterator> + use<'_, 'db> { self.autoderef_(db).map(move |ty| self.derived(ty)) } - fn autoderef_(&self, db: &dyn HirDatabase) -> impl Iterator { + fn autoderef_(&self, db: &'db dyn HirDatabase) -> impl Iterator { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(&self.ty); autoderef(db, self.env.clone(), canonical) @@ -5245,7 +5306,7 @@ impl Type { // lifetime problems, because we need to borrow temp `CrateImplDefs`. pub fn iterate_assoc_items( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, krate: Crate, mut callback: impl FnMut(AssocItem) -> Option, ) -> Option { @@ -5259,7 +5320,7 @@ impl Type { fn iterate_assoc_items_dyn( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, krate: Crate, callback: &mut dyn FnMut(AssocItemId) -> bool, ) { @@ -5298,7 +5359,7 @@ impl Type { /// - "String" /// - "U" /// ``` - pub fn type_arguments(&self) -> impl Iterator + '_ { + pub fn type_arguments(&self) -> impl Iterator> + '_ { self.ty .strip_references() .as_adt() @@ -5368,7 +5429,7 @@ impl Type { pub fn iterate_method_candidates_with_traits( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, traits_in_scope: &FxHashSet, with_local_impls: Option, @@ -5396,7 +5457,7 @@ impl Type { pub fn iterate_method_candidates( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, with_local_impls: Option, name: Option<&Name>, @@ -5418,7 +5479,7 @@ impl Type { /// are considered inherent methods. pub fn iterate_method_candidates_split_inherent( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, traits_in_scope: &FxHashSet, with_local_impls: Option, @@ -5486,7 +5547,7 @@ impl Type { #[tracing::instrument(skip_all, fields(name = ?name))] pub fn iterate_path_candidates( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, traits_in_scope: &FxHashSet, with_local_impls: Option, @@ -5521,7 +5582,7 @@ impl Type { #[tracing::instrument(skip_all, fields(name = ?name))] pub fn iterate_path_candidates_split_inherent( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, scope: &SemanticsScope<'_>, traits_in_scope: &FxHashSet, with_local_impls: Option, @@ -5584,10 +5645,10 @@ impl Type { /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type, /// or an empty iterator otherwise. - pub fn applicable_inherent_traits<'a>( - &'a self, - db: &'a dyn HirDatabase, - ) -> impl Iterator + 'a { + pub fn applicable_inherent_traits( + &self, + db: &'db dyn HirDatabase, + ) -> impl Iterator { let _p = tracing::info_span!("applicable_inherent_traits").entered(); self.autoderef_(db) .filter_map(|ty| ty.dyn_trait()) @@ -5595,7 +5656,7 @@ impl Type { .map(Trait::from) } - pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { + pub fn env_traits(&self, db: &'db dyn HirDatabase) -> impl Iterator { let _p = tracing::info_span!("env_traits").entered(); self.autoderef_(db) .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_))) @@ -5607,10 +5668,7 @@ impl Type { .map(Trait::from) } - pub fn as_impl_traits( - &self, - db: &dyn HirDatabase, - ) -> Option + use<>> { + pub fn as_impl_traits(&self, db: &'db dyn HirDatabase) -> Option> { self.ty.impl_trait_bounds(db).map(|it| { it.into_iter().filter_map(|pred| match pred.skip_binders() { hir_ty::WhereClause::Implemented(trait_ref) => { @@ -5621,33 +5679,33 @@ impl Type { }) } - pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option { + pub fn as_associated_type_parent_trait(&self, db: &'db dyn HirDatabase) -> Option { self.ty.associated_type_parent_trait(db).map(Into::into) } - fn derived(&self, ty: Ty) -> Type { - Type { env: self.env.clone(), ty } + fn derived(&self, ty: Ty) -> Self { + Type { env: self.env.clone(), ty, _pd: PhantomCovariantLifetime::new() } } /// Visits every type, including generic arguments, in this type. `cb` is called with type /// itself first, and then with its generic arguments. - pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { - fn walk_substs( - db: &dyn HirDatabase, - type_: &Type, + pub fn walk(&self, db: &'db dyn HirDatabase, mut cb: impl FnMut(Type<'db>)) { + fn walk_substs<'db>( + db: &'db dyn HirDatabase, + type_: &Type<'db>, substs: &Substitution, - cb: &mut impl FnMut(Type), + cb: &mut impl FnMut(Type<'db>), ) { for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) { walk_type(db, &type_.derived(ty.clone()), cb); } } - fn walk_bounds( - db: &dyn HirDatabase, - type_: &Type, + fn walk_bounds<'db>( + db: &'db dyn HirDatabase, + type_: &Type<'db>, bounds: &[QuantifiedWhereClause], - cb: &mut impl FnMut(Type), + cb: &mut impl FnMut(Type<'db>), ) { for pred in bounds { if let WhereClause::Implemented(trait_ref) = pred.skip_binders() { @@ -5664,7 +5722,11 @@ impl Type { } } - fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { + fn walk_type<'db>( + db: &'db dyn HirDatabase, + type_: &Type<'db>, + cb: &mut impl FnMut(Type<'db>), + ) { let ty = type_.ty.strip_references(); match ty.kind(Interner) { TyKind::Adt(_, substs) => { @@ -5732,7 +5794,7 @@ impl Type { /// /// Note that we consider placeholder types to unify with everything. /// For example `Option` and `Option` unify although there is unresolved goal `T = U`. - pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool { + pub fn could_unify_with(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone())); hir_ty::could_unify(db, self.env.clone(), &tys) } @@ -5741,17 +5803,17 @@ impl Type { /// /// This means that placeholder types are not considered to unify if there are any bounds set on /// them. For example `Option` and `Option` do not unify as we cannot show that `T = U` - pub fn could_unify_with_deeply(&self, db: &dyn HirDatabase, other: &Type) -> bool { + pub fn could_unify_with_deeply(&self, db: &'db dyn HirDatabase, other: &Type<'db>) -> bool { let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone())); hir_ty::could_unify_deeply(db, self.env.clone(), &tys) } - pub fn could_coerce_to(&self, db: &dyn HirDatabase, to: &Type) -> bool { + pub fn could_coerce_to(&self, db: &'db dyn HirDatabase, to: &Type<'db>) -> bool { let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), to.ty.clone())); hir_ty::could_coerce(db, self.env.clone(), &tys) } - pub fn as_type_param(&self, db: &dyn HirDatabase) -> Option { + pub fn as_type_param(&self, db: &'db dyn HirDatabase) -> Option { match self.ty.kind(Interner) { TyKind::Placeholder(p) => Some(TypeParam { id: TypeParamId::from_unchecked(hir_ty::from_placeholder_idx(db, *p)), @@ -5761,19 +5823,19 @@ impl Type { } /// Returns unique `GenericParam`s contained in this type. - pub fn generic_params(&self, db: &dyn HirDatabase) -> FxHashSet { + pub fn generic_params(&self, db: &'db dyn HirDatabase) -> FxHashSet { hir_ty::collect_placeholders(&self.ty, db) .into_iter() .map(|id| TypeOrConstParam { id }.split(db).either_into()) .collect() } - pub fn layout(&self, db: &dyn HirDatabase) -> Result { + pub fn layout(&self, db: &'db dyn HirDatabase) -> Result { db.layout_of_ty(self.ty.clone(), self.env.clone()) .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) } - pub fn drop_glue(&self, db: &dyn HirDatabase) -> DropGlue { + pub fn drop_glue(&self, db: &'db dyn HirDatabase) -> DropGlue { db.has_drop_glue(self.ty.clone(), self.env.clone()) } } @@ -5800,8 +5862,8 @@ impl InlineAsmOperand { // FIXME: Document this #[derive(Debug)] -pub struct Callable { - ty: Type, +pub struct Callable<'db> { + ty: Type<'db>, sig: CallableSig, callee: Callee, /// Whether this is a method that was called with method call syntax. @@ -5825,7 +5887,7 @@ pub enum CallableKind { FnImpl(FnTrait), } -impl Callable { +impl<'db> Callable<'db> { pub fn kind(&self) -> CallableKind { match self.callee { Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), @@ -5840,7 +5902,7 @@ impl Callable { Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_), } } - pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(SelfParam, Type)> { + pub fn receiver_param(&self, db: &'db dyn HirDatabase) -> Option<(SelfParam, Type<'db>)> { let func = match self.callee { Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it, _ => return None, @@ -5851,7 +5913,7 @@ impl Callable { pub fn n_params(&self) -> usize { self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } } - pub fn params(&self) -> Vec { + pub fn params(&self) -> Vec> { self.sig .params() .iter() @@ -5861,14 +5923,14 @@ impl Callable { .map(|(idx, ty)| Param { func: self.callee.clone(), idx, ty }) .collect() } - pub fn return_type(&self) -> Type { + pub fn return_type(&self) -> Type<'db> { self.ty.derived(self.sig.ret().clone()) } pub fn sig(&self) -> &CallableSig { &self.sig } - pub fn ty(&self) -> &Type { + pub fn ty(&self) -> &Type<'db> { &self.ty } } @@ -6070,9 +6132,9 @@ impl From for ScopeDef { } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Adjustment { - pub source: Type, - pub target: Type, +pub struct Adjustment<'db> { + pub source: Type<'db>, + pub target: Type<'db>, pub kind: Adjust, } @@ -6171,7 +6233,7 @@ impl HasCrate for TypeAlias { } } -impl HasCrate for Type { +impl HasCrate for Type<'_> { fn krate(&self, _db: &dyn HirDatabase) -> Crate { self.env.krate.into() } @@ -6325,9 +6387,9 @@ pub enum DocLinkDef { SelfType(Trait), } -fn push_ty_diagnostics( - db: &dyn HirDatabase, - acc: &mut Vec, +fn push_ty_diagnostics<'db>( + db: &'db dyn HirDatabase, + acc: &mut Vec>, diagnostics: Option>, source_map: &ExpressionStoreSourceMap, ) { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 10498958242a..d96975831e06 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -123,15 +123,15 @@ impl PathResolutionPerNs { } #[derive(Debug)] -pub struct TypeInfo { +pub struct TypeInfo<'db> { /// The original type of the expression or pattern. - pub original: Type, + pub original: Type<'db>, /// The adjusted type, if an adjustment happened. - pub adjusted: Option, + pub adjusted: Option>, } -impl TypeInfo { - pub fn original(self) -> Type { +impl<'db> TypeInfo<'db> { + pub fn original(self) -> Type<'db> { self.original } @@ -140,7 +140,7 @@ impl TypeInfo { } /// The adjusted type, or the original in case no adjustments occurred. - pub fn adjusted(self) -> Type { + pub fn adjusted(self) -> Type<'db> { self.adjusted.unwrap_or(self.original) } } @@ -1534,7 +1534,7 @@ impl<'db> SemanticsImpl<'db> { Some(Label { parent, label_id }) } - pub fn resolve_type(&self, ty: &ast::Type) -> Option { + pub fn resolve_type(&self, ty: &ast::Type) -> Option> { let analyze = self.analyze(ty.syntax())?; analyze.type_of_type(self.db, ty) } @@ -1553,7 +1553,7 @@ impl<'db> SemanticsImpl<'db> { } } - pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option> { + pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option>> { let mutability = |m| match m { hir_ty::Mutability::Not => Mutability::Shared, hir_ty::Mutability::Mut => Mutability::Mut, @@ -1596,13 +1596,13 @@ impl<'db> SemanticsImpl<'db> { }) } - pub fn type_of_expr(&self, expr: &ast::Expr) -> Option { + pub fn type_of_expr(&self, expr: &ast::Expr) -> Option> { self.analyze(expr.syntax())? .type_of_expr(self.db, expr) .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced }) } - pub fn type_of_pat(&self, pat: &ast::Pat) -> Option { + pub fn type_of_pat(&self, pat: &ast::Pat) -> Option> { self.analyze(pat.syntax())? .type_of_pat(self.db, pat) .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced }) @@ -1611,15 +1611,15 @@ impl<'db> SemanticsImpl<'db> { /// It also includes the changes that binding mode makes in the type. For example in /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option` but the result /// of this function is `&mut Option` - pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option { + pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option> { self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat) } - pub fn type_of_self(&self, param: &ast::SelfParam) -> Option { + pub fn type_of_self(&self, param: &ast::SelfParam) -> Option> { self.analyze(param.syntax())?.type_of_self(self.db, param) } - pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> { + pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type<'db>; 1]> { self.analyze(pat.syntax()) .and_then(|it| it.pattern_adjustments(self.db, pat)) .unwrap_or_default() @@ -1629,7 +1629,7 @@ impl<'db> SemanticsImpl<'db> { self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat) } - pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option { + pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option> { self.analyze(call.syntax())?.resolve_expr_as_callable(self.db, call) } @@ -1641,7 +1641,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_method_call_fallback( &self, call: &ast::MethodCallExpr, - ) -> Option<(Either, Option)> { + ) -> Option<(Either, Option>)> { self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call) } @@ -1649,10 +1649,10 @@ impl<'db> SemanticsImpl<'db> { // FIXME: better api for the trait environment pub fn resolve_trait_impl_method( &self, - env: Type, + env: Type<'db>, trait_: Trait, func: Function, - subst: impl IntoIterator, + subst: impl IntoIterator>, ) -> Option { let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None); for s in subst { @@ -1691,7 +1691,10 @@ impl<'db> SemanticsImpl<'db> { // This does not resolve the method call to the correct trait impl! // We should probably fix that. - pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { + pub fn resolve_method_call_as_callable( + &self, + call: &ast::MethodCallExpr, + ) -> Option> { self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call) } @@ -1702,14 +1705,15 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_field_fallback( &self, field: &ast::FieldExpr, - ) -> Option<(Either, Function>, Option)> { + ) -> Option<(Either, Function>, Option>)> + { self.analyze(field.syntax())?.resolve_field_fallback(self.db, field) } pub fn resolve_record_field( &self, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type)> { + ) -> Option<(Field, Option, Type<'db>)> { self.resolve_record_field_with_substitution(field) .map(|(field, local, ty, _)| (field, local, ty)) } @@ -1717,18 +1721,21 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_record_field_with_substitution( &self, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type, GenericSubstitution)> { + ) -> Option<(Field, Option, Type<'db>, GenericSubstitution<'db>)> { self.analyze(field.syntax())?.resolve_record_field(self.db, field) } - pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> { + pub fn resolve_record_pat_field( + &self, + field: &ast::RecordPatField, + ) -> Option<(Field, Type<'db>)> { self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty)) } pub fn resolve_record_pat_field_with_subst( &self, field: &ast::RecordPatField, - ) -> Option<(Field, Type, GenericSubstitution)> { + ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> { self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field) } @@ -1801,7 +1808,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_path_with_subst( &self, path: &ast::Path, - ) -> Option<(PathResolution, Option)> { + ) -> Option<(PathResolution, Option>)> { self.analyze(path.syntax())?.resolve_path(self.db, path) } @@ -1812,7 +1819,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_offset_of_field( &self, name_ref: &ast::NameRef, - ) -> Option<(Either, GenericSubstitution)> { + ) -> Option<(Either, GenericSubstitution<'db>)> { self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref) } @@ -1834,13 +1841,19 @@ impl<'db> SemanticsImpl<'db> { self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat) } - pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> { + pub fn record_literal_missing_fields( + &self, + literal: &ast::RecordExpr, + ) -> Vec<(Field, Type<'db>)> { self.analyze(literal.syntax()) .and_then(|it| it.record_literal_missing_fields(self.db, literal)) .unwrap_or_default() } - pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { + pub fn record_pattern_missing_fields( + &self, + pattern: &ast::RecordPat, + ) -> Vec<(Field, Type<'db>)> { self.analyze(pattern.syntax()) .and_then(|it| it.record_pattern_missing_fields(self.db, pattern)) .unwrap_or_default() diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 3273358b78e9..48543ca581ff 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -257,7 +257,11 @@ impl<'db> SourceAnalyzer<'db> { infer.expr_adjustments.get(&expr_id).map(|v| &**v) } - pub(crate) fn type_of_type(&self, db: &'db dyn HirDatabase, ty: &ast::Type) -> Option { + pub(crate) fn type_of_type( + &self, + db: &'db dyn HirDatabase, + ty: &ast::Type, + ) -> Option> { let type_ref = self.type_id(ty)?; let ty = TyLoweringContext::new( db, @@ -277,7 +281,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, expr: &ast::Expr, - ) -> Option<(Type, Option)> { + ) -> Option<(Type<'db>, Option>)> { let expr_id = self.expr_id(expr.clone())?; let infer = self.infer()?; let coerced = expr_id @@ -293,7 +297,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, pat: &ast::Pat, - ) -> Option<(Type, Option)> { + ) -> Option<(Type<'db>, Option>)> { let expr_or_pat_id = self.pat_id(pat)?; let infer = self.infer()?; let coerced = match expr_or_pat_id { @@ -316,7 +320,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, pat: &ast::IdentPat, - ) -> Option { + ) -> Option> { let binding_id = self.binding_id_of_pat(pat)?; let infer = self.infer()?; let ty = infer[binding_id].clone(); @@ -328,7 +332,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, _param: &ast::SelfParam, - ) -> Option { + ) -> Option> { let binding = self.body()?.self_param?; let ty = self.infer()?[binding].clone(); Some(Type::new_with_resolver(db, &self.resolver, ty)) @@ -353,7 +357,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, pat: &ast::Pat, - ) -> Option> { + ) -> Option; 1]>> { let pat_id = self.pat_id(pat)?; let infer = self.infer()?; Some( @@ -370,7 +374,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, call: &ast::MethodCallExpr, - ) -> Option { + ) -> Option> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; let (func, substs) = self.infer()?.method_resolution(expr_id)?; let ty = db.value_ty(func.into())?.substitute(Interner, &substs); @@ -395,7 +399,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, call: &ast::MethodCallExpr, - ) -> Option<(Either, Option)> { + ) -> Option<(Either, Option>)> { let expr_id = self.expr_id(call.clone().into())?.as_expr()?; let inference_result = self.infer()?; match inference_result.method_resolution(expr_id) { @@ -419,7 +423,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, call: &ast::Expr, - ) -> Option { + ) -> Option> { let (orig, adjusted) = self.type_of_expr(db, &call.clone())?; adjusted.unwrap_or(orig).as_callable(db) } @@ -440,7 +444,7 @@ impl<'db> SourceAnalyzer<'db> { field_expr: ExprId, infer: &InferenceResult, db: &'db dyn HirDatabase, - ) -> Option { + ) -> Option> { let body = self.store()?; if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] { let (adt, subst) = type_of_expr_including_adjust(infer, object_expr)?.as_adt()?; @@ -457,7 +461,8 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, field: &ast::FieldExpr, - ) -> Option<(Either, Function>, Option)> { + ) -> Option<(Either, Function>, Option>)> + { let (def, ..) = self.body_()?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; let inference_result = self.infer()?; @@ -680,7 +685,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type, GenericSubstitution)> { + ) -> Option<(Field, Option, Type<'db>, GenericSubstitution<'db>)> { let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let expr = ast::Expr::from(record_expr); let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?; @@ -724,7 +729,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, field: &ast::RecordPatField, - ) -> Option<(Field, Type, GenericSubstitution)> { + ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> { let field_name = field.field_name()?.as_name(); let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let pat_id = self.pat_id(&record_pat.into())?; @@ -779,7 +784,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, name_ref: &ast::NameRef, - ) -> Option<(Either, GenericSubstitution)> { + ) -> Option<(Either, GenericSubstitution<'db>)> { let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?; let container = offset_of_expr.ty()?; let container = self.type_of_type(db, &container)?; @@ -851,7 +856,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, path: &ast::Path, - ) -> Option<(PathResolution, Option)> { + ) -> Option<(PathResolution, Option>)> { let parent = path.syntax().parent(); let parent = || parent.clone(); @@ -1216,7 +1221,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, literal: &ast::RecordExpr, - ) -> Option> { + ) -> Option)>> { let body = self.store()?; let infer = self.infer()?; @@ -1239,7 +1244,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, pattern: &ast::RecordPat, - ) -> Option> { + ) -> Option)>> { let body = self.store()?; let infer = self.infer()?; @@ -1258,7 +1263,7 @@ impl<'db> SourceAnalyzer<'db> { substs: &Substitution, variant: VariantId, missing_fields: Vec, - ) -> Vec<(Field, Type)> { + ) -> Vec<(Field, Type<'db>)> { let field_types = db.field_types(variant); missing_fields diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs index af72179305c8..4b354e640628 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs @@ -22,20 +22,20 @@ enum NewTypesKey { /// Helper enum to squash big number of alternative trees into `Many` variant as there is too many /// to take into account. #[derive(Debug)] -enum AlternativeExprs { +enum AlternativeExprs<'db> { /// There are few trees, so we keep track of them all - Few(FxHashSet), + Few(FxHashSet>), /// There are too many trees to keep track of Many, } -impl AlternativeExprs { +impl<'db> AlternativeExprs<'db> { /// Construct alternative trees /// /// # Arguments /// `threshold` - threshold value for many trees (more than that is many) /// `exprs` - expressions iterator - fn new(threshold: usize, exprs: impl Iterator) -> AlternativeExprs { + fn new(threshold: usize, exprs: impl Iterator>) -> AlternativeExprs<'db> { let mut it = AlternativeExprs::Few(Default::default()); it.extend_with_threshold(threshold, exprs); it @@ -45,7 +45,7 @@ impl AlternativeExprs { /// /// # Arguments /// `ty` - Type of expressions queried (this is used to give type to `Expr::Many`) - fn exprs(&self, ty: &Type) -> Vec { + fn exprs(&self, ty: &Type<'db>) -> Vec> { match self { AlternativeExprs::Few(exprs) => exprs.iter().cloned().collect(), AlternativeExprs::Many => vec![Expr::Many(ty.clone())], @@ -57,7 +57,7 @@ impl AlternativeExprs { /// # Arguments /// `threshold` - threshold value for many trees (more than that is many) /// `exprs` - expressions iterator - fn extend_with_threshold(&mut self, threshold: usize, exprs: impl Iterator) { + fn extend_with_threshold(&mut self, threshold: usize, exprs: impl Iterator>) { match self { AlternativeExprs::Few(tts) => { for it in exprs { @@ -88,20 +88,20 @@ impl AlternativeExprs { /// Both of them are to speed up the term search by leaving out types / ScopeDefs that likely do /// not produce any new results. #[derive(Default, Debug)] -struct LookupTable { +struct LookupTable<'db> { /// All the `Expr`s in "value" produce the type of "key" - data: FxHashMap, + data: FxHashMap, AlternativeExprs<'db>>, /// New types reached since last query by the `NewTypesKey` - new_types: FxHashMap>, + new_types: FxHashMap>>, /// Types queried but not present - types_wishlist: FxHashSet, + types_wishlist: FxHashSet>, /// Threshold to squash trees to `Many` many_threshold: usize, } -impl LookupTable { +impl<'db> LookupTable<'db> { /// Initialize lookup table - fn new(many_threshold: usize, goal: Type) -> Self { + fn new(many_threshold: usize, goal: Type<'db>) -> Self { let mut res = Self { many_threshold, ..Default::default() }; res.new_types.insert(NewTypesKey::ImplMethod, Vec::new()); res.new_types.insert(NewTypesKey::StructProjection, Vec::new()); @@ -110,7 +110,7 @@ impl LookupTable { } /// Find all `Expr`s that unify with the `ty` - fn find(&mut self, db: &dyn HirDatabase, ty: &Type) -> Option> { + fn find(&mut self, db: &'db dyn HirDatabase, ty: &Type<'db>) -> Option>> { let res = self .data .iter() @@ -135,7 +135,7 @@ impl LookupTable { /// /// For example if we have type `i32` in data and we query for `&i32` it map all the type /// trees we have for `i32` with `Expr::Reference` and returns them. - fn find_autoref(&mut self, db: &dyn HirDatabase, ty: &Type) -> Option> { + fn find_autoref(&mut self, db: &'db dyn HirDatabase, ty: &Type<'db>) -> Option>> { let res = self .data .iter() @@ -174,7 +174,7 @@ impl LookupTable { /// Note that the types have to be the same, unification is not enough as unification is not /// transitive. For example Vec and FxHashSet both unify with Iterator, /// but they clearly do not unify themselves. - fn insert(&mut self, ty: Type, exprs: impl Iterator) { + fn insert(&mut self, ty: Type<'db>, exprs: impl Iterator>) { match self.data.get_mut(&ty) { Some(it) => { it.extend_with_threshold(self.many_threshold, exprs); @@ -192,14 +192,14 @@ impl LookupTable { } /// Iterate all the reachable types - fn iter_types(&self) -> impl Iterator + '_ { + fn iter_types(&self) -> impl Iterator> + '_ { self.data.keys().cloned() } /// Query new types reached since last query by key /// /// Create new key if you wish to query it to avoid conflicting with existing queries. - fn new_types(&mut self, key: NewTypesKey) -> Vec { + fn new_types(&mut self, key: NewTypesKey) -> Vec> { match self.new_types.get_mut(&key) { Some(it) => std::mem::take(it), None => Vec::new(), @@ -207,20 +207,20 @@ impl LookupTable { } /// Types queried but not found - fn types_wishlist(&mut self) -> &FxHashSet { + fn types_wishlist(&mut self) -> &FxHashSet> { &self.types_wishlist } } /// Context for the `term_search` function #[derive(Debug)] -pub struct TermSearchCtx<'a, DB: HirDatabase> { +pub struct TermSearchCtx<'db, DB: HirDatabase> { /// Semantics for the program - pub sema: &'a Semantics<'a, DB>, + pub sema: &'db Semantics<'db, DB>, /// Semantic scope, captures context for the term search - pub scope: &'a SemanticsScope<'a>, + pub scope: &'db SemanticsScope<'db>, /// Target / expected output type - pub goal: Type, + pub goal: Type<'db>, /// Configuration for term search pub config: TermSearchConfig, } @@ -263,7 +263,7 @@ impl Default for TermSearchConfig { /// Note that there are usually more ways we can get to the `goal` type but some are discarded to /// reduce the memory consumption. It is also unlikely anyone is willing ti browse through /// thousands of possible responses so we currently take first 10 from every tactic. -pub fn term_search(ctx: &TermSearchCtx<'_, DB>) -> Vec { +pub fn term_search<'db, DB: HirDatabase>(ctx: &'db TermSearchCtx<'db, DB>) -> Vec> { let module = ctx.scope.module(); let mut defs = FxHashSet::default(); defs.insert(ScopeDef::ModuleDef(ModuleDef::Module(module))); @@ -285,7 +285,7 @@ pub fn term_search(ctx: &TermSearchCtx<'_, DB>) -> Vec { }; // Try trivial tactic first, also populates lookup table - let mut solutions: Vec = tactics::trivial(ctx, &defs, &mut lookup).collect(); + let mut solutions: Vec> = tactics::trivial(ctx, &defs, &mut lookup).collect(); // Use well known types tactic before iterations as it does not depend on other tactics solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup)); solutions.extend(tactics::assoc_const(ctx, &defs, &mut lookup)); diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs index 78ee3b5aa683..843831948adc 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs @@ -59,7 +59,7 @@ fn mod_item_path_str( /// So in short it pretty much gives us a way to get type `Option` using the items we have in /// scope. #[derive(Debug, Clone, Eq, Hash, PartialEq)] -pub enum Expr { +pub enum Expr<'db> { /// Constant Const(Const), /// Static variable @@ -69,26 +69,31 @@ pub enum Expr { /// Constant generic parameter ConstParam(ConstParam), /// Well known type (such as `true` for bool) - FamousType { ty: Type, value: &'static str }, + FamousType { ty: Type<'db>, value: &'static str }, /// Function call (does not take self param) - Function { func: Function, generics: Vec, params: Vec }, + Function { func: Function, generics: Vec>, params: Vec> }, /// Method call (has self param) - Method { func: Function, generics: Vec, target: Box, params: Vec }, + Method { + func: Function, + generics: Vec>, + target: Box>, + params: Vec>, + }, /// Enum variant construction - Variant { variant: Variant, generics: Vec, params: Vec }, + Variant { variant: Variant, generics: Vec>, params: Vec> }, /// Struct construction - Struct { strukt: Struct, generics: Vec, params: Vec }, + Struct { strukt: Struct, generics: Vec>, params: Vec> }, /// Tuple construction - Tuple { ty: Type, params: Vec }, + Tuple { ty: Type<'db>, params: Vec> }, /// Struct field access - Field { expr: Box, field: Field }, + Field { expr: Box>, field: Field }, /// Passing type as reference (with `&`) - Reference(Box), + Reference(Box>), /// Indicates possibility of many different options that all evaluate to `ty` - Many(Type), + Many(Type<'db>), } -impl Expr { +impl<'db> Expr<'db> { /// Generate source code for type tree. /// /// Note that trait imports are not added to generated code. @@ -96,8 +101,8 @@ impl Expr { /// by `traits_used` method are also imported. pub fn gen_source_code( &self, - sema_scope: &SemanticsScope<'_>, - many_formatter: &mut dyn FnMut(&Type) -> String, + sema_scope: &SemanticsScope<'db>, + many_formatter: &mut dyn FnMut(&Type<'db>) -> String, cfg: ImportPathConfig, display_target: DisplayTarget, ) -> Result { @@ -298,7 +303,7 @@ impl Expr { /// Get type of the type tree. /// /// Same as getting the type of root node - pub fn ty(&self, db: &dyn HirDatabase) -> Type { + pub fn ty(&self, db: &'db dyn HirDatabase) -> Type<'db> { match self { Expr::Const(it) => it.ty(db), Expr::Static(it) => it.ty(db), diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs index bcff44fcd016..9df131f90e40 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs @@ -40,11 +40,11 @@ use super::{LookupTable, NewTypesKey, TermSearchCtx}; /// /// _Note that there is no use of calling this tactic in every iteration as the output does not /// depend on the current state of `lookup`_ -pub(super) fn trivial<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, defs: &'a FxHashSet, - lookup: &'a mut LookupTable, -) -> impl Iterator + 'a { + lookup: &'lt mut LookupTable<'db>, +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; defs.iter().filter_map(|def| { let expr = match def { @@ -104,11 +104,11 @@ pub(super) fn trivial<'a, DB: HirDatabase>( /// /// _Note that there is no use of calling this tactic in every iteration as the output does not /// depend on the current state of `lookup`_ -pub(super) fn assoc_const<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn assoc_const<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, defs: &'a FxHashSet, - lookup: &'a mut LookupTable, -) -> impl Iterator + 'a { + lookup: &'lt mut LookupTable<'db>, +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); @@ -152,12 +152,12 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>( /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types /// * `should_continue` - Function that indicates when to stop iterating -pub(super) fn data_constructor<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, _defs: &'a FxHashSet, - lookup: &'a mut LookupTable, + lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, -) -> impl Iterator + 'a { +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); lookup @@ -199,14 +199,14 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>( let generics: Vec<_> = ty.type_arguments().collect(); // Early exit if some param cannot be filled from lookup - let param_exprs: Vec> = fields + let param_exprs: Vec>> = fields .into_iter() .map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned()))) .collect::>()?; // Note that we need special case for 0 param constructors because of multi cartesian // product - let exprs: Vec = if param_exprs.is_empty() { + let exprs: Vec> = if param_exprs.is_empty() { vec![Expr::Struct { strukt, generics, params: Vec::new() }] } else { param_exprs @@ -247,7 +247,7 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>( .into_iter() .filter_map(|variant| { // Early exit if some param cannot be filled from lookup - let param_exprs: Vec> = variant + let param_exprs: Vec>> = variant .fields(db) .into_iter() .map(|field| { @@ -257,7 +257,7 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>( // Note that we need special case for 0 param constructors because of multi cartesian // product - let variant_exprs: Vec = if param_exprs.is_empty() { + let variant_exprs: Vec> = if param_exprs.is_empty() { vec![Expr::Variant { variant, generics: generics.clone(), @@ -301,12 +301,12 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>( /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types /// * `should_continue` - Function that indicates when to stop iterating -pub(super) fn free_function<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, defs: &'a FxHashSet, - lookup: &'a mut LookupTable, + lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, -) -> impl Iterator + 'a { +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); defs.iter() @@ -375,7 +375,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>( } // Early exit if some param cannot be filled from lookup - let param_exprs: Vec> = it + let param_exprs: Vec>> = it .params_without_self_with_args(db, generics.iter().cloned()) .into_iter() .map(|field| { @@ -389,7 +389,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>( // Note that we need special case for 0 param constructors because of multi cartesian // product - let fn_exprs: Vec = if param_exprs.is_empty() { + let fn_exprs: Vec> = if param_exprs.is_empty() { vec![Expr::Function { func: *it, generics, params: Vec::new() }] } else { param_exprs @@ -432,12 +432,12 @@ pub(super) fn free_function<'a, DB: HirDatabase>( /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types /// * `should_continue` - Function that indicates when to stop iterating -pub(super) fn impl_method<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, _defs: &'a FxHashSet, - lookup: &'a mut LookupTable, + lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, -) -> impl Iterator + 'a { +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); lookup @@ -507,14 +507,14 @@ pub(super) fn impl_method<'a, DB: HirDatabase>( let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup"); // Early exit if some param cannot be filled from lookup - let param_exprs: Vec> = it + let param_exprs: Vec>> = it .params_without_self_with_args(db, ty.type_arguments()) .into_iter() .map(|field| lookup.find_autoref(db, field.ty())) .collect::>()?; let generics: Vec<_> = ty.type_arguments().collect(); - let fn_exprs: Vec = std::iter::once(target_type_exprs) + let fn_exprs: Vec> = std::iter::once(target_type_exprs) .chain(param_exprs) .multi_cartesian_product() .map(|params| { @@ -547,12 +547,12 @@ pub(super) fn impl_method<'a, DB: HirDatabase>( /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types /// * `should_continue` - Function that indicates when to stop iterating -pub(super) fn struct_projection<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn struct_projection<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, _defs: &'a FxHashSet, - lookup: &'a mut LookupTable, + lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, -) -> impl Iterator + 'a { +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); lookup @@ -589,11 +589,11 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>( /// * `ctx` - Context for the term search /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types -pub(super) fn famous_types<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, _defs: &'a FxHashSet, - lookup: &'a mut LookupTable, -) -> impl Iterator + 'a { + lookup: &'lt mut LookupTable<'db>, +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); [ @@ -620,12 +620,12 @@ pub(super) fn famous_types<'a, DB: HirDatabase>( /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types /// * `should_continue` - Function that indicates when to stop iterating -pub(super) fn impl_static_method<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, _defs: &'a FxHashSet, - lookup: &'a mut LookupTable, + lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, -) -> impl Iterator + 'a { +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); lookup @@ -683,7 +683,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( } // Early exit if some param cannot be filled from lookup - let param_exprs: Vec> = it + let param_exprs: Vec>> = it .params_without_self_with_args(db, ty.type_arguments()) .into_iter() .map(|field| lookup.find_autoref(db, field.ty())) @@ -692,7 +692,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( // Note that we need special case for 0 param constructors because of multi cartesian // product let generics = ty.type_arguments().collect(); - let fn_exprs: Vec = if param_exprs.is_empty() { + let fn_exprs: Vec> = if param_exprs.is_empty() { vec![Expr::Function { func: it, generics, params: Vec::new() }] } else { param_exprs @@ -722,12 +722,12 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types /// * `should_continue` - Function that indicates when to stop iterating -pub(super) fn make_tuple<'a, DB: HirDatabase>( - ctx: &'a TermSearchCtx<'a, DB>, +pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>( + ctx: &'a TermSearchCtx<'db, DB>, _defs: &'a FxHashSet, - lookup: &'a mut LookupTable, + lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, -) -> impl Iterator + 'a { +) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; let module = ctx.scope.module(); @@ -749,15 +749,15 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>( } // Early exit if some param cannot be filled from lookup - let param_exprs: Vec> = + let param_exprs: Vec>> = ty.type_arguments().map(|field| lookup.find(db, &field)).collect::>()?; - let exprs: Vec = param_exprs + let exprs: Vec> = param_exprs .into_iter() .multi_cartesian_product() .filter(|_| should_continue()) .map(|params| { - let tys: Vec = params.iter().map(|it| it.ty(db)).collect(); + let tys: Vec> = params.iter().map(|it| it.ty(db)).collect(); let tuple_ty = Type::new_tuple(module.krate().into(), &tys); let expr = Expr::Tuple { ty: tuple_ty.clone(), params }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs index 9eb9452a2b83..207a7548f49b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs @@ -95,7 +95,7 @@ impl<'a> AssistContext<'a> { } } - pub(crate) fn db(&self) -> &RootDatabase { + pub(crate) fn db(&self) -> &'a RootDatabase { self.sema.db } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 6a55f39e6934..9f9d21923ff7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -192,7 +192,7 @@ fn add_missing_impl_members_inner( fn try_gen_trait_body( ctx: &AssistContext<'_>, func: &ast::Fn, - trait_ref: hir::TraitRef, + trait_ref: hir::TraitRef<'_>, impl_def: &ast::Impl, edition: Edition, ) -> Option<()> { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 682a8e6c78d3..1ece7ddab101 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -413,8 +413,8 @@ impl ExtendedEnum { fn enum_( db: &RootDatabase, enum_: hir::Enum, - enum_ty: &hir::Type, - self_ty: Option<&hir::Type>, + enum_ty: &hir::Type<'_>, + self_ty: Option<&hir::Type<'_>>, ) -> Self { ExtendedEnum::Enum { enum_, @@ -448,7 +448,7 @@ impl ExtendedEnum { fn resolve_enum_def( sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr, - self_ty: Option<&hir::Type>, + self_ty: Option<&hir::Type<'_>>, ) -> Option { sema.type_of_expr(expr)?.adjusted().autoderef(sema.db).find_map(|ty| match ty.as_adt() { Some(Adt::Enum(e)) => Some(ExtendedEnum::enum_(sema.db, e, &ty, self_ty)), @@ -459,7 +459,7 @@ fn resolve_enum_def( fn resolve_tuple_of_enum_def( sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr, - self_ty: Option<&hir::Type>, + self_ty: Option<&hir::Type<'_>>, ) -> Option> { sema.type_of_expr(expr)? .adjusted() @@ -483,7 +483,7 @@ fn resolve_tuple_of_enum_def( fn resolve_array_of_enum_def( sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr, - self_ty: Option<&hir::Type>, + self_ty: Option<&hir::Type<'_>>, ) -> Option<(ExtendedEnum, usize)> { sema.type_of_expr(expr)?.adjusted().as_array(sema.db).and_then(|(ty, len)| { ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index f3243d369a0b..bb6a10d40b71 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -164,9 +164,9 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< Some(()) } -pub(super) fn find_importable_node( - ctx: &AssistContext<'_>, -) -> Option<(ImportAssets, SyntaxNode, Option)> { +pub(super) fn find_importable_node<'a: 'db, 'db>( + ctx: &'a AssistContext<'db>, +) -> Option<(ImportAssets<'db>, SyntaxNode, Option>)> { // Deduplicate this with the `expected_type_and_name` logic for completions let expected = |expr_or_pat: Either| match expr_or_pat { Either::Left(expr) => { @@ -226,7 +226,7 @@ pub(super) fn find_importable_node( } } -fn group_label(import_candidate: &ImportCandidate) -> GroupLabel { +fn group_label(import_candidate: &ImportCandidate<'_>) -> GroupLabel { let name = match import_candidate { ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()), ImportCandidate::TraitAssocItem(candidate) => { @@ -244,7 +244,7 @@ fn group_label(import_candidate: &ImportCandidate) -> GroupLabel { pub(crate) fn relevance_score( ctx: &AssistContext<'_>, import: &LocatedImport, - expected: Option<&Type>, + expected: Option<&Type<'_>>, current_module: Option<&Module>, ) -> i32 { let mut score = 0; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index cf45ea0a30d0..00cbef1c01c0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -309,23 +309,23 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option { name: ast::NameRef, self_param: Option, - params: Vec, - control_flow: ControlFlow, - ret_ty: RetType, + params: Vec>, + control_flow: ControlFlow<'db>, + ret_ty: RetType<'db>, body: FunctionBody, outliving_locals: Vec, /// Whether at least one of the container's tail expr is contained in the range we're extracting. contains_tail_expr: bool, - mods: ContainerInfo, + mods: ContainerInfo<'db>, } #[derive(Debug)] -struct Param { +struct Param<'db> { var: Local, - ty: hir::Type, + ty: hir::Type<'db>, move_local: bool, requires_mut: bool, is_copy: bool, @@ -340,10 +340,10 @@ enum ParamKind { } #[derive(Debug)] -enum FunType { +enum FunType<'db> { Unit, - Single(hir::Type), - Tuple(Vec), + Single(hir::Type<'db>), + Tuple(Vec>), } /// Where to put extracted function definition @@ -358,19 +358,19 @@ enum Anchor { // FIXME: ControlFlow and ContainerInfo both track some function modifiers, feels like these two should // probably be merged somehow. #[derive(Debug)] -struct ControlFlow { - kind: Option, +struct ControlFlow<'db> { + kind: Option>, is_async: bool, is_unsafe: bool, } /// The thing whose expression we are extracting from. Can be a function, const, static, const arg, ... #[derive(Clone, Debug)] -struct ContainerInfo { +struct ContainerInfo<'db> { is_const: bool, parent_loop: Option, /// The function's return type, const's type etc. - ret_type: Option, + ret_type: Option>, generic_param_lists: Vec, where_clauses: Vec, edition: Edition, @@ -389,11 +389,11 @@ struct ContainerInfo { /// } /// ``` #[derive(Debug, Clone)] -enum FlowKind { +enum FlowKind<'db> { /// Return with value (`return $expr;`) Return(Option), Try { - kind: TryKind, + kind: TryKind<'db>, }, /// Break with label and value (`break 'label $expr;`) Break(Option, Option), @@ -402,18 +402,18 @@ enum FlowKind { } #[derive(Debug, Clone)] -enum TryKind { +enum TryKind<'db> { Option, - Result { ty: hir::Type }, + Result { ty: hir::Type<'db> }, } #[derive(Debug)] -enum RetType { - Expr(hir::Type), +enum RetType<'db> { + Expr(hir::Type<'db>), Stmt, } -impl RetType { +impl RetType<'_> { fn is_unit(&self) -> bool { match self { RetType::Expr(ty) => ty.is_unit(), @@ -456,8 +456,8 @@ impl LocalUsages { } } -impl Function { - fn return_type(&self, ctx: &AssistContext<'_>) -> FunType { +impl<'db> Function<'db> { + fn return_type(&self, ctx: &AssistContext<'db>) -> FunType<'db> { match &self.ret_ty { RetType::Expr(ty) if ty.is_unit() => FunType::Unit, RetType::Expr(ty) => FunType::Single(ty.clone()), @@ -487,7 +487,7 @@ impl ParamKind { } } -impl Param { +impl<'db> Param<'db> { fn kind(&self) -> ParamKind { match (self.move_local, self.requires_mut, self.is_copy) { (false, true, _) => ParamKind::MutRef, @@ -497,7 +497,7 @@ impl Param { } } - fn to_arg(&self, ctx: &AssistContext<'_>, edition: Edition) -> ast::Expr { + fn to_arg(&self, ctx: &AssistContext<'db>, edition: Edition) -> ast::Expr { let var = path_expr_from_local(ctx, self.var, edition); match self.kind() { ParamKind::Value | ParamKind::MutValue => var, @@ -532,8 +532,12 @@ impl Param { } } -impl TryKind { - fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>, edition: Edition) -> Option { +impl<'db> TryKind<'db> { + fn of_ty( + ty: hir::Type<'db>, + ctx: &AssistContext<'db>, + edition: Edition, + ) -> Option> { if ty.is_unknown() { // We favour Result for `expr?` return Some(TryKind::Result { ty }); @@ -551,7 +555,7 @@ impl TryKind { } } -impl FlowKind { +impl<'db> FlowKind<'db> { fn make_result_handler(&self, expr: Option) -> ast::Expr { match self { FlowKind::Return(_) => make::expr_return(expr), @@ -567,7 +571,7 @@ impl FlowKind { } } - fn expr_ty(&self, ctx: &AssistContext<'_>) -> Option { + fn expr_ty(&self, ctx: &AssistContext<'db>) -> Option> { match self { FlowKind::Return(Some(expr)) | FlowKind::Break(_, Some(expr)) => { ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted) @@ -876,11 +880,11 @@ impl FunctionBody { (res, self_param) } - fn analyze_container( + fn analyze_container<'db>( &self, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, edition: Edition, - ) -> Option<(ContainerInfo, bool)> { + ) -> Option<(ContainerInfo<'db>, bool)> { let mut ancestors = self.parent()?.ancestors(); let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted); let mut parent_loop = None; @@ -985,7 +989,7 @@ impl FunctionBody { )) } - fn return_ty(&self, ctx: &AssistContext<'_>) -> Option { + fn return_ty<'db>(&self, ctx: &AssistContext<'db>) -> Option> { match self.tail_expr() { Some(expr) => ctx.sema.type_of_expr(&expr).map(TypeInfo::original).map(RetType::Expr), None => Some(RetType::Stmt), @@ -1006,11 +1010,11 @@ impl FunctionBody { } /// Analyses the function body for external control flow. - fn external_control_flow( + fn external_control_flow<'db>( &self, - ctx: &AssistContext<'_>, - container_info: &ContainerInfo, - ) -> Option { + ctx: &AssistContext<'db>, + container_info: &ContainerInfo<'db>, + ) -> Option> { let mut ret_expr = None; let mut try_expr = None; let mut break_expr = None; @@ -1096,12 +1100,12 @@ impl FunctionBody { /// find variables that should be extracted as params /// /// Computes additional info that affects param type and mutability - fn extracted_function_params( + fn extracted_function_params<'db>( &self, - ctx: &AssistContext<'_>, - container_info: &ContainerInfo, + ctx: &AssistContext<'db>, + container_info: &ContainerInfo<'db>, locals: FxIndexSet, - ) -> Vec { + ) -> Vec> { locals .into_iter() .sorted() @@ -1449,7 +1453,7 @@ fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) { } } -fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> SyntaxNode { +fn make_call(ctx: &AssistContext<'_>, fun: &Function<'_>, indent: IndentLevel) -> SyntaxNode { let ret_ty = fun.return_type(ctx); let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition))); @@ -1508,17 +1512,17 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> Sy } } -enum FlowHandler { +enum FlowHandler<'db> { None, - Try { kind: TryKind }, - If { action: FlowKind }, - IfOption { action: FlowKind }, - MatchOption { none: FlowKind }, - MatchResult { err: FlowKind }, + Try { kind: TryKind<'db> }, + If { action: FlowKind<'db> }, + IfOption { action: FlowKind<'db> }, + MatchOption { none: FlowKind<'db> }, + MatchResult { err: FlowKind<'db> }, } -impl FlowHandler { - fn from_ret_ty(fun: &Function, ret_ty: &FunType) -> FlowHandler { +impl<'db> FlowHandler<'db> { + fn from_ret_ty(fun: &Function<'db>, ret_ty: &FunType<'db>) -> FlowHandler<'db> { if fun.contains_tail_expr { return FlowHandler::None; } @@ -1628,7 +1632,7 @@ fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local, edition: Edition) - fn format_function( ctx: &AssistContext<'_>, module: hir::Module, - fun: &Function, + fun: &Function<'_>, old_indent: IndentLevel, ) -> ast::Fn { let fun_name = make::name(&fun.name.text()); @@ -1654,7 +1658,7 @@ fn format_function( fn make_generic_params_and_where_clause( ctx: &AssistContext<'_>, - fun: &Function, + fun: &Function<'_>, ) -> (Option, Option) { let used_type_params = fun.type_params(ctx); @@ -1666,7 +1670,7 @@ fn make_generic_params_and_where_clause( fn make_generic_param_list( ctx: &AssistContext<'_>, - fun: &Function, + fun: &Function<'_>, used_type_params: &[TypeParam], ) -> Option { let mut generic_params = fun @@ -1703,7 +1707,7 @@ fn param_is_required( fn make_where_clause( ctx: &AssistContext<'_>, - fun: &Function, + fun: &Function<'_>, used_type_params: &[TypeParam], ) -> Option { let mut predicates = fun @@ -1743,9 +1747,9 @@ fn resolved_type_param(ctx: &AssistContext<'_>, pred: &ast::WherePred) -> Option } } -impl Function { +impl<'db> Function<'db> { /// Collect all the `TypeParam`s used in the `body` and `params`. - fn type_params(&self, ctx: &AssistContext<'_>) -> Vec { + fn type_params(&self, ctx: &AssistContext<'db>) -> Vec { let type_params_in_descendant_paths = self.body.descendant_paths().filter_map(|it| match ctx.sema.resolve_path(&it) { Some(PathResolution::TypeParam(type_param)) => Some(type_param), @@ -1808,8 +1812,8 @@ impl Function { } } -impl FunType { - fn make_ty(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type { +impl<'db> FunType<'db> { + fn make_ty(&self, ctx: &AssistContext<'db>, module: hir::Module) -> ast::Type { match self { FunType::Unit => make::ty_unit(), FunType::Single(ty) => make_ty(ty, ctx, module), @@ -1831,7 +1835,11 @@ impl FunType { } } -fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -> ast::BlockExpr { +fn make_body( + ctx: &AssistContext<'_>, + old_indent: IndentLevel, + fun: &Function<'_>, +) -> ast::BlockExpr { let ret_ty = fun.return_type(ctx); let handler = FlowHandler::from_ret_ty(fun, &ret_ty); @@ -2009,19 +2017,19 @@ fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr make::hacky_block_expr(elements, Some(tail_expr)) } -fn format_type(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> String { +fn format_type(ty: &hir::Type<'_>, ctx: &AssistContext<'_>, module: hir::Module) -> String { ty.display_source_code(ctx.db(), module.into(), true).ok().unwrap_or_else(|| "_".to_owned()) } -fn make_ty(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type { +fn make_ty(ty: &hir::Type<'_>, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type { let ty_str = format_type(ty, ctx, module); make::ty(&ty_str) } fn rewrite_body_segment( ctx: &AssistContext<'_>, - params: &[Param], - handler: &FlowHandler, + params: &[Param<'_>], + handler: &FlowHandler<'_>, syntax: &SyntaxNode, ) -> SyntaxNode { let syntax = fix_param_usages(ctx, params, syntax); @@ -2030,8 +2038,12 @@ fn rewrite_body_segment( } /// change all usages to account for added `&`/`&mut` for some params -fn fix_param_usages(ctx: &AssistContext<'_>, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode { - let mut usages_for_param: Vec<(&Param, Vec)> = Vec::new(); +fn fix_param_usages( + ctx: &AssistContext<'_>, + params: &[Param<'_>], + syntax: &SyntaxNode, +) -> SyntaxNode { + let mut usages_for_param: Vec<(&Param<'_>, Vec)> = Vec::new(); let tm = TreeMutator::new(syntax); @@ -2085,7 +2097,7 @@ fn fix_param_usages(ctx: &AssistContext<'_>, params: &[Param], syntax: &SyntaxNo res } -fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) { +fn update_external_control_flow(handler: &FlowHandler<'_>, syntax: &SyntaxNode) { let mut nested_loop = None; let mut nested_scope = None; for event in syntax.preorder() { @@ -2146,7 +2158,10 @@ fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) { } } -fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option) -> Option { +fn make_rewritten_flow( + handler: &FlowHandler<'_>, + arg_expr: Option, +) -> Option { let value = match handler { FlowHandler::None | FlowHandler::Try { .. } => return None, FlowHandler::If { .. } => make::expr_call( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 30084d23d1fb..78ae815dc87a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -307,7 +307,7 @@ impl FunctionBuilder { ctx: &AssistContext<'_>, call: &ast::MethodCallExpr, name: &ast::NameRef, - receiver_ty: Type, + receiver_ty: Type<'_>, target_module: Module, target: GeneratedFunctionTarget, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 6f028e58d0cd..b7b8bc604a51 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -283,11 +283,11 @@ impl CallInfo { } } -fn get_fn_params( - db: &dyn HirDatabase, +fn get_fn_params<'db>( + db: &'db dyn HirDatabase, function: hir::Function, param_list: &ast::ParamList, -) -> Option, hir::Param)>> { +) -> Option, hir::Param<'db>)>> { let mut assoc_fn_params = function.assoc_fn_params(db).into_iter(); let mut params = Vec::new(); @@ -316,7 +316,7 @@ fn inline( function_def_file_id: EditionedFileId, function: hir::Function, fn_body: &ast::BlockExpr, - params: &[(ast::Pat, Option, hir::Param)], + params: &[(ast::Pat, Option, hir::Param<'_>)], CallInfo { node, arguments, generic_arg_list, krate }: &CallInfo, ) -> ast::Expr { let file_id = sema.hir_file_for(fn_body.syntax()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs index e5ed04fdc7c9..b11d3792bc4c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs @@ -58,7 +58,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_> fn validate_type_recursively( ctx: &AssistContext<'_>, - ty_hir: Option<&hir::Type>, + ty_hir: Option<&hir::Type<'_>>, refed: bool, fuel: i32, ) -> Option<()> { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs index 42f35210b496..08170f81b283 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs @@ -105,7 +105,7 @@ fn contains_placeholder(a: &ast::MatchArm) -> bool { } fn are_same_types( - current_arm_types: &FxHashMap>, + current_arm_types: &FxHashMap>>, arm: &ast::MatchArm, ctx: &AssistContext<'_>, ) -> bool { @@ -121,15 +121,15 @@ fn are_same_types( true } -fn get_arm_types( - context: &AssistContext<'_>, +fn get_arm_types<'db>( + context: &AssistContext<'db>, arm: &ast::MatchArm, -) -> FxHashMap> { - let mut mapping: FxHashMap> = FxHashMap::default(); +) -> FxHashMap>> { + let mut mapping: FxHashMap>> = FxHashMap::default(); - fn recurse( - map: &mut FxHashMap>, - ctx: &AssistContext<'_>, + fn recurse<'db>( + map: &mut FxHashMap>>, + ctx: &AssistContext<'db>, pat: &Option, ) { if let Some(local_pat) = pat { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs index 07d2f52a34ee..8834ad97652e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs @@ -217,7 +217,7 @@ fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option { } } -fn group_label(candidate: &ImportCandidate) -> GroupLabel { +fn group_label(candidate: &ImportCandidate<'_>) -> GroupLabel { let name = match candidate { ImportCandidate::Path(it) => &it.name, ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => { @@ -230,7 +230,7 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { fn label( db: &RootDatabase, - candidate: &ImportCandidate, + candidate: &ImportCandidate<'_>, import: &LocatedImport, edition: Edition, ) -> String { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs index 6af8e1482c24..f01b7c0bc24a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs @@ -46,7 +46,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< return None; } - let mut formatter = |_: &hir::Type| String::from("todo!()"); + let mut formatter = |_: &hir::Type<'_>| String::from("todo!()"); let edition = scope.krate().edition(ctx.db()); let paths = paths diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index ef6914fda1d5..1a91053f93ca 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -405,7 +405,7 @@ pub(crate) fn does_pat_variant_nested_or_literal(ctx: &AssistContext<'_>, pat: & } fn check_pat_variant_from_enum(ctx: &AssistContext<'_>, pat: &ast::Pat) -> bool { - ctx.sema.type_of_pat(pat).is_none_or(|ty: hir::TypeInfo| { + ctx.sema.type_of_pat(pat).is_none_or(|ty: hir::TypeInfo<'_>| { ty.adjusted().as_adt().is_some_and(|adt| matches!(adt, hir::Adt::Enum(_))) }) } @@ -780,9 +780,9 @@ pub(crate) fn add_method_to_adt( } #[derive(Debug)] -pub(crate) struct ReferenceConversion { +pub(crate) struct ReferenceConversion<'db> { conversion: ReferenceConversionType, - ty: hir::Type, + ty: hir::Type<'db>, impls_deref: bool, } @@ -802,10 +802,10 @@ enum ReferenceConversionType { Result, } -impl ReferenceConversion { +impl<'db> ReferenceConversion<'db> { pub(crate) fn convert_type( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, display_target: DisplayTarget, ) -> ast::Type { let ty = match self.conversion { @@ -878,11 +878,11 @@ impl ReferenceConversion { // FIXME: It should return a new hir::Type, but currently constructing new types is too cumbersome // and all users of this function operate on string type names, so they can do the conversion // itself themselves. -pub(crate) fn convert_reference_type( - ty: hir::Type, - db: &RootDatabase, - famous_defs: &FamousDefs<'_, '_>, -) -> Option { +pub(crate) fn convert_reference_type<'db>( + ty: hir::Type<'db>, + db: &'db RootDatabase, + famous_defs: &FamousDefs<'_, 'db>, +) -> Option> { handle_copy(&ty, db) .or_else(|| handle_as_ref_str(&ty, db, famous_defs)) .or_else(|| handle_as_ref_slice(&ty, db, famous_defs)) @@ -892,18 +892,21 @@ pub(crate) fn convert_reference_type( .map(|(conversion, impls_deref)| ReferenceConversion { ty, conversion, impls_deref }) } -fn could_deref_to_target(ty: &hir::Type, target: &hir::Type, db: &dyn HirDatabase) -> bool { +fn could_deref_to_target(ty: &hir::Type<'_>, target: &hir::Type<'_>, db: &dyn HirDatabase) -> bool { let ty_ref = ty.add_reference(hir::Mutability::Shared); let target_ref = target.add_reference(hir::Mutability::Shared); ty_ref.could_coerce_to(db, &target_ref) } -fn handle_copy(ty: &hir::Type, db: &dyn HirDatabase) -> Option<(ReferenceConversionType, bool)> { +fn handle_copy( + ty: &hir::Type<'_>, + db: &dyn HirDatabase, +) -> Option<(ReferenceConversionType, bool)> { ty.is_copy(db).then_some((ReferenceConversionType::Copy, true)) } fn handle_as_ref_str( - ty: &hir::Type, + ty: &hir::Type<'_>, db: &dyn HirDatabase, famous_defs: &FamousDefs<'_, '_>, ) -> Option<(ReferenceConversionType, bool)> { @@ -914,7 +917,7 @@ fn handle_as_ref_str( } fn handle_as_ref_slice( - ty: &hir::Type, + ty: &hir::Type<'_>, db: &dyn HirDatabase, famous_defs: &FamousDefs<'_, '_>, ) -> Option<(ReferenceConversionType, bool)> { @@ -928,7 +931,7 @@ fn handle_as_ref_slice( } fn handle_dereferenced( - ty: &hir::Type, + ty: &hir::Type<'_>, db: &dyn HirDatabase, famous_defs: &FamousDefs<'_, '_>, ) -> Option<(ReferenceConversionType, bool)> { @@ -941,7 +944,7 @@ fn handle_dereferenced( } fn handle_option_as_ref( - ty: &hir::Type, + ty: &hir::Type<'_>, db: &dyn HirDatabase, famous_defs: &FamousDefs<'_, '_>, ) -> Option<(ReferenceConversionType, bool)> { @@ -953,7 +956,7 @@ fn handle_option_as_ref( } fn handle_result_as_ref( - ty: &hir::Type, + ty: &hir::Type<'_>, db: &dyn HirDatabase, famous_defs: &FamousDefs<'_, '_>, ) -> Option<(ReferenceConversionType, bool)> { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs index 4ea56dc46aaa..c58bdd9e8ede 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -17,7 +17,7 @@ pub(crate) fn gen_trait_fn_body( func: &ast::Fn, trait_path: &ast::Path, adt: &ast::Adt, - trait_ref: Option, + trait_ref: Option>, ) -> Option<()> { match trait_path.segment()?.name_ref()?.text().as_str() { "Clone" => gen_clone_impl(adt, func), @@ -405,7 +405,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { } /// Generate a `PartialEq` impl based on the fields and members of the target type. -fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) -> Option<()> { +fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option>) -> Option<()> { stdx::always!(func.name().is_some_and(|name| name.text() == "eq")); fn gen_eq_chain(expr: Option, cmp: ast::Expr) -> Option { match expr { @@ -599,7 +599,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) - Some(()) } -fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) -> Option<()> { +fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option>) -> Option<()> { stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp")); fn gen_partial_eq_match(match_target: ast::Expr) -> Option { let mut arms = vec![]; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 5d68aca9e615..65072d936f63 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -161,7 +161,11 @@ impl Completions { item.add_to(self, ctx.db); } - pub(crate) fn add_expr(&mut self, ctx: &CompletionContext<'_>, expr: &hir::term_search::Expr) { + pub(crate) fn add_expr( + &mut self, + ctx: &CompletionContext<'_>, + expr: &hir::term_search::Expr<'_>, + ) { if let Some(item) = render_expr(ctx, expr) { item.add_to(self, ctx.db) } @@ -170,7 +174,7 @@ impl Completions { pub(crate) fn add_crate_roots( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, ) { ctx.process_all_names(&mut |name, res, doc_aliases| match res { ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root() => { @@ -183,7 +187,7 @@ impl Completions { pub(crate) fn add_path_resolution( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, resolution: hir::ScopeDef, doc_aliases: Vec, @@ -232,7 +236,7 @@ impl Completions { pub(crate) fn add_enum_variants( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, e: hir::Enum, ) { if !ctx.check_stability_and_hidden(e) { @@ -246,7 +250,7 @@ impl Completions { pub(crate) fn add_module( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, module: hir::Module, local_name: hir::Name, doc_aliases: Vec, @@ -263,7 +267,7 @@ impl Completions { pub(crate) fn add_macro( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, mac: hir::Macro, local_name: hir::Name, ) { @@ -286,7 +290,7 @@ impl Completions { pub(crate) fn add_function( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, func: hir::Function, local_name: Option, ) { @@ -312,7 +316,7 @@ impl Completions { pub(crate) fn add_method( &mut self, ctx: &CompletionContext<'_>, - dot_access: &DotAccess, + dot_access: &DotAccess<'_>, func: hir::Function, receiver: Option, local_name: Option, @@ -340,7 +344,7 @@ impl Completions { pub(crate) fn add_method_with_import( &mut self, ctx: &CompletionContext<'_>, - dot_access: &DotAccess, + dot_access: &DotAccess<'_>, func: hir::Function, import: LocatedImport, ) { @@ -407,7 +411,7 @@ impl Completions { pub(crate) fn add_qualified_enum_variant( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, variant: hir::Variant, path: hir::ModPath, ) { @@ -424,7 +428,7 @@ impl Completions { pub(crate) fn add_enum_variant( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, variant: hir::Variant, local_name: Option, ) { @@ -447,10 +451,10 @@ impl Completions { pub(crate) fn add_field( &mut self, ctx: &CompletionContext<'_>, - dot_access: &DotAccess, + dot_access: &DotAccess<'_>, receiver: Option, field: hir::Field, - ty: &hir::Type, + ty: &hir::Type<'_>, ) { let is_private_editable = match ctx.is_visible(&field) { Visible::Yes => false, @@ -471,7 +475,7 @@ impl Completions { pub(crate) fn add_struct_literal( &mut self, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, strukt: hir::Struct, path: Option, local_name: Option, @@ -518,7 +522,7 @@ impl Completions { ctx: &CompletionContext<'_>, receiver: Option, field: usize, - ty: &hir::Type, + ty: &hir::Type<'_>, ) { // Only used for (unnamed) tuples, whose all fields *are* stable. No need to check // stability here. @@ -550,7 +554,7 @@ impl Completions { &mut self, ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, - path_ctx: Option<&PathCompletionCtx>, + path_ctx: Option<&PathCompletionCtx<'_>>, variant: hir::Variant, local_name: Option, ) { @@ -704,7 +708,7 @@ pub(super) fn complete_name( pub(super) fn complete_name_ref( acc: &mut Completions, ctx: &CompletionContext<'_>, - NameRefContext { nameref, kind }: &NameRefContext, + NameRefContext { nameref, kind }: &NameRefContext<'_>, ) { match kind { NameRefKind::Path(path_ctx) => { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index 705402c785a2..c542e140df54 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -86,7 +86,7 @@ pub(crate) fn complete_known_attribute_input( pub(crate) fn complete_attribute_path( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, + path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, &AttrCtx { kind, annotated_item_kind, ref derive_helpers }: &AttrCtx, ) { let is_inner = kind == AttrKind::Inner; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs index 2fc07e013828..267d92b6c090 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs @@ -13,7 +13,7 @@ use crate::{ pub(crate) fn complete_derive_path( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, + path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, existing_derives: &ExistingDerives, ) { let core = ctx.famous_defs().core(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index 4f21136d214e..5340d65a142d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -18,7 +18,7 @@ use crate::{ pub(crate) fn complete_dot( acc: &mut Completions, ctx: &CompletionContext<'_>, - dot_access: &DotAccess, + dot_access: &DotAccess<'_>, ) { let receiver_ty = match dot_access { DotAccess { receiver_ty: Some(receiver_ty), .. } => &receiver_ty.original, @@ -130,8 +130,8 @@ pub(crate) fn complete_dot( pub(crate) fn complete_undotted_self( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - expr_ctx: &PathExprCtx, + path_ctx: &PathCompletionCtx<'_>, + expr_ctx: &PathExprCtx<'_>, ) { if !ctx.config.enable_self_on_the_fly { return; @@ -198,9 +198,9 @@ pub(crate) fn complete_undotted_self( fn complete_fields( acc: &mut Completions, ctx: &CompletionContext<'_>, - receiver: &hir::Type, - mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type), - mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type), + receiver: &hir::Type<'_>, + mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type<'_>), + mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type<'_>), is_field_access: bool, is_method_access_with_parens: bool, ) { @@ -230,7 +230,7 @@ fn complete_fields( fn complete_methods( ctx: &CompletionContext<'_>, - receiver: &hir::Type, + receiver: &hir::Type<'_>, traits_in_scope: &FxHashSet, f: impl FnMut(hir::Function), ) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 7fbd1fbc1af4..062bc6106e49 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -47,8 +47,8 @@ where pub(crate) fn complete_expr_path( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - expr_ctx: &PathExprCtx, + path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, + expr_ctx: &PathExprCtx<'_>, ) { let _p = tracing::info_span!("complete_expr_path").entered(); if !ctx.qualifier_ctx.none() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs index 1441b0e3a01a..26afa9c8ad96 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/field.rs @@ -8,7 +8,7 @@ use crate::{ pub(crate) fn complete_field_list_tuple_variant( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, ) { if ctx.qualifier_ctx.vis_node.is_some() { } else if let PathCompletionCtx { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs index a74756138090..dad8a76de87d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs @@ -111,7 +111,7 @@ use crate::{ pub(crate) fn import_on_the_fly_path( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, ) -> Option<()> { if !ctx.config.enable_imports_on_the_fly { return None; @@ -175,7 +175,7 @@ pub(crate) fn import_on_the_fly_pat( pub(crate) fn import_on_the_fly_dot( acc: &mut Completions, ctx: &CompletionContext<'_>, - dot_access: &DotAccess, + dot_access: &DotAccess<'_>, ) -> Option<()> { if !ctx.config.enable_imports_on_the_fly { return None; @@ -203,8 +203,8 @@ pub(crate) fn import_on_the_fly_dot( fn import_on_the_fly( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx, - import_assets: ImportAssets, + path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx<'_>, + import_assets: ImportAssets<'_>, position: SyntaxNode, potential_import_name: String, ) -> Option<()> { @@ -290,7 +290,7 @@ fn import_on_the_fly_pat_( acc: &mut Completions, ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, - import_assets: ImportAssets, + import_assets: ImportAssets<'_>, position: SyntaxNode, potential_import_name: String, ) -> Option<()> { @@ -335,8 +335,8 @@ fn import_on_the_fly_pat_( fn import_on_the_fly_method( acc: &mut Completions, ctx: &CompletionContext<'_>, - dot_access: &DotAccess, - import_assets: ImportAssets, + dot_access: &DotAccess<'_>, + import_assets: ImportAssets<'_>, position: SyntaxNode, potential_import_name: String, ) -> Option<()> { @@ -400,11 +400,11 @@ fn import_name(ctx: &CompletionContext<'_>) -> String { if token_kind.is_any_identifier() { ctx.token.to_string() } else { String::new() } } -fn import_assets_for_path( - ctx: &CompletionContext<'_>, +fn import_assets_for_path<'db>( + ctx: &CompletionContext<'db>, potential_import_name: &str, qualifier: Option, -) -> Option { +) -> Option> { let _p = tracing::info_span!("import_assets_for_path", ?potential_import_name, ?qualifier).entered(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs index 893997cee473..6c001bd16bfe 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs @@ -10,8 +10,8 @@ pub(crate) mod trait_impl; pub(crate) fn complete_item_list_in_expr( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - expr_ctx: &PathExprCtx, + path_ctx: &PathCompletionCtx<'_>, + expr_ctx: &PathExprCtx<'_>, ) { if !expr_ctx.in_block_expr { return; @@ -25,7 +25,7 @@ pub(crate) fn complete_item_list_in_expr( pub(crate) fn complete_item_list( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, + path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, kind: &ItemListKind, ) { let _p = tracing::info_span!("complete_item_list").entered(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index 58aead73fd6f..092219a058a1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -122,7 +122,7 @@ fn complete_trait_impl_name( pub(crate) fn complete_trait_impl_item_by_name( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, name_ref: &Option, impl_: &Option, ) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs index ea3511d31caf..62fae1cb2374 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs @@ -124,7 +124,7 @@ pub(crate) fn complete_pattern( pub(crate) fn complete_pattern_path( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, + path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, ) { match qualified { Qualified::With { resolution: Some(resolution), super_chain_len, .. } => { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 3cdf2112835d..b79a97025b94 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -28,7 +28,7 @@ use crate::{ pub(crate) fn complete_postfix( acc: &mut Completions, ctx: &CompletionContext<'_>, - dot_access: &DotAccess, + dot_access: &DotAccess<'_>, ) { if !ctx.config.enable_postfix_completions { return; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs index c18aab007b2c..36f38a70db63 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs @@ -88,7 +88,7 @@ pub(crate) fn complete_record_expr_fields( pub(crate) fn add_default_update( acc: &mut Completions, ctx: &CompletionContext<'_>, - ty: Option, + ty: Option>, ) { let default_trait = ctx.famous_defs().core_default_Default(); let impls_default_trait = default_trait @@ -117,7 +117,7 @@ pub(crate) fn add_default_update( fn complete_fields( acc: &mut Completions, ctx: &CompletionContext<'_>, - missing_fields: Vec<(hir::Field, hir::Type)>, + missing_fields: Vec<(hir::Field, hir::Type<'_>)>, ) { for (field, ty) in missing_fields { // This should call something else, we shouldn't be synthesizing a DotAccess here diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs index 31aae1167622..ead9852eff53 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs @@ -11,8 +11,8 @@ use crate::{ pub(crate) fn complete_expr_snippet( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - &PathExprCtx { in_block_expr, .. }: &PathExprCtx, + path_ctx: &PathCompletionCtx<'_>, + &PathExprCtx { in_block_expr, .. }: &PathExprCtx<'_>, ) { if !matches!(path_ctx.qualified, Qualified::No) { return; @@ -51,7 +51,7 @@ macro_rules! $1 { pub(crate) fn complete_item_snippet( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, kind: &ItemListKind, ) { if !matches!(path_ctx.qualified, Qualified::No) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs index 79db705af495..7c38c7d8ce44 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs @@ -12,7 +12,7 @@ use crate::{ pub(crate) fn complete_type_path( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, + path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, location: &TypeLocation, ) { let _p = tracing::info_span!("complete_type_path").entered(); @@ -220,7 +220,7 @@ pub(crate) fn complete_type_path( pub(crate) fn complete_ascribed_type( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, ascription: &TypeAscriptionTarget, ) -> Option<()> { if !path_ctx.is_trivial_path() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs index 4d6d0b758a38..d2ab193ec3df 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs @@ -13,7 +13,7 @@ use crate::{ pub(crate) fn complete_use_path( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx, + path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx<'_>, name_ref: &Option, ) { match qualified { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs index d15c35ac8499..38761f77a2c5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs @@ -8,7 +8,7 @@ use crate::{ pub(crate) fn complete_vis_path( acc: &mut Completions, ctx: &CompletionContext<'_>, - path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, + path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, &has_in_token: &bool, ) { match qualified { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 5287627790ae..cfd7f80d40b3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -65,13 +65,13 @@ impl QualifierCtx { /// The state of the path we are currently completing. #[derive(Debug)] -pub(crate) struct PathCompletionCtx { +pub(crate) struct PathCompletionCtx<'db> { /// If this is a call with () already there (or {} in case of record patterns) pub(crate) has_call_parens: bool, /// If this has a macro call bang ! pub(crate) has_macro_bang: bool, /// The qualifier of the current path. - pub(crate) qualified: Qualified, + pub(crate) qualified: Qualified<'db>, /// The parent of the path we are completing. pub(crate) parent: Option, #[allow(dead_code)] @@ -79,14 +79,14 @@ pub(crate) struct PathCompletionCtx { pub(crate) path: ast::Path, /// The path of which we are completing the segment in the original file pub(crate) original_path: Option, - pub(crate) kind: PathKind, + pub(crate) kind: PathKind<'db>, /// Whether the path segment has type args or not. pub(crate) has_type_args: bool, /// Whether the qualifier comes from a use tree parent or not pub(crate) use_tree_parent: bool, } -impl PathCompletionCtx { +impl PathCompletionCtx<'_> { pub(crate) fn is_trivial_path(&self) -> bool { matches!( self, @@ -104,9 +104,9 @@ impl PathCompletionCtx { /// The kind of path we are completing right now. #[derive(Debug, PartialEq, Eq)] -pub(crate) enum PathKind { +pub(crate) enum PathKind<'db> { Expr { - expr_ctx: PathExprCtx, + expr_ctx: PathExprCtx<'db>, }, Type { location: TypeLocation, @@ -140,7 +140,7 @@ pub(crate) struct AttrCtx { } #[derive(Debug, PartialEq, Eq)] -pub(crate) struct PathExprCtx { +pub(crate) struct PathExprCtx<'db> { pub(crate) in_block_expr: bool, pub(crate) in_breakable: BreakableKind, pub(crate) after_if_expr: bool, @@ -152,7 +152,7 @@ pub(crate) struct PathExprCtx { /// The surrounding RecordExpression we are completing a functional update pub(crate) is_func_update: Option, pub(crate) self_param: Option, - pub(crate) innermost_ret_ty: Option, + pub(crate) innermost_ret_ty: Option>, pub(crate) impl_: Option, /// Whether this expression occurs in match arm guard position: before the /// fat arrow token @@ -241,7 +241,7 @@ pub(crate) enum ItemListKind { } #[derive(Debug)] -pub(crate) enum Qualified { +pub(crate) enum Qualified<'db> { No, With { path: ast::Path, @@ -260,7 +260,7 @@ pub(crate) enum Qualified { }, /// <_>:: TypeAnchor { - ty: Option, + ty: Option>, trait_: Option, }, /// Whether the path is an absolute path @@ -341,17 +341,17 @@ pub(crate) enum NameKind { /// The state of the NameRef we are completing. #[derive(Debug)] -pub(crate) struct NameRefContext { +pub(crate) struct NameRefContext<'db> { /// NameRef syntax in the original file pub(crate) nameref: Option, - pub(crate) kind: NameRefKind, + pub(crate) kind: NameRefKind<'db>, } /// The kind of the NameRef we are completing. #[derive(Debug)] -pub(crate) enum NameRefKind { - Path(PathCompletionCtx), - DotAccess(DotAccess), +pub(crate) enum NameRefKind<'db> { + Path(PathCompletionCtx<'db>), + DotAccess(DotAccess<'db>), /// Position where we are only interested in keyword completions Keyword(ast::Item), /// The record expression this nameref is a field of and whether a dot precedes the completion identifier. @@ -365,9 +365,9 @@ pub(crate) enum NameRefKind { /// The identifier we are currently completing. #[derive(Debug)] -pub(crate) enum CompletionAnalysis { +pub(crate) enum CompletionAnalysis<'db> { Name(NameContext), - NameRef(NameRefContext), + NameRef(NameRefContext<'db>), Lifetime(LifetimeContext), /// The string the cursor is currently inside String { @@ -386,9 +386,9 @@ pub(crate) enum CompletionAnalysis { /// Information about the field or method access we are completing. #[derive(Debug)] -pub(crate) struct DotAccess { +pub(crate) struct DotAccess<'db> { pub(crate) receiver: Option, - pub(crate) receiver_ty: Option, + pub(crate) receiver_ty: Option>, pub(crate) kind: DotAccessKind, pub(crate) ctx: DotAccessExprCtx, } @@ -457,7 +457,7 @@ pub(crate) struct CompletionContext<'a> { /// This is usually the parameter name of the function argument we are completing. pub(crate) expected_name: Option, /// The expected type of what we are completing. - pub(crate) expected_type: Option, + pub(crate) expected_type: Option>, pub(crate) qualifier_ctx: QualifierCtx, @@ -608,7 +608,7 @@ impl CompletionContext<'_> { pub(crate) fn iterate_path_candidates( &self, - ty: &hir::Type, + ty: &hir::Type<'_>, mut cb: impl FnMut(hir::AssocItem), ) { let mut seen = FxHashSet::default(); @@ -695,12 +695,12 @@ impl CompletionContext<'_> { } // CompletionContext construction -impl<'a> CompletionContext<'a> { +impl<'db> CompletionContext<'db> { pub(crate) fn new( - db: &'a RootDatabase, + db: &'db RootDatabase, position @ FilePosition { file_id, offset }: FilePosition, - config: &'a CompletionConfig<'a>, - ) -> Option<(CompletionContext<'a>, CompletionAnalysis)> { + config: &'db CompletionConfig<'db>, + ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> { let _p = tracing::info_span!("CompletionContext::new").entered(); let sema = Semantics::new(db); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 7a2230b3e361..6e3a76f346a8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -38,9 +38,9 @@ struct ExpansionResult { derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>, } -pub(super) struct AnalysisResult { - pub(super) analysis: CompletionAnalysis, - pub(super) expected: (Option, Option), +pub(super) struct AnalysisResult<'db> { + pub(super) analysis: CompletionAnalysis<'db>, + pub(super) expected: (Option>, Option), pub(super) qualifier_ctx: QualifierCtx, /// the original token of the expanded file pub(super) token: SyntaxToken, @@ -48,13 +48,13 @@ pub(super) struct AnalysisResult { pub(super) original_offset: TextSize, } -pub(super) fn expand_and_analyze( - sema: &Semantics<'_, RootDatabase>, +pub(super) fn expand_and_analyze<'db>( + sema: &Semantics<'db, RootDatabase>, original_file: InFile, speculative_file: SyntaxNode, offset: TextSize, original_token: &SyntaxToken, -) -> Option { +) -> Option> { // as we insert after the offset, right biased will *always* pick the identifier no matter // if there is an ident already typed or not let fake_ident_token = speculative_file.token_at_offset(offset).right_biased()?; @@ -432,12 +432,13 @@ fn expand( /// Fill the completion context, this is what does semantic reasoning about the surrounding context /// of the completion location. -fn analyze( - sema: &Semantics<'_, RootDatabase>, +fn analyze<'db>( + sema: &Semantics<'db, RootDatabase>, expansion_result: ExpansionResult, original_token: &SyntaxToken, self_token: &SyntaxToken, -) -> Option<(CompletionAnalysis, (Option, Option), QualifierCtx)> { +) -> Option<(CompletionAnalysis<'db>, (Option>, Option), QualifierCtx)> +{ let _p = tracing::info_span!("CompletionContext::analyze").entered(); let ExpansionResult { original_file, @@ -555,17 +556,17 @@ fn analyze( } /// Calculate the expected type and name of the cursor position. -fn expected_type_and_name( - sema: &Semantics<'_, RootDatabase>, +fn expected_type_and_name<'db>( + sema: &Semantics<'db, RootDatabase>, token: &SyntaxToken, name_like: &ast::NameLike, -) -> (Option, Option) { +) -> (Option>, Option) { let mut node = match token.parent() { Some(it) => it, None => return (None, None), }; - let strip_refs = |mut ty: Type| match name_like { + let strip_refs = |mut ty: Type<'db>| match name_like { ast::NameLike::NameRef(n) => { let p = match n.syntax().parent() { Some(it) => it, @@ -805,13 +806,13 @@ fn classify_name( Some(NameContext { name, kind }) } -fn classify_name_ref( - sema: &Semantics<'_, RootDatabase>, +fn classify_name_ref<'db>( + sema: &Semantics<'db, RootDatabase>, original_file: &SyntaxNode, name_ref: ast::NameRef, original_offset: TextSize, parent: SyntaxNode, -) -> Option<(NameRefContext, QualifierCtx)> { +) -> Option<(NameRefContext<'db>, QualifierCtx)> { let nameref = find_node_at_offset(original_file, original_offset); let make_res = |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default()); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index 19cdef30bd96..dcaac3997b27 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -502,7 +502,7 @@ pub(crate) struct Builder { impl Builder { pub(crate) fn from_resolution( ctx: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, resolution: hir::ScopeDef, ) -> Self { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 00c0b470f987..d6e30fe0c6ee 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -122,10 +122,10 @@ impl<'a> RenderContext<'a> { pub(crate) fn render_field( ctx: RenderContext<'_>, - dot_access: &DotAccess, + dot_access: &DotAccess<'_>, receiver: Option, field: hir::Field, - ty: &hir::Type, + ty: &hir::Type<'_>, ) -> CompletionItem { let db = ctx.db(); let is_deprecated = ctx.is_deprecated(field); @@ -204,7 +204,7 @@ pub(crate) fn render_tuple_field( ctx: RenderContext<'_>, receiver: Option, field: usize, - ty: &hir::Type, + ty: &hir::Type<'_>, ) -> CompletionItem { let mut item = CompletionItem::new( SymbolKind::Field, @@ -241,7 +241,7 @@ pub(crate) fn render_type_inference( pub(crate) fn render_path_resolution( ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, resolution: ScopeDef, ) -> Builder { @@ -259,7 +259,7 @@ pub(crate) fn render_pattern_resolution( pub(crate) fn render_resolution_with_import( ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, import_edit: LocatedImport, ) -> Option { let resolution = ScopeDef::from(import_edit.original_item); @@ -282,10 +282,10 @@ pub(crate) fn render_resolution_with_import_pat( pub(crate) fn render_expr( ctx: &CompletionContext<'_>, - expr: &hir::term_search::Expr, + expr: &hir::term_search::Expr<'_>, ) -> Option { let mut i = 1; - let mut snippet_formatter = |ty: &hir::Type| { + let mut snippet_formatter = |ty: &hir::Type<'_>| { let arg_name = ty .as_adt() .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str())) @@ -295,7 +295,7 @@ pub(crate) fn render_expr( res }; - let mut label_formatter = |ty: &hir::Type| { + let mut label_formatter = |ty: &hir::Type<'_>| { ty.as_adt() .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str())) .unwrap_or_else(|| String::from("...")) @@ -391,7 +391,7 @@ fn render_resolution_pat( fn render_resolution_path( ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, import_to_add: Option, resolution: ScopeDef, @@ -460,7 +460,7 @@ fn render_resolution_path( } } - let mut set_item_relevance = |ty: Type| { + let mut set_item_relevance = |ty: Type<'_>| { if !ty.is_unknown() { item.detail(ty.display(db, krate).to_string()); } @@ -593,8 +593,8 @@ fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: ScopeDef) -> boo // FIXME: This checks types without possible coercions which some completions might want to do fn match_types( ctx: &CompletionContext<'_>, - ty1: &hir::Type, - ty2: &hir::Type, + ty1: &hir::Type<'_>, + ty2: &hir::Type<'_>, ) -> Option { if ty1 == ty2 { Some(CompletionRelevanceTypeMatch::Exact) @@ -607,7 +607,7 @@ fn match_types( fn compute_type_match( ctx: &CompletionContext<'_>, - completion_ty: &hir::Type, + completion_ty: &hir::Type<'_>, ) -> Option { let expected_type = ctx.expected_type.as_ref()?; @@ -626,7 +626,7 @@ fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str) fn compute_ref_match( ctx: &CompletionContext<'_>, - completion_ty: &hir::Type, + completion_ty: &hir::Type<'_>, ) -> Option { let expected_type = ctx.expected_type.as_ref()?; let expected_without_ref = expected_type.remove_ref(); @@ -658,8 +658,8 @@ fn compute_ref_match( fn path_ref_match( completion: &CompletionContext<'_>, - path_ctx: &PathCompletionCtx, - ty: &hir::Type, + path_ctx: &PathCompletionCtx<'_>, + ty: &hir::Type<'_>, item: &mut Builder, ) { if let Some(original_path) = &path_ctx.original_path { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 2fe517fa8cd0..7669aec8f535 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -22,13 +22,13 @@ use crate::{ #[derive(Debug)] enum FuncKind<'ctx> { - Function(&'ctx PathCompletionCtx), - Method(&'ctx DotAccess, Option), + Function(&'ctx PathCompletionCtx<'ctx>), + Method(&'ctx DotAccess<'ctx>, Option), } pub(crate) fn render_fn( ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, local_name: Option, func: hir::Function, ) -> Builder { @@ -38,7 +38,7 @@ pub(crate) fn render_fn( pub(crate) fn render_method( ctx: RenderContext<'_>, - dot_access: &DotAccess, + dot_access: &DotAccess<'_>, receiver: Option, local_name: Option, func: hir::Function, @@ -186,8 +186,8 @@ fn render( fn compute_return_type_match( db: &dyn HirDatabase, ctx: &RenderContext<'_>, - self_type: hir::Type, - ret_type: &hir::Type, + self_type: hir::Type<'_>, + ret_type: &hir::Type<'_>, ) -> CompletionRelevanceReturnType { if match_types(ctx.completion, &self_type, ret_type).is_some() { // fn([..]) -> Self @@ -217,8 +217,8 @@ pub(super) fn add_call_parens<'b>( name: SmolStr, escaped_name: SmolStr, self_param: Option, - params: Vec, - ret_type: &hir::Type, + params: Vec>, + ret_type: &hir::Type<'_>, ) -> &'b mut Builder { cov_mark::hit!(inserts_parens_for_function_calls); @@ -288,7 +288,7 @@ pub(super) fn add_call_parens<'b>( builder.label(SmolStr::from_iter([&name, label_suffix])).insert_snippet(cap, snippet) } -fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str { +fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type<'_>) -> &'static str { if let Some(derefed_ty) = ty.remove_ref() { for (name, local) in ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()) { if name.as_str() == arg { @@ -369,12 +369,12 @@ fn params_display(ctx: &CompletionContext<'_>, detail: &mut String, func: hir::F } } -fn params( - ctx: &CompletionContext<'_>, +fn params<'db>( + ctx: &CompletionContext<'db>, func: hir::Function, func_kind: &FuncKind<'_>, has_dot_receiver: bool, -) -> Option<(Option, Vec)> { +) -> Option<(Option, Vec>)> { ctx.config.callable.as_ref()?; // Don't add parentheses if the expected type is a function reference with the same signature. diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs index 5a9e35a7290b..6c89e49f94e8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs @@ -21,7 +21,7 @@ use crate::{ pub(crate) fn render_variant_lit( ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, local_name: Option, variant: hir::Variant, path: Option, @@ -35,7 +35,7 @@ pub(crate) fn render_variant_lit( pub(crate) fn render_struct_literal( ctx: RenderContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, strukt: hir::Struct, path: Option, local_name: Option, @@ -49,7 +49,7 @@ pub(crate) fn render_struct_literal( fn render( ctx @ RenderContext { completion, .. }: RenderContext<'_>, - path_ctx: &PathCompletionCtx, + path_ctx: &PathCompletionCtx<'_>, thing: Variant, name: hir::Name, path: Option, @@ -194,7 +194,7 @@ impl Variant { } } - fn ty(self, db: &dyn HirDatabase) -> hir::Type { + fn ty(self, db: &dyn HirDatabase) -> hir::Type<'_> { match self { Variant::Struct(it) => it.ty(db), Variant::EnumVariant(it) => it.parent_enum(db).ty(db), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs index 4674dae03144..35fe407b2e68 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs @@ -12,7 +12,7 @@ use crate::{ pub(crate) fn render_macro( ctx: RenderContext<'_>, - PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx, + PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx<'_>, name: hir::Name, macro_: hir::Macro, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs index dcc51a86a8ed..60ec1128233e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs @@ -46,7 +46,7 @@ pub(crate) fn render_struct_pat( pub(crate) fn render_variant_pat( ctx: RenderContext<'_>, pattern_ctx: &PatternContext, - path_ctx: Option<&PathCompletionCtx>, + path_ctx: Option<&PathCompletionCtx<'_>>, variant: hir::Variant, local_name: Option, path: Option<&hir::ModPath>, @@ -109,7 +109,7 @@ fn build_completion( lookup: SmolStr, pat: String, def: impl HasDocs + Copy, - adt_ty: hir::Type, + adt_ty: hir::Type<'_>, // Missing in context of match statement completions is_variant_missing: bool, ) -> CompletionItem { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs index 7b5723f37f76..9edfc113f764 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs @@ -13,21 +13,21 @@ use syntax::{ use crate::RootDatabase; #[derive(Debug)] -pub struct ActiveParameter { - pub ty: Type, +pub struct ActiveParameter<'db> { + pub ty: Type<'db>, pub src: Option>>, } -impl ActiveParameter { +impl<'db> ActiveParameter<'db> { /// Returns information about the call argument this token is part of. - pub fn at_token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { + pub fn at_token(sema: &Semantics<'db, RootDatabase>, token: SyntaxToken) -> Option { let (signature, active_parameter) = callable_for_token(sema, token)?; Self::from_signature_and_active_parameter(sema, signature, active_parameter) } /// Returns information about the call argument this token is part of. pub fn at_arg( - sema: &Semantics<'_, RootDatabase>, + sema: &'db Semantics<'db, RootDatabase>, list: ast::ArgList, at: TextSize, ) -> Option { @@ -36,8 +36,8 @@ impl ActiveParameter { } fn from_signature_and_active_parameter( - sema: &Semantics<'_, RootDatabase>, - signature: hir::Callable, + sema: &Semantics<'db, RootDatabase>, + signature: hir::Callable<'db>, active_parameter: Option, ) -> Option { let idx = active_parameter?; @@ -63,10 +63,10 @@ impl ActiveParameter { } /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable. -pub fn callable_for_token( - sema: &Semantics<'_, RootDatabase>, +pub fn callable_for_token<'db>( + sema: &Semantics<'db, RootDatabase>, token: SyntaxToken, -) -> Option<(hir::Callable, Option)> { +) -> Option<(hir::Callable<'db>, Option)> { let offset = token.text_range().start(); // Find the calling expression and its NameRef let parent = token.parent()?; @@ -79,21 +79,21 @@ pub fn callable_for_token( } /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable. -pub fn callable_for_arg_list( - sema: &Semantics<'_, RootDatabase>, +pub fn callable_for_arg_list<'db>( + sema: &Semantics<'db, RootDatabase>, arg_list: ast::ArgList, at: TextSize, -) -> Option<(hir::Callable, Option)> { +) -> Option<(hir::Callable<'db>, Option)> { debug_assert!(arg_list.syntax().text_range().contains(at)); let callable = arg_list.syntax().parent().and_then(ast::CallableExpr::cast)?; callable_for_node(sema, &callable, at) } -pub fn callable_for_node( - sema: &Semantics<'_, RootDatabase>, +pub fn callable_for_node<'db>( + sema: &Semantics<'db, RootDatabase>, calling_node: &ast::CallableExpr, offset: TextSize, -) -> Option<(hir::Callable, Option)> { +) -> Option<(hir::Callable<'db>, Option)> { let callable = match calling_node { ast::CallableExpr::Call(call) => sema.resolve_expr_as_callable(&call.expr()?), ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index d5db1c481b69..a4a140ec57aa 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -385,17 +385,17 @@ fn find_std_module( // FIXME: IdentClass as a name no longer fits #[derive(Debug)] -pub enum IdentClass { - NameClass(NameClass), - NameRefClass(NameRefClass), +pub enum IdentClass<'db> { + NameClass(NameClass<'db>), + NameRefClass(NameRefClass<'db>), Operator(OperatorClass), } -impl IdentClass { +impl<'db> IdentClass<'db> { pub fn classify_node( - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, node: &SyntaxNode, - ) -> Option { + ) -> Option> { match_ast! { match node { ast::Name(name) => NameClass::classify(sema, &name).map(IdentClass::NameClass), @@ -418,23 +418,23 @@ impl IdentClass { } pub fn classify_token( - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, token: &SyntaxToken, - ) -> Option { + ) -> Option> { let parent = token.parent()?; Self::classify_node(sema, &parent) } pub fn classify_lifetime( - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, lifetime: &ast::Lifetime, - ) -> Option { + ) -> Option> { NameRefClass::classify_lifetime(sema, lifetime) .map(IdentClass::NameRefClass) .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass)) } - pub fn definitions(self) -> ArrayVec<(Definition, Option), 2> { + pub fn definitions(self) -> ArrayVec<(Definition, Option>), 2> { let mut res = ArrayVec::new(); match self { IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { @@ -518,7 +518,7 @@ impl IdentClass { /// /// A model special case is `None` constant in pattern. #[derive(Debug)] -pub enum NameClass { +pub enum NameClass<'db> { Definition(Definition), /// `None` in `if let None = Some(82) {}`. /// Syntactically, it is a name, but semantically it is a reference. @@ -528,11 +528,11 @@ pub enum NameClass { PatFieldShorthand { local_def: Local, field_ref: Field, - adt_subst: GenericSubstitution, + adt_subst: GenericSubstitution<'db>, }, } -impl NameClass { +impl<'db> NameClass<'db> { /// `Definition` defined by this name. pub fn defined(self) -> Option { let res = match self { @@ -545,7 +545,10 @@ impl NameClass { Some(res) } - pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option { + pub fn classify( + sema: &Semantics<'db, RootDatabase>, + name: &ast::Name, + ) -> Option> { let _p = tracing::info_span!("NameClass::classify").entered(); let parent = name.syntax().parent()?; @@ -597,10 +600,10 @@ impl NameClass { Some(definition) } - fn classify_ident_pat( - sema: &Semantics<'_, RootDatabase>, + fn classify_ident_pat<'db>( + sema: &Semantics<'db, RootDatabase>, ident_pat: ast::IdentPat, - ) -> Option { + ) -> Option> { if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) { return Some(NameClass::ConstReference(Definition::from(def))); } @@ -638,9 +641,9 @@ impl NameClass { } pub fn classify_lifetime( - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, lifetime: &ast::Lifetime, - ) -> Option { + ) -> Option> { let _p = tracing::info_span!("NameClass::classify_lifetime", ?lifetime).entered(); let parent = lifetime.syntax().parent()?; @@ -723,12 +726,12 @@ impl OperatorClass { /// A model special case is field shorthand syntax, which uses a single /// reference to point to two different defs. #[derive(Debug)] -pub enum NameRefClass { - Definition(Definition, Option), +pub enum NameRefClass<'db> { + Definition(Definition, Option>), FieldShorthand { local_ref: Local, field_ref: Field, - adt_subst: GenericSubstitution, + adt_subst: GenericSubstitution<'db>, }, /// The specific situation where we have an extern crate decl without a rename /// Here we have both a declaration and a reference. @@ -741,13 +744,13 @@ pub enum NameRefClass { }, } -impl NameRefClass { +impl<'db> NameRefClass<'db> { // Note: we don't have unit-tests for this rather important function. // It is primarily exercised via goto definition tests in `ide`. pub fn classify( - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, name_ref: &ast::NameRef, - ) -> Option { + ) -> Option> { let _p = tracing::info_span!("NameRefClass::classify", ?name_ref).entered(); let parent = name_ref.syntax().parent()?; @@ -866,9 +869,9 @@ impl NameRefClass { } pub fn classify_lifetime( - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, lifetime: &ast::Lifetime, - ) -> Option { + ) -> Option> { let _p = tracing::info_span!("NameRefClass::classify_lifetime", ?lifetime).entered(); if lifetime.text() == "'static" { return Some(NameRefClass::Definition( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index ac592dfe93cf..9f35988924b9 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -25,26 +25,26 @@ use crate::{ /// * assists /// * etc. #[derive(Debug)] -pub enum ImportCandidate { +pub enum ImportCandidate<'db> { /// A path, qualified (`std::collections::HashMap`) or not (`HashMap`). Path(PathImportCandidate), /// A trait associated function (with no self parameter) or an associated constant. /// For 'test_mod::TestEnum::test_function', `ty` is the `test_mod::TestEnum` expression type /// and `name` is the `test_function` - TraitAssocItem(TraitImportCandidate), + TraitAssocItem(TraitImportCandidate<'db>), /// A trait method with self parameter. /// For 'test_enum.test_method()', `ty` is the `test_enum` expression type /// and `name` is the `test_method` - TraitMethod(TraitImportCandidate), + TraitMethod(TraitImportCandidate<'db>), } /// A trait import needed for a given associated item access. /// For `some::path::SomeStruct::ASSOC_`, contains the /// type of `some::path::SomeStruct` and `ASSOC_` as the item name. #[derive(Debug)] -pub struct TraitImportCandidate { +pub struct TraitImportCandidate<'db> { /// A type of the item that has the associated item accessed at. - pub receiver_ty: Type, + pub receiver_ty: Type<'db>, /// The associated item name that the trait to import should contain. pub assoc_item_name: NameToImport, } @@ -100,16 +100,16 @@ impl NameToImport { /// A struct to find imports in the project, given a certain name (or its part) and the context. #[derive(Debug)] -pub struct ImportAssets { - import_candidate: ImportCandidate, +pub struct ImportAssets<'db> { + import_candidate: ImportCandidate<'db>, candidate_node: SyntaxNode, module_with_candidate: Module, } -impl ImportAssets { +impl<'db> ImportAssets<'db> { pub fn for_method_call( method_call: &ast::MethodCallExpr, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, ) -> Option { let candidate_node = method_call.syntax().clone(); Some(Self { @@ -121,7 +121,7 @@ impl ImportAssets { pub fn for_exact_path( fully_qualified_path: &ast::Path, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, ) -> Option { let candidate_node = fully_qualified_path.syntax().clone(); if let Some(use_tree) = candidate_node.ancestors().find_map(ast::UseTree::cast) { @@ -139,7 +139,7 @@ impl ImportAssets { }) } - pub fn for_ident_pat(sema: &Semantics<'_, RootDatabase>, pat: &ast::IdentPat) -> Option { + pub fn for_ident_pat(sema: &Semantics<'db, RootDatabase>, pat: &ast::IdentPat) -> Option { if !pat.is_simple_ident() { return None; } @@ -156,7 +156,7 @@ impl ImportAssets { module_with_candidate: Module, qualifier: Option, fuzzy_name: String, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, candidate_node: SyntaxNode, ) -> Option { Some(Self { @@ -168,7 +168,7 @@ impl ImportAssets { pub fn for_fuzzy_method_call( module_with_method_call: Module, - receiver_ty: Type, + receiver_ty: Type<'db>, fuzzy_method_name: String, candidate_node: SyntaxNode, ) -> Option { @@ -229,14 +229,14 @@ impl LocatedImport { } } -impl ImportAssets { - pub fn import_candidate(&self) -> &ImportCandidate { +impl<'db> ImportAssets<'db> { + pub fn import_candidate(&self) -> &ImportCandidate<'db> { &self.import_candidate } pub fn search_for_imports( &self, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, cfg: ImportPathConfig, prefix_kind: PrefixKind, ) -> impl Iterator { @@ -247,7 +247,7 @@ impl ImportAssets { /// This may return non-absolute paths if a part of the returned path is already imported into scope. pub fn search_for_relative_paths( &self, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, cfg: ImportPathConfig, ) -> impl Iterator { let _p = tracing::info_span!("ImportAssets::search_for_relative_paths").entered(); @@ -286,7 +286,7 @@ impl ImportAssets { fn search_for( &self, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, prefixed: Option, cfg: ImportPathConfig, ) -> impl Iterator { @@ -533,11 +533,11 @@ fn item_for_path_search_assoc(db: &RootDatabase, assoc_item: AssocItem) -> Optio }) } -fn trait_applicable_items( - db: &RootDatabase, +fn trait_applicable_items<'db>( + db: &'db RootDatabase, current_crate: Crate, - scope: &SemanticsScope<'_>, - trait_candidate: &TraitImportCandidate, + scope: &SemanticsScope<'db>, + trait_candidate: &TraitImportCandidate<'db>, trait_assoc_item: bool, mod_path: impl Fn(ItemInNs) -> Option, scope_filter: impl Fn(hir::Trait) -> bool, @@ -709,9 +709,9 @@ fn get_mod_path( } } -impl ImportCandidate { +impl<'db> ImportCandidate<'db> { fn for_method_call( - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, method_call: &ast::MethodCallExpr, ) -> Option { match sema.resolve_method_call(method_call) { @@ -725,7 +725,7 @@ impl ImportCandidate { } } - fn for_regular_path(sema: &Semantics<'_, RootDatabase>, path: &ast::Path) -> Option { + fn for_regular_path(sema: &Semantics<'db, RootDatabase>, path: &ast::Path) -> Option { if sema.resolve_path(path).is_some() { return None; } @@ -736,7 +736,7 @@ impl ImportCandidate { ) } - fn for_name(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option { + fn for_name(sema: &Semantics<'db, RootDatabase>, name: &ast::Name) -> Option { if sema .scope(name.syntax())? .speculative_resolve(&make::ext::ident_path(&name.text())) @@ -753,17 +753,17 @@ impl ImportCandidate { fn for_fuzzy_path( qualifier: Option, fuzzy_name: String, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, ) -> Option { path_import_candidate(sema, qualifier, NameToImport::fuzzy(fuzzy_name)) } } -fn path_import_candidate( - sema: &Semantics<'_, RootDatabase>, +fn path_import_candidate<'db>( + sema: &Semantics<'db, RootDatabase>, qualifier: Option, name: NameToImport, -) -> Option { +) -> Option> { Some(match qualifier { Some(qualifier) => match sema.resolve_path(&qualifier) { Some(PathResolution::Def(ModuleDef::BuiltinType(_))) | None => { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index c5ad64ed5941..7d460f72492c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -429,7 +429,7 @@ pub struct FindUsages<'a> { /// The container of our definition should it be an assoc item assoc_item_container: Option, /// whether to search for the `Self` type of the definition - include_self_kw_refs: Option, + include_self_kw_refs: Option>, /// whether to search for the `self` module search_self_mod: bool, } @@ -1087,12 +1087,12 @@ impl<'a> FindUsages<'a> { fn found_self_ty_name_ref( &self, - self_ty: &hir::Type, + self_ty: &hir::Type<'_>, name_ref: &ast::NameRef, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { // See https://github.com/rust-lang/rust-analyzer/pull/15864/files/e0276dc5ddc38c65240edb408522bb869f15afb4#r1389848845 - let ty_eq = |ty: hir::Type| match (ty.as_adt(), self_ty.as_adt()) { + let ty_eq = |ty: hir::Type<'_>| match (ty.as_adt(), self_ty.as_adt()) { (Some(ty), Some(self_ty)) => ty == self_ty, (None, None) => ty == *self_ty, _ => false, @@ -1315,7 +1315,7 @@ impl<'a> FindUsages<'a> { } } -fn def_to_ty(sema: &Semantics<'_, RootDatabase>, def: &Definition) -> Option { +fn def_to_ty<'db>(sema: &Semantics<'db, RootDatabase>, def: &Definition) -> Option> { match def { Definition::Adt(adt) => Some(adt.ty(sema.db)), Definition::TypeAlias(it) => Some(it.ty(sema.db)), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 9b9f450bc734..995bf72dca16 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -151,10 +151,10 @@ impl NameGenerator { /// - If `ty` is an `impl Trait`, it will suggest the name of the first trait. /// /// If the suggested name conflicts with reserved keywords, it will return `None`. - pub fn for_type( + pub fn for_type<'db>( &mut self, - ty: &hir::Type, - db: &RootDatabase, + ty: &hir::Type<'db>, + db: &'db RootDatabase, edition: Edition, ) -> Option { let name = name_of_type(ty, db, edition)?; @@ -373,7 +373,11 @@ fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option Option { +fn name_of_type<'db>( + ty: &hir::Type<'db>, + db: &'db RootDatabase, + edition: Edition, +) -> Option { let name = if let Some(adt) = ty.as_adt() { let name = adt.name(db).display(db, edition).to_string(); @@ -407,7 +411,11 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option, db: &RootDatabase, edition: Edition) -> SmolStr { +fn sequence_name<'db>( + inner_ty: Option<&hir::Type<'db>>, + db: &'db RootDatabase, + edition: Edition, +) -> SmolStr { let items_str = SmolStr::new_static("items"); let Some(inner_ty) = inner_ty else { return items_str; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs index 63ce0ddbb8fc..e8f2fbc9eb94 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs @@ -20,7 +20,7 @@ impl TryEnum { const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`. - pub fn from_ty(sema: &Semantics<'_, RootDatabase>, ty: &hir::Type) -> Option { + pub fn from_ty(sema: &Semantics<'_, RootDatabase>, ty: &hir::Type<'_>) -> Option { let enum_ = match ty.as_adt() { Some(hir::Adt::Enum(it)) => it, _ => return None, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs index a4a93e36f0e1..f63cd92694b3 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs @@ -11,7 +11,7 @@ use syntax::{ pub fn use_trivial_constructor( db: &crate::RootDatabase, path: Path, - ty: &hir::Type, + ty: &hir::Type<'_>, edition: Edition, ) -> Option { match ty.as_adt() { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs index 7d2ac373dc08..afd1687ae073 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -7,7 +7,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // This diagnostic is triggered if a call is made on something that is not callable. pub(crate) fn expected_function( ctx: &DiagnosticsContext<'_>, - d: &hir::ExpectedFunction, + d: &hir::ExpectedFunction<'_>, ) -> Diagnostic { Diagnostic::new_with_syntax_node_ptr( ctx, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs index 7a6e98fe1b54..a59077b757b1 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs @@ -18,7 +18,7 @@ macro_rules! format_ty { // Diagnostic: invalid-cast // // This diagnostic is triggered if the code contains an illegal cast -pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -> Diagnostic { +pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast<'_>) -> Diagnostic { let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into())); let (code, message) = match d.error { CastError::CastToBool => ( @@ -106,7 +106,10 @@ pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) - // Diagnostic: cast-to-unsized // // This diagnostic is triggered when casting to an unsized type -pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsized) -> Diagnostic { +pub(crate) fn cast_to_unsized( + ctx: &DiagnosticsContext<'_>, + d: &hir::CastToUnsized<'_>, +) -> Diagnostic { let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into())); Diagnostic::new( DiagnosticCode::RustcHardError("E0620"), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 2b76efb1965b..8a5d82b48c01 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -106,7 +106,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option| match ctx.config.expr_fill_default { ExprFillDefaultMode::Todo => make::ext::expr_todo(), ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), ExprFillDefaultMode::Default => { @@ -180,7 +180,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option, db: &dyn HirDatabase, module: hir::Module, edition: Edition, @@ -198,7 +198,7 @@ fn make_ty( fn get_default_constructor( ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields, - ty: &Type, + ty: &Type<'_>, ) -> Option { if let Some(builtin_ty) = ty.as_builtin() { if builtin_ty.is_int() || builtin_ty.is_uint() { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index 01cf5e8fa522..7181d708fe33 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -4,7 +4,10 @@ use hir::HirDisplay; // Diagnostic: moved-out-of-ref // // This diagnostic is triggered on moving non copy things out of references. -pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOfRef) -> Diagnostic { +pub(crate) fn moved_out_of_ref( + ctx: &DiagnosticsContext<'_>, + d: &hir::MovedOutOfRef<'_>, +) -> Diagnostic { Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0507"), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 076df1ab0f82..7b4c249554da 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -20,7 +20,7 @@ use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_dis // // This diagnostic is triggered when the type of an expression or pattern does not match // the expected type. -pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic { +pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Diagnostic { let display_range = adjusted_display_range(ctx, d.expr_or_pat, &|node| { let Either::Left(expr) = node else { return None }; let salient_token_range = match expr { @@ -59,7 +59,7 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) diag } -fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option> { +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Option> { let mut fixes = Vec::new(); if let Some(expr_ptr) = d.expr_or_pat.value.cast::() { @@ -76,7 +76,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option, - d: &hir::TypeMismatch, + d: &hir::TypeMismatch<'_>, expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { @@ -98,7 +98,7 @@ fn add_reference( fn add_missing_ok_or_some( ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMismatch, + d: &hir::TypeMismatch<'_>, expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { @@ -188,7 +188,7 @@ fn add_missing_ok_or_some( fn remove_unnecessary_wrapper( ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMismatch, + d: &hir::TypeMismatch<'_>, expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { @@ -271,7 +271,7 @@ fn remove_unnecessary_wrapper( fn remove_semicolon( ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMismatch, + d: &hir::TypeMismatch<'_>, expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { @@ -301,7 +301,7 @@ fn remove_semicolon( fn str_ref_to_owned( ctx: &DiagnosticsContext<'_>, - d: &hir::TypeMismatch, + d: &hir::TypeMismatch<'_>, expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 1915a88dd002..8d4277026905 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -20,7 +20,7 @@ use syntax::AstNode; // Diagnostic: typed-hole // // This diagnostic is triggered when an underscore expression is used in an invalid position. -pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Diagnostic { +pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole<'_>) -> Diagnostic { let display_range = ctx.sema.diagnostics_display_range(d.expr.map(|it| it.into())); let (message, fixes) = if d.expected.is_unknown() { ("`_` expressions may only appear on the left-hand side of an assignment".to_owned(), None) @@ -41,7 +41,7 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di .with_fixes(fixes) } -fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option> { +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole<'_>) -> Option> { let db = ctx.sema.db; let root = db.parse_or_expand(d.expr.file_id); let (original_range, _) = @@ -61,7 +61,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option }; let paths = term_search(&term_search_ctx); - let mut formatter = |_: &hir::Type| String::from("_"); + let mut formatter = |_: &hir::Type<'_>| String::from("_"); let assists: Vec = d .expected diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 0649c97f8205..690158989679 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -25,7 +25,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_display_ran // This diagnostic is triggered if a field does not exist on a given type. pub(crate) fn unresolved_field( ctx: &DiagnosticsContext<'_>, - d: &hir::UnresolvedField, + d: &hir::UnresolvedField<'_>, ) -> Diagnostic { let method_suffix = if d.method_with_same_name_exists { ", but a method with a similar name exists" @@ -54,7 +54,7 @@ pub(crate) fn unresolved_field( .with_fixes(fixes(ctx, d)) } -fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option> { +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField<'_>) -> Option> { let mut fixes = Vec::new(); if d.method_with_same_name_exists { fixes.extend(method_fix(ctx, &d.expr)); @@ -64,7 +64,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option, d: &hir::UnresolvedField) -> Option { +fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField<'_>) -> Option { // Get the FileRange of the invalid field access let root = ctx.sema.db.parse_or_expand(d.expr.file_id); let expr = d.expr.value.to_node(&root).left()?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 00c2a8c4c468..1f2d671249de 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -18,7 +18,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, adjusted_display_ran // This diagnostic is triggered if a method does not exist on a given type. pub(crate) fn unresolved_method( ctx: &DiagnosticsContext<'_>, - d: &hir::UnresolvedMethodCall, + d: &hir::UnresolvedMethodCall<'_>, ) -> Diagnostic { let suffix = if d.field_with_same_name.is_some() { ", but a field with a similar name exists" @@ -49,7 +49,7 @@ pub(crate) fn unresolved_method( .with_fixes(fixes(ctx, d)) } -fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option> { +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall<'_>) -> Option> { let field_fix = if let Some(ty) = &d.field_with_same_name { field_fix(ctx, d, ty) } else { @@ -72,8 +72,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option< fn field_fix( ctx: &DiagnosticsContext<'_>, - d: &hir::UnresolvedMethodCall, - ty: &hir::Type, + d: &hir::UnresolvedMethodCall<'_>, + ty: &hir::Type<'_>, ) -> Option { if !ty.impls_fnonce(ctx.sema.db) { return None; @@ -107,7 +107,10 @@ fn field_fix( }) } -fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option { +fn assoc_func_fix( + ctx: &DiagnosticsContext<'_>, + d: &hir::UnresolvedMethodCall<'_>, +) -> Option { if let Some(f) = d.assoc_func_with_same_name { let db = ctx.sema.db; diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index 43c56ac8bec5..e4b20f3f1aad 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -110,7 +110,7 @@ pub struct SsrMatches { pub struct MatchFinder<'db> { /// Our source of information about the user's code. sema: Semantics<'db, ide_db::RootDatabase>, - rules: Vec, + rules: Vec>, resolution_scope: resolving::ResolutionScope<'db>, restrict_ranges: Vec, } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index cff4eede0426..b350315ba548 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -84,12 +84,12 @@ pub(crate) struct MatchFailed { /// Checks if `code` matches the search pattern found in `search_scope`, returning information about /// the match, if it does. Since we only do matching in this module and searching is done by the /// parent module, we don't populate nested matches. -pub(crate) fn get_match( +pub(crate) fn get_match<'db>( debug_active: bool, - rule: &ResolvedRule, + rule: &ResolvedRule<'db>, code: &SyntaxNode, restrict_range: &Option, - sema: &Semantics<'_, ide_db::RootDatabase>, + sema: &Semantics<'db, ide_db::RootDatabase>, ) -> Result { record_match_fails_reasons_scope(debug_active, || { Matcher::try_match(rule, code, restrict_range, sema) @@ -102,7 +102,7 @@ struct Matcher<'db, 'sema> { /// If any placeholders come from anywhere outside of this range, then the match will be /// rejected. restrict_range: Option, - rule: &'sema ResolvedRule, + rule: &'sema ResolvedRule<'db>, } /// Which phase of matching we're currently performing. We do two phases because most attempted @@ -117,7 +117,7 @@ enum Phase<'a> { impl<'db, 'sema> Matcher<'db, 'sema> { fn try_match( - rule: &ResolvedRule, + rule: &ResolvedRule<'db>, code: &SyntaxNode, restrict_range: &Option, sema: &'sema Semantics<'db, ide_db::RootDatabase>, @@ -535,7 +535,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { fn attempt_match_ufcs_to_method_call( &self, phase: &mut Phase<'_>, - pattern_ufcs: &UfcsCallInfo, + pattern_ufcs: &UfcsCallInfo<'db>, code: &ast::MethodCallExpr, ) -> Result<(), MatchFailed> { use ast::HasArgList; @@ -597,7 +597,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { fn attempt_match_ufcs_to_ufcs( &self, phase: &mut Phase<'_>, - pattern_ufcs: &UfcsCallInfo, + pattern_ufcs: &UfcsCallInfo<'db>, code: &ast::CallExpr, ) -> Result<(), MatchFailed> { use ast::HasArgList; @@ -615,7 +615,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> { /// times. Returns the number of times it needed to be dereferenced. fn check_expr_type( &self, - pattern_type: &hir::Type, + pattern_type: &hir::Type<'db>, expr: &ast::Expr, ) -> Result { use hir::HirDisplay; @@ -656,10 +656,10 @@ impl<'db, 'sema> Matcher<'db, 'sema> { } impl Match { - fn render_template_paths( + fn render_template_paths<'db>( &mut self, - template: &ResolvedPattern, - sema: &Semantics<'_, ide_db::RootDatabase>, + template: &ResolvedPattern<'db>, + sema: &Semantics<'db, ide_db::RootDatabase>, ) -> Result<(), MatchFailed> { let module = sema .scope(&self.matched_node) diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs index 3c92697926f3..752edd6535a6 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs @@ -14,21 +14,21 @@ use crate::{Match, SsrMatches, fragments, resolving::ResolvedRule}; /// Returns a text edit that will replace each match in `matches` with its corresponding replacement /// template. Placeholders in the template will have been substituted with whatever they matched to /// in the original code. -pub(crate) fn matches_to_edit( - db: &dyn hir::db::ExpandDatabase, +pub(crate) fn matches_to_edit<'db>( + db: &'db dyn hir::db::ExpandDatabase, matches: &SsrMatches, file_src: &str, - rules: &[ResolvedRule], + rules: &[ResolvedRule<'db>], ) -> TextEdit { matches_to_edit_at_offset(db, matches, file_src, 0.into(), rules) } -fn matches_to_edit_at_offset( - db: &dyn hir::db::ExpandDatabase, +fn matches_to_edit_at_offset<'db>( + db: &'db dyn hir::db::ExpandDatabase, matches: &SsrMatches, file_src: &str, relative_start: TextSize, - rules: &[ResolvedRule], + rules: &[ResolvedRule<'db>], ) -> TextEdit { let mut edit_builder = TextEdit::builder(); for m in &matches.matches { @@ -40,12 +40,12 @@ fn matches_to_edit_at_offset( edit_builder.finish() } -struct ReplacementRenderer<'a> { - db: &'a dyn hir::db::ExpandDatabase, +struct ReplacementRenderer<'a, 'db> { + db: &'db dyn hir::db::ExpandDatabase, match_info: &'a Match, file_src: &'a str, - rules: &'a [ResolvedRule], - rule: &'a ResolvedRule, + rules: &'a [ResolvedRule<'db>], + rule: &'a ResolvedRule<'db>, out: String, // Map from a range within `out` to a token in `template` that represents a placeholder. This is // used to validate that the generated source code doesn't split any placeholder expansions (see @@ -58,11 +58,11 @@ struct ReplacementRenderer<'a> { edition: Edition, } -fn render_replace( - db: &dyn hir::db::ExpandDatabase, +fn render_replace<'db>( + db: &'db dyn hir::db::ExpandDatabase, match_info: &Match, file_src: &str, - rules: &[ResolvedRule], + rules: &[ResolvedRule<'db>], edition: Edition, ) -> String { let rule = &rules[match_info.rule_index]; @@ -89,7 +89,7 @@ fn render_replace( renderer.out } -impl ReplacementRenderer<'_> { +impl<'db> ReplacementRenderer<'_, 'db> { fn render_node_children(&mut self, node: &SyntaxNode) { for node_or_token in node.children_with_tokens() { self.render_node_or_token(&node_or_token); diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs index a687db4bf58d..8f28a1cd3a62 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs @@ -15,18 +15,18 @@ pub(crate) struct ResolutionScope<'db> { node: SyntaxNode, } -pub(crate) struct ResolvedRule { - pub(crate) pattern: ResolvedPattern, - pub(crate) template: Option, +pub(crate) struct ResolvedRule<'db> { + pub(crate) pattern: ResolvedPattern<'db>, + pub(crate) template: Option>, pub(crate) index: usize, } -pub(crate) struct ResolvedPattern { +pub(crate) struct ResolvedPattern<'db> { pub(crate) placeholders_by_stand_in: FxHashMap, pub(crate) node: SyntaxNode, // Paths in `node` that we've resolved. pub(crate) resolved_paths: FxHashMap, - pub(crate) ufcs_function_calls: FxHashMap, + pub(crate) ufcs_function_calls: FxHashMap>, pub(crate) contains_self: bool, } @@ -36,18 +36,18 @@ pub(crate) struct ResolvedPath { pub(crate) depth: u32, } -pub(crate) struct UfcsCallInfo { +pub(crate) struct UfcsCallInfo<'db> { pub(crate) call_expr: ast::CallExpr, pub(crate) function: hir::Function, - pub(crate) qualifier_type: Option, + pub(crate) qualifier_type: Option>, } -impl ResolvedRule { +impl<'db> ResolvedRule<'db> { pub(crate) fn new( rule: parsing::ParsedRule, - resolution_scope: &ResolutionScope<'_>, + resolution_scope: &ResolutionScope<'db>, index: usize, - ) -> Result { + ) -> Result, SsrError> { let resolver = Resolver { resolution_scope, placeholders_by_stand_in: rule.placeholders_by_stand_in }; let resolved_template = match rule.template { @@ -74,8 +74,8 @@ struct Resolver<'a, 'db> { placeholders_by_stand_in: FxHashMap, } -impl Resolver<'_, '_> { - fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result { +impl<'db> Resolver<'_, 'db> { + fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result, SsrError> { use syntax::ast::AstNode; use syntax::{SyntaxElement, T}; let mut resolved_paths = FxHashMap::default(); @@ -250,7 +250,7 @@ impl<'db> ResolutionScope<'db> { } } - fn qualifier_type(&self, path: &SyntaxNode) -> Option { + fn qualifier_type(&self, path: &SyntaxNode) -> Option> { use syntax::ast::AstNode; if let Some(path) = ast::Path::cast(path.clone()) { if let Some(qualifier) = path.qualifier() { diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs index 9afbedbb1ab4..99a98fb2a713 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs @@ -21,13 +21,13 @@ pub(crate) struct UsageCache { usages: Vec<(Definition, UsageSearchResult)>, } -impl MatchFinder<'_> { +impl<'db> MatchFinder<'db> { /// Adds all matches for `rule` to `matches_out`. Matches may overlap in ways that make /// replacement impossible, so further processing is required in order to properly nest matches /// and remove overlapping matches. This is done in the `nesting` module. pub(crate) fn find_matches_for_rule( &self, - rule: &ResolvedRule, + rule: &ResolvedRule<'db>, usage_cache: &mut UsageCache, matches_out: &mut Vec, ) { @@ -49,8 +49,8 @@ impl MatchFinder<'_> { fn find_matches_for_pattern_tree( &self, - rule: &ResolvedRule, - pattern: &ResolvedPattern, + rule: &ResolvedRule<'db>, + pattern: &ResolvedPattern<'db>, usage_cache: &mut UsageCache, matches_out: &mut Vec, ) { @@ -144,7 +144,7 @@ impl MatchFinder<'_> { SearchScope::files(&files) } - fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec) { + fn slow_scan(&self, rule: &ResolvedRule<'db>, matches_out: &mut Vec) { self.search_files_do(|file_id| { let file = self.sema.parse_guess_edition(file_id); let code = file.syntax(); @@ -177,7 +177,7 @@ impl MatchFinder<'_> { fn slow_scan_node( &self, code: &SyntaxNode, - rule: &ResolvedRule, + rule: &ResolvedRule<'db>, restrict_range: &Option, matches_out: &mut Vec, ) { @@ -206,7 +206,7 @@ impl MatchFinder<'_> { fn try_add_match( &self, - rule: &ResolvedRule, + rule: &ResolvedRule<'db>, code: &SyntaxNode, restrict_range: &Option, matches_out: &mut Vec, @@ -274,7 +274,7 @@ impl UsageCache { /// Returns a path that's suitable for path resolution. We exclude builtin types, since they aren't /// something that we can find references to. We then somewhat arbitrarily pick the path that is the /// longest as this is hopefully more likely to be less common, making it faster to find. -fn pick_path_for_usages(pattern: &ResolvedPattern) -> Option<&ResolvedPath> { +fn pick_path_for_usages<'a>(pattern: &'a ResolvedPattern<'_>) -> Option<&'a ResolvedPath> { // FIXME: Take the scope of the resolved path into account. e.g. if there are any paths that are // private to the current module, then we definitely would want to pick them over say a path // from std. Possibly we should go further than this and intersect the search scopes for all diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs index 1bc28f28b6f5..02d96a647328 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs @@ -83,7 +83,7 @@ pub(crate) fn goto_implementation( Some(RangeInfo { range, info: navs }) } -fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type) -> Vec { +fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type<'_>) -> Vec { Impl::all_for_type(sema.db, ty) .into_iter() .filter_map(|imp| imp.try_to_nav(sema.db)) diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index 9781e7116dec..86d72fefe05e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -38,7 +38,7 @@ pub(crate) fn goto_type_definition( } } }; - let mut process_ty = |ty: hir::Type| { + let mut process_ty = |ty: hir::Type<'_>| { // collect from each `ty` into the `res` result vec let ty = ty.strip_references(); ty.walk(db, |t| { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 5404a9dc2cec..e4d6279759ed 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -426,7 +426,7 @@ pub(crate) fn hover_for_definition( sema: &Semantics<'_, RootDatabase>, file_id: FileId, def: Definition, - subst: Option, + subst: Option>, scope_node: &SyntaxNode, macro_arm: Option, render_extras: bool, @@ -483,10 +483,10 @@ pub(crate) fn hover_for_definition( } } -fn notable_traits( - db: &RootDatabase, - ty: &hir::Type, -) -> Vec<(hir::Trait, Vec<(Option, hir::Name)>)> { +fn notable_traits<'db>( + db: &'db RootDatabase, + ty: &hir::Type<'db>, +) -> Vec<(hir::Trait, Vec<(Option>, hir::Name)>)> { db.notable_traits_in_deps(ty.krate(db).into()) .iter() .flat_map(|it| &**it) @@ -567,8 +567,8 @@ fn runnable_action( fn goto_type_action_for_def( db: &RootDatabase, def: Definition, - notable_traits: &[(hir::Trait, Vec<(Option, hir::Name)>)], - subst_types: Option>, + notable_traits: &[(hir::Trait, Vec<(Option>, hir::Name)>)], + subst_types: Option)>>, edition: Edition, ) -> Option { let mut targets: Vec = Vec::new(); @@ -622,7 +622,7 @@ fn goto_type_action_for_def( fn walk_and_push_ty( db: &RootDatabase, - ty: &hir::Type, + ty: &hir::Type<'_>, push_new_def: &mut dyn FnMut(hir::ModuleDef), ) { ty.walk(db, |t| { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index c24864a18bdf..670210d4998d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -476,10 +476,10 @@ pub(super) fn definition( db: &RootDatabase, def: Definition, famous_defs: Option<&FamousDefs<'_, '_>>, - notable_traits: &[(Trait, Vec<(Option, Name)>)], + notable_traits: &[(Trait, Vec<(Option>, Name)>)], macro_arm: Option, render_extras: bool, - subst_types: Option<&Vec<(Symbol, Type)>>, + subst_types: Option<&Vec<(Symbol, Type<'_>)>>, config: &HoverConfig, edition: Edition, display_target: DisplayTarget, @@ -938,7 +938,7 @@ pub(super) fn literal( fn render_notable_trait( db: &RootDatabase, - notable_traits: &[(Trait, Vec<(Option, Name)>)], + notable_traits: &[(Trait, Vec<(Option>, Name)>)], edition: Edition, display_target: DisplayTarget, ) -> Option { @@ -979,7 +979,7 @@ fn render_notable_trait( fn type_info( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, - ty: TypeInfo, + ty: TypeInfo<'_>, edition: Edition, display_target: DisplayTarget, ) -> Option { @@ -1038,7 +1038,7 @@ fn type_info( fn closure_ty( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, - TypeInfo { original, adjusted }: &TypeInfo, + TypeInfo { original, adjusted }: &TypeInfo<'_>, edition: Edition, display_target: DisplayTarget, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index b094b098462f..19e5509681aa 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -722,14 +722,14 @@ impl InlayHintLabelBuilder<'_> { fn label_of_ty( famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - ty: &hir::Type, + ty: &hir::Type<'_>, display_target: DisplayTarget, ) -> Option { fn rec( sema: &Semantics<'_, RootDatabase>, famous_defs: &FamousDefs<'_, '_>, mut max_length: Option, - ty: &hir::Type, + ty: &hir::Type<'_>, label_builder: &mut InlayHintLabelBuilder<'_>, config: &InlayHintsConfig, display_target: DisplayTarget, @@ -788,11 +788,11 @@ fn label_of_ty( } /// Checks if the type is an Iterator from std::iter and returns the iterator trait and the item type of the concrete iterator. -fn hint_iterator( - sema: &Semantics<'_, RootDatabase>, - famous_defs: &FamousDefs<'_, '_>, - ty: &hir::Type, -) -> Option<(hir::Trait, hir::TypeAlias, hir::Type)> { +fn hint_iterator<'db>( + sema: &Semantics<'db, RootDatabase>, + famous_defs: &FamousDefs<'_, 'db>, + ty: &hir::Type<'db>, +) -> Option<(hir::Trait, hir::TypeAlias, hir::Type<'db>)> { let db = sema.db; let strukt = ty.strip_references().as_adt()?; let krate = strukt.module(db).krate(); @@ -826,7 +826,7 @@ fn ty_to_text_edit( sema: &Semantics<'_, RootDatabase>, config: &InlayHintsConfig, node_for_hint: &SyntaxNode, - ty: &hir::Type, + ty: &hir::Type<'_>, offset_to_insert_ty: TextSize, additional_edits: &dyn Fn(&mut TextEditBuilder), prefix: impl Into, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index 5ff9fee60abf..5174228466c0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -87,10 +87,10 @@ pub(super) fn hints( Some(()) } -fn get_callable( - sema: &Semantics<'_, RootDatabase>, +fn get_callable<'db>( + sema: &Semantics<'db, RootDatabase>, expr: &ast::Expr, -) -> Option<(hir::Callable, ast::ArgList)> { +) -> Option<(hir::Callable<'db>, ast::ArgList)> { match expr { ast::Expr::CallExpr(expr) => { let descended = sema.descend_node_into_attributes(expr.clone()).pop(); diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 0e17b3559074..e30a3ebefb98 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -278,7 +278,7 @@ fn signature_help_for_call( } res.signature.push(')'); - let mut render = |ret_type: hir::Type| { + let mut render = |ret_type: hir::Type<'_>| { if !ret_type.is_unit() { format_to!(res.signature, " -> {}", ret_type.display(db, display_target)); } @@ -597,11 +597,11 @@ fn signature_help_for_tuple_expr( Some(res) } -fn signature_help_for_record_( - sema: &Semantics<'_, RootDatabase>, +fn signature_help_for_record_<'db>( + sema: &Semantics<'db, RootDatabase>, field_list_children: SyntaxElementChildren, path: &ast::Path, - fields2: impl Iterator, + fields2: impl Iterator)>, token: SyntaxToken, edition: Edition, display_target: DisplayTarget, @@ -689,13 +689,13 @@ fn signature_help_for_record_( Some(res) } -fn signature_help_for_tuple_pat_ish( - db: &RootDatabase, +fn signature_help_for_tuple_pat_ish<'db>( + db: &'db RootDatabase, mut res: SignatureHelp, pat: &SyntaxNode, token: SyntaxToken, mut field_pats: AstChildren, - fields: impl ExactSizeIterator, + fields: impl ExactSizeIterator>, display_target: DisplayTarget, ) -> SignatureHelp { let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_))); diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 140ae4265be7..63701a4d15e9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -107,7 +107,7 @@ pub(crate) fn view_memory_layout( fn read_layout( nodes: &mut Vec, db: &RootDatabase, - ty: &Type, + ty: &Type<'_>, layout: &Layout, parent_idx: usize, display_target: DisplayTarget, diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs index baac3e8bbfe7..c151cca07272 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs @@ -74,8 +74,8 @@ impl ToTokens for TrackedQuery { quote! { #sig { #annotation - fn #shim( - db: &dyn #trait_name, + fn #shim<'db>( + db: &'db dyn #trait_name, _input: #input_struct_name, #(#pat_and_tys),* ) #ret @@ -88,8 +88,8 @@ impl ToTokens for TrackedQuery { quote! { #sig { #annotation - fn #shim( - db: &dyn #trait_name, + fn #shim<'db>( + db: &'db dyn #trait_name, #(#pat_and_tys),* ) #ret #invoke_block diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 12b393b80c0d..0ee01982fea2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -532,7 +532,7 @@ impl flags::AnalysisStats { } let todo = syntax::ast::make::ext::expr_todo().to_string(); - let mut formatter = |_: &hir::Type| todo.clone(); + let mut formatter = |_: &hir::Type<'_>| todo.clone(); let mut syntax_hit_found = false; for term in found_terms { let generated = term diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index 9a292eacd7f7..978c50d807bc 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -13,6 +13,7 @@ pub mod panic_context; pub mod process; pub mod rand; pub mod thread; +pub mod variance; pub use itertools; diff --git a/src/tools/rust-analyzer/crates/stdx/src/variance.rs b/src/tools/rust-analyzer/crates/stdx/src/variance.rs new file mode 100644 index 000000000000..8465d72bf371 --- /dev/null +++ b/src/tools/rust-analyzer/crates/stdx/src/variance.rs @@ -0,0 +1,270 @@ +//! This is a copy of [`std::marker::variance`]. + +use std::any::type_name; +use std::cmp::Ordering; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; + +macro_rules! first_token { + ($first:tt $($rest:tt)*) => { + $first + }; +} +macro_rules! phantom_type { + ($( + $(#[$attr:meta])* + pub struct $name:ident <$t:ident> ($($inner:tt)*); + )*) => {$( + $(#[$attr])* + pub struct $name<$t>($($inner)*) where T: ?Sized; + + impl $name + where T: ?Sized + { + /// Constructs a new instance of the variance marker. + pub const fn new() -> Self { + Self(PhantomData) + } + } + + impl self::sealed::Sealed for $name where T: ?Sized { + const VALUE: Self = Self::new(); + } + + impl Variance for $name where T: ?Sized {} + + impl Default for $name + where T: ?Sized + { + fn default() -> Self { + Self(PhantomData) + } + } + + impl fmt::Debug for $name + where T: ?Sized + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}<{}>", stringify!($name), type_name::()) + } + } + + impl Clone for $name + where T: ?Sized + { + fn clone(&self) -> Self { + *self + } + } + + impl Copy for $name where T: ?Sized {} + + impl PartialEq for $name + where T: ?Sized + { + fn eq(&self, _: &Self) -> bool { + true + } + } + + impl Eq for $name where T: ?Sized {} + + #[allow(clippy::non_canonical_partial_ord_impl)] + impl PartialOrd for $name + where T: ?Sized + { + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) + } + } + + impl Ord for $name + where T: ?Sized + { + fn cmp(&self, _: &Self) -> Ordering { + Ordering::Equal + } + } + + impl Hash for $name + where T: ?Sized + { + fn hash(&self, _: &mut H) {} + } + )*}; +} + +macro_rules! phantom_lifetime { + ($( + $(#[$attr:meta])* + pub struct $name:ident <$lt:lifetime> ($($inner:tt)*); + )*) => {$( + $(#[$attr])* + + #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $name<$lt>($($inner)*); + + impl $name<'_> { + /// Constructs a new instance of the variance marker. + pub const fn new() -> Self { + Self(first_token!($($inner)*)(PhantomData)) + } + } + + impl self::sealed::Sealed for $name<'_> { + const VALUE: Self = Self::new(); + } + + impl Variance for $name<'_> {} + + impl fmt::Debug for $name<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", stringify!($name)) + } + } + )*}; +} + +phantom_lifetime! { + /// Zero-sized type used to mark a lifetime as covariant. + /// + /// Covariant lifetimes must live at least as long as declared. See [the reference][1] for more + /// information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `'a`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + + pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>); + /// Zero-sized type used to mark a lifetime as contravariant. + /// + /// Contravariant lifetimes must live at most as long as declared. See [the reference][1] for + /// more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `'a`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + + pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>); + /// Zero-sized type used to mark a lifetime as invariant. + /// + /// Invariant lifetimes must be live for the exact length declared, neither shorter nor longer. + /// See [the reference][1] for more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `'a`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + + pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>); + +} + +phantom_type! { + /// Zero-sized type used to mark a type parameter as covariant. + /// + /// Types used as part of the return value from a function are covariant. If the type is _also_ + /// passed as a parameter then it is [invariant][PhantomInvariant]. See [the reference][1] for + /// more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `T`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + + pub struct PhantomCovariant(PhantomData T>); + /// Zero-sized type used to mark a type parameter as contravariant. + /// + /// Types passed as arguments to a function are contravariant. If the type is _also_ part of the + /// return value from a function then it is [invariant][PhantomInvariant]. See [the + /// reference][1] for more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `T`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + + pub struct PhantomContravariant(PhantomData); + /// Zero-sized type used to mark a type parameter as invariant. + /// + /// Types that are both passed as an argument _and_ used as part of the return value from a + /// function are invariant. See [the reference][1] for more information. + /// + /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance + /// + /// ## Layout + /// + /// For all `T`, the following are guaranteed: + /// * `size_of::>() == 0` + /// * `align_of::>() == 1` + + pub struct PhantomInvariant(PhantomData T>); + +} + +mod sealed { + + pub trait Sealed { + const VALUE: Self; + } +} +/// A marker trait for phantom variance types. +pub trait Variance: sealed::Sealed + Default {} +/// Construct a variance marker; equivalent to [`Default::default`]. +/// +/// This type can be any of the following. You generally should not need to explicitly name the +/// type, however. +/// +/// - [`PhantomCovariant`] +/// - [`PhantomContravariant`] +/// - [`PhantomInvariant`] +/// - [`PhantomCovariantLifetime`] +/// - [`PhantomContravariantLifetime`] +/// - [`PhantomInvariantLifetime`] +/// +/// # Example +/// +/// ```rust +/// #![feature(phantom_variance_markers)] +/// +/// use core::marker::{PhantomCovariant, variance}; +/// +/// struct BoundFn +/// where +/// F: Fn(P) -> R, +/// { +/// function: F, +/// parameter: P, +/// return_value: PhantomCovariant, +/// } +/// +/// let bound_fn = BoundFn { +/// function: core::convert::identity, +/// parameter: 5u8, +/// return_value: variance(), +/// }; +/// ``` +pub const fn variance() -> T +where + T: Variance, +{ + T::VALUE +} From 7d10a149f146436d59dab4e723922c588c48ef14 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 17 Jun 2025 11:02:20 +0200 Subject: [PATCH 068/356] fix: Reload workspaces when cargo configs change --- .../rust-analyzer/src/handlers/notification.rs | 2 +- .../crates/rust-analyzer/src/reload.rs | 10 ++++++++++ src/tools/rust-analyzer/editors/code/src/config.ts | 14 ++++---------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index b7373f274f05..200e972e4289 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -239,7 +239,7 @@ pub(crate) fn handle_did_change_configuration( let (config, e, _) = config.apply_change(change); this.config_errors = e.is_empty().not().then_some(e); - // Client config changes neccesitates .update_config method to be called. + // Client config changes necessitates .update_config method to be called. this.update_configuration(config); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 4677880daaf9..189d95ec7ed4 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -114,6 +114,16 @@ impl GlobalState { Durability::HIGH, ); } + + if self.config.cargo(None) != old_config.cargo(None) { + let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }; + self.fetch_workspaces_queue.request_op("cargo config changed".to_owned(), req) + } + + if self.config.cfg_set_test(None) != old_config.cfg_set_test(None) { + let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }; + self.fetch_workspaces_queue.request_op("cfg_set_test config changed".to_owned(), req) + } } pub(crate) fn current_status(&self) -> lsp_ext::ServerStatusParams { diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index f36e18a73da0..d2dc740c09b5 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -20,15 +20,9 @@ export class Config { configureLang: vscode.Disposable | undefined; readonly rootSection = "rust-analyzer"; - private readonly requiresServerReloadOpts = [ - "cargo", - "procMacro", - "serverPath", - "server", - "files", - "cfg", - "showSyntaxTree", - ].map((opt) => `${this.rootSection}.${opt}`); + private readonly requiresServerReloadOpts = ["server", "files", "showSyntaxTree"].map( + (opt) => `${this.rootSection}.${opt}`, + ); private readonly requiresWindowReloadOpts = ["testExplorer"].map( (opt) => `${this.rootSection}.${opt}`, @@ -208,7 +202,7 @@ export class Config { } get serverPath() { - return this.get("server.path") ?? this.get("serverPath"); + return this.get("server.path"); } get serverExtraEnv(): Env { From a1aac53d6fa72e89efd4881dcf80a8b74469c201 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 17 Jun 2025 12:48:19 +0300 Subject: [PATCH 069/356] Never make type mismatch diagnostic stable, even when there is a fix We show fixes now even for experimental diagnostics anyway, and it has false positives. --- .../crates/ide-diagnostics/src/handlers/type_mismatch.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 7b4c249554da..e2957fcaefb4 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -39,7 +39,7 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch< cov_mark::hit!(type_mismatch_range_adjustment); Some(salient_token_range) }); - let mut diag = Diagnostic::new( + Diagnostic::new( DiagnosticCode::RustcHardError("E0308"), format!( "expected {}, found {}", @@ -52,11 +52,7 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch< ), display_range, ) - .with_fixes(fixes(ctx, d)); - if diag.fixes.is_some() { - diag.experimental = false; - } - diag + .with_fixes(fixes(ctx, d)) } fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<'_>) -> Option> { From 646fecf3150192cf5a50bffcc50b9da793075c95 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 17 Jun 2025 13:33:30 +0200 Subject: [PATCH 070/356] Improve completions in if / while expression conditions --- .../ide-completion/src/completions/postfix.rs | 352 +++++++++++------- .../crates/ide-completion/src/render.rs | 16 +- .../crates/ide-db/src/ty_filter.rs | 2 +- 3 files changed, 236 insertions(+), 134 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 3cdf2112835d..0ac7578d2592 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -11,6 +11,7 @@ use ide_db::{ text_edit::TextEdit, ty_filter::TryEnum, }; +use itertools::Either; use stdx::never; use syntax::{ SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR}, @@ -86,98 +87,10 @@ pub(crate) fn complete_postfix( } } - let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references()); - if let Some(try_enum) = &try_enum { - match try_enum { - TryEnum::Result => { - postfix_snippet( - "ifl", - "if let Ok {}", - &format!("if let Ok($1) = {receiver_text} {{\n $0\n}}"), - ) - .add_to(acc, ctx.db); - - postfix_snippet( - "lete", - "let Ok else {}", - &format!("let Ok($1) = {receiver_text} else {{\n $2\n}};\n$0"), - ) - .add_to(acc, ctx.db); - - postfix_snippet( - "while", - "while let Ok {}", - &format!("while let Ok($1) = {receiver_text} {{\n $0\n}}"), - ) - .add_to(acc, ctx.db); - } - TryEnum::Option => { - postfix_snippet( - "ifl", - "if let Some {}", - &format!("if let Some($1) = {receiver_text} {{\n $0\n}}"), - ) - .add_to(acc, ctx.db); - - postfix_snippet( - "lete", - "let Some else {}", - &format!("let Some($1) = {receiver_text} else {{\n $2\n}};\n$0"), - ) - .add_to(acc, ctx.db); - - postfix_snippet( - "while", - "while let Some {}", - &format!("while let Some($1) = {receiver_text} {{\n $0\n}}"), - ) - .add_to(acc, ctx.db); - } - } - } else if receiver_ty.is_bool() || receiver_ty.is_unknown() { - postfix_snippet("if", "if expr {}", &format!("if {receiver_text} {{\n $0\n}}")) - .add_to(acc, ctx.db); - postfix_snippet("while", "while expr {}", &format!("while {receiver_text} {{\n $0\n}}")) - .add_to(acc, ctx.db); - postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db); - } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() { - if receiver_ty.impls_trait(ctx.db, trait_, &[]) { - postfix_snippet( - "for", - "for ele in expr {}", - &format!("for ele in {receiver_text} {{\n $0\n}}"), - ) - .add_to(acc, ctx.db); - } - } - postfix_snippet("ref", "&expr", &format!("&{receiver_text}")).add_to(acc, ctx.db); postfix_snippet("refm", "&mut expr", &format!("&mut {receiver_text}")).add_to(acc, ctx.db); postfix_snippet("deref", "*expr", &format!("*{receiver_text}")).add_to(acc, ctx.db); - let mut block_should_be_wrapped = true; - if dot_receiver.syntax().kind() == BLOCK_EXPR { - block_should_be_wrapped = false; - if let Some(parent) = dot_receiver.syntax().parent() { - if matches!(parent.kind(), IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR) { - block_should_be_wrapped = true; - } - } - }; - let unsafe_completion_string = if block_should_be_wrapped { - format!("unsafe {{ {receiver_text} }}") - } else { - format!("unsafe {receiver_text}") - }; - postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc, ctx.db); - - let const_completion_string = if block_should_be_wrapped { - format!("const {{ {receiver_text} }}") - } else { - format!("const {receiver_text}") - }; - postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db); - // The rest of the postfix completions create an expression that moves an argument, // so it's better to consider references now to avoid breaking the compilation @@ -195,37 +108,6 @@ pub(crate) fn complete_postfix( add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text); } - match try_enum { - Some(try_enum) => match try_enum { - TryEnum::Result => { - postfix_snippet( - "match", - "match expr {}", - &format!("match {receiver_text} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}"), - ) - .add_to(acc, ctx.db); - } - TryEnum::Option => { - postfix_snippet( - "match", - "match expr {}", - &format!( - "match {receiver_text} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}" - ), - ) - .add_to(acc, ctx.db); - } - }, - None => { - postfix_snippet( - "match", - "match expr {}", - &format!("match {receiver_text} {{\n ${{1:_}} => {{$0}},\n}}"), - ) - .add_to(acc, ctx.db); - } - } - postfix_snippet("box", "Box::new(expr)", &format!("Box::new({receiver_text})")) .add_to(acc, ctx.db); postfix_snippet("dbg", "dbg!(expr)", &format!("dbg!({receiver_text})")).add_to(acc, ctx.db); // fixme @@ -233,15 +115,187 @@ pub(crate) fn complete_postfix( postfix_snippet("call", "function(expr)", &format!("${{1}}({receiver_text})")) .add_to(acc, ctx.db); - if let Some(parent) = dot_receiver_including_refs.syntax().parent().and_then(|p| p.parent()) { - if matches!(parent.kind(), STMT_LIST | EXPR_STMT) { - postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) - .add_to(acc, ctx.db); - postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) - .add_to(acc, ctx.db); + let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references()); + let mut is_in_cond = false; + if let Some(parent) = dot_receiver_including_refs.syntax().parent() { + if let Some(second_ancestor) = parent.parent() { + let sec_ancestor_kind = second_ancestor.kind(); + if let Some(expr) = >::cast(second_ancestor) { + is_in_cond = match expr { + Either::Left(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent), + Either::Right(it) => { + it.condition().is_some_and(|cond| *cond.syntax() == parent) + } + } + } + match &try_enum { + Some(try_enum) if is_in_cond => match try_enum { + TryEnum::Result => { + postfix_snippet( + "let", + "let Ok(_)", + &format!("let Ok($0) = {receiver_text}"), + ) + .add_to(acc, ctx.db); + postfix_snippet( + "letm", + "let Ok(mut _)", + &format!("let Ok(mut $0) = {receiver_text}"), + ) + .add_to(acc, ctx.db); + } + TryEnum::Option => { + postfix_snippet( + "let", + "let Some(_)", + &format!("let Some($0) = {receiver_text}"), + ) + .add_to(acc, ctx.db); + postfix_snippet( + "letm", + "let Some(mut _)", + &format!("let Some(mut $0) = {receiver_text}"), + ) + .add_to(acc, ctx.db); + } + }, + _ if matches!(sec_ancestor_kind, STMT_LIST | EXPR_STMT) => { + postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) + .add_to(acc, ctx.db); + postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) + .add_to(acc, ctx.db); + } + _ => (), + } } } + if !is_in_cond { + match try_enum { + Some(try_enum) => match try_enum { + TryEnum::Result => { + postfix_snippet( + "match", + "match expr {}", + &format!("match {receiver_text} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}"), + ) + .add_to(acc, ctx.db); + } + TryEnum::Option => { + postfix_snippet( + "match", + "match expr {}", + &format!( + "match {receiver_text} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}" + ), + ) + .add_to(acc, ctx.db); + } + }, + None => { + postfix_snippet( + "match", + "match expr {}", + &format!("match {receiver_text} {{\n ${{1:_}} => {{$0}},\n}}"), + ) + .add_to(acc, ctx.db); + } + } + if let Some(try_enum) = &try_enum { + match try_enum { + TryEnum::Result => { + postfix_snippet( + "ifl", + "if let Ok {}", + &format!("if let Ok($1) = {receiver_text} {{\n $0\n}}"), + ) + .add_to(acc, ctx.db); + + postfix_snippet( + "lete", + "let Ok else {}", + &format!("let Ok($1) = {receiver_text} else {{\n $2\n}};\n$0"), + ) + .add_to(acc, ctx.db); + + postfix_snippet( + "while", + "while let Ok {}", + &format!("while let Ok($1) = {receiver_text} {{\n $0\n}}"), + ) + .add_to(acc, ctx.db); + } + TryEnum::Option => { + postfix_snippet( + "ifl", + "if let Some {}", + &format!("if let Some($1) = {receiver_text} {{\n $0\n}}"), + ) + .add_to(acc, ctx.db); + + postfix_snippet( + "lete", + "let Some else {}", + &format!("let Some($1) = {receiver_text} else {{\n $2\n}};\n$0"), + ) + .add_to(acc, ctx.db); + + postfix_snippet( + "while", + "while let Some {}", + &format!("while let Some($1) = {receiver_text} {{\n $0\n}}"), + ) + .add_to(acc, ctx.db); + } + } + } else if receiver_ty.is_bool() || receiver_ty.is_unknown() { + postfix_snippet("if", "if expr {}", &format!("if {receiver_text} {{\n $0\n}}")) + .add_to(acc, ctx.db); + postfix_snippet( + "while", + "while expr {}", + &format!("while {receiver_text} {{\n $0\n}}"), + ) + .add_to(acc, ctx.db); + postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db); + } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() { + if receiver_ty.impls_trait(ctx.db, trait_, &[]) { + postfix_snippet( + "for", + "for ele in expr {}", + &format!("for ele in {receiver_text} {{\n $0\n}}"), + ) + .add_to(acc, ctx.db); + } + } + } + + let mut block_should_be_wrapped = true; + if dot_receiver.syntax().kind() == BLOCK_EXPR { + block_should_be_wrapped = false; + if let Some(parent) = dot_receiver.syntax().parent() { + if matches!(parent.kind(), IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR) { + block_should_be_wrapped = true; + } + } + }; + { + let (open_brace, close_brace) = + if block_should_be_wrapped { ("{ ", " }") } else { ("", "") }; + let (open_paren, close_paren) = if is_in_cond { ("(", ")") } else { ("", "") }; + let unsafe_completion_string = format!( + "{}unsafe {}{receiver_text}{}{}", + open_paren, open_brace, close_brace, close_paren + ); + postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc, ctx.db); + + let const_completion_string = format!( + "{}const {}{receiver_text}{}{}", + open_paren, open_brace, close_brace, close_paren + ); + postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db); + } + if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone() { if let Some(literal_text) = ast::String::cast(literal.token()) { add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text); @@ -567,6 +621,54 @@ fn main() { ); } + #[test] + fn option_iflet_cond() { + check( + r#" +//- minicore: option +fn main() { + let bar = Some(true); + if bar.$0 +} +"#, + expect![[r#" + me and(…) fn(self, Option) -> Option + me as_ref() const fn(&self) -> Option<&T> + me ok_or(…) const fn(self, E) -> Result + me unwrap() const fn(self) -> T + me unwrap_or(…) fn(self, T) -> T + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let Some(_) + sn letm let Some(mut _) + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); + check_edit( + "let", + r#" +//- minicore: option +fn main() { + let bar = Some(true); + if bar.$0 +} +"#, + r#" +fn main() { + let bar = Some(true); + if let Some($0) = bar +} +"#, + ); + } + #[test] fn option_letelse() { check_edit( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 00c0b470f987..ba1f96a5b6e1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -3000,18 +3000,18 @@ fn main() { expect![[r#" sn not !expr [snippet] me not() fn(self) -> ::Output [type_could_unify+requires_import] - sn if if expr {} [] - sn while while expr {} [] sn ref &expr [] sn refm &mut expr [] sn deref *expr [] - sn unsafe unsafe {} [] - sn const const {} [] - sn match match expr {} [] sn box Box::new(expr) [] sn dbg dbg!(expr) [] sn dbgr dbg!(&expr) [] sn call function(expr) [] + sn match match expr {} [] + sn if if expr {} [] + sn while while expr {} [] + sn unsafe unsafe {} [] + sn const const {} [] sn return return expr [] "#]], ); @@ -3036,15 +3036,15 @@ fn main() { sn ref &expr [] sn refm &mut expr [] sn deref *expr [] - sn unsafe unsafe {} [] - sn const const {} [] - sn match match expr {} [] sn box Box::new(expr) [] sn dbg dbg!(expr) [] sn dbgr dbg!(&expr) [] sn call function(expr) [] sn let let [] sn letm let mut [] + sn match match expr {} [] + sn unsafe unsafe {} [] + sn const const {} [] sn return return expr [] "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs index 63ce0ddbb8fc..2665dabb6663 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs @@ -10,7 +10,7 @@ use syntax::ast::{self, Pat, make}; use crate::RootDatabase; /// Enum types that implement `std::ops::Try` trait. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum TryEnum { Result, Option, From 7ba853c5e90181edcd139d01e98bfff09f7b0562 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 17 Jun 2025 13:34:54 +0200 Subject: [PATCH 071/356] Better completion test sorting --- .../crates/ide-completion/src/render.rs | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index ba1f96a5b6e1..0732bd965970 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -733,7 +733,7 @@ mod tests { ) { let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None); actual.retain(|it| kinds.contains(&it.kind)); - actual.sort_by_key(|it| cmp::Reverse(it.relevance.score())); + actual.sort_by_key(|it| (cmp::Reverse(it.relevance.score()), it.label.primary.clone())); check_relevance_(actual, expect); } @@ -743,7 +743,7 @@ mod tests { actual.retain(|it| it.kind != CompletionItemKind::Snippet); actual.retain(|it| it.kind != CompletionItemKind::Keyword); actual.retain(|it| it.kind != CompletionItemKind::BuiltinType); - actual.sort_by_key(|it| cmp::Reverse(it.relevance.score())); + actual.sort_by_key(|it| (cmp::Reverse(it.relevance.score()), it.label.primary.clone())); check_relevance_(actual, expect); } @@ -824,9 +824,9 @@ fn main() { st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct { } [type_could_unify] ex dep::test_mod_b::Struct { } [type_could_unify] st Struct Struct [type_could_unify+requires_import] + md dep [] fn main() fn() [] fn test(…) fn(Struct) [] - md dep [] st Struct Struct [requires_import] "#]], ); @@ -862,9 +862,9 @@ fn main() { "#, expect![[r#" un Union Union [type_could_unify+requires_import] + md dep [] fn main() fn() [] fn test(…) fn(Union) [] - md dep [] en Union Union [requires_import] "#]], ); @@ -900,9 +900,9 @@ fn main() { ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type_could_unify] ex dep::test_mod_b::Enum::variant [type_could_unify] en Enum Enum [type_could_unify+requires_import] + md dep [] fn main() fn() [] fn test(…) fn(Enum) [] - md dep [] en Enum Enum [requires_import] "#]], ); @@ -937,9 +937,9 @@ fn main() { expect![[r#" ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type_could_unify] ex dep::test_mod_b::Enum::Variant [type_could_unify] + md dep [] fn main() fn() [] fn test(…) fn(Enum) [] - md dep [] "#]], ); } @@ -967,9 +967,9 @@ fn main() { } "#, expect![[r#" + md dep [] fn main() fn() [] fn test(…) fn(fn(usize) -> i32) [] - md dep [] fn function fn(usize) -> i32 [requires_import] fn function(…) fn(isize) -> i32 [requires_import] "#]], @@ -1000,9 +1000,9 @@ fn main() { "#, expect![[r#" ct CONST i32 [type_could_unify+requires_import] + md dep [] fn main() fn() [] fn test(…) fn(i32) [] - md dep [] ct CONST i64 [requires_import] "#]], ); @@ -1032,9 +1032,9 @@ fn main() { "#, expect![[r#" sc STATIC i32 [type_could_unify+requires_import] + md dep [] fn main() fn() [] fn test(…) fn(i32) [] - md dep [] sc STATIC i64 [requires_import] "#]], ); @@ -1090,8 +1090,8 @@ fn func(input: Struct) { } "#, expect![[r#" - st Struct Struct [type] st Self Self [type] + st Struct Struct [type] sp Self Struct [type] st Struct Struct [type] ex Struct [type] @@ -1119,9 +1119,9 @@ fn main() { "#, expect![[r#" lc input bool [type+name+local] + ex false [type] ex input [type] ex true [type] - ex false [type] lc inputbad i32 [local] fn main() fn() [] fn test(…) fn(bool) [] @@ -2088,9 +2088,9 @@ fn f() { A { bar: b$0 }; } "#, expect![[r#" fn bar() fn() -> u8 [type+name] + ex bar() [type] fn baz() fn() -> u8 [type] ex baz() [type] - ex bar() [type] st A A [] fn f() fn() [] "#]], @@ -2199,8 +2199,8 @@ fn main() { lc s S [type+name+local] st S S [type] st S S [type] - ex s [type] ex S [type] + ex s [type] fn foo(…) fn(&mut S) [] fn main() fn() [] "#]], @@ -2218,8 +2218,8 @@ fn main() { st S S [type] lc ssss S [type+local] st S S [type] - ex ssss [type] ex S [type] + ex ssss [type] fn foo(…) fn(&mut S) [] fn main() fn() [] "#]], @@ -2252,11 +2252,11 @@ fn main() { ex Foo [type] lc foo &Foo [local] lc *foo [type+local] - fn bar(…) fn(Foo) [] - fn main() fn() [] - md core [] tt Clone [] tt Copy [] + fn bar(…) fn(Foo) [] + md core [] + fn main() fn() [] "#]], ); } @@ -2297,9 +2297,9 @@ fn main() { st &S [type] st T T [] st &T [type] + md core [] fn foo(…) fn(&S) [] fn main() fn() [] - md core [] "#]], ) } @@ -2346,9 +2346,9 @@ fn main() { st &mut S [type] st T T [] st &mut T [type] + md core [] fn foo(…) fn(&mut S) [] fn main() fn() [] - md core [] "#]], ) } @@ -2364,8 +2364,8 @@ fn foo(bar: u32) { } "#, expect![[r#" - lc baz i32 [local] lc bar u32 [local] + lc baz i32 [local] fn foo(…) fn(u32) [] "#]], ); @@ -2449,9 +2449,9 @@ fn main() { st &T [type] fn bar() fn() -> T [] fn &bar() [type] + md core [] fn foo(…) fn(&S) [] fn main() fn() [] - md core [] "#]], ) } @@ -2702,8 +2702,8 @@ fn test() { fn fn_builder() fn() -> FooBuilder [type_could_unify] fn fn_ctr_wrapped() fn() -> Option> [type_could_unify] fn fn_ctr_wrapped_2() fn() -> Result, u32> [type_could_unify] - me fn_returns_unit(…) fn(&self) [type_could_unify] fn fn_other() fn() -> Option [type_could_unify] + me fn_returns_unit(…) fn(&self) [type_could_unify] "#]], ); } @@ -2965,12 +2965,12 @@ fn foo() { ev Foo::B Foo::B [type_could_unify] ev Foo::A(…) Foo::A(T) [type_could_unify] lc foo Foo [type+local] - ex foo [type] ex Foo::B [type] + ex foo [type] en Foo Foo<{unknown}> [type_could_unify] - fn foo() fn() [] fn bar() fn() -> Foo [] fn baz() fn() -> Foo [] + fn foo() fn() [] "#]], ); } @@ -3000,19 +3000,19 @@ fn main() { expect![[r#" sn not !expr [snippet] me not() fn(self) -> ::Output [type_could_unify+requires_import] - sn ref &expr [] - sn refm &mut expr [] - sn deref *expr [] sn box Box::new(expr) [] + sn call function(expr) [] + sn const const {} [] sn dbg dbg!(expr) [] sn dbgr dbg!(&expr) [] - sn call function(expr) [] - sn match match expr {} [] + sn deref *expr [] sn if if expr {} [] - sn while while expr {} [] - sn unsafe unsafe {} [] - sn const const {} [] + sn match match expr {} [] + sn ref &expr [] + sn refm &mut expr [] sn return return expr [] + sn unsafe unsafe {} [] + sn while while expr {} [] "#]], ); } @@ -3033,19 +3033,19 @@ fn main() { &[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)], expect![[r#" me f() fn(&self) [] - sn ref &expr [] - sn refm &mut expr [] - sn deref *expr [] sn box Box::new(expr) [] + sn call function(expr) [] + sn const const {} [] sn dbg dbg!(expr) [] sn dbgr dbg!(&expr) [] - sn call function(expr) [] + sn deref *expr [] sn let let [] sn letm let mut [] sn match match expr {} [] - sn unsafe unsafe {} [] - sn const const {} [] + sn ref &expr [] + sn refm &mut expr [] sn return return expr [] + sn unsafe unsafe {} [] "#]], ); } From da831be4034d11297ab02740d52ae454a60dcc6f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 17 Jun 2025 12:00:57 +0000 Subject: [PATCH 072/356] Rustup to rustc 1.89.0-nightly (45acf54ee 2025-06-16) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index d92c80a3d934..a9ca0f23d8be 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-16" +channel = "nightly-2025-06-17" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 442862bc78b24f6019e4f3e32cfe2380dd480f26 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 24 Apr 2025 10:49:06 +0100 Subject: [PATCH 073/356] Don't build `ParamEnv` and do trait solving in `ItemCtxt`s --- compiler/rustc_hir_analysis/src/collect.rs | 70 +++++++- .../src/hir_ty_lowering/errors.rs | 7 +- .../src/hir_ty_lowering/mod.rs | 151 +++++------------- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 76 ++++++++- .../rustc_middle/src/ty/inhabitedness/mod.rs | 10 +- compiler/rustc_type_ir/src/fast_reject.rs | 7 + tests/crashes/136678.rs | 18 --- tests/crashes/138131.rs | 9 +- .../bound_vars_in_args.rs | 23 +++ .../bound_vars_in_args.stderr | 37 +++++ .../bugs/cycle-iat-inside-of-adt.stderr | 33 ---- .../cycle-iat-inside-of-where-predicate.rs | 16 -- ...cycle-iat-inside-of-where-predicate.stderr | 37 ----- .../candidate-with-alias-2.rs | 26 +++ .../candidate-with-alias-2.stderr | 20 +++ .../candidate-with-alias.rs | 27 ++++ .../iat-in-where-bound.rs | 14 ++ ...-inside-of-adt.rs => iat-inside-of-adt.rs} | 9 +- .../inhabited-predicates.rs} | 7 +- .../inhabited-predicates.stderr | 27 ++++ .../multiple-candidates-in-adt-field-1.rs | 23 +++ .../multiple-candidates-in-adt-field-2.rs | 29 ++++ .../multiple-candidates-in-adt-field-2.stderr | 20 +++ .../multiple-candidates-in-adt-field-3.rs | 27 ++++ ...-self-type-differs-shadowing-trait-item.rs | 2 +- ...fers-shadowing-trait-item.uncovered.stderr | 18 +-- .../really_deep_self_ty_mismatch.rs | 26 +++ .../const-generics/mgca/unresolved-iac-1.rs | 11 ++ .../mgca/unresolved-iac-1.stderr | 16 ++ .../const-generics/mgca/unresolved-iac-2.rs | 14 ++ .../mgca/unresolved-iac-2.stderr | 15 ++ 31 files changed, 576 insertions(+), 249 deletions(-) delete mode 100644 tests/crashes/136678.rs create mode 100644 tests/ui/associated-inherent-types/bound_vars_in_args.rs create mode 100644 tests/ui/associated-inherent-types/bound_vars_in_args.stderr delete mode 100644 tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr delete mode 100644 tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs delete mode 100644 tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr create mode 100644 tests/ui/associated-inherent-types/candidate-with-alias-2.rs create mode 100644 tests/ui/associated-inherent-types/candidate-with-alias-2.stderr create mode 100644 tests/ui/associated-inherent-types/candidate-with-alias.rs create mode 100644 tests/ui/associated-inherent-types/iat-in-where-bound.rs rename tests/ui/associated-inherent-types/{bugs/cycle-iat-inside-of-adt.rs => iat-inside-of-adt.rs} (61%) rename tests/{crashes/125879.rs => ui/associated-inherent-types/inhabited-predicates.rs} (50%) create mode 100644 tests/ui/associated-inherent-types/inhabited-predicates.stderr create mode 100644 tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs create mode 100644 tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs create mode 100644 tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr create mode 100644 tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs create mode 100644 tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs create mode 100644 tests/ui/const-generics/mgca/unresolved-iac-1.rs create mode 100644 tests/ui/const-generics/mgca/unresolved-iac-1.stderr create mode 100644 tests/ui/const-generics/mgca/unresolved-iac-2.rs create mode 100644 tests/ui/const-generics/mgca/unresolved-iac-2.stderr diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 6e22ac5a28a8..fd8c702a76b3 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -34,16 +34,22 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions}; +use rustc_middle::ty::{ + self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions, +}; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::{ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations}; +use rustc_trait_selection::traits::{ + FulfillmentError, ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations, +}; use tracing::{debug, instrument}; use crate::errors; -use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; +use crate::hir_ty_lowering::{ + FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason, +}; pub(crate) mod dump; mod generics_of; @@ -364,6 +370,64 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident)) } + #[instrument(level = "debug", skip(self, _span), ret)] + fn select_inherent_assoc_candidates( + &self, + _span: Span, + self_ty: Ty<'tcx>, + candidates: Vec, + ) -> (Vec, Vec>) { + assert!(!self_ty.has_infer()); + + // We don't just call the normal normalization routine here as we can't provide the + // correct `ParamEnv` and it seems dubious to invoke arbitrary trait solving under + // the wrong `ParamEnv`. Expanding free aliases doesn't need a `ParamEnv` so we do + // this just to make resolution a little bit smarter. + let self_ty = self.tcx.expand_free_alias_tys(self_ty); + debug!("select_inherent_assoc_candidates: self_ty={:?}", self_ty); + + // We make an infcx and replace any escaping vars with placeholders so that IAT res + // with type/const bound vars in arguments is slightly smarter. `for >::IAT` + // would otherwise unify with `impl Foo` when ideally we would not. + let infcx = self.tcx().infer_ctxt().build(TypingMode::non_body_analysis()); + let mut universes = if self_ty.has_escaping_bound_vars() { + vec![None; self_ty.outer_exclusive_binder().as_usize()] + } else { + vec![] + }; + let candidates = + rustc_trait_selection::traits::with_replaced_escaping_bound_vars( + &infcx, + &mut universes, + self_ty, + |self_ty| { + candidates + .into_iter() + .filter(|&InherentAssocCandidate { impl_, .. }| { + let impl_ty = self.tcx().type_of(impl_).instantiate_identity(); + + // See comment on doing this operation for `self_ty` + let impl_ty = self.tcx.expand_free_alias_tys(impl_ty); + debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty); + + // We treat parameters in the self ty as rigid and parameters in the impl ty as infers + // because it allows `impl Foo` to unify with `Foo::IAT`, while also disallowing + // `Foo::IAT` from unifying with `impl Foo`. + // + // We don't really care about a depth limit here because we're only working with user-written types + // and if they wrote a type that would take hours to walk then that's kind of on them. On the other + // hand the default depth limit is relatively low and could realistically be hit by users in normal + // cases. + ty::DeepRejectCtxt::relate_rigid_infer(self.tcx) + .types_may_unify_with_depth(self_ty, impl_ty, usize::MAX) + }) + .collect() + }, + ); + + (candidates, vec![]) + } + fn lower_assoc_item_path( &self, span: Span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 45fee0fa4024..f62e149191da 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -26,6 +26,7 @@ use rustc_trait_selection::traits::{ use smallvec::SmallVec; use tracing::debug; +use super::InherentAssocCandidate; use crate::errors::{ self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, @@ -742,7 +743,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, name: Ident, self_ty: Ty<'tcx>, - candidates: Vec<(DefId, (DefId, DefId))>, + candidates: Vec, fulfillment_errors: Vec>, span: Span, assoc_tag: ty::AssocTag, @@ -776,8 +777,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let type_candidates = candidates .iter() .take(limit) - .map(|&(impl_, _)| { - format!("- `{}`", tcx.at(span).type_of(impl_).instantiate_identity()) + .map(|cand| { + format!("- `{}`", tcx.at(span).type_of(cand.impl_).instantiate_identity()) }) .collect::>() .join("\n"); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index bf407cbaccb5..b99f7b44661e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -33,13 +33,14 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; +use rustc_infer::traits::DynCompatibilityViolation; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, TypingMode, Upcast, fold_regions, + self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, + TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -47,7 +48,7 @@ use rustc_session::parse::feature_err; use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; -use rustc_trait_selection::traits::{self, ObligationCtxt}; +use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; use crate::check::check_abi_fn_ptr; @@ -99,6 +100,13 @@ pub enum RegionInferReason<'a> { OutlivesBound, } +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Debug)] +pub struct InherentAssocCandidate { + pub impl_: DefId, + pub assoc_item: DefId, + pub scope: DefId, +} + /// A context which can lower type-system entities from the [HIR][hir] to /// the [`rustc_middle::ty`] representation. /// @@ -148,6 +156,13 @@ pub trait HirTyLowerer<'tcx> { assoc_ident: Ident, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>; + fn select_inherent_assoc_candidates( + &self, + span: Span, + self_ty: Ty<'tcx>, + candidates: Vec, + ) -> (Vec, Vec>); + /// Lower a path to an associated item (of a trait) to a projection. /// /// This method has to be defined by the concrete lowering context because @@ -1449,48 +1464,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .filter_map(|&impl_| { let (item, scope) = self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?; - Some((impl_, (item.def_id, scope))) + Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope }) }) .collect(); - if candidates.is_empty() { - return Ok(None); - } + let (applicable_candidates, fulfillment_errors) = + self.select_inherent_assoc_candidates(span, self_ty, candidates.clone()); - // - // Select applicable inherent associated type candidates modulo regions. - // + let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } = + match &applicable_candidates[..] { + &[] => Err(self.report_unresolved_inherent_assoc_item( + name, + self_ty, + candidates, + fulfillment_errors, + span, + assoc_tag, + )), - // In contexts that have no inference context, just make a new one. - // We do need a local variable to store it, though. - let infcx = match self.infcx() { - Some(infcx) => infcx, - None => { - assert!(!self_ty.has_infer()); - &tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()) - } - }; + &[applicable_candidate] => Ok(applicable_candidate), - // FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors - // when inside of an ADT (#108491) or where clause. - let param_env = tcx.param_env(block.owner); - - let mut universes = if self_ty.has_escaping_bound_vars() { - vec![None; self_ty.outer_exclusive_binder().as_usize()] - } else { - vec![] - }; - - let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars( - infcx, - &mut universes, - self_ty, - |self_ty| { - self.select_inherent_assoc_candidates( - infcx, name, span, self_ty, param_env, candidates, assoc_tag, - ) - }, - )?; + &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item( + name, + candidates.into_iter().map(|cand| cand.assoc_item).collect(), + span, + )), + }?; self.check_assoc_item(assoc_item, name, def_scope, block, span); @@ -1507,78 +1506,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok(Some((assoc_item, args))) } - fn select_inherent_assoc_candidates( - &self, - infcx: &InferCtxt<'tcx>, - name: Ident, - span: Span, - self_ty: Ty<'tcx>, - param_env: ParamEnv<'tcx>, - candidates: Vec<(DefId, (DefId, DefId))>, - assoc_tag: ty::AssocTag, - ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> { - let tcx = self.tcx(); - let mut fulfillment_errors = Vec::new(); - - let applicable_candidates: Vec<_> = candidates - .iter() - .copied() - .filter(|&(impl_, _)| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new_with_diagnostics(infcx); - let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty); - - let impl_args = infcx.fresh_args_for_item(span, impl_); - let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); - let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty); - - // Check that the self types can be related. - if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() { - return false; - } - - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); - let impl_bounds = - ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds); - let impl_obligations = traits::predicates_for_generics( - |_, _| ObligationCause::dummy(), - param_env, - impl_bounds, - ); - ocx.register_obligations(impl_obligations); - - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return false; - } - - true - }) - }) - .collect(); - - match &applicable_candidates[..] { - &[] => Err(self.report_unresolved_inherent_assoc_item( - name, - self_ty, - candidates, - fulfillment_errors, - span, - assoc_tag, - )), - - &[applicable_candidate] => Ok(applicable_candidate), - - &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item( - name, - applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(), - span, - )), - } - } - /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1]. /// /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e979798a4029..d8efb0aac4d7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -12,7 +12,9 @@ use hir::def_id::CRATE_DEF_ID; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, HirId, ItemLocalMap}; -use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; +use rustc_hir_analysis::hir_ty_lowering::{ + HirTyLowerer, InherentAssocCandidate, RegionInferReason, +}; use rustc_infer::infer; use rustc_infer::traits::{DynCompatibilityViolation, Obligation}; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; @@ -20,7 +22,9 @@ use rustc_session::Session; use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym}; use rustc_trait_selection::error_reporting::TypeErrCtxt; use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations; -use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; +use rustc_trait_selection::traits::{ + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, +}; use crate::coercion::DynamicCoerceMany; use crate::fallback::DivergingFallbackBehavior; @@ -310,6 +314,74 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { )) } + fn select_inherent_assoc_candidates( + &self, + span: Span, + self_ty: Ty<'tcx>, + candidates: Vec, + ) -> (Vec, Vec>) { + let tcx = self.tcx(); + let infcx = &self.infcx; + + let mut universes = if self_ty.has_escaping_bound_vars() { + vec![None; self_ty.outer_exclusive_binder().as_usize()] + } else { + vec![] + }; + + let mut fulfillment_errors = vec![]; + let candidates = + traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| { + candidates + .into_iter() + .filter(|&InherentAssocCandidate { impl_, .. }| { + infcx.probe(|_| { + let ocx = ObligationCtxt::new_with_diagnostics(self); + let self_ty = + ocx.normalize(&ObligationCause::dummy(), self.param_env, self_ty); + + let impl_args = infcx.fresh_args_for_item(span, impl_); + let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); + let impl_ty = + ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty); + + // Check that the self types can be related. + if ocx + .eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty) + .is_err() + { + return false; + } + + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); + let impl_bounds = ocx.normalize( + &ObligationCause::dummy(), + self.param_env, + impl_bounds, + ); + let impl_obligations = traits::predicates_for_generics( + |_, _| ObligationCause::dummy(), + self.param_env, + impl_bounds, + ); + ocx.register_obligations(impl_obligations); + + let mut errors = ocx.select_where_possible(); + if !errors.is_empty() { + fulfillment_errors.append(&mut errors); + return false; + } + + true + }) + }) + .collect() + }); + + (candidates, fulfillment_errors) + } + fn lower_assoc_item_path( &self, span: Span, diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index d8bab58545fc..2a336cc21f49 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -127,7 +127,9 @@ impl<'tcx> Ty<'tcx> { InhabitedPredicate::True } Never => InhabitedPredicate::False, - Param(_) | Alias(ty::Projection | ty::Free, _) => InhabitedPredicate::GenericType(self), + Param(_) | Alias(ty::Inherent | ty::Projection | ty::Free, _) => { + InhabitedPredicate::GenericType(self) + } Alias(ty::Opaque, alias_ty) => { match alias_ty.def_id.as_local() { // Foreign opaque is considered inhabited. @@ -139,12 +141,6 @@ impl<'tcx> Ty<'tcx> { } } } - // FIXME(inherent_associated_types): Most likely we can just map to `GenericType` like above. - // However it's unclear if the args passed to `InhabitedPredicate::instantiate` are of the correct - // format, i.e. don't contain parent args. If you hit this case, please verify this beforehand. - Alias(ty::Inherent, _) => { - bug!("unimplemented: inhabitedness checking for inherent projections") - } Tuple(tys) if tys.is_empty() => InhabitedPredicate::True, // use a query for more complex cases Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self), diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index fa5e8d43702c..a5d461c57cd4 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -240,6 +240,13 @@ impl bool { + if lhs == rhs { + return true; + } + self.types_may_unify_inner(lhs, rhs, depth_limit) + } + fn args_may_unify_inner( self, obligation_args: I::GenericArgs, diff --git a/tests/crashes/136678.rs b/tests/crashes/136678.rs deleted file mode 100644 index e7d7de23bfeb..000000000000 --- a/tests/crashes/136678.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #136678 -#![feature(inherent_associated_types)] -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - -struct B; - -struct Test; - -impl Test { - type B = B<{ A }>; - - fn test(a: Self::B) -> Self::B { - a - } -} - -pub fn main() {} diff --git a/tests/crashes/138131.rs b/tests/crashes/138131.rs index f400c02de8d6..d0f91b748401 100644 --- a/tests/crashes/138131.rs +++ b/tests/crashes/138131.rs @@ -1,12 +1,15 @@ //@ known-bug: #138131 -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] + +#![feature(min_generic_const_args, generic_const_items)] + +const BAR<'a>: usize = 10; + struct Foo<'a> { x: &'a (), } impl<'a> Foo<'a> { - fn foo(_: [u8; Foo::X]) {} + fn foo(_: [u8; BAR]) {} } fn main() {} diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.rs b/tests/ui/associated-inherent-types/bound_vars_in_args.rs new file mode 100644 index 000000000000..276e3cf1da04 --- /dev/null +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.rs @@ -0,0 +1,23 @@ +#![feature(non_lifetime_binders, inherent_associated_types)] +#![expect(incomplete_features)] + +// Test that we can resolve to the right IAT when the self type +// contains a bound type. + +struct Foo(T); + +impl Foo<[u8]> { + type IAT = u8; +} + +impl Foo { + type IAT = u8; +} + +struct Bar +//~^ ERROR: the size for values of type `T` cannot be known at compilation time +//~| ERROR: the size for values of type `T` cannot be known at compilation time +where + for Foo::IAT: Sized; + +fn main() {} diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.stderr b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr new file mode 100644 index 000000000000..108f1e531af6 --- /dev/null +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr @@ -0,0 +1,37 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bound_vars_in_args.rs:17:1 + | +LL | struct Bar + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `T` +note: required by a bound in `Foo::IAT` + --> $DIR/bound_vars_in_args.rs:13:9 + | +LL | impl Foo { + | ^^^^^ required by this bound in `Foo::IAT` +LL | type IAT = u8; + | --- required by a bound in this associated type + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/bound_vars_in_args.rs:17:1 + | +LL | / struct Bar +LL | | +LL | | +LL | | where +LL | | for Foo::IAT: Sized; + | |______________________________^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `T` +note: required by a bound in `Foo::IAT` + --> $DIR/bound_vars_in_args.rs:13:9 + | +LL | impl Foo { + | ^^^^^ required by this bound in `Foo::IAT` +LL | type IAT = u8; + | --- required by a bound in this associated type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr deleted file mode 100644 index 7f8ed8985252..000000000000 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0391]: cycle detected when computing predicates of `Foo` - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ - | -note: ...which requires computing inferred outlives-predicates of `Foo`... - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ - = note: ...which requires computing the inferred outlives-predicates for items in this crate... -note: ...which requires computing type of `Foo::bar`... - --> $DIR/cycle-iat-inside-of-adt.rs:8:5 - | -LL | bar: Self::Bar, - | ^^^^^^^^^^^^^^ -note: ...which requires computing normalized predicates of `Foo`... - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ - = note: ...which again requires computing predicates of `Foo`, completing the cycle -note: cycle used when checking that `Foo` is well-formed - --> $DIR/cycle-iat-inside-of-adt.rs:7:1 - | -LL | struct Foo { - | ^^^^^^^^^^ - = 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: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs deleted file mode 100644 index 902094b98628..000000000000 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: unknown - -#![feature(inherent_associated_types)] -#![allow(incomplete_features)] - -// FIXME(inherent_associated_types): This shouldn't lead to a cycle error. - -fn user() where S::P: std::fmt::Debug {} - -struct S; - -impl S { - type P = (); -} - -fn main() {} diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr b/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr deleted file mode 100644 index e97a5df9d491..000000000000 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-where-predicate.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0391]: cycle detected when computing predicates of `user` - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user() where S::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires computing explicit predicates of `user`... - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user() where S::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires computing normalized predicates of `user`... - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user() where S::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing predicates of `user`, completing the cycle -note: cycle used when checking that `user` is well-formed - --> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1 - | -LL | fn user() where S::P: std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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[E0392]: type parameter `T` is never used - --> $DIR/cycle-iat-inside-of-where-predicate.rs:10:10 - | -LL | struct S; - | ^ unused type parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0391, E0392. -For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/associated-inherent-types/candidate-with-alias-2.rs b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs new file mode 100644 index 000000000000..d7be825a9c22 --- /dev/null +++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs @@ -0,0 +1,26 @@ +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +trait Identity { + type Assoc; +} +impl Identity for T { + type Assoc = T; +} + +struct Foo(T); +impl Foo<::Assoc> { + type Inherent = u8; +} +impl Foo<::Assoc> { + type Inherent = u32; +} + +struct Bar { + field: >::Inherent, + //~^ ERROR: multiple applicable items in scope +} + +fn main() { + Bar { field: 10_u8 }; +} diff --git a/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr b/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr new file mode 100644 index 000000000000..335e35a95778 --- /dev/null +++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/candidate-with-alias-2.rs:20:23 + | +LL | field: >::Inherent, + | ^^^^^^^^ multiple `Inherent` found + | +note: candidate #1 is defined in an impl for the type `Foo<::Assoc>` + --> $DIR/candidate-with-alias-2.rs:13:5 + | +LL | type Inherent = u8; + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo<::Assoc>` + --> $DIR/candidate-with-alias-2.rs:16:5 + | +LL | type Inherent = u32; + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/associated-inherent-types/candidate-with-alias.rs b/tests/ui/associated-inherent-types/candidate-with-alias.rs new file mode 100644 index 000000000000..d4dd002a7741 --- /dev/null +++ b/tests/ui/associated-inherent-types/candidate-with-alias.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +trait Identity { + type Assoc; +} +impl Identity for T { + type Assoc = T; +} + +struct Foo(T); +impl Foo<::Assoc> { + type Inherent = u8; +} +impl Foo { + type Inherent = u32; +} + +struct Bar { + field: >::Inherent, +} + +fn main() { + Bar { field: 10_u8 }; +} diff --git a/tests/ui/associated-inherent-types/iat-in-where-bound.rs b/tests/ui/associated-inherent-types/iat-in-where-bound.rs new file mode 100644 index 000000000000..3b8b95eec9a4 --- /dev/null +++ b/tests/ui/associated-inherent-types/iat-in-where-bound.rs @@ -0,0 +1,14 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +fn user() where S::P: std::fmt::Debug {} + +struct S(T); + +impl S { + type P = (); +} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs b/tests/ui/associated-inherent-types/iat-inside-of-adt.rs similarity index 61% rename from tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs rename to tests/ui/associated-inherent-types/iat-inside-of-adt.rs index 64168cb8c14f..3d88016d0f87 100644 --- a/tests/ui/associated-inherent-types/bugs/cycle-iat-inside-of-adt.rs +++ b/tests/ui/associated-inherent-types/iat-inside-of-adt.rs @@ -1,8 +1,7 @@ -//@ known-bug: #108491 +//@ check-pass #![feature(inherent_associated_types)] #![allow(incomplete_features)] -// FIXME(inherent_associated_types): This should pass. struct Foo { bar: Self::Bar, @@ -11,4 +10,8 @@ impl Foo { pub type Bar = usize; } -fn main() {} +fn main() { + Foo { + bar: 10_usize, + }; +} diff --git a/tests/crashes/125879.rs b/tests/ui/associated-inherent-types/inhabited-predicates.rs similarity index 50% rename from tests/crashes/125879.rs rename to tests/ui/associated-inherent-types/inhabited-predicates.rs index 4318842e4551..2b041d4e1be2 100644 --- a/tests/crashes/125879.rs +++ b/tests/ui/associated-inherent-types/inhabited-predicates.rs @@ -1,8 +1,10 @@ -//@ known-bug: rust-lang/rust#125879 +//@ check-pass + #![feature(inherent_associated_types)] -#![allow(incomplete_features)] +#![expect(incomplete_features)] pub type PubAlias0 = PubTy::PrivAssocTy; +//~^ WARN: associated type `PubTy::PrivAssocTy` is more private than the item `PubAlias0` pub struct PubTy; impl PubTy { @@ -10,6 +12,7 @@ impl PubTy { } pub struct S(pub PubAlias0); +//~^ WARN: associated type `PubTy::PrivAssocTy` is more private than the item `S::0` pub unsafe fn foo(a: S) -> S { a diff --git a/tests/ui/associated-inherent-types/inhabited-predicates.stderr b/tests/ui/associated-inherent-types/inhabited-predicates.stderr new file mode 100644 index 000000000000..e43cd034e675 --- /dev/null +++ b/tests/ui/associated-inherent-types/inhabited-predicates.stderr @@ -0,0 +1,27 @@ +warning: associated type `PubTy::PrivAssocTy` is more private than the item `PubAlias0` + --> $DIR/inhabited-predicates.rs:6:1 + | +LL | pub type PubAlias0 = PubTy::PrivAssocTy; + | ^^^^^^^^^^^^^^^^^^ type alias `PubAlias0` is reachable at visibility `pub` + | +note: but associated type `PubTy::PrivAssocTy` is only usable at visibility `pub(crate)` + --> $DIR/inhabited-predicates.rs:11:5 + | +LL | type PrivAssocTy = (); + | ^^^^^^^^^^^^^^^^ + = note: `#[warn(private_interfaces)]` on by default + +warning: associated type `PubTy::PrivAssocTy` is more private than the item `S::0` + --> $DIR/inhabited-predicates.rs:14:14 + | +LL | pub struct S(pub PubAlias0); + | ^^^^^^^^^^^^^ field `S::0` is reachable at visibility `pub` + | +note: but associated type `PubTy::PrivAssocTy` is only usable at visibility `pub(crate)` + --> $DIR/inhabited-predicates.rs:11:5 + | +LL | type PrivAssocTy = (); + | ^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs new file mode 100644 index 000000000000..7723ee9c58d9 --- /dev/null +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-1.rs @@ -0,0 +1,23 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Test that when resolving an IAT we select candidates based +// off whether the self type matches not just the name of the IAT + +struct Foo(T); +impl Foo { + type Inherent = u8; +} +impl Foo { + type Inherent = u32; +} + +struct Bar { + field: >::Inherent, +} + +fn main() { + Bar { field: 10_u32 }; +} diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs new file mode 100644 index 000000000000..b942c303d3e8 --- /dev/null +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs @@ -0,0 +1,29 @@ +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Test that when we have an unnormalized projection we don't normalize it +// to determine which IAT to resolve to. + +struct Foo(T); +impl Foo { + type Inherent = u16; +} +impl Foo { + type Inherent = u32; +} + +struct Bar { + field: ::This>>::Inherent, + //~^ ERROR: multiple applicable items in scope +} + +trait Identity { + type This; +} +impl Identity for T { type This = T; } + +fn main() { + Bar { + field: 1_u16, + }; +} diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr new file mode 100644 index 000000000000..df8c124f77fa --- /dev/null +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/multiple-candidates-in-adt-field-2.rs:16:43 + | +LL | field: ::This>>::Inherent, + | ^^^^^^^^ multiple `Inherent` found + | +note: candidate #1 is defined in an impl for the type `Foo` + --> $DIR/multiple-candidates-in-adt-field-2.rs:9:5 + | +LL | type Inherent = u16; + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo` + --> $DIR/multiple-candidates-in-adt-field-2.rs:12:5 + | +LL | type Inherent = u32; + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs new file mode 100644 index 000000000000..4c5b382463d5 --- /dev/null +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-3.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![feature(inherent_associated_types, lazy_type_alias)] +#![expect(incomplete_features)] + +// Test that we *do* normalize free aliases in order to resolve +// between multiple IAT candidates + +type Free = u8; + +struct Foo(T); +impl Foo { + type Assoc = u16; +} +impl Foo { + type Assoc = u32; +} + +struct Bar { + field: >::Assoc, +} + +fn main() { + Bar { + field: 1_u16, + }; +} diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs index c205cb800d2f..337fd8fa00c5 100644 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs +++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs @@ -27,5 +27,5 @@ impl S<()> { fn main() { let _: S::::Pr = (); //[shadowed]~^ ERROR associated type `Pr` not found - //[uncovered]~^^ ERROR ambiguous associated type + //[uncovered]~^^ ERROR associated type `Pr` not found } diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr index 3e914e0538d0..f35158c5b410 100644 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr +++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr @@ -1,15 +1,15 @@ -error[E0223]: ambiguous associated type - --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:12 +error[E0220]: associated type `Pr` not found for `S` in the current scope + --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23 | +LL | struct S(T); + | ----------- associated type `Pr` not found for this struct +... LL | let _: S::::Pr = (); - | ^^^^^^^^^^^^^ - | -help: use fully-qualified syntax - | -LL - let _: S::::Pr = (); -LL + let _: as Tr>::Pr = (); + | ^^ associated item not found in `S` | + = note: the associated type was found for + error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0223`. +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs b/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs new file mode 100644 index 000000000000..eac33f631bbc --- /dev/null +++ b/tests/ui/associated-inherent-types/really_deep_self_ty_mismatch.rs @@ -0,0 +1,26 @@ +//@ check-pass + +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Test that IAT resolution doesn't bail out when the self type is +// very nested. + +struct Foo(T); +#[rustfmt::skip] +impl Foo>>>>>>>>>> { + type Inherent = u16; +} +#[rustfmt::skip] +impl Foo>>>>>>>>>> { + type Inherent = u32; +} + +#[rustfmt::skip] +struct Bar { + field: >>>>>>>>>>>::Inherent, +} + +fn main() { + Bar { field: 1_u16 }; +} diff --git a/tests/ui/const-generics/mgca/unresolved-iac-1.rs b/tests/ui/const-generics/mgca/unresolved-iac-1.rs new file mode 100644 index 000000000000..a0700aa5b65f --- /dev/null +++ b/tests/ui/const-generics/mgca/unresolved-iac-1.rs @@ -0,0 +1,11 @@ +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +struct A(Box<[u8; Box::b]>); +//~^ ERROR: associated constant `b` not found for + +impl A { + fn c(self) { self.0.d() } +} +fn main() {} diff --git a/tests/ui/const-generics/mgca/unresolved-iac-1.stderr b/tests/ui/const-generics/mgca/unresolved-iac-1.stderr new file mode 100644 index 000000000000..4bf1191e786a --- /dev/null +++ b/tests/ui/const-generics/mgca/unresolved-iac-1.stderr @@ -0,0 +1,16 @@ +error[E0220]: associated constant `b` not found for `Box<{type error}, {type error}>` in the current scope + --> $DIR/unresolved-iac-1.rs:5:24 + | +LL | struct A(Box<[u8; Box::b]>); + | ^ associated item not found in `Box<{type error}, {type error}>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: associated constant `b` not found for this struct + | + = note: the associated constant was found for + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/const-generics/mgca/unresolved-iac-2.rs b/tests/ui/const-generics/mgca/unresolved-iac-2.rs new file mode 100644 index 000000000000..72bb5d7f627a --- /dev/null +++ b/tests/ui/const-generics/mgca/unresolved-iac-2.rs @@ -0,0 +1,14 @@ +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +struct Foo<'a> { + x: &'a (), +} + +impl<'a> Foo<'a> { + fn foo(_: [u8; Foo::X]) {} + //~^ ERROR: associated constant `X` not found for `Foo<'_>` in the current scope +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/unresolved-iac-2.stderr b/tests/ui/const-generics/mgca/unresolved-iac-2.stderr new file mode 100644 index 000000000000..a6c12877a4e0 --- /dev/null +++ b/tests/ui/const-generics/mgca/unresolved-iac-2.stderr @@ -0,0 +1,15 @@ +error[E0220]: associated constant `X` not found for `Foo<'_>` in the current scope + --> $DIR/unresolved-iac-2.rs:10:25 + | +LL | struct Foo<'a> { + | -------------- associated constant `X` not found for this struct +... +LL | fn foo(_: [u8; Foo::X]) {} + | ^ associated item not found in `Foo<'_>` + | + = note: the associated constant was found for + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0220`. From 2a950b5637febcf7e526942d6755698defcec2a6 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 27 May 2025 18:21:24 +0100 Subject: [PATCH 074/356] Test whether we use DeepRejectCtxt --- compiler/rustc_hir_analysis/src/collect.rs | 12 ++++--- .../impl_params_are_infers.rs | 34 +++++++++++++++++++ .../impl_params_are_infers.stderr | 20 +++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 tests/ui/associated-inherent-types/impl_params_are_infers.rs create mode 100644 tests/ui/associated-inherent-types/impl_params_are_infers.stderr diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index fd8c702a76b3..ea4194079a63 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -414,10 +414,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { // because it allows `impl Foo` to unify with `Foo::IAT`, while also disallowing // `Foo::IAT` from unifying with `impl Foo`. // - // We don't really care about a depth limit here because we're only working with user-written types - // and if they wrote a type that would take hours to walk then that's kind of on them. On the other - // hand the default depth limit is relatively low and could realistically be hit by users in normal - // cases. + // We don't really care about a depth limit here because we're only working with user-written + // types and if they wrote a type that would take hours to walk then that's kind of on them. On + // the other hand the default depth limit is relatively low and could realistically be hit by + // users in normal cases. + // + // `DeepRejectCtxt` leads to slightly worse IAT resolution than real type equality in cases + // where the `impl_ty` has repeated uses of generic parameters. E.g. `impl Foo` would + // be considered a valid candidate when resolving `Foo::IAT`. ty::DeepRejectCtxt::relate_rigid_infer(self.tcx) .types_may_unify_with_depth(self_ty, impl_ty, usize::MAX) }) diff --git a/tests/ui/associated-inherent-types/impl_params_are_infers.rs b/tests/ui/associated-inherent-types/impl_params_are_infers.rs new file mode 100644 index 000000000000..55d29a35a231 --- /dev/null +++ b/tests/ui/associated-inherent-types/impl_params_are_infers.rs @@ -0,0 +1,34 @@ +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Test whether IAT resolution in item signatures will actually instantiate the +// impl's params with infers before equating self types, or if we "cheat" and +// use a heuristic (e.g. DeepRejectCtxt). + +struct Foo(T, U, V); + +impl Foo { + type IAT = u8; +} + +impl Foo { + type IAT = u16; +} + +trait Identity { + type This; +} +impl Identity for T { + type This = T; +} + +struct Bar { + // It would be illegal to resolve to `Foo::IAT` as `T` and `U` are + // different types. However, currently we treat all impl-side params sort of like + // they're infers and assume they can unify with anything, so we consider it a + // valid candidate. + field: Foo::This>::IAT, + //~^ ERROR: multiple applicable items in scope +} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/impl_params_are_infers.stderr b/tests/ui/associated-inherent-types/impl_params_are_infers.stderr new file mode 100644 index 000000000000..fd31693cbedc --- /dev/null +++ b/tests/ui/associated-inherent-types/impl_params_are_infers.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/impl_params_are_infers.rs:30:48 + | +LL | field: Foo::This>::IAT, + | ^^^ multiple `IAT` found + | +note: candidate #1 is defined in an impl for the type `Foo` + --> $DIR/impl_params_are_infers.rs:11:5 + | +LL | type IAT = u8; + | ^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo` + --> $DIR/impl_params_are_infers.rs:15:5 + | +LL | type IAT = u16; + | ^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. From 9961747414891126720b22050f2b049f0e2457c7 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 17 Jun 2025 14:28:46 +0100 Subject: [PATCH 075/356] rebase --- tests/ui/const-generics/mgca/unresolved-iac-1.rs | 11 ----------- .../const-generics/mgca/unresolved-iac-1.stderr | 16 ---------------- tests/ui/const-generics/mgca/unresolved-iac-2.rs | 14 -------------- .../const-generics/mgca/unresolved-iac-2.stderr | 15 --------------- 4 files changed, 56 deletions(-) delete mode 100644 tests/ui/const-generics/mgca/unresolved-iac-1.rs delete mode 100644 tests/ui/const-generics/mgca/unresolved-iac-1.stderr delete mode 100644 tests/ui/const-generics/mgca/unresolved-iac-2.rs delete mode 100644 tests/ui/const-generics/mgca/unresolved-iac-2.stderr diff --git a/tests/ui/const-generics/mgca/unresolved-iac-1.rs b/tests/ui/const-generics/mgca/unresolved-iac-1.rs deleted file mode 100644 index a0700aa5b65f..000000000000 --- a/tests/ui/const-generics/mgca/unresolved-iac-1.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -#![expect(incomplete_features)] - -struct A(Box<[u8; Box::b]>); -//~^ ERROR: associated constant `b` not found for - -impl A { - fn c(self) { self.0.d() } -} -fn main() {} diff --git a/tests/ui/const-generics/mgca/unresolved-iac-1.stderr b/tests/ui/const-generics/mgca/unresolved-iac-1.stderr deleted file mode 100644 index 4bf1191e786a..000000000000 --- a/tests/ui/const-generics/mgca/unresolved-iac-1.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0220]: associated constant `b` not found for `Box<{type error}, {type error}>` in the current scope - --> $DIR/unresolved-iac-1.rs:5:24 - | -LL | struct A(Box<[u8; Box::b]>); - | ^ associated item not found in `Box<{type error}, {type error}>` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL - | - = note: associated constant `b` not found for this struct - | - = note: the associated constant was found for - - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/const-generics/mgca/unresolved-iac-2.rs b/tests/ui/const-generics/mgca/unresolved-iac-2.rs deleted file mode 100644 index 72bb5d7f627a..000000000000 --- a/tests/ui/const-generics/mgca/unresolved-iac-2.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(min_generic_const_args)] -#![feature(inherent_associated_types)] -#![expect(incomplete_features)] - -struct Foo<'a> { - x: &'a (), -} - -impl<'a> Foo<'a> { - fn foo(_: [u8; Foo::X]) {} - //~^ ERROR: associated constant `X` not found for `Foo<'_>` in the current scope -} - -fn main() {} diff --git a/tests/ui/const-generics/mgca/unresolved-iac-2.stderr b/tests/ui/const-generics/mgca/unresolved-iac-2.stderr deleted file mode 100644 index a6c12877a4e0..000000000000 --- a/tests/ui/const-generics/mgca/unresolved-iac-2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0220]: associated constant `X` not found for `Foo<'_>` in the current scope - --> $DIR/unresolved-iac-2.rs:10:25 - | -LL | struct Foo<'a> { - | -------------- associated constant `X` not found for this struct -... -LL | fn foo(_: [u8; Foo::X]) {} - | ^ associated item not found in `Foo<'_>` - | - = note: the associated constant was found for - - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0220`. From ae65625252df45569940336bea6df8fe0c4826e6 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 17 Jun 2025 14:45:47 +0100 Subject: [PATCH 076/356] Dont replace escaping bound vars in item sigs --- compiler/rustc_hir_analysis/src/collect.rs | 72 ++++++++---------- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 75 +++++++++---------- tests/crashes/138131.rs | 15 ---- .../bound_vars_in_args.rs | 3 +- .../bound_vars_in_args.stderr | 41 +++------- .../issue-109299-1.rs | 4 +- .../issue-109299-1.stderr | 28 +------ 7 files changed, 80 insertions(+), 158 deletions(-) delete mode 100644 tests/crashes/138131.rs diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ea4194079a63..176d955bf032 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -380,54 +380,44 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { assert!(!self_ty.has_infer()); // We don't just call the normal normalization routine here as we can't provide the - // correct `ParamEnv` and it seems dubious to invoke arbitrary trait solving under + // correct `ParamEnv` and it would be wrong to invoke arbitrary trait solving under // the wrong `ParamEnv`. Expanding free aliases doesn't need a `ParamEnv` so we do // this just to make resolution a little bit smarter. let self_ty = self.tcx.expand_free_alias_tys(self_ty); debug!("select_inherent_assoc_candidates: self_ty={:?}", self_ty); - // We make an infcx and replace any escaping vars with placeholders so that IAT res - // with type/const bound vars in arguments is slightly smarter. `for >::IAT` - // would otherwise unify with `impl Foo` when ideally we would not. - let infcx = self.tcx().infer_ctxt().build(TypingMode::non_body_analysis()); - let mut universes = if self_ty.has_escaping_bound_vars() { - vec![None; self_ty.outer_exclusive_binder().as_usize()] - } else { - vec![] - }; - let candidates = - rustc_trait_selection::traits::with_replaced_escaping_bound_vars( - &infcx, - &mut universes, - self_ty, - |self_ty| { - candidates - .into_iter() - .filter(|&InherentAssocCandidate { impl_, .. }| { - let impl_ty = self.tcx().type_of(impl_).instantiate_identity(); + let candidates = candidates + .into_iter() + .filter(|&InherentAssocCandidate { impl_, .. }| { + let impl_ty = self.tcx().type_of(impl_).instantiate_identity(); - // See comment on doing this operation for `self_ty` - let impl_ty = self.tcx.expand_free_alias_tys(impl_ty); - debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty); + // See comment on doing this operation for `self_ty` + let impl_ty = self.tcx.expand_free_alias_tys(impl_ty); + debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty); - // We treat parameters in the self ty as rigid and parameters in the impl ty as infers - // because it allows `impl Foo` to unify with `Foo::IAT`, while also disallowing - // `Foo::IAT` from unifying with `impl Foo`. - // - // We don't really care about a depth limit here because we're only working with user-written - // types and if they wrote a type that would take hours to walk then that's kind of on them. On - // the other hand the default depth limit is relatively low and could realistically be hit by - // users in normal cases. - // - // `DeepRejectCtxt` leads to slightly worse IAT resolution than real type equality in cases - // where the `impl_ty` has repeated uses of generic parameters. E.g. `impl Foo` would - // be considered a valid candidate when resolving `Foo::IAT`. - ty::DeepRejectCtxt::relate_rigid_infer(self.tcx) - .types_may_unify_with_depth(self_ty, impl_ty, usize::MAX) - }) - .collect() - }, - ); + // We treat parameters in the self ty as rigid and parameters in the impl ty as infers + // because it allows `impl Foo` to unify with `Foo::IAT`, while also disallowing + // `Foo::IAT` from unifying with `impl Foo`. + // + // We don't really care about a depth limit here because we're only working with user-written + // types and if they wrote a type that would take hours to walk then that's kind of on them. On + // the other hand the default depth limit is relatively low and could realistically be hit by + // users in normal cases. + // + // `DeepRejectCtxt` leads to slightly worse IAT resolution than real type equality in cases + // where the `impl_ty` has repeated uses of generic parameters. E.g. `impl Foo` would + // be considered a valid candidate when resolving `Foo::IAT`. + // + // Not replacing escaping bound vars in `self_ty` with placeholders also leads to slightly worse + // resolution, but it probably won't come up in practice and it would be backwards compatible + // to switch over to doing that. + ty::DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify_with_depth( + self_ty, + impl_ty, + usize::MAX, + ) + }) + .collect(); (candidates, vec![]) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index d8efb0aac4d7..8c18642e54a1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -322,6 +322,39 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { ) -> (Vec, Vec>) { let tcx = self.tcx(); let infcx = &self.infcx; + let mut fulfillment_errors = vec![]; + + let mut filter_iat_candidate = |self_ty, impl_| { + let ocx = ObligationCtxt::new_with_diagnostics(self); + let self_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, self_ty); + + let impl_args = infcx.fresh_args_for_item(span, impl_); + let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); + let impl_ty = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty); + + // Check that the self types can be related. + if ocx.eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty).is_err() { + return false; + } + + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); + let impl_bounds = ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_bounds); + let impl_obligations = traits::predicates_for_generics( + |_, _| ObligationCause::dummy(), + self.param_env, + impl_bounds, + ); + ocx.register_obligations(impl_obligations); + + let mut errors = ocx.select_where_possible(); + if !errors.is_empty() { + fulfillment_errors.append(&mut errors); + return false; + } + + true + }; let mut universes = if self_ty.has_escaping_bound_vars() { vec![None; self_ty.outer_exclusive_binder().as_usize()] @@ -329,52 +362,12 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { vec![] }; - let mut fulfillment_errors = vec![]; let candidates = traits::with_replaced_escaping_bound_vars(infcx, &mut universes, self_ty, |self_ty| { candidates .into_iter() .filter(|&InherentAssocCandidate { impl_, .. }| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new_with_diagnostics(self); - let self_ty = - ocx.normalize(&ObligationCause::dummy(), self.param_env, self_ty); - - let impl_args = infcx.fresh_args_for_item(span, impl_); - let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); - let impl_ty = - ocx.normalize(&ObligationCause::dummy(), self.param_env, impl_ty); - - // Check that the self types can be related. - if ocx - .eq(&ObligationCause::dummy(), self.param_env, impl_ty, self_ty) - .is_err() - { - return false; - } - - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); - let impl_bounds = ocx.normalize( - &ObligationCause::dummy(), - self.param_env, - impl_bounds, - ); - let impl_obligations = traits::predicates_for_generics( - |_, _| ObligationCause::dummy(), - self.param_env, - impl_bounds, - ); - ocx.register_obligations(impl_obligations); - - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return false; - } - - true - }) + infcx.probe(|_| filter_iat_candidate(self_ty, impl_)) }) .collect() }); diff --git a/tests/crashes/138131.rs b/tests/crashes/138131.rs deleted file mode 100644 index d0f91b748401..000000000000 --- a/tests/crashes/138131.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #138131 - -#![feature(min_generic_const_args, generic_const_items)] - -const BAR<'a>: usize = 10; - -struct Foo<'a> { - x: &'a (), -} - -impl<'a> Foo<'a> { - fn foo(_: [u8; BAR]) {} -} - -fn main() {} diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.rs b/tests/ui/associated-inherent-types/bound_vars_in_args.rs index 276e3cf1da04..0baa242af768 100644 --- a/tests/ui/associated-inherent-types/bound_vars_in_args.rs +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.rs @@ -15,9 +15,8 @@ impl Foo { } struct Bar -//~^ ERROR: the size for values of type `T` cannot be known at compilation time -//~| ERROR: the size for values of type `T` cannot be known at compilation time where for Foo::IAT: Sized; + //~^ ERROR: multiple applicable items in scope fn main() {} diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.stderr b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr index 108f1e531af6..9e880476f6a9 100644 --- a/tests/ui/associated-inherent-types/bound_vars_in_args.stderr +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.stderr @@ -1,37 +1,20 @@ -error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bound_vars_in_args.rs:17:1 +error[E0034]: multiple applicable items in scope + --> $DIR/bound_vars_in_args.rs:19:20 | -LL | struct Bar - | ^^^^^^^^^^ doesn't have a size known at compile-time +LL | for Foo::IAT: Sized; + | ^^^ multiple `IAT` found | - = help: the trait `Sized` is not implemented for `T` -note: required by a bound in `Foo::IAT` - --> $DIR/bound_vars_in_args.rs:13:9 +note: candidate #1 is defined in an impl for the type `Foo<[u8]>` + --> $DIR/bound_vars_in_args.rs:10:5 | -LL | impl Foo { - | ^^^^^ required by this bound in `Foo::IAT` LL | type IAT = u8; - | --- required by a bound in this associated type - -error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/bound_vars_in_args.rs:17:1 + | ^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Foo` + --> $DIR/bound_vars_in_args.rs:14:5 | -LL | / struct Bar -LL | | -LL | | -LL | | where -LL | | for Foo::IAT: Sized; - | |______________________________^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `T` -note: required by a bound in `Foo::IAT` - --> $DIR/bound_vars_in_args.rs:13:9 - | -LL | impl Foo { - | ^^^^^ required by this bound in `Foo::IAT` LL | type IAT = u8; - | --- required by a bound in this associated type + | ^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs index 4546785f0b1c..3132d9fef697 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.rs +++ b/tests/ui/associated-inherent-types/issue-109299-1.rs @@ -8,8 +8,6 @@ impl Lexer { } type X = impl for Fn() -> Lexer::Cursor; -//~^ ERROR associated type `Cursor` not found for `Lexer` in the current scope -//~| ERROR associated type `Cursor` not found for `Lexer` in the current scope -//~| ERROR: unconstrained opaque type +//~^ ERROR: unconstrained opaque type fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr index 6bc7a539680c..bc8ea6acf28c 100644 --- a/tests/ui/associated-inherent-types/issue-109299-1.stderr +++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr @@ -6,31 +6,5 @@ LL | type X = impl for Fn() -> Lexer::Cursor; | = note: `X` must be used in combination with a concrete type within the same crate -error[E0220]: associated type `Cursor` not found for `Lexer` in the current scope - --> $DIR/issue-109299-1.rs:10:40 - | -LL | struct Lexer(T); - | --------------- associated type `Cursor` not found for this struct -... -LL | type X = impl for Fn() -> Lexer::Cursor; - | ^^^^^^ associated item not found in `Lexer` - | - = note: the associated type was found for - - `Lexer` +error: aborting due to 1 previous error -error[E0220]: associated type `Cursor` not found for `Lexer` in the current scope - --> $DIR/issue-109299-1.rs:10:40 - | -LL | struct Lexer(T); - | --------------- associated type `Cursor` not found for this struct -... -LL | type X = impl for Fn() -> Lexer::Cursor; - | ^^^^^^ associated item not found in `Lexer` - | - = note: the associated type was found for - - `Lexer` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0220`. From 1f24f02696d26f35969b3ec8afad104f187312a1 Mon Sep 17 00:00:00 2001 From: Charlotte Smith Date: Tue, 17 Jun 2025 15:38:15 +0100 Subject: [PATCH 077/356] Hide imported privates if private editable is disabled --- .../ide-completion/src/completions/expr.rs | 14 ++- .../ide-completion/src/tests/visibility.rs | 89 ++++++++++++++++++- 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 062bc6106e49..2133291b1de1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -145,10 +145,16 @@ pub(crate) fn complete_expr_path( }); match resolution { hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { - // Set visible_from to None so private items are returned. - // They will be possibly filtered out in add_path_resolution() - // via def_is_visible(). - let module_scope = module.scope(ctx.db, None); + let visible_from = if ctx.config.enable_private_editable { + // Set visible_from to None so private items are returned. + // They will be possibly filtered out in add_path_resolution() + // via def_is_visible(). + None + } else { + Some(ctx.module) + }; + + let module_scope = module.scope(ctx.db, visible_from); for (name, def) in module_scope { if scope_def_applicable(def) { acc.add_path_resolution( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs index 4b5a0ac1c2b9..b404011dfe65 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs @@ -1,7 +1,7 @@ //! Completion tests for visibility modifiers. use expect_test::expect; -use crate::tests::{check, check_with_trigger_character}; +use crate::tests::{check, check_with_private_editable, check_with_trigger_character}; #[test] fn empty_pub() { @@ -78,3 +78,90 @@ mod bar {} "#]], ); } + +#[test] +fn use_inner_public_function() { + check( + r#" +//- /inner.rs crate:inner +pub fn inner_public() {} +fn inner_private() {} +//- /foo.rs crate:foo deps:inner +use inner::inner_public; +pub fn outer_public() {} +//- /lib.rs crate:lib deps:foo +fn x() { + foo::$0 +} + "#, + expect![[r#" + fn outer_public() fn() + "#]], + ); +} + +#[test] +fn pub_use_inner_public_function() { + check( + r#" +//- /inner.rs crate:inner +pub fn inner_public() {} +fn inner_private() {} +//- /foo.rs crate:foo deps:inner +pub use inner::inner_public; +pub fn outer_public() {} +//- /lib.rs crate:lib deps:foo +fn x() { + foo::$0 +} + "#, + expect![[r#" + fn inner_public() fn() + fn outer_public() fn() + "#]], + ); +} + +#[test] +fn use_inner_public_function_private_editable() { + check_with_private_editable( + r#" +//- /inner.rs crate:inner +pub fn inner_public() {} +fn inner_private() {} +//- /foo.rs crate:foo deps:inner +use inner::inner_public; +pub fn outer_public() {} +//- /lib.rs crate:lib deps:foo +fn x() { + foo::$0 +} + "#, + expect![[r#" + fn inner_public() fn() + fn outer_public() fn() + "#]], + ); +} + +#[test] +fn pub_use_inner_public_function_private_editable() { + check_with_private_editable( + r#" +//- /inner.rs crate:inner +pub fn inner_public() {} +fn inner_private() {} +//- /foo.rs crate:foo deps:inner +pub use inner::inner_public; +pub fn outer_public() {} +//- /lib.rs crate:lib deps:foo +fn x() { + foo::$0 +} + "#, + expect![[r#" + fn inner_public() fn() + fn outer_public() fn() + "#]], + ); +} From 7eaf7386b93dbeb5029cc99538b3b25fc81928aa Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 17 Jun 2025 12:22:13 -0500 Subject: [PATCH 078/356] bootstrap.example.toml: use less contextual format prefixing each key with its section means you don't need to scroll up 4 pages to see which section a particular key is from. target specific options were kept in old format since the exact section name depends on the target, so those options must now be moved to the bottom of the file. --- bootstrap.example.toml | 383 ++++++++++++++++++++--------------------- 1 file changed, 189 insertions(+), 194 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 19cf360b0fb8..38c3195deb9d 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -44,7 +44,6 @@ # ============================================================================= # Tweaking how LLVM is compiled # ============================================================================= -[llvm] # Whether to use Rust CI built LLVM instead of locally building it. # @@ -62,50 +61,50 @@ # # Note that many of the LLVM options are not currently supported for # downloading. Currently only the "assertions" option can be toggled. -#download-ci-llvm = true +#llvm.download-ci-llvm = true # Indicates whether the LLVM build is a Release or Debug build -#optimize = true +#llvm.optimize = true # Indicates whether LLVM should be built with ThinLTO. Note that this will # only succeed if you use clang, lld, llvm-ar, and llvm-ranlib in your C/C++ # toolchain (see the `cc`, `cxx`, `linker`, `ar`, and `ranlib` options below). # More info at: https://clang.llvm.org/docs/ThinLTO.html#clang-bootstrap -#thin-lto = false +#llvm.thin-lto = false # Indicates whether an LLVM Release build should include debug info -#release-debuginfo = false +#llvm.release-debuginfo = false # Indicates whether the LLVM assertions are enabled or not # NOTE: When assertions are disabled, bugs in the integration between rustc and LLVM can lead to # unsoundness (segfaults, etc.) in the rustc process itself, not just in the generated code. -#assertions = false +#llvm.assertions = false # Indicates whether the LLVM testsuite is enabled in the build or not. Does # not execute the tests as part of the build as part of x.py build et al, # just makes it possible to do `ninja check-llvm` in the staged LLVM build # directory when doing LLVM development as part of Rust development. -#tests = false +#llvm.tests = false # Indicates whether the LLVM plugin is enabled or not -#plugins = false +#llvm.plugins = false # Whether to build Enzyme as AutoDiff backend. -#enzyme = false +#llvm.enzyme = false # Whether to build LLVM with support for it's gpu offload runtime. -#offload = false +#llvm.offload = false # When true, link libstdc++ statically into the rustc_llvm. # This is useful if you don't want to use the dynamic version of that # library provided by LLVM. -#static-libstdcpp = false +#llvm.static-libstdcpp = false # Enable LLVM to use zstd for compression. -#libzstd = false +#llvm.libzstd = false # Whether to use Ninja to build LLVM. This runs much faster than make. -#ninja = true +#llvm.ninja = true # LLVM targets to build support for. # Note: this is NOT related to Rust compilation targets. However, as Rust is @@ -113,13 +112,13 @@ # the resulting rustc being unable to compile for the disabled architectures. # # To add support for new targets, see https://rustc-dev-guide.rust-lang.org/building/new-target.html. -#targets = "AArch64;AMDGPU;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" +#llvm.targets = "AArch64;AMDGPU;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" # LLVM experimental targets to build support for. These targets are specified in # the same format as above, but since these targets are experimental, they are # not built by default and the experimental Rust compilation targets that depend # on them will not work unless the user opts in to building them. -#experimental-targets = "AVR;M68k;CSKY" +#llvm.experimental-targets = "AVR;M68k;CSKY" # Cap the number of parallel linker invocations when compiling LLVM. # This can be useful when building LLVM with debug info, which significantly @@ -127,86 +126,84 @@ # each linker process. # If set to 0, linker invocations are treated like any other job and # controlled by bootstrap's -j parameter. -#link-jobs = 0 +#llvm.link-jobs = 0 # Whether to build LLVM as a dynamically linked library (as opposed to statically linked). # Under the hood, this passes `--shared` to llvm-config. # NOTE: To avoid performing LTO multiple times, we suggest setting this to `true` when `thin-lto` is enabled. -#link-shared = llvm.thin-lto +#llvm.link-shared = llvm.thin-lto # When building llvm, this configures what is being appended to the version. # To use LLVM version as is, provide an empty string. -#version-suffix = if rust.channel == "dev" { "-rust-dev" } else { "-rust-$version-$channel" } +#llvm.version-suffix = if rust.channel == "dev" { "-rust-dev" } else { "-rust-$version-$channel" } # On MSVC you can compile LLVM with clang-cl, but the test suite doesn't pass # with clang-cl, so this is special in that it only compiles LLVM with clang-cl. # Note that this takes a /path/to/clang-cl, not a boolean. -#clang-cl = cc +#llvm.clang-cl = cc # Pass extra compiler and linker flags to the LLVM CMake build. -#cflags = "" -#cxxflags = "" -#ldflags = "" +#llvm.cflags = "" +#llvm.cxxflags = "" +#llvm.ldflags = "" # Use libc++ when building LLVM instead of libstdc++. This is the default on # platforms already use libc++ as the default C++ library, but this option # allows you to use libc++ even on platforms when it's not. You need to ensure # that your host compiler ships with libc++. -#use-libcxx = false +#llvm.use-libcxx = false # The value specified here will be passed as `-DLLVM_USE_LINKER` to CMake. -#use-linker = (path) +#llvm.use-linker = (path) # Whether or not to specify `-DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=YES` -#allow-old-toolchain = false +#llvm.allow-old-toolchain = false # Whether to include the Polly optimizer. -#polly = false +#llvm.polly = false # Whether to build the clang compiler. -#clang = false +#llvm.clang = false # Whether to enable llvm compilation warnings. -#enable-warnings = false +#llvm.enable-warnings = false # Custom CMake defines to set when building LLVM. -#build-config = {} +#llvm.build-config = {} # ============================================================================= # Tweaking how GCC is compiled # ============================================================================= -[gcc] # Download GCC from CI instead of building it locally. # Note that this will attempt to download GCC even if there are local # modifications to the `src/gcc` submodule. # Currently, this is only supported for the `x86_64-unknown-linux-gnu` target. -#download-ci-gcc = false +#gcc.download-ci-gcc = false # ============================================================================= # General build configuration options # ============================================================================= -[build] # The default stage to use for the `check` subcommand -#check-stage = 0 +#build.check-stage = 0 # The default stage to use for the `doc` subcommand -#doc-stage = 0 +#build.doc-stage = 0 # The default stage to use for the `build` subcommand -#build-stage = 1 +#build.build-stage = 1 # The default stage to use for the `test` subcommand -#test-stage = 1 +#build.test-stage = 1 # The default stage to use for the `dist` subcommand -#dist-stage = 2 +#build.dist-stage = 2 # The default stage to use for the `install` subcommand -#install-stage = 2 +#build.install-stage = 2 # The default stage to use for the `bench` subcommand -#bench-stage = 2 +#build.bench-stage = 2 # A descriptive string to be appended to version output (e.g., `rustc --version`), # which is also used in places like debuginfo `DW_AT_producer`. This may be useful for @@ -217,7 +214,7 @@ # upstream Rust you need to set this to "". However, note that if you set this to "" but # are not actually compatible -- for example if you've backported patches that change # behavior -- this may lead to miscompilations or other bugs. -#description = "" +#build.description = "" # Build triple for the pre-compiled snapshot compiler. If `rustc` is set, this must match its host # triple (see `rustc --version --verbose`; cross-compiling the rust build system itself is NOT @@ -229,14 +226,14 @@ # Otherwise, `x.py` will try to infer it from the output of `uname`. # If `uname` is not found in PATH, we assume this is `x86_64-pc-windows-msvc`. # This may be changed in the future. -#build = "x86_64-unknown-linux-gnu" (as an example) +#build.build = "x86_64-unknown-linux-gnu" (as an example) # Which triples to produce a compiler toolchain for. Each of these triples will be bootstrapped from # the build triple themselves. In other words, this is the list of triples for which to build a # compiler that can RUN on that triple. # # Defaults to just the `build` triple. -#host = [build.build] (list of triples) +#build.host = [build.build] (list of triples) # Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of these triples will # be bootstrapped from the build triple themselves. In other words, this is the list of triples for @@ -245,32 +242,32 @@ # Defaults to `host`. If you set this explicitly, you likely want to add all # host triples to this list as well in order for those host toolchains to be # able to compile programs for their native target. -#target = build.host (list of triples) +#build.target = build.host (list of triples) # Use this directory to store build artifacts. Paths are relative to the current directory, not to # the root of the repository. -#build-dir = "build" +#build.build-dir = "build" # Instead of downloading the src/stage0 version of Cargo specified, use # this Cargo binary instead to build all Rust code # If you set this, you likely want to set `rustc` as well. -#cargo = "/path/to/cargo" +#build.cargo = "/path/to/cargo" # Instead of downloading the src/stage0 version of the compiler # specified, use this rustc binary instead as the stage0 snapshot compiler. # If you set this, you likely want to set `cargo` as well. -#rustc = "/path/to/rustc" +#build.rustc = "/path/to/rustc" # Instead of downloading the src/stage0 version of rustfmt specified, # use this rustfmt binary instead as the stage0 snapshot rustfmt. -#rustfmt = "/path/to/rustfmt" +#build.rustfmt = "/path/to/rustfmt" # Instead of downloading the src/stage0 version of cargo-clippy specified, # use this cargo-clippy binary instead as the stage0 snapshot cargo-clippy. # # Note that this option should be used with the same toolchain as the `rustc` option above. # Otherwise, clippy is likely to fail due to a toolchain conflict. -#cargo-clippy = "/path/to/cargo-clippy" +#build.cargo-clippy = "/path/to/cargo-clippy" # Whether to build documentation by default. If false, rustdoc and # friends will still be compiled but they will not be used to generate any @@ -278,47 +275,47 @@ # # You can still build documentation when this is disabled by explicitly passing paths, # e.g. `x doc library`. -#docs = true +#build.docs = true # Flag to specify whether CSS, JavaScript, and HTML are minified when # docs are generated. JSON is always minified, because it's enormous, # and generated in already-minified form from the beginning. -#docs-minification = true +#build.docs-minification = true # Flag to specify whether private items should be included in the library docs. -#library-docs-private-items = false +#build.library-docs-private-items = false # Indicate whether to build compiler documentation by default. # You can still build documentation when this is disabled by explicitly passing a path: `x doc compiler`. -#compiler-docs = false +#build.compiler-docs = false # Indicate whether git submodules are managed and updated automatically. -#submodules = true +#build.submodules = true # The path to (or name of) the GDB executable to use. This is only used for # executing the debuginfo test suite. -#gdb = "gdb" +#build.gdb = "gdb" # The path to (or name of) the LLDB executable to use. This is only used for # executing the debuginfo test suite. -#lldb = "lldb" +#build.lldb = "lldb" # The node.js executable to use. Note that this is only used for the emscripten # target when running tests, otherwise this can be omitted. -#nodejs = "node" +#build.nodejs = "node" # The npm executable to use. Note that this is used for rustdoc-gui tests, # otherwise this can be omitted. # # Under Windows this should be `npm.cmd` or path to it (verified on nodejs v18.06), or # error will be emitted. -#npm = "npm" +#build.npm = "npm" # Python interpreter to use for various tasks throughout the build, notably # rustdoc tests, the lldb python interpreter, and some dist bits and pieces. # # Defaults to the Python interpreter used to execute x.py. -#python = "python" +#build.python = "python" # The path to the REUSE executable to use. Note that REUSE is not required in # most cases, as our tooling relies on a cached (and shrunk) copy of the @@ -328,17 +325,17 @@ # repository to change, and the cached copy has to be regenerated. # # Defaults to the "reuse" command in the system path. -#reuse = "reuse" +#build.reuse = "reuse" # Force Cargo to check that Cargo.lock describes the precise dependency # set that all the Cargo.toml files create, instead of updating it. -#locked-deps = false +#build.locked-deps = false # Indicate whether the vendored sources are used for Rust dependencies or not. # # Vendoring requires additional setup. We recommend using the pre-generated source tarballs if you # want to use vendoring. See https://forge.rust-lang.org/infra/other-installation-methods.html#source-code. -#vendor = if "is a tarball source" && "vendor" dir exists && ".cargo/config.toml" file exists { true } else { false } +#build.vendor = if "is a tarball source" && "vendor" dir exists && ".cargo/config.toml" file exists { true } else { false } # Typically the build system will build the Rust compiler twice. The second # compiler, however, will simply use its own libraries to link against. If you @@ -346,11 +343,11 @@ # then you can set this option to true. # # This is only useful for verifying that rustc generates reproducible builds. -#full-bootstrap = false +#build.full-bootstrap = false # Set the bootstrap/download cache path. It is useful when building rust # repeatedly in a CI environment. -#bootstrap-cache-path = /path/to/shared/cache +#build.bootstrap-cache-path = /path/to/shared/cache # Enable a build of the extended Rust tool set which is not only the compiler # but also tools such as Cargo. This will also produce "combined installers" @@ -359,7 +356,7 @@ # which tools should be built if `extended = true`. # # This is disabled by default. -#extended = false +#build.extended = false # Set of tools to be included in the installation. # @@ -368,7 +365,7 @@ # If `extended = true`, they are all included. # # If any enabled tool fails to build, the installation fails. -#tools = [ +#build.tools = [ # "cargo", # "clippy", # "rustdoc", @@ -391,14 +388,14 @@ #tool.TOOL_NAME.features = [FEATURE1, FEATURE2] # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation -#verbose = 0 +#build.verbose = 0 # Build the sanitizer runtimes -#sanitizers = false +#build.sanitizers = false # Build the profiler runtime (required when compiling with options that depend # on this runtime, such as `-C profile-generate` or `-C instrument-coverage`). -#profiler = false +#build.profiler = false # Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics. # Requires the LLVM submodule to be managed by bootstrap (i.e. not external) so that `compiler-rt` @@ -406,102 +403,100 @@ # # Setting this to `false` generates slower code, but removes the requirement for a C toolchain in # order to run `x check`. -#optimized-compiler-builtins = if rust.channel == "dev" { false } else { true } +#build.optimized-compiler-builtins = if rust.channel == "dev" { false } else { true } # Indicates whether the native libraries linked into Cargo will be statically # linked or not. -#cargo-native-static = false +#build.cargo-native-static = false # Run the build with low priority, by setting the process group's "nice" value # to +10 on Unix platforms, and by using a "low priority" job object on Windows. -#low-priority = false +#build.low-priority = false # Arguments passed to the `./configure` script, used during distcheck. You # probably won't fill this in but rather it's filled in by the `./configure` # script. Useful for debugging. -#configure-args = [] +#build.configure-args = [] # Indicates that a local rebuild is occurring instead of a full bootstrap, # essentially skipping stage0 as the local compiler is recompiling itself again. # Useful for modifying only the stage2 compiler without having to pass `--keep-stage 0` each time. -#local-rebuild = false +#build.local-rebuild = false # Print out how long each bootstrap step took (mostly intended for CI and # tracking over time) -#print-step-timings = false +#build.print-step-timings = false # Print out resource usage data for each bootstrap step, as defined by the Unix # struct rusage. (Note that this setting is completely unstable: the data it # captures, what platforms it supports, the format of its associated output, and # this setting's very existence, are all subject to change.) -#print-step-rusage = false +#build.print-step-rusage = false # Always patch binaries for usage with Nix toolchains. If `true` then binaries # will be patched unconditionally. If `false` or unset, binaries will be patched # only if the current distribution is NixOS. This option is useful when using # a Nix toolchain on non-NixOS distributions. -#patch-binaries-for-nix = false +#build.patch-binaries-for-nix = false # Collect information and statistics about the current build, and write it to # disk. Enabling this has no impact on the resulting build output. The # schema of the file generated by the build metrics feature is unstable, and # this is not intended to be used during local development. -#metrics = false +#build.metrics = false # Specify the location of the Android NDK. Used when targeting Android. -#android-ndk = "/path/to/android-ndk-r26d" +#build.android-ndk = "/path/to/android-ndk-r26d" # Number of parallel jobs to be used for building and testing. If set to `0` or # omitted, it will be automatically determined. This is the `-j`/`--jobs` flag # passed to cargo invocations. -#jobs = 0 +#build.jobs = 0 # What custom diff tool to use for displaying compiletest tests. -#compiletest-diff-tool = +#build.compiletest-diff-tool = # Whether to use the precompiled stage0 libtest with compiletest. -#compiletest-use-stage0-libtest = true +#build.compiletest-use-stage0-libtest = true # Indicates whether ccache is used when building certain artifacts (e.g. LLVM). # Set to `true` to use the first `ccache` in PATH, or set an absolute path to use # a specific version. -#ccache = false +#build.ccache = false # List of paths to exclude from the build and test processes. # For example, exclude = ["tests/ui", "src/tools/tidy"]. -#exclude = [] +#build.exclude = [] # ============================================================================= # General install configuration options # ============================================================================= -[install] # Where to install the generated toolchain. Must be an absolute path. -#prefix = "/usr/local" +#install.prefix = "/usr/local" # Where to install system configuration files. # If this is a relative path, it will get installed in `prefix` above -#sysconfdir = "/etc" +#install.sysconfdir = "/etc" # Where to install documentation in `prefix` above -#docdir = "share/doc/rust" +#install.docdir = "share/doc/rust" # Where to install binaries in `prefix` above -#bindir = "bin" +#install.bindir = "bin" # Where to install libraries in `prefix` above -#libdir = "lib" +#install.libdir = "lib" # Where to install man pages in `prefix` above -#mandir = "share/man" +#install.mandir = "share/man" # Where to install data in `prefix` above -#datadir = "share" +#install.datadir = "share" # ============================================================================= # Options for compiling Rust code itself # ============================================================================= -[rust] # Whether or not to optimize when compiling the compiler and standard library, # and what level of optimization to use. @@ -517,7 +512,7 @@ # 3 - All optimizations. # "s" - Optimize for binary size. # "z" - Optimize for binary size, but also turn off loop vectorization. -#optimize = true +#rust.optimize = true # Indicates that the build should be configured for debugging Rust. A # `debug`-enabled compiler and standard library will be somewhat @@ -540,7 +535,7 @@ # "maximally debuggable" environment (notably libstd) takes # hours to build. # -#debug = false +#rust.debug = false # Whether to download the stage 1 and 2 compilers from CI. This is useful if you # are working on tools, doc-comments, or library (you will be able to build the @@ -553,37 +548,37 @@ # # Set this to `true` to always download or `false` to always use the in-tree # compiler. -#download-rustc = false +#rust.download-rustc = false # Number of codegen units to use for each compiler invocation. A value of 0 # means "the number of cores on this machine", and 1+ is passed through to the # compiler. # # Uses the rustc defaults: https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units -#codegen-units = if incremental { 256 } else { 16 } +#rust.codegen-units = if incremental { 256 } else { 16 } # Sets the number of codegen units to build the standard library with, # regardless of what the codegen-unit setting for the rest of the compiler is. # NOTE: building with anything other than 1 is known to occasionally have bugs. -#codegen-units-std = codegen-units +#rust.codegen-units-std = codegen-units # Whether or not debug assertions are enabled for the compiler and standard library. # These can help find bugs at the cost of a small runtime slowdown. # # Defaults to rust.debug value -#debug-assertions = rust.debug (boolean) +#rust.debug-assertions = rust.debug (boolean) # Whether or not debug assertions are enabled for the standard library. # Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value -#debug-assertions-std = rust.debug-assertions (boolean) +#rust.debug-assertions-std = rust.debug-assertions (boolean) # Whether or not debug assertions are enabled for the tools built by bootstrap. # Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value -#debug-assertions-tools = rust.debug-assertions (boolean) +#rust.debug-assertions-tools = rust.debug-assertions (boolean) # Whether or not to leave debug! and trace! calls in the rust binary. # @@ -591,22 +586,22 @@ # # If you see a message from `tracing` saying "some trace filter directives would enable traces that # are disabled statically" because `max_level_info` is enabled, set this value to `true`. -#debug-logging = rust.debug-assertions (boolean) +#rust.debug-logging = rust.debug-assertions (boolean) # Whether or not to build rustc, tools and the libraries with randomized type layout -#randomize-layout = false +#rust.randomize-layout = false # Whether or not overflow checks are enabled for the compiler and standard # library. # # Defaults to rust.debug value -#overflow-checks = rust.debug (boolean) +#rust.overflow-checks = rust.debug (boolean) # Whether or not overflow checks are enabled for the standard library. # Overrides the `overflow-checks` option, if defined. # # Defaults to rust.overflow-checks value -#overflow-checks-std = rust.overflow-checks (boolean) +#rust.overflow-checks-std = rust.overflow-checks (boolean) # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # See https://doc.rust-lang.org/rustc/codegen-options/index.html#debuginfo for available options. @@ -617,20 +612,20 @@ # # Note that debuginfo-level = 2 generates several gigabytes of debuginfo # and will slow down the linking process significantly. -#debuginfo-level = if rust.debug { 1 } else { 0 } +#rust.debuginfo-level = if rust.debug { 1 } else { 0 } # Debuginfo level for the compiler. -#debuginfo-level-rustc = rust.debuginfo-level +#rust.debuginfo-level-rustc = rust.debuginfo-level # Debuginfo level for the standard library. -#debuginfo-level-std = rust.debuginfo-level +#rust.debuginfo-level-std = rust.debuginfo-level # Debuginfo level for the tools. -#debuginfo-level-tools = rust.debuginfo-level +#rust.debuginfo-level-tools = rust.debuginfo-level # Debuginfo level for the test suites run with compiletest. # FIXME(#61117): Some tests fail when this option is enabled. -#debuginfo-level-tests = 0 +#rust.debuginfo-level-tests = 0 # Should rustc and the standard library be built with split debuginfo? Default # is platform dependent. @@ -640,13 +635,13 @@ # The value specified here is only used when targeting the `build.build` triple, # and is overridden by `target..split-debuginfo` if specified. # -#split-debuginfo = see target..split-debuginfo +#rust.split-debuginfo = see target..split-debuginfo # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) -#backtrace = true +#rust.backtrace = true # Whether to always use incremental compilation when building rustc -#incremental = false +#rust.incremental = false # The default linker that will be hard-coded into the generated # compiler for targets that don't specify a default linker explicitly @@ -656,7 +651,7 @@ # setting. # # See https://doc.rust-lang.org/rustc/codegen-options/index.html#linker for more information. -#default-linker = (path) +#rust.default-linker = (path) # The "channel" for the Rust build to produce. The stable/beta channels only # allow using stable features, whereas the nightly and dev channels allow using @@ -665,7 +660,7 @@ # You can set the channel to "auto-detect" to load the channel name from `src/ci/channel`. # # If using tarball sources, default value is "auto-detect", otherwise, it's "dev". -#channel = if "is a tarball source" { "auto-detect" } else { "dev" } +#rust.channel = if "is a tarball source" { "auto-detect" } else { "dev" } # The root location of the musl installation directory. The library directory # will also need to contain libunwind.a for an unwinding implementation. Note @@ -673,65 +668,65 @@ # linked binaries. # # Defaults to /usr on musl hosts. Has no default otherwise. -#musl-root = (path) +#rust.musl-root = (path) # By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix # platforms to ensure that the compiler is usable by default from the build # directory (as it links to a number of dynamic libraries). This may not be # desired in distributions, for example. -#rpath = true +#rust.rpath = true # Indicates whether symbols should be stripped using `-Cstrip=symbols`. -#strip = false +#rust.strip = false # Forces frame pointers to be used with `-Cforce-frame-pointers`. # This can be helpful for profiling at a small performance cost. -#frame-pointers = false +#rust.frame-pointers = false # Indicates whether stack protectors should be used # via the unstable option `-Zstack-protector`. # # Valid options are : `none`(default),`basic`,`strong`, or `all`. # `strong` and `basic` options may be buggy and are not recommended, see rust-lang/rust#114903. -#stack-protector = "none" +#rust.stack-protector = "none" # Prints each test name as it is executed, to help debug issues in the test harness itself. -#verbose-tests = if is_verbose { true } else { false } +#rust.verbose-tests = if is_verbose { true } else { false } # Flag indicating whether tests are compiled with optimizations (the -O flag). -#optimize-tests = true +#rust.optimize-tests = true # Flag indicating whether codegen tests will be run or not. If you get an error # saying that the FileCheck executable is missing, you may want to disable this. # Also see the target's llvm-filecheck option. -#codegen-tests = true +#rust.codegen-tests = true # Flag indicating whether git info will be retrieved from .git automatically. # Having the git information can cause a lot of rebuilds during development. -#omit-git-hash = if rust.channel == "dev" { true } else { false } +#rust.omit-git-hash = if rust.channel == "dev" { true } else { false } # Whether to create a source tarball by default when running `x dist`. # # You can still build a source tarball when this is disabled by explicitly passing `x dist rustc-src`. -#dist-src = true +#rust.dist-src = true # After building or testing an optional component (e.g. the nomicon or reference), append the # result (broken, compiling, testing) into this JSON file. -#save-toolstates = (path) +#rust.save-toolstates = (path) # This is an array of the codegen backends that will be compiled for the rustc # that's being compiled. The default is to only build the LLVM codegen backend, # and currently the only standard options supported are `"llvm"`, `"cranelift"` # and `"gcc"`. The first backend in this list will be used as default by rustc # when no explicit backend is specified. -#codegen-backends = ["llvm"] +#rust.codegen-backends = ["llvm"] # Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and # whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be # when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from # the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will # make this default to false. -#lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true +#rust.lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true # Indicates whether LLD will be used to link Rust crates during bootstrap on # supported platforms. @@ -742,56 +737,56 @@ # On MSVC, LLD will not be used if we're cross linking. # # Explicitly setting the linker for a target will override this option when targeting MSVC. -#use-lld = false +#rust.use-lld = false # Indicates whether some LLVM tools, like llvm-objdump, will be made available in the # sysroot. -#llvm-tools = true +#rust.llvm-tools = true # Indicates whether the `self-contained` llvm-bitcode-linker, will be made available # in the sysroot. It is required for running nvptx tests. -#llvm-bitcode-linker = false +#rust.llvm-bitcode-linker = false # Whether to deny warnings in crates -#deny-warnings = true +#rust.deny-warnings = true # Print backtrace on internal compiler errors during bootstrap -#backtrace-on-ice = false +#rust.backtrace-on-ice = false # Whether to verify generated LLVM IR -#verify-llvm-ir = false +#rust.verify-llvm-ir = false # Compile the compiler with a non-default ThinLTO import limit. This import # limit controls the maximum size of functions imported by ThinLTO. Decreasing # will make code compile faster at the expense of lower runtime performance. -#thin-lto-import-instr-limit = if incremental { 10 } else { LLVM default (currently 100) } +#rust.thin-lto-import-instr-limit = if incremental { 10 } else { LLVM default (currently 100) } # Map debuginfo paths to `/rust/$sha/...`. # Useful for reproducible builds. Generally only set for releases -#remap-debuginfo = false +#rust.remap-debuginfo = false # Link the compiler and LLVM against `jemalloc` instead of the default libc allocator. # This option is only tested on Linux and OSX. It can also be configured per-target in the # [target.] section. -#jemalloc = false +#rust.jemalloc = false # Run tests in various test suites with the "nll compare mode" in addition to # running the tests in normal mode. Largely only used on CI and during local # development of NLL -#test-compare-mode = false +#rust.test-compare-mode = false # Global default for llvm-libunwind for all targets. See the target-specific # documentation for llvm-libunwind below. Note that the target-specific # option will override this if set. -#llvm-libunwind = 'no' +#rust.llvm-libunwind = 'no' # Enable Windows Control Flow Guard checks in the standard library. # This only applies from stage 1 onwards, and only for Windows targets. -#control-flow-guard = false +#rust.control-flow-guard = false # Enable Windows EHCont Guard checks in the standard library. # This only applies from stage 1 onwards, and only for Windows targets. -#ehcont-guard = false +#rust.ehcont-guard = false # Enable symbol-mangling-version v0. This can be helpful when profiling rustc, # as generics will be preserved in symbols (rather than erased into opaque T). @@ -799,16 +794,16 @@ # compiler and its tools and the legacy scheme will be used when compiling the # standard library. # If an explicit setting is given, it will be used for all parts of the codebase. -#new-symbol-mangling = true|false (see comment) +#rust.new-symbol-mangling = true|false (see comment) # Select LTO mode that will be used for compiling rustc. By default, thin local LTO # (LTO within a single crate) is used (like for any Rust crate). You can also select # "thin" or "fat" to apply Thin/Fat LTO to the `rustc_driver` dylib, or "off" to disable # LTO entirely. -#lto = "thin-local" +#rust.lto = "thin-local" # Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std` -#validate-mir-opts = 3 +#rust.validate-mir-opts = 3 # Configure `std` features used during bootstrap. # @@ -822,7 +817,57 @@ # # Since libstd also builds libcore and liballoc as dependencies and all their features are mirrored # as libstd features, this option can also be used to configure features such as optimize_for_size. -#std-features = ["panic_unwind"] +#rust.std-features = ["panic_unwind"] + +# ============================================================================= +# Distribution options +# +# These options are related to distribution, mostly for the Rust project itself. +# You probably won't need to concern yourself with any of these options +# ============================================================================= + +# This is the folder of artifacts that the build system will sign. All files in +# this directory will be signed with the default gpg key using the system `gpg` +# binary. The `asc` and `sha256` files will all be output into the standard dist +# output folder (currently `build/dist`) +# +# This folder should be populated ahead of time before the build system is +# invoked. +#dist.sign-folder = (path) + +# The remote address that all artifacts will eventually be uploaded to. The +# build system generates manifests which will point to these urls, and for the +# manifests to be correct they'll have to have the right URLs encoded. +# +# Note that this address should not contain a trailing slash as file names will +# be appended to it. +#dist.upload-addr = (URL) + +# Whether to build a plain source tarball to upload +# We disable that on Windows not to override the one already uploaded on S3 +# as the one built on Windows will contain backslashes in paths causing problems +# on linux +#dist.src-tarball = true + +# List of compression formats to use when generating dist tarballs. The list of +# formats is provided to rust-installer, which must support all of them. +# +# This list must be non-empty. +#dist.compression-formats = ["gz", "xz"] + +# How much time should be spent compressing the tarballs. The better the +# compression profile, the longer compression will take. +# +# Available options: fast, balanced, best +#dist.compression-profile = "fast" + +# Copy the linker, DLLs, and various libraries from MinGW into the Rust toolchain. +# Only applies when the host or target is pc-windows-gnu. +#dist.include-mingw-linker = true + +# Whether to vendor dependencies for the dist tarball. +#dist.vendor = if "is a tarball source" || "is a git repository" { true } else { false } + # ============================================================================= # Options for specific targets @@ -973,53 +1018,3 @@ # Link the compiler and LLVM against `jemalloc` instead of the default libc allocator. # This overrides the global `rust.jemalloc` option. See that option for more info. #jemalloc = rust.jemalloc (bool) - -# ============================================================================= -# Distribution options -# -# These options are related to distribution, mostly for the Rust project itself. -# You probably won't need to concern yourself with any of these options -# ============================================================================= -[dist] - -# This is the folder of artifacts that the build system will sign. All files in -# this directory will be signed with the default gpg key using the system `gpg` -# binary. The `asc` and `sha256` files will all be output into the standard dist -# output folder (currently `build/dist`) -# -# This folder should be populated ahead of time before the build system is -# invoked. -#sign-folder = (path) - -# The remote address that all artifacts will eventually be uploaded to. The -# build system generates manifests which will point to these urls, and for the -# manifests to be correct they'll have to have the right URLs encoded. -# -# Note that this address should not contain a trailing slash as file names will -# be appended to it. -#upload-addr = (URL) - -# Whether to build a plain source tarball to upload -# We disable that on Windows not to override the one already uploaded on S3 -# as the one built on Windows will contain backslashes in paths causing problems -# on linux -#src-tarball = true - -# List of compression formats to use when generating dist tarballs. The list of -# formats is provided to rust-installer, which must support all of them. -# -# This list must be non-empty. -#compression-formats = ["gz", "xz"] - -# How much time should be spent compressing the tarballs. The better the -# compression profile, the longer compression will take. -# -# Available options: fast, balanced, best -#compression-profile = "fast" - -# Copy the linker, DLLs, and various libraries from MinGW into the Rust toolchain. -# Only applies when the host or target is pc-windows-gnu. -#include-mingw-linker = true - -# Whether to vendor dependencies for the dist tarball. -#vendor = if "is a tarball source" || "is a git repository" { true } else { false } From 57fdde331b225b8a8c1010dcc69868ccf7a1747d Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 17 Jun 2025 18:03:45 +0000 Subject: [PATCH 079/356] Update libc to 0.2.174 This includes a fix for building on gnux32. [1]: https://github.com/rust-lang/libc/releases/tag/0.2.174 --- Cargo.lock | 4 ++-- library/Cargo.lock | 4 ++-- src/tools/rustbook/Cargo.lock | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b107b11cff8..b31bb7ce062b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2045,9 +2045,9 @@ checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7" [[package]] name = "libc" -version = "0.2.173" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libdbus-sys" diff --git a/library/Cargo.lock b/library/Cargo.lock index c7d59655ea46..34012d6943b7 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -141,9 +141,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.173" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" dependencies = [ "rustc-std-workspace-core", ] diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 3e83a2168ff1..7bf3bb195ee0 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -808,9 +808,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.173" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "linereader" From 81f7eebb23cf4583d3c6d14009935aafe5326316 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Tue, 17 Jun 2025 12:24:44 -0700 Subject: [PATCH 080/356] Add a missing colon at the end of the expected panic message in location-detail-unwrap-multiline.rs --- tests/ui/panics/location-detail-unwrap-multiline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/panics/location-detail-unwrap-multiline.rs b/tests/ui/panics/location-detail-unwrap-multiline.rs index 56e1760d851b..e49e11a60610 100644 --- a/tests/ui/panics/location-detail-unwrap-multiline.rs +++ b/tests/ui/panics/location-detail-unwrap-multiline.rs @@ -1,7 +1,7 @@ //@ run-fail //@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only -Copt-level=0 //@ exec-env:RUST_BACKTRACE=1 -//@ regex-error-pattern: location-detail-unwrap-multiline\.rs:11(:10)?\n +//@ regex-error-pattern: location-detail-unwrap-multiline\.rs:11(:10)?:\n //@ needs-unwind //@ ignore-android FIXME #17520 From 42bb66add31d196bb8d0f0bfb79a00dfd2cad55b Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 17 Jun 2025 23:27:06 +0200 Subject: [PATCH 081/356] Also emit suggestions for usages in the `non_upper_case_globals` lint --- compiler/rustc_lint/src/lints.rs | 2 + compiler/rustc_lint/src/nonstandard_style.rs | 79 ++++++++++++++++--- tests/ui/lint/lint-non-uppercase-usages.fixed | 39 +++++++++ tests/ui/lint/lint-non-uppercase-usages.rs | 39 +++++++++ .../ui/lint/lint-non-uppercase-usages.stderr | 64 +++++++++++++++ 5 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 tests/ui/lint/lint-non-uppercase-usages.fixed create mode 100644 tests/ui/lint/lint-non-uppercase-usages.rs create mode 100644 tests/ui/lint/lint-non-uppercase-usages.stderr diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 3d17dfbc4519..d157bf6986ce 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1348,6 +1348,8 @@ pub(crate) struct NonUpperCaseGlobal<'a> { pub name: &'a str, #[subdiagnostic] pub sub: NonUpperCaseGlobalSub, + #[subdiagnostic] + pub usages: Vec, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 1b60466a589d..a5b3eb3f0ffb 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -2,8 +2,9 @@ use rustc_abi::ExternAbi; use rustc_attr_data_structures::{AttributeKind, ReprAttr}; use rustc_attr_parsing::AttributeParser; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::FnKind; +use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; +use rustc_middle::hir::nested_filter::All; use rustc_middle::ty; use rustc_session::config::CrateType; use rustc_session::{declare_lint, declare_lint_pass}; @@ -489,21 +490,59 @@ declare_lint! { declare_lint_pass!(NonUpperCaseGlobals => [NON_UPPER_CASE_GLOBALS]); impl NonUpperCaseGlobals { - fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) { + fn check_upper_case(cx: &LateContext<'_>, sort: &str, did: Option, ident: &Ident) { let name = ident.name.as_str(); if name.chars().any(|c| c.is_lowercase()) { let uc = NonSnakeCase::to_snake_case(name).to_uppercase(); + // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". - let sub = if *name != uc { - NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc } - } else { - NonUpperCaseGlobalSub::Label { span: ident.span } + let sub = |span| { + if *name != uc { + NonUpperCaseGlobalSub::Suggestion { span, replace: uc.clone() } + } else { + NonUpperCaseGlobalSub::Label { span } + } }; + + struct UsageCollector<'a, 'tcx> { + cx: &'tcx LateContext<'a>, + did: LocalDefId, + collected: Vec, + } + + impl<'v, 'tcx> Visitor<'v> for UsageCollector<'v, 'tcx> { + type NestedFilter = All; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.cx.tcx + } + + fn visit_path( + &mut self, + path: &rustc_hir::Path<'v>, + _id: rustc_hir::HirId, + ) -> Self::Result { + for seg in path.segments { + if seg.res.opt_def_id() == Some(self.did.to_def_id()) { + self.collected.push(seg.ident.span); + } + } + } + } + + let usages = if let Some(did) = did { + let mut usage_collector = UsageCollector { cx, did, collected: Vec::new() }; + cx.tcx.hir_walk_toplevel_module(&mut usage_collector); + usage_collector.collected.into_iter().map(|span| sub(span)).collect() + } else { + vec![] + }; + cx.emit_span_lint( NON_UPPER_CASE_GLOBALS, ident.span, - NonUpperCaseGlobal { sort, name, sub }, + NonUpperCaseGlobal { sort, name, sub: sub(ident.span), usages }, ); } } @@ -516,10 +555,20 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { hir::ItemKind::Static(_, ident, ..) if !ast::attr::contains_name(attrs, sym::no_mangle) => { - NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident); + NonUpperCaseGlobals::check_upper_case( + cx, + "static variable", + Some(it.owner_id.def_id), + &ident, + ); } hir::ItemKind::Const(ident, ..) => { - NonUpperCaseGlobals::check_upper_case(cx, "constant", &ident); + NonUpperCaseGlobals::check_upper_case( + cx, + "constant", + Some(it.owner_id.def_id), + &ident, + ); } _ => {} } @@ -527,7 +576,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_trait_item(&mut self, cx: &LateContext<'_>, ti: &hir::TraitItem<'_>) { if let hir::TraitItemKind::Const(..) = ti.kind { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ti.ident); + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ti.ident); } } @@ -535,7 +584,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident); + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ii.ident); } } @@ -551,6 +600,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { NonUpperCaseGlobals::check_upper_case( cx, "constant in pattern", + None, &segment.ident, ); } @@ -560,7 +610,12 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) { if let GenericParamKind::Const { .. } = param.kind { - NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident()); + NonUpperCaseGlobals::check_upper_case( + cx, + "const parameter", + Some(param.def_id), + ¶m.name.ident(), + ); } } } diff --git a/tests/ui/lint/lint-non-uppercase-usages.fixed b/tests/ui/lint/lint-non-uppercase-usages.fixed new file mode 100644 index 000000000000..048a936ff273 --- /dev/null +++ b/tests/ui/lint/lint-non-uppercase-usages.fixed @@ -0,0 +1,39 @@ +// Checks that the `non_upper_case_globals` emits suggestions for usages as well +// + +//@ check-pass +//@ run-rustfix + +#![allow(dead_code)] + +use std::cell::Cell; + +const MY_STATIC: u32 = 0; +//~^ WARN constant `my_static` should have an upper case name +//~| SUGGESTION MY_STATIC + +const LOL: u32 = MY_STATIC + 0; +//~^ SUGGESTION MY_STATIC + +thread_local! { + static FOO_FOO: Cell = unreachable!(); + //~^ WARN constant `fooFOO` should have an upper case name + //~| SUGGESTION FOO_FOO +} + +fn foo() { + //~^ WARN const parameter `foo` should have an upper case name + //~| SUGGESTION FOO + let _a = FOO + 1; + //~^ SUGGESTION FOO +} + +fn main() { + let _a = crate::MY_STATIC; + //~^ SUGGESTION MY_STATIC + + FOO_FOO.set(9); + //~^ SUGGESTION FOO_FOO + println!("{}", FOO_FOO.get()); + //~^ SUGGESTION FOO_FOO +} diff --git a/tests/ui/lint/lint-non-uppercase-usages.rs b/tests/ui/lint/lint-non-uppercase-usages.rs new file mode 100644 index 000000000000..b5b9ffac6bce --- /dev/null +++ b/tests/ui/lint/lint-non-uppercase-usages.rs @@ -0,0 +1,39 @@ +// Checks that the `non_upper_case_globals` emits suggestions for usages as well +// + +//@ check-pass +//@ run-rustfix + +#![allow(dead_code)] + +use std::cell::Cell; + +const my_static: u32 = 0; +//~^ WARN constant `my_static` should have an upper case name +//~| SUGGESTION MY_STATIC + +const LOL: u32 = my_static + 0; +//~^ SUGGESTION MY_STATIC + +thread_local! { + static fooFOO: Cell = unreachable!(); + //~^ WARN constant `fooFOO` should have an upper case name + //~| SUGGESTION FOO_FOO +} + +fn foo() { + //~^ WARN const parameter `foo` should have an upper case name + //~| SUGGESTION FOO + let _a = foo + 1; + //~^ SUGGESTION FOO +} + +fn main() { + let _a = crate::my_static; + //~^ SUGGESTION MY_STATIC + + fooFOO.set(9); + //~^ SUGGESTION FOO_FOO + println!("{}", fooFOO.get()); + //~^ SUGGESTION FOO_FOO +} diff --git a/tests/ui/lint/lint-non-uppercase-usages.stderr b/tests/ui/lint/lint-non-uppercase-usages.stderr new file mode 100644 index 000000000000..fa47b4ba6a8f --- /dev/null +++ b/tests/ui/lint/lint-non-uppercase-usages.stderr @@ -0,0 +1,64 @@ +warning: constant `my_static` should have an upper case name + --> $DIR/lint-non-uppercase-usages.rs:11:7 + | +LL | const my_static: u32 = 0; + | ^^^^^^^^^ + | + = note: `#[warn(non_upper_case_globals)]` on by default +help: convert the identifier to upper case + | +LL - const my_static: u32 = 0; +LL + const MY_STATIC: u32 = 0; + | +help: convert the identifier to upper case + | +LL - const LOL: u32 = my_static + 0; +LL + const LOL: u32 = MY_STATIC + 0; + | +help: convert the identifier to upper case + | +LL - let _a = crate::my_static; +LL + let _a = crate::MY_STATIC; + | + +warning: constant `fooFOO` should have an upper case name + --> $DIR/lint-non-uppercase-usages.rs:19:12 + | +LL | static fooFOO: Cell = unreachable!(); + | ^^^^^^ + | +help: convert the identifier to upper case + | +LL - static fooFOO: Cell = unreachable!(); +LL + static FOO_FOO: Cell = unreachable!(); + | +help: convert the identifier to upper case + | +LL - fooFOO.set(9); +LL + FOO_FOO.set(9); + | +help: convert the identifier to upper case + | +LL - println!("{}", fooFOO.get()); +LL + println!("{}", FOO_FOO.get()); + | + +warning: const parameter `foo` should have an upper case name + --> $DIR/lint-non-uppercase-usages.rs:24:14 + | +LL | fn foo() { + | ^^^ + | +help: convert the identifier to upper case (notice the capitalization difference) + | +LL - fn foo() { +LL + fn foo() { + | +help: convert the identifier to upper case (notice the capitalization difference) + | +LL - let _a = foo + 1; +LL + let _a = FOO + 1; + | + +warning: 3 warnings emitted + From 66e056a3a7f16a61865ce5feb581d267e400016b Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 17 Jun 2025 16:10:35 -0700 Subject: [PATCH 082/356] library: Increase timeout on mpmc test to reduce flakes This recently spuriously failed in a rollup, so I think we can afford to increase the base timeout and the amount of time slept for to provide a much wider margin for the timeout to be reached. --- library/std/tests/sync/mpmc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/tests/sync/mpmc.rs b/library/std/tests/sync/mpmc.rs index 594fc2180d83..bf80ab96a88b 100644 --- a/library/std/tests/sync/mpmc.rs +++ b/library/std/tests/sync/mpmc.rs @@ -463,12 +463,12 @@ fn oneshot_single_thread_recv_timeout() { fn stress_recv_timeout_two_threads() { let (tx, rx) = channel(); let stress = stress_factor() + 50; - let timeout = Duration::from_millis(5); + let timeout = Duration::from_millis(10); thread::spawn(move || { for i in 0..stress { if i % 2 == 0 { - thread::sleep(timeout * 2); + thread::sleep(timeout * 4); } tx.send(1usize).unwrap(); } From eee2d7b1016d6f2743c5f61989b28e05fefd9aff Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Tue, 17 Jun 2025 10:14:05 +0700 Subject: [PATCH 083/356] AsyncDrop trait without sync Drop generates an error --- compiler/rustc_hir_analysis/messages.ftl | 3 +++ compiler/rustc_hir_analysis/src/check/mod.rs | 10 +++++++++- compiler/rustc_hir_analysis/src/errors.rs | 8 ++++++++ .../async-drop/async-without-sync.rs | 19 +++++++++++++++++++ .../async-drop/async-without-sync.stderr | 10 ++++++++++ 5 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/ui/async-await/async-drop/async-without-sync.rs create mode 100644 tests/ui/async-await/async-drop/async-without-sync.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index f768bd157abc..bd2252c1bf8f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -46,6 +46,9 @@ hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the {$ hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes +hir_analysis_async_drop_without_sync_drop = `AsyncDrop` impl without `Drop` impl + .help = type implementing `AsyncDrop` trait must also implement `Drop` trait to be used in sync context and unwinds + hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` .label = deref recursion limit reached .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index c5c7e6b2aa72..de8cbc3a57ff 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -113,7 +113,15 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_dtor(def_id, always_applicable::check_drop_impl) + let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl); + if dtor.is_none() && tcx.features().async_drop() { + if let Some(async_dtor) = adt_async_destructor(tcx, def_id) { + // When type has AsyncDrop impl, but doesn't have Drop impl, generate error + let span = tcx.def_span(async_dtor.impl_did); + tcx.dcx().emit_err(errors::AsyncDropWithoutSyncDrop { span }); + } + } + dtor } fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 8de2aec95a7b..318aaab50f4d 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1712,3 +1712,11 @@ pub(crate) struct AbiCustomClothedFunction { )] pub naked_span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_async_drop_without_sync_drop)] +#[help] +pub(crate) struct AsyncDropWithoutSyncDrop { + #[primary_span] + pub span: Span, +} diff --git a/tests/ui/async-await/async-drop/async-without-sync.rs b/tests/ui/async-await/async-drop/async-without-sync.rs new file mode 100644 index 000000000000..8a748636cc78 --- /dev/null +++ b/tests/ui/async-await/async-drop/async-without-sync.rs @@ -0,0 +1,19 @@ +//@ edition: 2024 +#![feature(async_drop)] +#![allow(incomplete_features)] +#![crate_type = "lib"] + +use std::future::AsyncDrop; +use std::pin::Pin; + +async fn foo() { + let _st = St; +} + +struct St; + +impl AsyncDrop for St { //~ ERROR: `AsyncDrop` impl without `Drop` impl + async fn drop(self: Pin<&mut Self>) { + println!("123"); + } +} diff --git a/tests/ui/async-await/async-drop/async-without-sync.stderr b/tests/ui/async-await/async-drop/async-without-sync.stderr new file mode 100644 index 000000000000..0eaca322dc03 --- /dev/null +++ b/tests/ui/async-await/async-drop/async-without-sync.stderr @@ -0,0 +1,10 @@ +error: `AsyncDrop` impl without `Drop` impl + --> $DIR/async-without-sync.rs:15:1 + | +LL | impl AsyncDrop for St { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: type implementing `AsyncDrop` trait must also implement `Drop` trait to be used in sync context and unwinds + +error: aborting due to 1 previous error + From b3914945ae2d77770c25ed124a8450d82c8f7fe9 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Wed, 18 Jun 2025 00:38:55 -0400 Subject: [PATCH 084/356] add ChildExt(::send_signal) --- library/std/src/os/unix/mod.rs | 3 ++ library/std/src/os/unix/process.rs | 35 +++++++++++++++++++ library/std/src/sys/pal/unix/linux/pidfd.rs | 6 +++- library/std/src/sys/process/unix/fuchsia.rs | 5 +++ library/std/src/sys/process/unix/unix.rs | 12 ++++--- .../std/src/sys/process/unix/unsupported.rs | 6 +++- library/std/src/sys/process/unix/vxworks.rs | 8 +++-- 7 files changed, 67 insertions(+), 8 deletions(-) diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 5802b6539651..78c957270c45 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -116,6 +116,9 @@ pub mod prelude { #[stable(feature = "rust1", since = "1.0.0")] pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[doc(no_inline)] + #[unstable(feature = "unix_send_signal", issue = "141975")] + pub use super::process::ChildExt; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::process::{CommandExt, ExitStatusExt}; #[doc(no_inline)] diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 57ce3c5a4bf4..3f4fe2e56ec3 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -378,6 +378,41 @@ impl ExitStatusExt for process::ExitStatusError { } } +#[unstable(feature = "unix_send_signal", issue = "141975")] +pub trait ChildExt: Sealed { + /// Sends a signal to a child process. + /// + /// # Errors + /// + /// This function will return an error if the signal is invalid. The integer values associated + /// with signals are implemenation-specific, so it's encouraged to use a crate that provides + /// posix bindings. + /// + /// # Examples + /// + /// ```rust + /// #![feature(unix_send_signal)] + /// + /// use std::{io, os::unix::process::ChildExt, process::{Command, Stdio}}; + /// + /// use libc::SIGTERM; + /// + /// fn main() -> io::Result<()> { + /// let child = Command::new("cat").stdin(Stdio::piped()).spawn()?; + /// child.send_signal(SIGTERM)?; + /// Ok(()) + /// } + /// ``` + fn send_signal(&self, signal: i32) -> io::Result<()>; +} + +#[unstable(feature = "unix_send_signal", issue = "141975")] +impl ChildExt for process::Child { + fn send_signal(&self, signal: i32) -> io::Result<()> { + self.handle.send_signal(signal) + } +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawFd for process::Stdio { #[inline] diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs index 2d949ec9e91f..47e9a616bfda 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd.rs @@ -13,11 +13,15 @@ pub(crate) struct PidFd(FileDesc); impl PidFd { pub fn kill(&self) -> io::Result<()> { + self.send_signal(libc::SIGKILL) + } + + pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> { cvt(unsafe { libc::syscall( libc::SYS_pidfd_send_signal, self.0.as_raw_fd(), - libc::SIGKILL, + signal, crate::ptr::null::<()>(), 0, ) diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs index 017ab91797ce..d71be510b6af 100644 --- a/library/std/src/sys/process/unix/fuchsia.rs +++ b/library/std/src/sys/process/unix/fuchsia.rs @@ -152,6 +152,11 @@ impl Process { Ok(()) } + pub fn send_signal(&self, _signal: i32) -> io::Result<()> { + // Fuchsia doesn't have a direct equivalent for signals + unimplemented!() + } + pub fn wait(&mut self) -> io::Result { let mut proc_info: zx_info_process_t = Default::default(); let mut actual: size_t = 0; diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 4f595ac9a1c5..1fe80c13b81c 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -963,9 +963,13 @@ impl Process { self.pid as u32 } - pub fn kill(&mut self) -> io::Result<()> { + pub fn kill(&self) -> io::Result<()> { + self.send_signal(libc::SIGKILL) + } + + pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> { // If we've already waited on this process then the pid can be recycled - // and used for another process, and we probably shouldn't be killing + // and used for another process, and we probably shouldn't be signaling // random processes, so return Ok because the process has exited already. if self.status.is_some() { return Ok(()); @@ -973,9 +977,9 @@ impl Process { #[cfg(target_os = "linux")] if let Some(pid_fd) = self.pidfd.as_ref() { // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too - return pid_fd.kill(); + return pid_fd.send_signal(signal); } - cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) + cvt(unsafe { libc::kill(self.pid, signal) }).map(drop) } pub fn wait(&mut self) -> io::Result { diff --git a/library/std/src/sys/process/unix/unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs index e86561a5c5c4..87403cd50f82 100644 --- a/library/std/src/sys/process/unix/unsupported.rs +++ b/library/std/src/sys/process/unix/unsupported.rs @@ -40,7 +40,11 @@ impl Process { 0 } - pub fn kill(&mut self) -> io::Result<()> { + pub fn kill(&self) -> io::Result<()> { + unsupported() + } + + pub fn send_signal(&self, _signal: i32) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs index f33b4a375da8..51ae8c56bdb9 100644 --- a/library/std/src/sys/process/unix/vxworks.rs +++ b/library/std/src/sys/process/unix/vxworks.rs @@ -146,14 +146,18 @@ impl Process { self.pid as u32 } - pub fn kill(&mut self) -> io::Result<()> { + pub fn kill(&self) -> io::Result<()> { + self.send_signal(libc::SIGKILL) + } + + pub fn send_signal(&self, signal: i32) -> io::Result<()> { // If we've already waited on this process then the pid can be recycled // and used for another process, and we probably shouldn't be killing // random processes, so return Ok because the process has exited already. if self.status.is_some() { Ok(()) } else { - cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop) + cvt(unsafe { libc::kill(self.pid, signal) }).map(drop) } } From 5d1a8690cb62abc2dd3d2f1696c272c56bece3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 18 Jun 2025 09:23:00 +0300 Subject: [PATCH 085/356] Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index af0dd5c9acda..a454087b0cdc 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -7c10378e1fee5ddc6573b916aeb884ab10e0de17 +27733d46d79f4eb92e240fbba502c43022665735 From 8ff2c1a97ed9dab37bca913fab0e4cce783e521c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 May 2025 17:40:30 +0200 Subject: [PATCH 086/356] Allow storing `format_args!()` in `let`. This uses `super let` to allow let f = format_args!("Hello {}", world); println!("{f}"); to work. --- compiler/rustc_ast_lowering/src/expr.rs | 12 +- compiler/rustc_ast_lowering/src/format.rs | 213 ++++++++-------------- compiler/rustc_ast_lowering/src/lib.rs | 20 ++ library/core/src/fmt/rt.rs | 38 +--- 4 files changed, 109 insertions(+), 174 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 718edad0cc61..f297bf9f4cfe 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2289,12 +2289,12 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, elements: &'hir [hir::Expr<'hir>], ) -> hir::Expr<'hir> { - let addrof = hir::ExprKind::AddrOf( - hir::BorrowKind::Ref, - hir::Mutability::Not, - self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))), - ); - self.expr(span, addrof) + let array = self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))); + self.expr_ref(span, array) + } + + pub(super) fn expr_ref(&mut self, span: Span, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> { + self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr)) } pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> { diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 17b443b8ecc2..4138cc426c75 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -1,7 +1,5 @@ -use core::ops::ControlFlow; use std::borrow::Cow; -use rustc_ast::visit::Visitor; use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; @@ -476,77 +474,52 @@ fn expand_format_args<'hir>( return hir::ExprKind::Call(new, new_args); } - // If the args array contains exactly all the original arguments once, - // in order, we can use a simple array instead of a `match` construction. - // However, if there's a yield point in any argument except the first one, - // we don't do this, because an Argument cannot be kept across yield points. - // - // This is an optimization, speeding up compilation about 1-2% in some cases. - // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609 - let use_simple_array = argmap.len() == arguments.len() - && argmap.iter().enumerate().all(|(i, (&(j, _), _))| i == j) - && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr)); - - let args = if arguments.is_empty() { + let (let_statements, args) = if arguments.is_empty() { // Generate: - // &::none() + // [] + (vec![], ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(&[])))) + } else if argmap.len() == 1 && arguments.len() == 1 { + // Only one argument, so we don't need to make the `args` tuple. // - // Note: - // `none()` just returns `[]`. We use `none()` rather than `[]` to limit the lifetime. - // - // This makes sure that this still fails to compile, even when the argument is inlined: - // - // ``` - // let f = format_args!("{}", "a"); - // println!("{f}"); // error E0716 - // ``` - // - // Cases where keeping the object around is allowed, such as `format_args!("a")`, - // are handled above by the `allow_const` case. - let none_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - macsp, - hir::LangItem::FormatArgument, - sym::none, - )); - let none = ctx.expr_call(macsp, none_fn, &[]); - ctx.expr(macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, none)) - } else if use_simple_array { // Generate: - // &[ - // ::new_display(&arg0), - // ::new_lower_hex(&arg1), - // ::new_debug(&arg2), - // … - // ] - let elements = ctx.arena.alloc_from_iter(arguments.iter().zip(argmap).map( - |(arg, ((_, ty), placeholder_span))| { + // super let args = [::new_display(&arg)]; + let args = ctx.arena.alloc_from_iter(argmap.iter().map( + |(&(arg_index, ty), &placeholder_span)| { + let arg = &arguments[arg_index]; let placeholder_span = placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); - let arg_span = match arg.kind { - FormatArgumentKind::Captured(_) => placeholder_span, - _ => arg.expr.span.with_ctxt(macsp.ctxt()), - }; let arg = ctx.lower_expr(&arg.expr); - let ref_arg = ctx.arena.alloc(ctx.expr( - arg_span, - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg), - )); + let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span, arg)); make_argument(ctx, placeholder_span, ref_arg, ty) }, )); - ctx.expr_array_ref(macsp, elements) - } else { - // Generate: - // &match (&arg0, &arg1, &…) { - // args => [ - // ::new_display(args.0), - // ::new_lower_hex(args.1), - // ::new_debug(args.0), - // … - // ] - // } + let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args))); let args_ident = Ident::new(sym::args, macsp); let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); + let let_statement = ctx.stmt_super_let_pat(macsp, args_pat, Some(args)); + (vec![let_statement], ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id))) + } else { + // Generate: + // super let args = (&arg0, &arg1, &…); + let args_ident = Ident::new(sym::args, macsp); + let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); + let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| { + let arg_expr = ctx.lower_expr(&arg.expr); + ctx.expr( + arg.expr.span.with_ctxt(macsp.ctxt()), + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr), + ) + })); + let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements))); + let let_statement_1 = ctx.stmt_super_let_pat(macsp, args_pat, Some(args_tuple)); + + // Generate: + // super let args = [ + // ::new_display(args.0), + // ::new_lower_hex(args.1), + // ::new_debug(args.0), + // … + // ]; let args = ctx.arena.alloc_from_iter(argmap.iter().map( |(&(arg_index, ty), &placeholder_span)| { let arg = &arguments[arg_index]; @@ -567,58 +540,48 @@ fn expand_format_args<'hir>( make_argument(ctx, placeholder_span, arg, ty) }, )); - let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| { - let arg_expr = ctx.lower_expr(&arg.expr); - ctx.expr( - arg.expr.span.with_ctxt(macsp.ctxt()), - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr), - ) - })); - let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements))); - let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args))); - let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]); - let match_expr = ctx.arena.alloc(ctx.expr_match( - macsp, - args_tuple, - match_arms, - hir::MatchSource::FormatArgs, - )); - ctx.expr( - macsp, - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr), + let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args))); + let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident); + let let_statement_2 = ctx.stmt_super_let_pat(macsp, args_pat, Some(args)); + ( + vec![let_statement_1, let_statement_2], + ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)), ) }; - if let Some(format_options) = format_options { + // Generate: + // &args + let args = + ctx.expr(macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, args)); + + let call = if let Some(format_options) = format_options { // Generate: - // ::new_v1_formatted( - // lit_pieces, - // args, - // format_options, - // unsafe { ::core::fmt::UnsafeArg::new() } - // ) + // unsafe { + // ::new_v1_formatted( + // lit_pieces, + // args, + // format_options, + // ) + // } let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative( macsp, hir::LangItem::FormatArguments, sym::new_v1_formatted, )); - let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( - macsp, - hir::LangItem::FormatUnsafeArg, - sym::new, - )); - let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]); + let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options]); + let call = ctx.expr_call(macsp, new_v1_formatted, args); let hir_id = ctx.next_id(); - let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block { - stmts: &[], - expr: Some(unsafe_arg_new_call), - hir_id, - rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated), - span: macsp, - targeted_by_break: false, - })); - let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]); - hir::ExprKind::Call(new_v1_formatted, args) + hir::ExprKind::Block( + ctx.arena.alloc(hir::Block { + stmts: &[], + expr: Some(call), + hir_id, + rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated), + span: macsp, + targeted_by_break: false, + }), + None, + ) } else { // Generate: // ::new_v1( @@ -632,37 +595,23 @@ fn expand_format_args<'hir>( )); let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]); hir::ExprKind::Call(new_v1, new_args) + }; + + if !let_statements.is_empty() { + // Generate: + // { + // super let … + // super let … + // ::new_…(…) + // } + let call = ctx.arena.alloc(ctx.expr(macsp, call)); + let block = ctx.block_all(macsp, ctx.arena.alloc_from_iter(let_statements), Some(call)); + hir::ExprKind::Block(block, None) + } else { + call } } -fn may_contain_yield_point(e: &ast::Expr) -> bool { - struct MayContainYieldPoint; - - impl Visitor<'_> for MayContainYieldPoint { - type Result = ControlFlow<()>; - - fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> { - if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind { - ControlFlow::Break(()) - } else { - visit::walk_expr(self, e) - } - } - - fn visit_mac_call(&mut self, _: &ast::MacCall) -> ControlFlow<()> { - // Macros should be expanded at this point. - unreachable!("unexpanded macro in ast lowering"); - } - - fn visit_item(&mut self, _: &ast::Item) -> ControlFlow<()> { - // Do not recurse into nested items. - ControlFlow::Continue(()) - } - } - - MayContainYieldPoint.visit_expr(e).is_break() -} - fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) { for piece in template { let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3b99a653417a..048408155766 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2301,6 +2301,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local))) } + fn stmt_super_let_pat( + &mut self, + span: Span, + pat: &'hir hir::Pat<'hir>, + init: Option<&'hir hir::Expr<'hir>>, + ) -> hir::Stmt<'hir> { + let hir_id = self.next_id(); + let local = hir::LetStmt { + super_: Some(span), + hir_id, + init, + pat, + els: None, + source: hir::LocalSource::Normal, + span: self.lower_span(span), + ty: None, + }; + self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local))) + } + fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> { self.block_all(expr.span, &[], Some(expr)) } diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 7fd8d3e5b531..fb858a057261 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -183,38 +183,6 @@ impl Argument<'_> { ArgumentType::Placeholder { .. } => None, } } - - /// Used by `format_args` when all arguments are gone after inlining, - /// when using `&[]` would incorrectly allow for a bigger lifetime. - /// - /// This fails without format argument inlining, and that shouldn't be different - /// when the argument is inlined: - /// - /// ```compile_fail,E0716 - /// let f = format_args!("{}", "a"); - /// println!("{f}"); - /// ``` - #[inline] - pub const fn none() -> [Self; 0] { - [] - } -} - -/// This struct represents the unsafety of constructing an `Arguments`. -/// It exists, rather than an unsafe function, in order to simplify the expansion -/// of `format_args!(..)` and reduce the scope of the `unsafe` block. -#[lang = "format_unsafe_arg"] -pub struct UnsafeArg { - _private: (), -} - -impl UnsafeArg { - /// See documentation where `UnsafeArg` is required to know when it is safe to - /// create and use `UnsafeArg`. - #[inline] - pub const unsafe fn new() -> Self { - Self { _private: () } - } } /// Used by the format_args!() macro to create a fmt::Arguments object. @@ -248,8 +216,7 @@ impl<'a> Arguments<'a> { /// Specifies nonstandard formatting parameters. /// - /// An `rt::UnsafeArg` is required because the following invariants must be held - /// in order for this function to be safe: + /// SAFETY: the following invariants must be held: /// 1. The `pieces` slice must be at least as long as `fmt`. /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. @@ -261,11 +228,10 @@ impl<'a> Arguments<'a> { /// const _: () = if false { panic!("a {:1}", "a") }; /// ``` #[inline] - pub fn new_v1_formatted( + pub unsafe fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [rt::Argument<'a>], fmt: &'a [rt::Placeholder], - _unsafe_arg: rt::UnsafeArg, ) -> Arguments<'a> { Arguments { pieces, fmt: Some(fmt), args } } From 5b763fb1b7a06393c5dc21502ac0b28776ce058f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 May 2025 17:41:26 +0200 Subject: [PATCH 087/356] Add test for new format_args!() temporary lifetimes. --- library/coretests/tests/fmt/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs index d9060fe903d2..16f116d25901 100644 --- a/library/coretests/tests/fmt/mod.rs +++ b/library/coretests/tests/fmt/mod.rs @@ -2,6 +2,21 @@ mod builders; mod float; mod num; +#[test] +fn test_lifetime() { + // Trigger all different forms of expansion, + // and check that each of them can be stored as a variable. + let a = format_args!("hello"); + let a = format_args!("hello {a}"); + let a = format_args!("hello {a:1}"); + let a = format_args!("hello {a} {a:?}"); + assert_eq!(a.to_string(), "hello hello hello hello hello hello hello"); + + // Without arguments, it should also work in consts. + const A: std::fmt::Arguments<'static> = format_args!("hello"); + assert_eq!(A.to_string(), "hello"); +} + #[test] fn test_format_flags() { // No residual flags left by pointer formatting From ddd9ee9756643dc3ed28c4fc9da4815fe4a37f1d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 May 2025 17:42:04 +0200 Subject: [PATCH 088/356] Remove outdated test. We no longer error in this case! --- src/tools/tidy/src/issues.txt | 1 - .../issue-114374-invalid-help-fmt-args.rs | 16 ---------- .../issue-114374-invalid-help-fmt-args.stderr | 31 ------------------- 3 files changed, 48 deletions(-) delete mode 100644 tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs delete mode 100644 tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 045f2f0692a1..b3517b2e9da0 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -305,7 +305,6 @@ ui/borrowck/issue-104639-lifetime-order.rs ui/borrowck/issue-10876.rs ui/borrowck/issue-109271-pass-self-into-closure.rs ui/borrowck/issue-111554.rs -ui/borrowck/issue-114374-invalid-help-fmt-args.rs ui/borrowck/issue-11493.rs ui/borrowck/issue-115259-suggest-iter-mut.rs ui/borrowck/issue-119915-bad-clone-suggestion.rs diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs deleted file mode 100644 index 4a6c2f9ed065..000000000000 --- a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![allow(dead_code)] - -fn bar<'a>(_: std::fmt::Arguments<'a>) {} -fn main() { - let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3); - //~^ ERROR temporary value dropped while borrowed - - bar(x); - - let foo = format_args!("{}", "hi"); - //~^ ERROR temporary value dropped while borrowed - bar(foo); - - let foo = format_args!("hi"); // no placeholder in arguments, so no error - bar(foo); -} diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr deleted file mode 100644 index 30f292f71a28..000000000000 --- a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-114374-invalid-help-fmt-args.rs:5:13 - | -LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -... -LL | bar(x); - | - borrow later used here - | - = note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used - = note: to learn more, visit - -error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-114374-invalid-help-fmt-args.rs:10:15 - | -LL | let foo = format_args!("{}", "hi"); - | ^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement - | | - | creates a temporary value which is freed while still in use -LL | -LL | bar(foo); - | --- borrow later used here - | - = note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used - = note: to learn more, visit - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0716`. From 4ca0f01a5a2b69cd250d27fb3bc6719985a2cc0d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 May 2025 17:43:11 +0200 Subject: [PATCH 089/356] Update mir-opt tests. --- ...mes.foo.ScalarReplacementOfAggregates.diff | 159 +++++++++++------- 1 file changed, 94 insertions(+), 65 deletions(-) diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index 33f1ad9bef4e..e2d3c6c41b89 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -11,28 +11,29 @@ let _9: (); let _10: (); let mut _11: std::fmt::Arguments<'_>; - let mut _12: &[&str; 3]; - let _13: &[&str; 3]; - let _14: [&str; 3]; - let mut _15: &[core::fmt::rt::Argument<'_>; 2]; - let _16: &[core::fmt::rt::Argument<'_>; 2]; - let _17: [core::fmt::rt::Argument<'_>; 2]; + let mut _13: &std::boxed::Box; + let mut _14: &u32; + let mut _16: core::fmt::rt::Argument<'_>; + let mut _17: &std::boxed::Box; let mut _18: core::fmt::rt::Argument<'_>; - let mut _19: &std::boxed::Box; - let _20: &std::boxed::Box; - let mut _21: core::fmt::rt::Argument<'_>; - let mut _22: &u32; - let _23: &u32; - let mut _25: bool; - let mut _26: isize; - let mut _27: isize; - let mut _28: isize; -+ let _29: std::result::Result, ::Err>; -+ let _30: u32; + let mut _19: &u32; + let mut _20: &[&str; 3]; + let _21: &[&str; 3]; + let _22: [&str; 3]; + let mut _23: &[core::fmt::rt::Argument<'_>; 2]; + let _24: &[core::fmt::rt::Argument<'_>; 2]; + let mut _26: &std::boxed::Box; + let mut _27: &u32; + let mut _28: bool; + let mut _29: isize; + let mut _30: isize; + let mut _31: isize; ++ let _32: std::result::Result, ::Err>; ++ let _33: u32; scope 1 { - debug foo => _1; -+ debug ((foo: Foo).0: std::result::Result, ::Err>) => _29; -+ debug ((foo: Foo).1: u32) => _30; ++ debug ((foo: Foo).0: std::result::Result, ::Err>) => _32; ++ debug ((foo: Foo).1: u32) => _33; let _5: std::result::Result, ::Err>; scope 2 { debug x => _5; @@ -42,17 +43,29 @@ scope 4 { debug x => _8; let _8: std::boxed::Box; - let mut _24: &[&str; 3]; + let _12: (&std::boxed::Box, &u32); ++ let _34: &std::boxed::Box; ++ let _35: &u32; + scope 5 { +- debug args => _12; ++ debug ((args: (&Box, &u32)).0: &std::boxed::Box) => _34; ++ debug ((args: (&Box, &u32)).1: &u32) => _35; + let _15: [core::fmt::rt::Argument<'_>; 2]; + scope 6 { + debug args => _15; + let mut _25: &[&str; 3]; + } + } } } } } bb0: { - _25 = const false; + _28 = const false; - StorageLive(_1); -+ StorageLive(_29); -+ StorageLive(_30); ++ StorageLive(_32); ++ StorageLive(_33); + nop; StorageLive(_2); StorageLive(_3); @@ -66,77 +79,93 @@ _2 = Result::, ::Err>::Ok(move _3); StorageDead(_3); - _1 = Foo:: { x: move _2, y: const 7_u32 }; -+ _29 = move _2; -+ _30 = const 7_u32; ++ _32 = move _2; ++ _33 = const 7_u32; + nop; StorageDead(_2); StorageLive(_5); - _25 = const true; + _28 = const true; - _5 = move (_1.0: std::result::Result, ::Err>); -+ _5 = move _29; ++ _5 = move _32; StorageLive(_6); - _6 = copy (_1.1: u32); -+ _6 = copy _30; ++ _6 = copy _33; _7 = discriminant(_5); switchInt(move _7) -> [0: bb2, otherwise: bb7]; } bb2: { StorageLive(_8); - _25 = const false; + _28 = const false; _8 = move ((_5 as Ok).0: std::boxed::Box); StorageLive(_9); StorageLive(_10); StorageLive(_11); - StorageLive(_12); +- StorageLive(_12); ++ StorageLive(_34); ++ StorageLive(_35); ++ nop; StorageLive(_13); - _24 = const foo::::promoted[0]; - _13 = &(*_24); - _12 = &(*_13); + _13 = &_8; + StorageLive(_14); + _14 = &_6; +- _12 = (move _13, move _14); ++ _34 = move _13; ++ _35 = move _14; ++ nop; + StorageDead(_14); + StorageDead(_13); StorageLive(_15); StorageLive(_16); StorageLive(_17); - StorageLive(_18); - StorageLive(_19); - StorageLive(_20); - _20 = &_8; - _19 = &(*_20); - _18 = core::fmt::rt::Argument::<'_>::new_display::>(move _19) -> [return: bb3, unwind unreachable]; +- _26 = deref_copy (_12.0: &std::boxed::Box); ++ _26 = deref_copy _34; + _17 = &(*_26); + _16 = core::fmt::rt::Argument::<'_>::new_display::>(move _17) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_19); - StorageLive(_21); - StorageLive(_22); - StorageLive(_23); - _23 = &_6; - _22 = &(*_23); - _21 = core::fmt::rt::Argument::<'_>::new_display::(move _22) -> [return: bb4, unwind unreachable]; + StorageDead(_17); + StorageLive(_18); + StorageLive(_19); +- _27 = deref_copy (_12.1: &u32); ++ _27 = deref_copy _35; + _19 = &(*_27); + _18 = core::fmt::rt::Argument::<'_>::new_display::(move _19) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_22); - _17 = [move _18, move _21]; - StorageDead(_21); + StorageDead(_19); + _15 = [move _16, move _18]; StorageDead(_18); - _16 = &_17; - _15 = &(*_16); - _11 = core::fmt::rt::>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable]; + StorageDead(_16); + StorageLive(_20); + StorageLive(_21); + _25 = const foo::::promoted[0]; + _21 = &(*_25); + _20 = &(*_21); + StorageLive(_23); + StorageLive(_24); + _24 = &_15; + _23 = &(*_24); + _11 = core::fmt::rt::>::new_v1::<3, 2>(move _20, move _23) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_15); - StorageDead(_12); + StorageDead(_24); + StorageDead(_23); + StorageDead(_21); + StorageDead(_20); _10 = _eprint(move _11) -> [return: bb6, unwind unreachable]; } bb6: { StorageDead(_11); - StorageDead(_23); - StorageDead(_20); - StorageDead(_17); - StorageDead(_16); - StorageDead(_13); + StorageDead(_15); +- StorageDead(_12); ++ StorageDead(_34); ++ StorageDead(_35); ++ nop; StorageDead(_10); _9 = const (); StorageDead(_9); @@ -156,22 +185,22 @@ bb9: { StorageDead(_6); - _26 = discriminant(_5); - switchInt(move _26) -> [0: bb11, otherwise: bb13]; + _29 = discriminant(_5); + switchInt(move _29) -> [0: bb11, otherwise: bb13]; } bb10: { - _25 = const false; + _28 = const false; StorageDead(_5); - StorageDead(_1); -+ StorageDead(_29); -+ StorageDead(_30); ++ StorageDead(_32); ++ StorageDead(_33); + nop; return; } bb11: { - switchInt(copy _25) -> [0: bb10, otherwise: bb12]; + switchInt(copy _28) -> [0: bb10, otherwise: bb12]; } bb12: { From f608da2ad83dbc215dae197e0c3a39b50e48ea39 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 May 2025 17:47:58 +0200 Subject: [PATCH 090/356] Remove 'this error originates in format_args_nl' from test output. This message is no longer generated. This is probably a good thing. The relevant span is entirely in user code, and "format_args_nl" is an implementation detail with a name that isn't even public. --- tests/ui/borrowck/borrowck-and-init.stderr | 2 -- tests/ui/borrowck/borrowck-break-uninit-2.stderr | 1 - tests/ui/borrowck/borrowck-break-uninit.stderr | 1 - tests/ui/borrowck/borrowck-or-init.stderr | 2 -- tests/ui/borrowck/borrowck-while-break.stderr | 2 -- tests/ui/borrowck/issue-24267-flow-exit.stderr | 2 -- tests/ui/borrowck/issue-47646.stderr | 2 -- tests/ui/borrowck/suggest-assign-rvalue.stderr | 10 ---------- .../2229_closure_analysis/diagnostics/arrays.stderr | 2 -- .../2229_closure_analysis/diagnostics/box.stderr | 2 -- .../diagnostics/repr_packed.stderr | 1 - .../diagnostics/simple-struct-min-capture.stderr | 2 -- tests/ui/closures/issue-111932.stderr | 1 - tests/ui/codemap_tests/tab_3.stderr | 1 - tests/ui/consts/const-eval/issue-44578.stderr | 3 +-- tests/ui/coroutine/yield-while-ref-reborrowed.stderr | 2 -- tests/ui/fmt/ifmt-unimpl.stderr | 1 - ...issue-107745-avoid-expr-from-macro-expansion.stderr | 2 -- tests/ui/issues/issue-42796.stderr | 1 - tests/ui/liveness/liveness-move-in-while.stderr | 1 - tests/ui/liveness/liveness-use-after-move.stderr | 1 - tests/ui/liveness/liveness-use-after-send.stderr | 1 - tests/ui/loops/loop-proper-liveness.stderr | 1 - tests/ui/modules/issue-107649.stderr | 2 +- .../moves-based-on-type-capture-clause-bad.stderr | 2 -- .../rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr | 2 +- tests/ui/span/issue-39698.stderr | 2 -- tests/ui/suggestions/bound-suggestions.stderr | 5 ----- tests/ui/suggestions/issue-97760.stderr | 1 - tests/ui/suggestions/path-display.stderr | 2 -- tests/ui/try-block/try-block-maybe-bad-lifetime.stderr | 1 - tests/ui/type-alias-impl-trait/nested.stderr | 1 - ...nding-assigned-block-without-tail-expression.stderr | 4 ---- tests/ui/use/use-after-move-based-on-type.stderr | 1 - tests/ui/walk-struct-literal-with.stderr | 1 - 35 files changed, 3 insertions(+), 65 deletions(-) diff --git a/tests/ui/borrowck/borrowck-and-init.stderr b/tests/ui/borrowck/borrowck-and-init.stderr index 37386f1c4651..e6d49bc6e471 100644 --- a/tests/ui/borrowck/borrowck-and-init.stderr +++ b/tests/ui/borrowck/borrowck-and-init.stderr @@ -8,8 +8,6 @@ LL | println!("{}", false && { i = 5; true }); | ----- binding initialized here in some conditions LL | println!("{}", i); | ^ `i` used here but it is possibly-uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.stderr b/tests/ui/borrowck/borrowck-break-uninit-2.stderr index e23ca534e745..03730e338ee0 100644 --- a/tests/ui/borrowck/borrowck-break-uninit-2.stderr +++ b/tests/ui/borrowck/borrowck-break-uninit-2.stderr @@ -7,7 +7,6 @@ LL | let x: isize; LL | println!("{}", x); | ^ `x` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: isize = 42; diff --git a/tests/ui/borrowck/borrowck-break-uninit.stderr b/tests/ui/borrowck/borrowck-break-uninit.stderr index 0367d224f801..6ed095f2e4a3 100644 --- a/tests/ui/borrowck/borrowck-break-uninit.stderr +++ b/tests/ui/borrowck/borrowck-break-uninit.stderr @@ -7,7 +7,6 @@ LL | let x: isize; LL | println!("{}", x); | ^ `x` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: isize = 42; diff --git a/tests/ui/borrowck/borrowck-or-init.stderr b/tests/ui/borrowck/borrowck-or-init.stderr index 7b43f2aee30e..63c0c982351b 100644 --- a/tests/ui/borrowck/borrowck-or-init.stderr +++ b/tests/ui/borrowck/borrowck-or-init.stderr @@ -8,8 +8,6 @@ LL | println!("{}", false || { i = 5; true }); | ----- binding initialized here in some conditions LL | println!("{}", i); | ^ `i` used here but it is possibly-uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-while-break.stderr b/tests/ui/borrowck/borrowck-while-break.stderr index e91af728b649..68333ce0a75d 100644 --- a/tests/ui/borrowck/borrowck-while-break.stderr +++ b/tests/ui/borrowck/borrowck-while-break.stderr @@ -8,8 +8,6 @@ LL | while cond { ... LL | println!("{}", v); | ^ `v` used here but it is possibly-uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-24267-flow-exit.stderr b/tests/ui/borrowck/issue-24267-flow-exit.stderr index 216f8d49b1b0..e81f00f8c157 100644 --- a/tests/ui/borrowck/issue-24267-flow-exit.stderr +++ b/tests/ui/borrowck/issue-24267-flow-exit.stderr @@ -7,7 +7,6 @@ LL | loop { x = break; } LL | println!("{}", x); | ^ `x` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: i32 = 42; @@ -22,7 +21,6 @@ LL | for _ in 0..10 { x = continue; } LL | println!("{}", x); | ^ `x` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: i32 = 42; diff --git a/tests/ui/borrowck/issue-47646.stderr b/tests/ui/borrowck/issue-47646.stderr index cfe6f3f39938..c8d48b76757a 100644 --- a/tests/ui/borrowck/issue-47646.stderr +++ b/tests/ui/borrowck/issue-47646.stderr @@ -12,8 +12,6 @@ LL | println!("{:?}", heap); ... LL | }; | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option>, ())` - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/suggest-assign-rvalue.stderr b/tests/ui/borrowck/suggest-assign-rvalue.stderr index daaef6e3892d..6ae893915aa9 100644 --- a/tests/ui/borrowck/suggest-assign-rvalue.stderr +++ b/tests/ui/borrowck/suggest-assign-rvalue.stderr @@ -19,7 +19,6 @@ LL | let my_float: f32; LL | println!("my_float: {}", my_float); | ^^^^^^^^ `my_float` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let my_float: f32 = 3.14159; @@ -33,7 +32,6 @@ LL | let demo: Demo; LL | println!("demo: {:?}", demo); | ^^^^ `demo` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let demo: Demo = Default::default(); @@ -47,7 +45,6 @@ LL | let demo_no: DemoNoDef; LL | println!("demo_no: {:?}", demo_no); | ^^^^^^^ `demo_no` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let demo_no: DemoNoDef = /* value */; @@ -61,7 +58,6 @@ LL | let arr: [i32; 5]; LL | println!("arr: {:?}", arr); | ^^^ `arr` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let arr: [i32; 5] = [42; 5]; @@ -75,7 +71,6 @@ LL | let foo: Vec<&str>; LL | println!("foo: {:?}", foo); | ^^^ `foo` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let foo: Vec<&str> = vec![]; @@ -89,7 +84,6 @@ LL | let my_string: String; LL | println!("my_string: {}", my_string); | ^^^^^^^^^ `my_string` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let my_string: String = Default::default(); @@ -103,7 +97,6 @@ LL | let my_int: &i32; LL | println!("my_int: {}", *my_int); | ^^^^^^^ `*my_int` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let my_int: &i32 = &42; @@ -117,7 +110,6 @@ LL | let hello: &str; LL | println!("hello: {}", hello); | ^^^^^ `hello` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let hello: &str = ""; @@ -130,8 +122,6 @@ LL | let never: !; | ----- binding declared here but left uninitialized LL | println!("never: {}", never); | ^^^^^ `never` used here but it isn't initialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr index 97ecdfab8205..4249dea10a36 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr @@ -53,8 +53,6 @@ LL | println!("{}", arr[3]); ... LL | c(); | - mutable borrow later used here - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable --> $DIR/arrays.rs:71:24 diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr index 2e3259e64059..09143f44dc83 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr @@ -25,8 +25,6 @@ LL | println!("{}", e.0.0.m.x); LL | LL | c(); | - mutable borrow later used here - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed --> $DIR/box.rs:55:5 diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr index c9972c8e7e34..9a75fcc520d5 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr @@ -7,7 +7,6 @@ LL | println!("{}", foo.x); = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr index 68fdb3ce131f..406f7c63b734 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr @@ -13,8 +13,6 @@ LL | println!("{:?}", p); LL | LL | c(); | - mutable borrow later used here - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/closures/issue-111932.stderr b/tests/ui/closures/issue-111932.stderr index 93488ad2011e..7d06db03c3bc 100644 --- a/tests/ui/closures/issue-111932.stderr +++ b/tests/ui/closures/issue-111932.stderr @@ -19,7 +19,6 @@ LL | println!("{:?}", foo); = help: the trait `Sized` is not implemented for `dyn Foo` note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'_>::new_debug` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/codemap_tests/tab_3.stderr b/tests/ui/codemap_tests/tab_3.stderr index 7ae21a57052f..2a0a9e2d48f3 100644 --- a/tests/ui/codemap_tests/tab_3.stderr +++ b/tests/ui/codemap_tests/tab_3.stderr @@ -11,7 +11,6 @@ LL | println!("{:?}", some_vec); | note: `into_iter` takes ownership of the receiver `self`, which moves `some_vec` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: you can `clone` the value and consume it, but this might not be your desired behavior | LL | some_vec.clone().into_iter(); diff --git a/tests/ui/consts/const-eval/issue-44578.stderr b/tests/ui/consts/const-eval/issue-44578.stderr index fd0b9ae1e17d..43bad0666a71 100644 --- a/tests/ui/consts/const-eval/issue-44578.stderr +++ b/tests/ui/consts/const-eval/issue-44578.stderr @@ -24,7 +24,7 @@ note: erroneous constant encountered LL | println!("{}", as Foo>::AMT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: erroneous constant encountered --> $DIR/issue-44578.rs:26:20 @@ -33,7 +33,6 @@ LL | println!("{}", as Foo>::AMT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/yield-while-ref-reborrowed.stderr b/tests/ui/coroutine/yield-while-ref-reborrowed.stderr index 7c9b766457db..643c4134b36e 100644 --- a/tests/ui/coroutine/yield-while-ref-reborrowed.stderr +++ b/tests/ui/coroutine/yield-while-ref-reborrowed.stderr @@ -10,8 +10,6 @@ LL | println!("{}", x); | ^ second borrow occurs here LL | Pin::new(&mut b).resume(()); | ------ first borrow later used here - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index b8d4425a4a71..7ca3c97a297b 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -19,7 +19,6 @@ LL | format!("{:X}", "3"); = note: required for `&str` to implement `UpperHex` note: required by a bound in `core::fmt::rt::Argument::<'_>::new_upper_hex` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL - = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr index 3de317d2af6d..ff668f88d4d1 100644 --- a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr +++ b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr @@ -3,8 +3,6 @@ error[E0282]: type annotations needed | LL | println!("{:?}", []); | ^^ cannot infer type - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-42796.stderr b/tests/ui/issues/issue-42796.stderr index 670b98c77089..0e7ce9e98c4d 100644 --- a/tests/ui/issues/issue-42796.stderr +++ b/tests/ui/issues/issue-42796.stderr @@ -9,7 +9,6 @@ LL | let mut s_copy = s; LL | println!("{}", s); | ^ value borrowed here after move | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | let mut s_copy = s.clone(); diff --git a/tests/ui/liveness/liveness-move-in-while.stderr b/tests/ui/liveness/liveness-move-in-while.stderr index dc48c4cc9acf..1bb97ad68c7c 100644 --- a/tests/ui/liveness/liveness-move-in-while.stderr +++ b/tests/ui/liveness/liveness-move-in-while.stderr @@ -35,7 +35,6 @@ LL | while true { while true { while true { x = y; x.clone(); } } } | | inside of this loop | inside of this loop | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | while true { while true { while true { x = y.clone(); x.clone(); } } } diff --git a/tests/ui/liveness/liveness-use-after-move.stderr b/tests/ui/liveness/liveness-use-after-move.stderr index eab51edca37f..a94ceae79d56 100644 --- a/tests/ui/liveness/liveness-use-after-move.stderr +++ b/tests/ui/liveness/liveness-use-after-move.stderr @@ -9,7 +9,6 @@ LL | LL | println!("{}", *x); | ^^ value borrowed here after move | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | let y = x.clone(); diff --git a/tests/ui/liveness/liveness-use-after-send.stderr b/tests/ui/liveness/liveness-use-after-send.stderr index 2323451a7d2d..da682325347c 100644 --- a/tests/ui/liveness/liveness-use-after-send.stderr +++ b/tests/ui/liveness/liveness-use-after-send.stderr @@ -13,7 +13,6 @@ note: consider changing this parameter type in function `send` to borrow instead | LL | fn send(ch: Chan, data: T) { | ---- in this function ^ this parameter takes ownership of the value - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | send(ch, message.clone()); diff --git a/tests/ui/loops/loop-proper-liveness.stderr b/tests/ui/loops/loop-proper-liveness.stderr index cd4c064bcd19..5432043c7d24 100644 --- a/tests/ui/loops/loop-proper-liveness.stderr +++ b/tests/ui/loops/loop-proper-liveness.stderr @@ -7,7 +7,6 @@ LL | let x: i32; LL | println!("{:?}", x); | ^ `x` used here but it isn't initialized | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: i32 = 42; diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index 0d203c1aacba..577d99281c4b 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -6,7 +6,7 @@ error[E0277]: `Dummy` doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `Dummy` = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 | diff --git a/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr index c2b9aeab2374..12a0f31c4512 100644 --- a/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr +++ b/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr @@ -10,8 +10,6 @@ LL | println!("{}", x); LL | }); LL | println!("{}", x); | ^ value borrowed here after move - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 7ec018a95cc7..96029cd8fc61 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -6,7 +6,7 @@ LL | let _: NotDebug = dbg!(NotDebug); | = help: the trait `Debug` is not implemented for `NotDebug` = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` | LL + #[derive(Debug)] diff --git a/tests/ui/span/issue-39698.stderr b/tests/ui/span/issue-39698.stderr index 73fcc5c84775..1581c19afef8 100644 --- a/tests/ui/span/issue-39698.stderr +++ b/tests/ui/span/issue-39698.stderr @@ -47,8 +47,6 @@ LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?} | | binding initialized here in some conditions | binding initialized here in some conditions | binding declared here but left uninitialized - | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 5 previous errors diff --git a/tests/ui/suggestions/bound-suggestions.stderr b/tests/ui/suggestions/bound-suggestions.stderr index f23e086afe4e..e94c8f1a0e8b 100644 --- a/tests/ui/suggestions/bound-suggestions.stderr +++ b/tests/ui/suggestions/bound-suggestions.stderr @@ -4,7 +4,6 @@ error[E0277]: `impl Sized` doesn't implement `Debug` LL | println!("{:?}", t); | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting opaque type `impl Sized` with trait `Debug` | LL | fn test_impl(t: impl Sized + std::fmt::Debug) { @@ -16,7 +15,6 @@ error[E0277]: `T` doesn't implement `Debug` LL | println!("{:?}", t); | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `Debug` | LL | fn test_no_bounds(t: T) { @@ -28,7 +26,6 @@ error[E0277]: `T` doesn't implement `Debug` LL | println!("{:?}", t); | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `T` with trait `Debug` | LL | fn test_one_bound(t: T) { @@ -52,7 +49,6 @@ error[E0277]: `X` doesn't implement `Debug` LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` with trait `Debug` | LL | fn test_one_bound_where(x: X) where X: Sized + std::fmt::Debug { @@ -64,7 +60,6 @@ error[E0277]: `X` doesn't implement `Debug` LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` with trait `Debug` | LL | fn test_many_bounds_where(x: X) where X: Sized + std::fmt::Debug, X: Sized { diff --git a/tests/ui/suggestions/issue-97760.stderr b/tests/ui/suggestions/issue-97760.stderr index c3cf7e13987b..f3dc3f74efe8 100644 --- a/tests/ui/suggestions/issue-97760.stderr +++ b/tests/ui/suggestions/issue-97760.stderr @@ -6,7 +6,6 @@ LL | println!("{x}"); | = help: the trait `std::fmt::Display` is not implemented for `::Item` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: introduce a type parameter with a trait bound instead of using `impl Trait` | LL ~ pub fn print_values(values: &I) diff --git a/tests/ui/suggestions/path-display.stderr b/tests/ui/suggestions/path-display.stderr index 46d0b35825bc..d26885971a5c 100644 --- a/tests/ui/suggestions/path-display.stderr +++ b/tests/ui/suggestions/path-display.stderr @@ -7,7 +7,6 @@ LL | println!("{}", path); = help: the trait `std::fmt::Display` is not implemented for `Path` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `PathBuf` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:9:20 @@ -18,7 +17,6 @@ LL | println!("{}", path); = help: the trait `std::fmt::Display` is not implemented for `PathBuf` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr b/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr index 71c7e460c399..7fe151021976 100644 --- a/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr +++ b/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr @@ -22,7 +22,6 @@ LL | }; LL | println!("{}", x); | ^ value borrowed here after move | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | ::std::mem::drop(x.clone()); diff --git a/tests/ui/type-alias-impl-trait/nested.stderr b/tests/ui/type-alias-impl-trait/nested.stderr index 59911f65a234..502fa00892f5 100644 --- a/tests/ui/type-alias-impl-trait/nested.stderr +++ b/tests/ui/type-alias-impl-trait/nested.stderr @@ -18,7 +18,6 @@ LL | println!("{:?}", bar()); | ^^^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `Bar` - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/type/binding-assigned-block-without-tail-expression.stderr b/tests/ui/type/binding-assigned-block-without-tail-expression.stderr index 3e96d7f317b4..335d3e80b773 100644 --- a/tests/ui/type/binding-assigned-block-without-tail-expression.stderr +++ b/tests/ui/type/binding-assigned-block-without-tail-expression.stderr @@ -9,7 +9,6 @@ LL | println!("{}", x); | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/binding-assigned-block-without-tail-expression.rs:15:20 @@ -22,7 +21,6 @@ LL | println!("{}", y); | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/binding-assigned-block-without-tail-expression.rs:16:20 @@ -35,7 +33,6 @@ LL | println!("{}", z); | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/binding-assigned-block-without-tail-expression.rs:17:20 @@ -51,7 +48,6 @@ LL | println!("{}", s); | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/binding-assigned-block-without-tail-expression.rs:18:18 diff --git a/tests/ui/use/use-after-move-based-on-type.stderr b/tests/ui/use/use-after-move-based-on-type.stderr index 02a6ed599a92..1e72b3a1e95a 100644 --- a/tests/ui/use/use-after-move-based-on-type.stderr +++ b/tests/ui/use/use-after-move-based-on-type.stderr @@ -8,7 +8,6 @@ LL | let _y = x; LL | println!("{}", x); | ^ value borrowed here after move | - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | let _y = x.clone(); diff --git a/tests/ui/walk-struct-literal-with.stderr b/tests/ui/walk-struct-literal-with.stderr index 34b501f8ec88..7db8ee1fe5b6 100644 --- a/tests/ui/walk-struct-literal-with.stderr +++ b/tests/ui/walk-struct-literal-with.stderr @@ -13,7 +13,6 @@ note: `Mine::make_string_bar` takes ownership of the receiver `self`, which move | LL | fn make_string_bar(mut self) -> Mine{ | ^^^^ - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error From 58a5ab5a6d3e9cd5312eae7e9c33440b3c402ce8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 May 2025 17:49:11 +0200 Subject: [PATCH 091/356] Update unpretty tests. --- tests/ui/unpretty/exhaustive.hir.stdout | 6 ++++-- tests/ui/unpretty/flattened-format-args.stdout | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index c20f123b16e8..5d6e3907d757 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -405,8 +405,10 @@ mod expressions { fn expr_format_args() { let expr; format_arguments::new_const(&[]); - format_arguments::new_v1(&[""], - &[format_argument::new_display(&expr)]); + { + super let args = [format_argument::new_display(&expr)]; + format_arguments::new_v1(&[""], &args) + }; } } mod items { diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout index a5d943281ad8..4af82924c7b4 100644 --- a/tests/ui/unpretty/flattened-format-args.stdout +++ b/tests/ui/unpretty/flattened-format-args.stdout @@ -10,7 +10,9 @@ fn main() { let x = 1; // Should flatten to println!("a 123 b {x} xyz\n"): { - ::std::io::_print(format_arguments::new_v1(&["a 123 b ", " xyz\n"], - &[format_argument::new_display(&x)])); + ::std::io::_print({ + super let args = [format_argument::new_display(&x)]; + format_arguments::new_v1(&["a 123 b ", " xyz\n"], &args) + }); }; } From 42fc5aee6499ed6f7d1fca0d2fbac1515291b978 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 4 Jun 2025 11:54:20 +0200 Subject: [PATCH 092/356] Fix span of AddrOf in format_args!() expansion. Diagnostics should know that the `&` for arguments in format_args!() come from the macro expansion rather than from the original source. --- compiler/rustc_ast_lowering/src/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 4138cc426c75..7a4e056175c0 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -489,7 +489,7 @@ fn expand_format_args<'hir>( let placeholder_span = placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt()); let arg = ctx.lower_expr(&arg.expr); - let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span, arg)); + let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span.with_ctxt(macsp.ctxt()), arg)); make_argument(ctx, placeholder_span, ref_arg, ty) }, )); From a693c521735b24af6a116b0a149d10dc5aeb4af2 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 7 May 2025 17:56:39 +0200 Subject: [PATCH 093/356] Bless/update tests. --- tests/ui/borrowck/borrowck-and-init.stderr | 2 ++ tests/ui/borrowck/borrowck-break-uninit-2.stderr | 1 + tests/ui/borrowck/borrowck-break-uninit.stderr | 1 + tests/ui/borrowck/borrowck-or-init.stderr | 2 ++ tests/ui/borrowck/borrowck-while-break.stderr | 2 ++ tests/ui/borrowck/clone-on-ref.stderr | 4 ++-- tests/ui/borrowck/issue-24267-flow-exit.stderr | 2 ++ tests/ui/borrowck/issue-47646.stderr | 2 ++ tests/ui/borrowck/suggest-assign-rvalue.stderr | 10 ++++++++++ .../2229_closure_analysis/diagnostics/arrays.stderr | 2 ++ .../2229_closure_analysis/diagnostics/box.stderr | 2 ++ .../diagnostics/repr_packed.stderr | 1 + .../diagnostics/simple-struct-min-capture.stderr | 2 ++ tests/ui/closures/issue-111932.stderr | 1 + tests/ui/codemap_tests/tab_3.stderr | 1 + tests/ui/consts/const-eval/issue-44578.stderr | 3 ++- tests/ui/consts/recursive-const-in-impl.stderr | 5 +++-- tests/ui/coroutine/yield-while-ref-reborrowed.stderr | 2 ++ tests/ui/fmt/ifmt-unimpl.stderr | 1 + .../impl-trait/precise-capturing/foreign-2021.stderr | 2 +- .../impl-trait/precise-capturing/migration-note.stderr | 10 +++++----- ...issue-107745-avoid-expr-from-macro-expansion.stderr | 2 ++ tests/ui/issues/issue-42796.stderr | 1 + .../temporary-lifetime-extension-tuple-ctor.stderr | 2 +- tests/ui/liveness/liveness-move-in-while.stderr | 1 + tests/ui/liveness/liveness-use-after-move.stderr | 1 + tests/ui/liveness/liveness-use-after-send.stderr | 1 + tests/ui/loops/loop-proper-liveness.stderr | 1 + .../ui/macros/format-args-temporaries-in-write.stderr | 10 ---------- tests/ui/modules/issue-107649.stderr | 2 +- .../moves-based-on-type-capture-clause-bad.stderr | 2 ++ .../rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr | 2 +- tests/ui/sized/unsized-binding.rs | 4 ++-- tests/ui/span/issue-39698.stderr | 2 ++ tests/ui/suggestions/bound-suggestions.stderr | 5 +++++ tests/ui/suggestions/issue-97760.stderr | 5 +++-- tests/ui/suggestions/path-display.stderr | 2 ++ tests/ui/try-block/try-block-maybe-bad-lifetime.stderr | 1 + tests/ui/type-alias-impl-trait/nested.stderr | 1 + ...nding-assigned-block-without-tail-expression.stderr | 4 ++++ tests/ui/use/use-after-move-based-on-type.stderr | 1 + tests/ui/walk-struct-literal-with.stderr | 1 + 42 files changed, 81 insertions(+), 28 deletions(-) diff --git a/tests/ui/borrowck/borrowck-and-init.stderr b/tests/ui/borrowck/borrowck-and-init.stderr index e6d49bc6e471..37386f1c4651 100644 --- a/tests/ui/borrowck/borrowck-and-init.stderr +++ b/tests/ui/borrowck/borrowck-and-init.stderr @@ -8,6 +8,8 @@ LL | println!("{}", false && { i = 5; true }); | ----- binding initialized here in some conditions LL | println!("{}", i); | ^ `i` used here but it is possibly-uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.stderr b/tests/ui/borrowck/borrowck-break-uninit-2.stderr index 03730e338ee0..e23ca534e745 100644 --- a/tests/ui/borrowck/borrowck-break-uninit-2.stderr +++ b/tests/ui/borrowck/borrowck-break-uninit-2.stderr @@ -7,6 +7,7 @@ LL | let x: isize; LL | println!("{}", x); | ^ `x` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: isize = 42; diff --git a/tests/ui/borrowck/borrowck-break-uninit.stderr b/tests/ui/borrowck/borrowck-break-uninit.stderr index 6ed095f2e4a3..0367d224f801 100644 --- a/tests/ui/borrowck/borrowck-break-uninit.stderr +++ b/tests/ui/borrowck/borrowck-break-uninit.stderr @@ -7,6 +7,7 @@ LL | let x: isize; LL | println!("{}", x); | ^ `x` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: isize = 42; diff --git a/tests/ui/borrowck/borrowck-or-init.stderr b/tests/ui/borrowck/borrowck-or-init.stderr index 63c0c982351b..7b43f2aee30e 100644 --- a/tests/ui/borrowck/borrowck-or-init.stderr +++ b/tests/ui/borrowck/borrowck-or-init.stderr @@ -8,6 +8,8 @@ LL | println!("{}", false || { i = 5; true }); | ----- binding initialized here in some conditions LL | println!("{}", i); | ^ `i` used here but it is possibly-uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-while-break.stderr b/tests/ui/borrowck/borrowck-while-break.stderr index 68333ce0a75d..e91af728b649 100644 --- a/tests/ui/borrowck/borrowck-while-break.stderr +++ b/tests/ui/borrowck/borrowck-while-break.stderr @@ -8,6 +8,8 @@ LL | while cond { ... LL | println!("{}", v); | ^ `v` used here but it is possibly-uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/clone-on-ref.stderr b/tests/ui/borrowck/clone-on-ref.stderr index 911c136086cf..72580e7464b7 100644 --- a/tests/ui/borrowck/clone-on-ref.stderr +++ b/tests/ui/borrowck/clone-on-ref.stderr @@ -30,7 +30,7 @@ LL | drop(x); | ^ move out of `x` occurs here LL | LL | println!("{b}"); - | --- borrow later used here + | - borrow later used here | help: if `T` implemented `Clone`, you could clone the value --> $DIR/clone-on-ref.rs:11:8 @@ -57,7 +57,7 @@ LL | drop(x); | ^ move out of `x` occurs here LL | LL | println!("{b:?}"); - | ----- borrow later used here + | - borrow later used here | note: if `A` implemented `Clone`, you could clone the value --> $DIR/clone-on-ref.rs:19:1 diff --git a/tests/ui/borrowck/issue-24267-flow-exit.stderr b/tests/ui/borrowck/issue-24267-flow-exit.stderr index e81f00f8c157..216f8d49b1b0 100644 --- a/tests/ui/borrowck/issue-24267-flow-exit.stderr +++ b/tests/ui/borrowck/issue-24267-flow-exit.stderr @@ -7,6 +7,7 @@ LL | loop { x = break; } LL | println!("{}", x); | ^ `x` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: i32 = 42; @@ -21,6 +22,7 @@ LL | for _ in 0..10 { x = continue; } LL | println!("{}", x); | ^ `x` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: i32 = 42; diff --git a/tests/ui/borrowck/issue-47646.stderr b/tests/ui/borrowck/issue-47646.stderr index c8d48b76757a..cfe6f3f39938 100644 --- a/tests/ui/borrowck/issue-47646.stderr +++ b/tests/ui/borrowck/issue-47646.stderr @@ -12,6 +12,8 @@ LL | println!("{:?}", heap); ... LL | }; | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option>, ())` + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/suggest-assign-rvalue.stderr b/tests/ui/borrowck/suggest-assign-rvalue.stderr index 6ae893915aa9..daaef6e3892d 100644 --- a/tests/ui/borrowck/suggest-assign-rvalue.stderr +++ b/tests/ui/borrowck/suggest-assign-rvalue.stderr @@ -19,6 +19,7 @@ LL | let my_float: f32; LL | println!("my_float: {}", my_float); | ^^^^^^^^ `my_float` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let my_float: f32 = 3.14159; @@ -32,6 +33,7 @@ LL | let demo: Demo; LL | println!("demo: {:?}", demo); | ^^^^ `demo` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let demo: Demo = Default::default(); @@ -45,6 +47,7 @@ LL | let demo_no: DemoNoDef; LL | println!("demo_no: {:?}", demo_no); | ^^^^^^^ `demo_no` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let demo_no: DemoNoDef = /* value */; @@ -58,6 +61,7 @@ LL | let arr: [i32; 5]; LL | println!("arr: {:?}", arr); | ^^^ `arr` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let arr: [i32; 5] = [42; 5]; @@ -71,6 +75,7 @@ LL | let foo: Vec<&str>; LL | println!("foo: {:?}", foo); | ^^^ `foo` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let foo: Vec<&str> = vec![]; @@ -84,6 +89,7 @@ LL | let my_string: String; LL | println!("my_string: {}", my_string); | ^^^^^^^^^ `my_string` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let my_string: String = Default::default(); @@ -97,6 +103,7 @@ LL | let my_int: &i32; LL | println!("my_int: {}", *my_int); | ^^^^^^^ `*my_int` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let my_int: &i32 = &42; @@ -110,6 +117,7 @@ LL | let hello: &str; LL | println!("hello: {}", hello); | ^^^^^ `hello` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let hello: &str = ""; @@ -122,6 +130,8 @@ LL | let never: !; | ----- binding declared here but left uninitialized LL | println!("never: {}", never); | ^^^^^ `never` used here but it isn't initialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr index 4249dea10a36..97ecdfab8205 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr @@ -53,6 +53,8 @@ LL | println!("{}", arr[3]); ... LL | c(); | - mutable borrow later used here + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable --> $DIR/arrays.rs:71:24 diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr index 09143f44dc83..2e3259e64059 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/box.stderr @@ -25,6 +25,8 @@ LL | println!("{}", e.0.0.m.x); LL | LL | c(); | - mutable borrow later used here + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed --> $DIR/box.rs:55:5 diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr index 9a75fcc520d5..c9972c8e7e34 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr @@ -7,6 +7,7 @@ LL | println!("{}", foo.x); = note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses = note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr index 406f7c63b734..68fdb3ce131f 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr @@ -13,6 +13,8 @@ LL | println!("{:?}", p); LL | LL | c(); | - mutable borrow later used here + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/closures/issue-111932.stderr b/tests/ui/closures/issue-111932.stderr index 7d06db03c3bc..93488ad2011e 100644 --- a/tests/ui/closures/issue-111932.stderr +++ b/tests/ui/closures/issue-111932.stderr @@ -19,6 +19,7 @@ LL | println!("{:?}", foo); = help: the trait `Sized` is not implemented for `dyn Foo` note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'_>::new_debug` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/codemap_tests/tab_3.stderr b/tests/ui/codemap_tests/tab_3.stderr index 2a0a9e2d48f3..7ae21a57052f 100644 --- a/tests/ui/codemap_tests/tab_3.stderr +++ b/tests/ui/codemap_tests/tab_3.stderr @@ -11,6 +11,7 @@ LL | println!("{:?}", some_vec); | note: `into_iter` takes ownership of the receiver `self`, which moves `some_vec` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: you can `clone` the value and consume it, but this might not be your desired behavior | LL | some_vec.clone().into_iter(); diff --git a/tests/ui/consts/const-eval/issue-44578.stderr b/tests/ui/consts/const-eval/issue-44578.stderr index 43bad0666a71..fd0b9ae1e17d 100644 --- a/tests/ui/consts/const-eval/issue-44578.stderr +++ b/tests/ui/consts/const-eval/issue-44578.stderr @@ -24,7 +24,7 @@ note: erroneous constant encountered LL | println!("{}", as Foo>::AMT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered --> $DIR/issue-44578.rs:26:20 @@ -33,6 +33,7 @@ LL | println!("{}", as Foo>::AMT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/consts/recursive-const-in-impl.stderr b/tests/ui/consts/recursive-const-in-impl.stderr index 6175112c8cc0..035d9c2f21c5 100644 --- a/tests/ui/consts/recursive-const-in-impl.stderr +++ b/tests/ui/consts/recursive-const-in-impl.stderr @@ -1,11 +1,12 @@ error: queries overflow the depth limit! - --> $DIR/recursive-const-in-impl.rs:11:14 + --> $DIR/recursive-const-in-impl.rs:11:20 | LL | println!("{}", Thing::::X); - | ^^^^ + | ^^^^^^^^^^^^^^^ | = help: consider increasing the recursion limit by adding a `#![recursion_limit = "14"]` attribute to your crate (`recursive_const_in_impl`) = note: query depth increased by 9 when simplifying constant for the type system `main::promoted[1]` + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/yield-while-ref-reborrowed.stderr b/tests/ui/coroutine/yield-while-ref-reborrowed.stderr index 643c4134b36e..7c9b766457db 100644 --- a/tests/ui/coroutine/yield-while-ref-reborrowed.stderr +++ b/tests/ui/coroutine/yield-while-ref-reborrowed.stderr @@ -10,6 +10,8 @@ LL | println!("{}", x); | ^ second borrow occurs here LL | Pin::new(&mut b).resume(()); | ------ first borrow later used here + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index 7ca3c97a297b..b8d4425a4a71 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -19,6 +19,7 @@ LL | format!("{:X}", "3"); = note: required for `&str` to implement `UpperHex` note: required by a bound in `core::fmt::rt::Argument::<'_>::new_upper_hex` --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr index cd9ed0fb8851..1dcd800cfc51 100644 --- a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr +++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr @@ -8,7 +8,7 @@ LL | x.push(0); | ^^^^^^^^^ mutable borrow occurs here ... LL | println!("{h}"); - | --- immutable borrow later used here + | - immutable borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules --> $DIR/foreign-2021.rs:7:13 diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr index 676b6c12f52a..aa0f64000915 100644 --- a/tests/ui/impl-trait/precise-capturing/migration-note.stderr +++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr @@ -23,7 +23,7 @@ LL | x.push(1); | ^^^^^^^^^ mutable borrow occurs here ... LL | println!("{a}"); - | --- immutable borrow later used here + | - immutable borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules --> $DIR/migration-note.rs:16:13 @@ -99,7 +99,7 @@ LL | x.push(1); | ^ second mutable borrow occurs here ... LL | println!("{a}"); - | --- first borrow later used here + | - first borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules --> $DIR/migration-note.rs:63:13 @@ -175,7 +175,7 @@ LL | s.f = 1; | ^^^^^^^ `s.f` is assigned to here but it was already borrowed ... LL | println!("{a}"); - | --- borrow later used here + | - borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules --> $DIR/migration-note.rs:112:13 @@ -197,7 +197,7 @@ LL | s.f = 1; | ^^^^^^^ `s.f` is assigned to here but it was already borrowed ... LL | println!("{a}"); - | --- borrow later used here + | - borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules --> $DIR/migration-note.rs:128:13 @@ -219,7 +219,7 @@ LL | s.f; | ^^^ use of borrowed `s.f` ... LL | println!("{a}"); - | --- borrow later used here + | - borrow later used here | note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules --> $DIR/migration-note.rs:140:13 diff --git a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr index ff668f88d4d1..3de317d2af6d 100644 --- a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr +++ b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr @@ -3,6 +3,8 @@ error[E0282]: type annotations needed | LL | println!("{:?}", []); | ^^ cannot infer type + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-42796.stderr b/tests/ui/issues/issue-42796.stderr index 0e7ce9e98c4d..670b98c77089 100644 --- a/tests/ui/issues/issue-42796.stderr +++ b/tests/ui/issues/issue-42796.stderr @@ -9,6 +9,7 @@ LL | let mut s_copy = s; LL | println!("{}", s); | ^ value borrowed here after move | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | let mut s_copy = s.clone(); diff --git a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr index 66f9140f63cf..b0d64b531cb4 100644 --- a/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr +++ b/tests/ui/lifetimes/temporary-lifetime-extension-tuple-ctor.stderr @@ -6,7 +6,7 @@ LL | let g = some(&temp()); | | | creates a temporary value which is freed while still in use LL | println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?}"); - | ----- borrow later used here + | - borrow later used here | help: consider using a `let` binding to create a longer lived value | diff --git a/tests/ui/liveness/liveness-move-in-while.stderr b/tests/ui/liveness/liveness-move-in-while.stderr index 1bb97ad68c7c..dc48c4cc9acf 100644 --- a/tests/ui/liveness/liveness-move-in-while.stderr +++ b/tests/ui/liveness/liveness-move-in-while.stderr @@ -35,6 +35,7 @@ LL | while true { while true { while true { x = y; x.clone(); } } } | | inside of this loop | inside of this loop | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | while true { while true { while true { x = y.clone(); x.clone(); } } } diff --git a/tests/ui/liveness/liveness-use-after-move.stderr b/tests/ui/liveness/liveness-use-after-move.stderr index a94ceae79d56..eab51edca37f 100644 --- a/tests/ui/liveness/liveness-use-after-move.stderr +++ b/tests/ui/liveness/liveness-use-after-move.stderr @@ -9,6 +9,7 @@ LL | LL | println!("{}", *x); | ^^ value borrowed here after move | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | let y = x.clone(); diff --git a/tests/ui/liveness/liveness-use-after-send.stderr b/tests/ui/liveness/liveness-use-after-send.stderr index da682325347c..2323451a7d2d 100644 --- a/tests/ui/liveness/liveness-use-after-send.stderr +++ b/tests/ui/liveness/liveness-use-after-send.stderr @@ -13,6 +13,7 @@ note: consider changing this parameter type in function `send` to borrow instead | LL | fn send(ch: Chan, data: T) { | ---- in this function ^ this parameter takes ownership of the value + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | send(ch, message.clone()); diff --git a/tests/ui/loops/loop-proper-liveness.stderr b/tests/ui/loops/loop-proper-liveness.stderr index 5432043c7d24..cd4c064bcd19 100644 --- a/tests/ui/loops/loop-proper-liveness.stderr +++ b/tests/ui/loops/loop-proper-liveness.stderr @@ -7,6 +7,7 @@ LL | let x: i32; LL | println!("{:?}", x); | ^ `x` used here but it isn't initialized | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider assigning a value | LL | let x: i32 = 42; diff --git a/tests/ui/macros/format-args-temporaries-in-write.stderr b/tests/ui/macros/format-args-temporaries-in-write.stderr index e58a43383f6e..489987899cd7 100644 --- a/tests/ui/macros/format-args-temporaries-in-write.stderr +++ b/tests/ui/macros/format-args-temporaries-in-write.stderr @@ -13,11 +13,6 @@ LL | }; | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` | | | `mutex` dropped here while still borrowed - | -help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped - | -LL | write!(Out, "{}", mutex.lock()); /* no semicolon */ - | + error[E0597]: `mutex` does not live long enough --> $DIR/format-args-temporaries-in-write.rs:47:29 @@ -34,11 +29,6 @@ LL | }; | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard` | | | `mutex` dropped here while still borrowed - | -help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped - | -LL | writeln!(Out, "{}", mutex.lock()); /* no semicolon */ - | + error: aborting due to 2 previous errors diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index 577d99281c4b..0d203c1aacba 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -6,7 +6,7 @@ error[E0277]: `Dummy` doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `Dummy` = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 | diff --git a/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr index 12a0f31c4512..c2b9aeab2374 100644 --- a/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr +++ b/tests/ui/moves/moves-based-on-type-capture-clause-bad.stderr @@ -10,6 +10,8 @@ LL | println!("{}", x); LL | }); LL | println!("{}", x); | ^ value borrowed here after move + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 96029cd8fc61..7ec018a95cc7 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -6,7 +6,7 @@ LL | let _: NotDebug = dbg!(NotDebug); | = help: the trait `Debug` is not implemented for `NotDebug` = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` - = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` | LL + #[derive(Debug)] diff --git a/tests/ui/sized/unsized-binding.rs b/tests/ui/sized/unsized-binding.rs index 3b99b0f6e965..ce6c15273764 100644 --- a/tests/ui/sized/unsized-binding.rs +++ b/tests/ui/sized/unsized-binding.rs @@ -1,5 +1,5 @@ fn main() { let x = *""; //~ ERROR E0277 - println!("{}", x); - println!("{}", x); + drop(x); + drop(x); } diff --git a/tests/ui/span/issue-39698.stderr b/tests/ui/span/issue-39698.stderr index 1581c19afef8..73fcc5c84775 100644 --- a/tests/ui/span/issue-39698.stderr +++ b/tests/ui/span/issue-39698.stderr @@ -47,6 +47,8 @@ LL | T::T1(a, d) | T::T2(d, b) | T::T3(c) | T::T4(a) => { println!("{:?} | | binding initialized here in some conditions | binding initialized here in some conditions | binding declared here but left uninitialized + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 5 previous errors diff --git a/tests/ui/suggestions/bound-suggestions.stderr b/tests/ui/suggestions/bound-suggestions.stderr index e94c8f1a0e8b..f23e086afe4e 100644 --- a/tests/ui/suggestions/bound-suggestions.stderr +++ b/tests/ui/suggestions/bound-suggestions.stderr @@ -4,6 +4,7 @@ error[E0277]: `impl Sized` doesn't implement `Debug` LL | println!("{:?}", t); | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug` | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting opaque type `impl Sized` with trait `Debug` | LL | fn test_impl(t: impl Sized + std::fmt::Debug) { @@ -15,6 +16,7 @@ error[E0277]: `T` doesn't implement `Debug` LL | println!("{:?}", t); | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `Debug` | LL | fn test_no_bounds(t: T) { @@ -26,6 +28,7 @@ error[E0277]: `T` doesn't implement `Debug` LL | println!("{:?}", t); | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `T` with trait `Debug` | LL | fn test_one_bound(t: T) { @@ -49,6 +52,7 @@ error[E0277]: `X` doesn't implement `Debug` LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` with trait `Debug` | LL | fn test_one_bound_where(x: X) where X: Sized + std::fmt::Debug { @@ -60,6 +64,7 @@ error[E0277]: `X` doesn't implement `Debug` LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` with trait `Debug` | LL | fn test_many_bounds_where(x: X) where X: Sized + std::fmt::Debug, X: Sized { diff --git a/tests/ui/suggestions/issue-97760.stderr b/tests/ui/suggestions/issue-97760.stderr index f3dc3f74efe8..ddd143b967c4 100644 --- a/tests/ui/suggestions/issue-97760.stderr +++ b/tests/ui/suggestions/issue-97760.stderr @@ -1,11 +1,12 @@ error[E0277]: `::Item` doesn't implement `std::fmt::Display` - --> $DIR/issue-97760.rs:4:19 + --> $DIR/issue-97760.rs:4:20 | LL | println!("{x}"); - | ^^^ `::Item` cannot be formatted with the default formatter + | ^ `::Item` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `::Item` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: introduce a type parameter with a trait bound instead of using `impl Trait` | LL ~ pub fn print_values(values: &I) diff --git a/tests/ui/suggestions/path-display.stderr b/tests/ui/suggestions/path-display.stderr index d26885971a5c..46d0b35825bc 100644 --- a/tests/ui/suggestions/path-display.stderr +++ b/tests/ui/suggestions/path-display.stderr @@ -7,6 +7,7 @@ LL | println!("{}", path); = help: the trait `std::fmt::Display` is not implemented for `Path` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `PathBuf` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:9:20 @@ -17,6 +18,7 @@ LL | println!("{}", path); = help: the trait `std::fmt::Display` is not implemented for `PathBuf` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr b/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr index 7fe151021976..71c7e460c399 100644 --- a/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr +++ b/tests/ui/try-block/try-block-maybe-bad-lifetime.stderr @@ -22,6 +22,7 @@ LL | }; LL | println!("{}", x); | ^ value borrowed here after move | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | ::std::mem::drop(x.clone()); diff --git a/tests/ui/type-alias-impl-trait/nested.stderr b/tests/ui/type-alias-impl-trait/nested.stderr index 502fa00892f5..59911f65a234 100644 --- a/tests/ui/type-alias-impl-trait/nested.stderr +++ b/tests/ui/type-alias-impl-trait/nested.stderr @@ -18,6 +18,7 @@ LL | println!("{:?}", bar()); | ^^^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `Bar` + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/type/binding-assigned-block-without-tail-expression.stderr b/tests/ui/type/binding-assigned-block-without-tail-expression.stderr index 335d3e80b773..3e96d7f317b4 100644 --- a/tests/ui/type/binding-assigned-block-without-tail-expression.stderr +++ b/tests/ui/type/binding-assigned-block-without-tail-expression.stderr @@ -9,6 +9,7 @@ LL | println!("{}", x); | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/binding-assigned-block-without-tail-expression.rs:15:20 @@ -21,6 +22,7 @@ LL | println!("{}", y); | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/binding-assigned-block-without-tail-expression.rs:16:20 @@ -33,6 +35,7 @@ LL | println!("{}", z); | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/binding-assigned-block-without-tail-expression.rs:17:20 @@ -48,6 +51,7 @@ LL | println!("{}", s); | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> $DIR/binding-assigned-block-without-tail-expression.rs:18:18 diff --git a/tests/ui/use/use-after-move-based-on-type.stderr b/tests/ui/use/use-after-move-based-on-type.stderr index 1e72b3a1e95a..02a6ed599a92 100644 --- a/tests/ui/use/use-after-move-based-on-type.stderr +++ b/tests/ui/use/use-after-move-based-on-type.stderr @@ -8,6 +8,7 @@ LL | let _y = x; LL | println!("{}", x); | ^ value borrowed here after move | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | LL | let _y = x.clone(); diff --git a/tests/ui/walk-struct-literal-with.stderr b/tests/ui/walk-struct-literal-with.stderr index 7db8ee1fe5b6..34b501f8ec88 100644 --- a/tests/ui/walk-struct-literal-with.stderr +++ b/tests/ui/walk-struct-literal-with.stderr @@ -13,6 +13,7 @@ note: `Mine::make_string_bar` takes ownership of the receiver `self`, which move | LL | fn make_string_bar(mut self) -> Mine{ | ^^^^ + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error From 2c175e1c6d9fdba51e0bef17f73e4c9e1b36ec4b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 4 Jun 2025 14:33:31 +0200 Subject: [PATCH 094/356] Update/bless clippy tests. --- .../tests/ui/author/macro_in_closure.stdout | 39 +++++++++++-------- .../tests/ui/author/macro_in_loop.stdout | 35 ++++++++++------- .../clippy/tests/ui/manual_inspect.fixed | 1 - src/tools/clippy/tests/ui/manual_inspect.rs | 1 - .../clippy/tests/ui/manual_inspect.stderr | 23 ++--------- 5 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout index 5f8a4ce23630..49595e2fec25 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout @@ -9,28 +9,35 @@ if let StmtKind::Let(local) = stmt.kind && let ExprKind::Call(func, args) = e.kind && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed && args.len() == 1 - && let ExprKind::Call(func1, args1) = args[0].kind - && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed - && args1.len() == 2 + && let ExprKind::Block(block1, None) = args[0].kind + && block1.stmts.len() == 1 + && let StmtKind::Let(local1) = block1.stmts[0].kind + && let Some(init1) = local1.init + && let ExprKind::Array(elements) = init1.kind + && elements.len() == 1 + && let ExprKind::Call(func1, args1) = elements[0].kind + && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed + && args1.len() == 1 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind - && let ExprKind::Array(elements) = inner.kind - && elements.len() == 2 - && let ExprKind::Lit(ref lit) = elements[0].kind + && let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind + && name.as_str() == "args" + && let Some(trailing_expr) = block1.expr + && let ExprKind::Call(func2, args2) = trailing_expr.kind + && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed + && args2.len() == 2 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind + && let ExprKind::Array(elements1) = inner1.kind + && elements1.len() == 2 + && let ExprKind::Lit(ref lit) = elements1[0].kind && let LitKind::Str(s, _) = lit.node && s.as_str() == "" - && let ExprKind::Lit(ref lit1) = elements[1].kind + && let ExprKind::Lit(ref lit1) = elements1[1].kind && let LitKind::Str(s1, _) = lit1.node && s1.as_str() == "\n" - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind - && let ExprKind::Array(elements1) = inner1.kind - && elements1.len() == 1 - && let ExprKind::Call(func2, args2) = elements1[0].kind - && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed - && args2.len() == 1 - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind && block.expr.is_none() - && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind - && name.as_str() == "print_text" + && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind + && name1.as_str() == "print_text" { // report your lint here } diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout index ecc252543117..4fc7b49464db 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout @@ -19,25 +19,32 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && let ExprKind::Call(func, args) = e1.kind && paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed && args.len() == 1 - && let ExprKind::Call(func1, args1) = args[0].kind - && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed - && args1.len() == 2 + && let ExprKind::Block(block2, None) = args[0].kind + && block2.stmts.len() == 1 + && let StmtKind::Let(local) = block2.stmts[0].kind + && let Some(init) = local.init + && let ExprKind::Array(elements) = init.kind + && elements.len() == 1 + && let ExprKind::Call(func1, args1) = elements[0].kind + && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed + && args1.len() == 1 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind - && let ExprKind::Array(elements) = inner.kind - && elements.len() == 2 - && let ExprKind::Lit(ref lit2) = elements[0].kind + && let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind + && name1.as_str() == "args" + && let Some(trailing_expr) = block2.expr + && let ExprKind::Call(func2, args2) = trailing_expr.kind + && paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed + && args2.len() == 2 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind + && let ExprKind::Array(elements1) = inner1.kind + && elements1.len() == 2 + && let ExprKind::Lit(ref lit2) = elements1[0].kind && let LitKind::Str(s, _) = lit2.node && s.as_str() == "" - && let ExprKind::Lit(ref lit3) = elements[1].kind + && let ExprKind::Lit(ref lit3) = elements1[1].kind && let LitKind::Str(s1, _) = lit3.node && s1.as_str() == "\n" - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind - && let ExprKind::Array(elements1) = inner1.kind - && elements1.len() == 1 - && let ExprKind::Call(func2, args2) = elements1[0].kind - && paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed - && args2.len() == 1 - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind && block1.expr.is_none() && block.expr.is_none() { diff --git a/src/tools/clippy/tests/ui/manual_inspect.fixed b/src/tools/clippy/tests/ui/manual_inspect.fixed index 9b768dbad700..00a19155a516 100644 --- a/src/tools/clippy/tests/ui/manual_inspect.fixed +++ b/src/tools/clippy/tests/ui/manual_inspect.fixed @@ -154,7 +154,6 @@ fn main() { }); let _ = [0] - //~^ suspicious_map .into_iter() .inspect(|&x| { //~^ manual_inspect diff --git a/src/tools/clippy/tests/ui/manual_inspect.rs b/src/tools/clippy/tests/ui/manual_inspect.rs index e679636201e6..b3b17139cde3 100644 --- a/src/tools/clippy/tests/ui/manual_inspect.rs +++ b/src/tools/clippy/tests/ui/manual_inspect.rs @@ -165,7 +165,6 @@ fn main() { }); let _ = [0] - //~^ suspicious_map .into_iter() .map(|x| { //~^ manual_inspect diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr index 78b085fdfca3..70c00c1f7558 100644 --- a/src/tools/clippy/tests/ui/manual_inspect.stderr +++ b/src/tools/clippy/tests/ui/manual_inspect.stderr @@ -157,25 +157,8 @@ LL | LL ~ println!("{}", x); | -error: this call to `map()` won't have an effect on the call to `count()` - --> tests/ui/manual_inspect.rs:167:13 - | -LL | let _ = [0] - | _____________^ -LL | | -LL | | .into_iter() -LL | | .map(|x| { -... | -LL | | }) -LL | | .count(); - | |________________^ - | - = help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect` - = note: `-D clippy::suspicious-map` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` - error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:170:10 + --> tests/ui/manual_inspect.rs:169:10 | LL | .map(|x| { | ^^^ @@ -188,7 +171,7 @@ LL ~ println!("{}", x); | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:203:30 + --> tests/ui/manual_inspect.rs:202:30 | LL | if let Some(x) = Some(1).map(|x| { println!("{x}"); | ^^^ @@ -200,5 +183,5 @@ LL | // Do not collapse code into this comment LL ~ }) { | -error: aborting due to 14 previous errors +error: aborting due to 13 previous errors From b2fe858a4e69e51e97d737496e938589b26db709 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 24 May 2025 11:56:41 +0000 Subject: [PATCH 095/356] `Result::expect` instead of `match` and `panic!` --- src/librustdoc/html/render/write_shared.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index fb2b45802a67..09b2b01486ec 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -439,12 +439,8 @@ impl CratesIndexPart { let content = format!("

List of all crates

    {DELIMITER}
"); let template = layout::render(layout, &page, "", content, style_files); - match SortedTemplate::from_template(&template, DELIMITER) { - Ok(template) => template, - Err(e) => panic!( - "Object Replacement Character (U+FFFC) should not appear in the --index-page: {e}" - ), - } + SortedTemplate::from_template(&template, DELIMITER) + .expect("Object Replacement Character (U+FFFC) should not appear in the --index-page") } /// Might return parts that are duplicate with ones in prexisting index.html From 1fdf2b562070ec98c5b32ee67b8c6d8145127a6e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 9 Jun 2025 20:08:52 +0200 Subject: [PATCH 096/356] add `#[align]` attribute Right now it's used for functions with `fn_align`, in the future it will get more uses (statics, struct fields, etc.) --- .../src/attributes.rs | 3 + compiler/rustc_attr_parsing/messages.ftl | 3 + .../rustc_attr_parsing/src/attributes/repr.rs | 58 +++++++++++++- compiler/rustc_attr_parsing/src/context.rs | 3 +- .../src/session_diagnostics.rs | 8 ++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 14 +--- compiler/rustc_feature/src/builtin_attrs.rs | 1 + .../src/middle/codegen_fn_attrs.rs | 3 +- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/messages.ftl | 15 ++-- compiler/rustc_passes/src/check_attr.rs | 75 ++++++++++++------- compiler/rustc_passes/src/errors.rs | 30 ++++++-- src/tools/miri/tests/pass/fn_align.rs | 10 +-- tests/assembly/naked-functions/wasm32.rs | 2 +- tests/codegen/align-fn.rs | 22 +++--- tests/codegen/min-function-alignment.rs | 6 +- tests/codegen/naked-fn/aligned.rs | 2 +- .../naked-fn/min-function-alignment.rs | 4 +- tests/ui/asm/naked-with-invalid-repr-attr.rs | 3 +- .../asm/naked-with-invalid-repr-attr.stderr | 12 +-- .../attributes/arg-error-issue-121425.stderr | 12 +-- tests/ui/attributes/invalid-repr.rs | 2 +- tests/ui/attributes/invalid-repr.stderr | 4 +- tests/ui/attributes/malformed-fn-align.rs | 17 ++++- tests/ui/attributes/malformed-fn-align.stderr | 69 +++++++++++++++-- .../ui/feature-gates/feature-gate-fn_align.rs | 7 +- .../feature-gate-fn_align.stderr | 41 ++++++---- tests/ui/repr/attr-usage-repr.rs | 2 +- tests/ui/repr/attr-usage-repr.stderr | 4 +- tests/ui/repr/malformed-repr-hints.stderr | 24 +++--- 30 files changed, 322 insertions(+), 135 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d4c434560496..cdc01dc6c91a 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -182,6 +182,9 @@ impl Deprecation { #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub enum AttributeKind { // tidy-alphabetical-start + /// Represents `#[align(N)]`. + Align { align: Align, span: Span }, + /// Represents `#[rustc_allow_const_fn_unstable]`. AllowConstFnUnstable(ThinVec), diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index b9b386635f63..0891afc003e1 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -44,6 +44,9 @@ attr_parsing_incorrect_repr_format_packed_expect_integer = attr_parsing_incorrect_repr_format_packed_one_or_zero_arg = incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all +attr_parsing_invalid_alignment_value = + invalid alignment value: {$error_part} + attr_parsing_invalid_issue_string = `issue` must be a non-zero numeric string or "none" .must_not_be_zero = `issue` must not be "0", use "none" instead diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index ae9e7871874d..c9f9f34bdb7c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; use rustc_feature::{AttributeTemplate, template}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; -use super::{CombineAttributeParser, ConvertFn}; +use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext}; use crate::context::{AcceptContext, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; use crate::session_diagnostics; @@ -203,7 +203,7 @@ fn parse_repr_align( }); } Align => { - cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { + cx.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { span: param_span, }); } @@ -266,3 +266,57 @@ fn parse_alignment(node: &LitKind) -> Result { Err("not an unsuffixed integer") } } + +/// Parse #[align(N)]. +#[derive(Default)] +pub(crate) struct AlignParser(Option<(Align, Span)>); + +impl AlignParser { + const PATH: &'static [Symbol] = &[sym::align]; + const TEMPLATE: AttributeTemplate = template!(Word, List: ""); + + fn parse<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) { + match args { + ArgParser::NoArgs | ArgParser::NameValue(_) => { + cx.expected_list(cx.attr_span); + } + ArgParser::List(list) => { + let Some(align) = list.single() else { + cx.expected_single_argument(list.span); + return; + }; + + let Some(lit) = align.lit() else { + cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger { + span: align.span(), + }); + + return; + }; + + match parse_alignment(&lit.kind) { + Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))), + Err(message) => { + cx.emit_err(session_diagnostics::InvalidAlignmentValue { + span: lit.span, + error_part: message, + }); + } + } + } + } + } +} + +impl AttributeParser for AlignParser { + const ATTRIBUTES: AcceptMapping = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { + let (align, span) = self.0?; + Some(AttributeKind::Align { align, span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 51c1760da300..d7570634c1f7 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -19,7 +19,7 @@ use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::lint_helpers::AsPtrParser; -use crate::attributes::repr::ReprParser; +use crate::attributes::repr::{AlignParser, ReprParser}; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; @@ -90,6 +90,7 @@ macro_rules! attribute_parsers { attribute_parsers!( pub(crate) static ATTRIBUTE_PARSERS = [ // tidy-alphabetical-start + AlignParser, BodyStabilityParser, ConfusablesParser, ConstStabilityParser, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 57ac92a0ca19..337921a318c3 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -450,6 +450,14 @@ pub(crate) struct EmptyConfusables { pub span: Span, } +#[derive(Diagnostic)] +#[diag(attr_parsing_invalid_alignment_value, code = E0589)] +pub(crate) struct InvalidAlignmentValue { + #[primary_span] + pub span: Span, + pub error_part: &'static str, +} + #[derive(Diagnostic)] #[diag(attr_parsing_repr_ident, code = E0565)] pub(crate) struct ReprIdent { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 188a9a98ce7a..98742255063f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -3,7 +3,6 @@ use std::str::FromStr; use rustc_abi::ExternAbi; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; -use rustc_attr_data_structures::ReprAttr::ReprAlign; use rustc_attr_data_structures::{ AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr, }; @@ -110,17 +109,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } }; - if let hir::Attribute::Parsed(p) = attr { - match p { - AttributeKind::Repr(reprs) => { - codegen_fn_attrs.alignment = reprs - .iter() - .filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }) - .max(); - } - - _ => {} - } + if let hir::Attribute::Parsed(AttributeKind::Align { align, .. }) = attr { + codegen_fn_attrs.alignment = Some(*align); } let Some(Ident { name, .. }) = attr.ident() else { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index b5218ec267cc..5b1f1684d54c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -495,6 +495,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), + gated!(align, Normal, template!(List: "alignment"), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(align)), ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index f21cf5fa45e6..2f16d385efb3 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -47,8 +47,7 @@ pub struct CodegenFnAttrs { /// be generated against a specific instruction set. Only usable on architectures which allow /// switching between multiple instruction sets. pub instruction_set: Option, - /// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be - /// aligned to. + /// The `#[align(...)]` attribute. Determines the alignment of the function body. pub alignment: Option, /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around /// the function entry. diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index b3096e46b09c..a12215a44f95 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -289,6 +289,7 @@ fn emit_malformed_attribute( | sym::rustc_force_inline | sym::rustc_confusables | sym::repr + | sym::align | sym::deprecated ) { return; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 7c237d708c0a..c1a2b3b29733 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -13,6 +13,10 @@ passes_abi_ne = passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} +passes_align_should_be_repr_align = + `#[align(...)]` is not supported on {$item} items + .suggestion = use `#[repr(align(...))]` instead + passes_allow_incoherent_impl = `rustc_allow_incoherent_impl` attribute should be applied to impl items .label = the only currently supported targets are inherent methods @@ -29,10 +33,6 @@ passes_attr_application_struct = attribute should be applied to a struct .label = not a struct -passes_attr_application_struct_enum_function_method_union = - attribute should be applied to a struct, enum, function, associated function, or union - .label = not a struct, enum, function, associated function, or union - passes_attr_application_struct_enum_union = attribute should be applied to a struct, enum, or union .label = not a struct, enum, or union @@ -583,13 +583,14 @@ passes_remove_fields = *[other] fields } -passes_repr_align_function = - `repr(align)` attributes on functions are unstable - passes_repr_align_greater_than_target_max = alignment must not be greater than `isize::MAX` bytes .note = `isize::MAX` is {$size} for the current target +passes_repr_align_should_be_align = + `#[repr(align(...))]` is not supported on {$item} items + .help = use `#[align(...)]` instead + passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5ce803aa1f8a..50d6c5d9764a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -146,6 +146,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ } + Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => { + self.check_align(span, target, *align, *repr_span) + } + Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -643,6 +647,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::naked, sym::instruction_set, sym::repr, + sym::align, sym::rustc_std_internal_symbol, // code generation sym::cold, @@ -679,7 +684,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // this check can be part of the parser and be removed here match other_attr { Attribute::Parsed( - AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. }, + AttributeKind::Deprecation { .. } + | AttributeKind::Repr { .. } + | AttributeKind::Align { .. }, ) => { continue; } @@ -1964,6 +1971,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + /// Checks if the `#[align]` attributes on `item` are valid. + fn check_align(&self, span: Span, target: Target, align: Align, repr_span: Span) { + match target { + Target::Fn | Target::Method(_) => {} + Target::Struct | Target::Union | Target::Enum => { + self.dcx().emit_err(errors::AlignShouldBeReprAlign { + span: repr_span, + item: target.name(), + align_bytes: align.bytes(), + }); + } + _ => { + self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { + hint_span: repr_span, + span, + }); + } + } + + self.check_align_value(align, repr_span); + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, @@ -2016,23 +2045,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct | Target::Union | Target::Enum => {} Target::Fn | Target::Method(_) => { - if !self.tcx.features().fn_align() { - feature_err( - &self.tcx.sess, - sym::fn_align, - *repr_span, - fluent::passes_repr_align_function, - ) - .emit(); - } + self.dcx().emit_err(errors::ReprAlignShouldBeAlign { + span: *repr_span, + item: target.name(), + }); } _ => { - self.dcx().emit_err( - errors::AttrApplication::StructEnumFunctionMethodUnion { - hint_span: *repr_span, - span, - }, - ); + self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { + hint_span: *repr_span, + span, + }); } } @@ -2090,21 +2112,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct | Target::Union | Target::Enum => continue, Target::Fn | Target::Method(_) => { - feature_err( - &self.tcx.sess, - sym::fn_align, - *repr_span, - fluent::passes_repr_align_function, - ) - .emit(); + self.dcx().emit_err(errors::ReprAlignShouldBeAlign { + span: *repr_span, + item: target.name(), + }); } _ => { - self.dcx().emit_err( - errors::AttrApplication::StructEnumFunctionMethodUnion { - hint_span: *repr_span, - span, - }, - ); + self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { + hint_span: *repr_span, + span, + }); } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f0d4b610f638..587d9170f067 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1308,13 +1308,6 @@ pub(crate) enum AttrApplication { #[label] span: Span, }, - #[diag(passes_attr_application_struct_enum_function_method_union, code = E0517)] - StructEnumFunctionMethodUnion { - #[primary_span] - hint_span: Span, - #[label] - span: Span, - }, } #[derive(Diagnostic)] @@ -1816,3 +1809,26 @@ pub(crate) enum UnexportableItem<'a> { field_name: &'a str, }, } + +#[derive(Diagnostic)] +#[diag(passes_repr_align_should_be_align)] +pub(crate) struct ReprAlignShouldBeAlign { + #[primary_span] + #[help] + pub span: Span, + pub item: &'static str, +} + +#[derive(Diagnostic)] +#[diag(passes_align_should_be_repr_align)] +pub(crate) struct AlignShouldBeReprAlign { + #[primary_span] + #[suggestion( + style = "verbose", + applicability = "machine-applicable", + code = "#[repr(align({align_bytes}))]" + )] + pub span: Span, + pub item: &'static str, + pub align_bytes: u64, +} diff --git a/src/tools/miri/tests/pass/fn_align.rs b/src/tools/miri/tests/pass/fn_align.rs index 550bb1cb4d71..28f929958800 100644 --- a/src/tools/miri/tests/pass/fn_align.rs +++ b/src/tools/miri/tests/pass/fn_align.rs @@ -1,21 +1,21 @@ //@compile-flags: -Zmin-function-alignment=8 #![feature(fn_align)] -// When a function uses `repr(align(N))`, the function address should be a multiple of `N`. +// When a function uses `align(N)`, the function address should be a multiple of `N`. -#[repr(align(256))] +#[align(256)] fn foo() {} -#[repr(align(16))] +#[align(16)] fn bar() {} -#[repr(align(4))] +#[align(4)] fn baz() {} fn main() { assert!((foo as usize).is_multiple_of(256)); assert!((bar as usize).is_multiple_of(16)); - // The maximum of `repr(align(N))` and `-Zmin-function-alignment=N` is used. + // The maximum of `align(N)` and `-Zmin-function-alignment=N` is used. assert!((baz as usize).is_multiple_of(8)); } diff --git a/tests/assembly/naked-functions/wasm32.rs b/tests/assembly/naked-functions/wasm32.rs index 984152f2b453..5f114246ad55 100644 --- a/tests/assembly/naked-functions/wasm32.rs +++ b/tests/assembly/naked-functions/wasm32.rs @@ -37,7 +37,7 @@ extern "C" fn nop() { #[unsafe(naked)] #[linkage = "weak"] // wasm functions cannot be aligned, so this has no effect -#[repr(align(32))] +#[align(32)] extern "C" fn weak_aligned_nop() { naked_asm!("nop") } diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs index 660d8cd2bbf4..267da0602406 100644 --- a/tests/codegen/align-fn.rs +++ b/tests/codegen/align-fn.rs @@ -5,7 +5,7 @@ // CHECK: align 16 #[no_mangle] -#[repr(align(16))] +#[align(16)] pub fn fn_align() {} pub struct A; @@ -13,12 +13,12 @@ pub struct A; impl A { // CHECK: align 16 #[no_mangle] - #[repr(align(16))] + #[align(16)] pub fn method_align(self) {} // CHECK: align 16 #[no_mangle] - #[repr(align(16))] + #[align(16)] pub fn associated_fn() {} } @@ -26,19 +26,19 @@ trait T: Sized { fn trait_fn() {} // CHECK: align 32 - #[repr(align(32))] + #[align(32)] fn trait_method(self) {} } impl T for A { // CHECK: align 16 #[no_mangle] - #[repr(align(16))] + #[align(16)] fn trait_fn() {} // CHECK: align 16 #[no_mangle] - #[repr(align(16))] + #[align(16)] fn trait_method(self) {} } @@ -51,18 +51,20 @@ pub fn foo() { // CHECK-LABEL: align_specified_twice_1 // CHECK-SAME: align 64 #[no_mangle] -#[repr(align(32), align(64))] +#[align(32)] +#[align(64)] pub fn align_specified_twice_1() {} // CHECK-LABEL: align_specified_twice_2 // CHECK-SAME: align 128 #[no_mangle] -#[repr(align(128), align(32))] +#[align(128)] +#[align(32)] pub fn align_specified_twice_2() {} // CHECK-LABEL: align_specified_twice_3 // CHECK-SAME: align 256 #[no_mangle] -#[repr(align(32))] -#[repr(align(256))] +#[align(32)] +#[align(256)] pub fn align_specified_twice_3() {} diff --git a/tests/codegen/min-function-alignment.rs b/tests/codegen/min-function-alignment.rs index 7c0ad12402aa..75f845572a4a 100644 --- a/tests/codegen/min-function-alignment.rs +++ b/tests/codegen/min-function-alignment.rs @@ -18,16 +18,16 @@ pub fn no_explicit_align() {} // align16: align 16 // align1024: align 1024 #[no_mangle] -#[repr(align(8))] +#[align(8)] pub fn lower_align() {} -// the higher value of min-function-alignment and repr(align) wins out +// the higher value of min-function-alignment and the align attribute wins out // // CHECK-LABEL: @higher_align // align16: align 32 // align1024: align 1024 #[no_mangle] -#[repr(align(32))] +#[align(32)] pub fn higher_align() {} // cold functions follow the same rules as other functions diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs index 47ef779f1b21..f9fce8e5a5d5 100644 --- a/tests/codegen/naked-fn/aligned.rs +++ b/tests/codegen/naked-fn/aligned.rs @@ -8,7 +8,7 @@ use std::arch::naked_asm; // CHECK: .balign 16 // CHECK-LABEL: naked_empty: -#[repr(align(16))] +#[align(16)] #[no_mangle] #[unsafe(naked)] pub extern "C" fn naked_empty() { diff --git a/tests/codegen/naked-fn/min-function-alignment.rs b/tests/codegen/naked-fn/min-function-alignment.rs index 1d778be8c90d..59554c1cae55 100644 --- a/tests/codegen/naked-fn/min-function-alignment.rs +++ b/tests/codegen/naked-fn/min-function-alignment.rs @@ -16,7 +16,7 @@ pub extern "C" fn naked_no_explicit_align() { // CHECK: .balign 16 #[no_mangle] -#[repr(align(8))] +#[align(8)] #[unsafe(naked)] pub extern "C" fn naked_lower_align() { core::arch::naked_asm!("ret") @@ -24,7 +24,7 @@ pub extern "C" fn naked_lower_align() { // CHECK: .balign 32 #[no_mangle] -#[repr(align(32))] +#[align(32)] #[unsafe(naked)] pub extern "C" fn naked_higher_align() { core::arch::naked_asm!("ret") diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs index 96eed70dc550..bfbbf29a69ee 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.rs +++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs @@ -19,8 +19,9 @@ extern "C" fn example2() { naked_asm!("") } -#[repr(align(16), C)] +#[repr(C)] //~^ ERROR attribute should be applied to a struct, enum, or union [E0517] +#[align(16)] #[unsafe(naked)] extern "C" fn example3() { //~^ NOTE not a struct, enum, or union diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.stderr b/tests/ui/asm/naked-with-invalid-repr-attr.stderr index f173a39e5bf6..4eb4a4e5a048 100644 --- a/tests/ui/asm/naked-with-invalid-repr-attr.stderr +++ b/tests/ui/asm/naked-with-invalid-repr-attr.stderr @@ -23,10 +23,10 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:22:19 + --> $DIR/naked-with-invalid-repr-attr.rs:22:8 | -LL | #[repr(align(16), C)] - | ^ +LL | #[repr(C)] + | ^ ... LL | / extern "C" fn example3() { LL | | @@ -35,7 +35,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/naked-with-invalid-repr-attr.rs:31:8 + --> $DIR/naked-with-invalid-repr-attr.rs:32:8 | LL | #[repr(C, packed)] | ^ @@ -48,7 +48,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct or union - --> $DIR/naked-with-invalid-repr-attr.rs:31:11 + --> $DIR/naked-with-invalid-repr-attr.rs:32:11 | LL | #[repr(C, packed)] | ^^^^^^ @@ -61,7 +61,7 @@ LL | | } | |_- not a struct or union error[E0517]: attribute should be applied to an enum - --> $DIR/naked-with-invalid-repr-attr.rs:41:8 + --> $DIR/naked-with-invalid-repr-attr.rs:42:8 | LL | #[repr(u8)] | ^^ diff --git a/tests/ui/attributes/arg-error-issue-121425.stderr b/tests/ui/attributes/arg-error-issue-121425.stderr index 6e71f15fdc87..1beb99b1703c 100644 --- a/tests/ui/attributes/arg-error-issue-121425.stderr +++ b/tests/ui/attributes/arg-error-issue-121425.stderr @@ -1,9 +1,3 @@ -error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses - --> $DIR/arg-error-issue-121425.rs:16:8 - | -LL | #[repr(align())] - | ^^^^^^^ - error[E0693]: incorrect `repr(align)` attribute format: `align` expects a literal integer as argument --> $DIR/arg-error-issue-121425.rs:4:14 | @@ -22,6 +16,12 @@ error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer LL | #[repr(align("str"))] | ^^^^^ +error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses + --> $DIR/arg-error-issue-121425.rs:16:8 + | +LL | #[repr(align())] + | ^^^^^^^ + error[E0552]: incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument --> $DIR/arg-error-issue-121425.rs:21:15 | diff --git a/tests/ui/attributes/invalid-repr.rs b/tests/ui/attributes/invalid-repr.rs index 10a487c127ec..d7933533405c 100644 --- a/tests/ui/attributes/invalid-repr.rs +++ b/tests/ui/attributes/invalid-repr.rs @@ -1,5 +1,5 @@ #[repr(align(16))] -//~^ ERROR attribute should be applied to a struct, enum, function, associated function, or union +//~^ ERROR attribute should be applied to a struct, enum, or union pub type Foo = i32; fn main() {} diff --git a/tests/ui/attributes/invalid-repr.stderr b/tests/ui/attributes/invalid-repr.stderr index 681460ad0812..3f5a305c6b70 100644 --- a/tests/ui/attributes/invalid-repr.stderr +++ b/tests/ui/attributes/invalid-repr.stderr @@ -1,11 +1,11 @@ -error[E0517]: attribute should be applied to a struct, enum, function, associated function, or union +error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/invalid-repr.rs:1:8 | LL | #[repr(align(16))] | ^^^^^^^^^ LL | LL | pub type Foo = i32; - | ------------------- not a struct, enum, function, associated function, or union + | ------------------- not a struct, enum, or union error: aborting due to 1 previous error diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs index 4aaad01b7235..35ffd6d8acce 100644 --- a/tests/ui/attributes/malformed-fn-align.rs +++ b/tests/ui/attributes/malformed-fn-align.rs @@ -2,6 +2,21 @@ #![crate_type = "lib"] trait MyTrait { - #[repr(align)] //~ ERROR invalid `repr(align)` attribute: `align` needs an argument + #[align] //~ ERROR malformed `align` attribute input fn myfun(); } + +#[align = 16] //~ ERROR malformed `align` attribute input +fn f1() {} + +#[align("hello")] //~ ERROR invalid alignment value: not an unsuffixed integer +fn f2() {} + +#[align(0)] //~ ERROR invalid alignment value: not a power of two +fn f3() {} + +#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on function items +fn f4() {} + +#[align(16)] //~ ERROR `#[align(...)]` is not supported on struct items +struct S1; diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr index 57913c48ef78..765255c2c3a9 100644 --- a/tests/ui/attributes/malformed-fn-align.stderr +++ b/tests/ui/attributes/malformed-fn-align.stderr @@ -1,9 +1,66 @@ -error[E0589]: invalid `repr(align)` attribute: `align` needs an argument - --> $DIR/malformed-fn-align.rs:5:12 +error[E0539]: malformed `align` attribute input + --> $DIR/malformed-fn-align.rs:5:5 | -LL | #[repr(align)] - | ^^^^^ help: supply an argument here: `align(...)` +LL | #[align] + | ^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[align()] + | ++++++++++++++++++++++ -error: aborting due to 1 previous error +error[E0539]: malformed `align` attribute input + --> $DIR/malformed-fn-align.rs:9:1 + | +LL | #[align = 16] + | ^^^^^^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[align = 16] +LL + #[align()] + | +LL - #[align = 16] +LL + #[align] + | -For more information about this error, try `rustc --explain E0589`. +error[E0589]: invalid alignment value: not an unsuffixed integer + --> $DIR/malformed-fn-align.rs:12:9 + | +LL | #[align("hello")] + | ^^^^^^^ + +error[E0589]: invalid alignment value: not a power of two + --> $DIR/malformed-fn-align.rs:15:9 + | +LL | #[align(0)] + | ^ + +error: `#[repr(align(...))]` is not supported on function items + --> $DIR/malformed-fn-align.rs:18:8 + | +LL | #[repr(align(16))] + | ^^^^^^^^^ + | +help: use `#[align(...)]` instead + --> $DIR/malformed-fn-align.rs:18:8 + | +LL | #[repr(align(16))] + | ^^^^^^^^^ + +error: `#[align(...)]` is not supported on struct items + --> $DIR/malformed-fn-align.rs:21:1 + | +LL | #[align(16)] + | ^^^^^^^^^^^^ + | +help: use `#[repr(align(...))]` instead + | +LL - #[align(16)] +LL + #[repr(align(16))] + | + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0539, E0589. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/feature-gates/feature-gate-fn_align.rs b/tests/ui/feature-gates/feature-gate-fn_align.rs index 744877704dd1..b6c300e5cbe6 100644 --- a/tests/ui/feature-gates/feature-gate-fn_align.rs +++ b/tests/ui/feature-gates/feature-gate-fn_align.rs @@ -1,9 +1,12 @@ #![crate_type = "lib"] -#[repr(align(16))] //~ ERROR `repr(align)` attributes on functions are unstable +#[align(16)] +//~^ ERROR the `#[align]` attribute is an experimental feature fn requires_alignment() {} trait MyTrait { - #[repr(align)] //~ ERROR invalid `repr(align)` attribute: `align` needs an argument + #[align] + //~^ ERROR the `#[align]` attribute is an experimental feature + //~| ERROR malformed `align` attribute input fn myfun(); } diff --git a/tests/ui/feature-gates/feature-gate-fn_align.stderr b/tests/ui/feature-gates/feature-gate-fn_align.stderr index ff17c29fe029..93ef136dc73c 100644 --- a/tests/ui/feature-gates/feature-gate-fn_align.stderr +++ b/tests/ui/feature-gates/feature-gate-fn_align.stderr @@ -1,20 +1,35 @@ -error[E0589]: invalid `repr(align)` attribute: `align` needs an argument - --> $DIR/feature-gate-fn_align.rs:7:12 +error[E0658]: the `#[align]` attribute is an experimental feature + --> $DIR/feature-gate-fn_align.rs:3:1 | -LL | #[repr(align)] - | ^^^^^ help: supply an argument here: `align(...)` - -error[E0658]: `repr(align)` attributes on functions are unstable - --> $DIR/feature-gate-fn_align.rs:3:8 - | -LL | #[repr(align(16))] - | ^^^^^^^^^ +LL | #[align(16)] + | ^^^^^^^^^^^^ | = note: see issue #82232 for more information = help: add `#![feature(fn_align)]` 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]: the `#[align]` attribute is an experimental feature + --> $DIR/feature-gate-fn_align.rs:8:5 + | +LL | #[align] + | ^^^^^^^^ + | + = note: see issue #82232 for more information + = help: add `#![feature(fn_align)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -Some errors have detailed explanations: E0589, E0658. -For more information about an error, try `rustc --explain E0589`. +error[E0539]: malformed `align` attribute input + --> $DIR/feature-gate-fn_align.rs:8:5 + | +LL | #[align] + | ^^^^^^^^ expected this to be a list + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[align()] + | ++++++++++++++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0539, E0658. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/repr/attr-usage-repr.rs b/tests/ui/repr/attr-usage-repr.rs index cbf99f16e036..ca63ac564fc5 100644 --- a/tests/ui/repr/attr-usage-repr.rs +++ b/tests/ui/repr/attr-usage-repr.rs @@ -45,7 +45,7 @@ enum EInt { B, } -#[repr()] //~ ERROR attribute should be applied to a struct, enum, function, associated function, or union [E0517] +#[repr()] //~ ERROR attribute should be applied to a struct, enum, or union [E0517] type SirThisIsAType = i32; #[repr()] diff --git a/tests/ui/repr/attr-usage-repr.stderr b/tests/ui/repr/attr-usage-repr.stderr index a25e68c483f6..a62992c597a2 100644 --- a/tests/ui/repr/attr-usage-repr.stderr +++ b/tests/ui/repr/attr-usage-repr.stderr @@ -36,13 +36,13 @@ LL | | B, LL | | } | |_- not a struct -error[E0517]: attribute should be applied to a struct, enum, function, associated function, or union +error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/attr-usage-repr.rs:48:1 | LL | #[repr()] | ^^^^^^^^^ LL | type SirThisIsAType = i32; - | -------------------------- not a struct, enum, function, associated function, or union + | -------------------------- not a struct, enum, or union error: aborting due to 5 previous errors diff --git a/tests/ui/repr/malformed-repr-hints.stderr b/tests/ui/repr/malformed-repr-hints.stderr index 7a6e9ccc73eb..6fb927557619 100644 --- a/tests/ui/repr/malformed-repr-hints.stderr +++ b/tests/ui/repr/malformed-repr-hints.stderr @@ -1,15 +1,3 @@ -error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses - --> $DIR/malformed-repr-hints.rs:14:8 - | -LL | #[repr(align(2, 4))] - | ^^^^^^^^^^^ - -error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses - --> $DIR/malformed-repr-hints.rs:18:8 - | -LL | #[repr(align())] - | ^^^^^^^ - error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all --> $DIR/malformed-repr-hints.rs:6:8 | @@ -22,6 +10,18 @@ error[E0589]: invalid `repr(align)` attribute: `align` needs an argument LL | #[repr(align)] | ^^^^^ help: supply an argument here: `align(...)` +error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses + --> $DIR/malformed-repr-hints.rs:14:8 + | +LL | #[repr(align(2, 4))] + | ^^^^^^^^^^^ + +error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses + --> $DIR/malformed-repr-hints.rs:18:8 + | +LL | #[repr(align())] + | ^^^^^^^ + error[E0552]: invalid representation hint: `Rust` does not take a parenthesized argument list --> $DIR/malformed-repr-hints.rs:23:8 | From a27bdea4b7b5107ea912659813418445d9e46ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 5 Mar 2025 20:18:05 +0100 Subject: [PATCH 097/356] Enable automatic cross-compilation in run-make tests --- .../src/external_deps/rustc.rs | 24 +++++++++++++------ src/tools/run-make-support/src/macros.rs | 9 +++++++ .../run-make/apple-deployment-target/rmake.rs | 5 ---- tests/run-make/apple-sdk-version/rmake.rs | 9 +++---- tests/run-make/mte-ffi/rmake.rs | 6 +---- tests/run-make/rustc-macro-dep-files/rmake.rs | 2 +- tests/run-make/static-pie/rmake.rs | 1 - .../sysroot-crates-are-unstable/rmake.rs | 1 - 8 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index a7081d4f86a2..72a1e062a38d 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -6,7 +6,7 @@ use crate::command::Command; use crate::env::env_var; use crate::path_helpers::cwd; use crate::util::set_host_compiler_dylib_path; -use crate::{is_aix, is_darwin, is_msvc, is_windows, uname}; +use crate::{is_aix, is_darwin, is_msvc, is_windows, target, uname}; /// Construct a new `rustc` invocation. This will automatically set the library /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. @@ -27,9 +27,15 @@ pub fn bare_rustc() -> Rustc { #[must_use] pub struct Rustc { cmd: Command, + target: Option, } -crate::macros::impl_common_helpers!(Rustc); +// Only fill in the target just before execution, so that it can be overridden. +crate::macros::impl_common_helpers!(Rustc, |rustc: &mut Rustc| { + if let Some(target) = &rustc.target { + rustc.cmd.arg(&format!("--target={target}")); + } +}); pub fn rustc_path() -> String { env_var("RUSTC") @@ -46,19 +52,22 @@ impl Rustc { // `rustc` invocation constructor methods /// Construct a new `rustc` invocation. This will automatically set the library - /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. + /// search path as `-L cwd()` and also the compilation target. + /// Use [`bare_rustc`] to avoid this. #[track_caller] pub fn new() -> Self { let mut cmd = setup_common(); cmd.arg("-L").arg(cwd()); - Self { cmd } + + // Automatically default to cross-compilation + Self { cmd, target: Some(target()) } } /// Construct a bare `rustc` invocation with no flags set. #[track_caller] pub fn bare() -> Self { let cmd = setup_common(); - Self { cmd } + Self { cmd, target: None } } // Argument provider methods @@ -234,8 +243,9 @@ impl Rustc { /// Specify the target triple, or a path to a custom target json spec file. pub fn target>(&mut self, target: S) -> &mut Self { - let target = target.as_ref(); - self.cmd.arg(format!("--target={target}")); + // We store the target as a separate field, so that it can be specified multiple times. + // This is in particular useful to override the default target set in Rustc::new(). + self.target = Some(target.as_ref().to_string()); self } diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs index 9d5cc4e5876d..b9208382a982 100644 --- a/src/tools/run-make-support/src/macros.rs +++ b/src/tools/run-make-support/src/macros.rs @@ -23,10 +23,16 @@ /// } /// ``` /// +/// You can pass an optional second parameter which should be a function that is passed +/// `&mut self` just before the command is executed. +/// /// [`Command`]: crate::command::Command /// [`CompletedProcess`]: crate::command::CompletedProcess macro_rules! impl_common_helpers { ($wrapper: ident) => { + $crate::macros::impl_common_helpers!($wrapper, |_| {}); + }; + ($wrapper: ident, $before_exec: expr) => { impl $wrapper { /// In very rare circumstances, you may need a e.g. `bare_rustc()` or `bare_rustdoc()` /// with host runtime libs configured, but want the underlying raw @@ -130,12 +136,14 @@ macro_rules! impl_common_helpers { /// Run the constructed command and assert that it is successfully run. #[track_caller] pub fn run(&mut self) -> crate::command::CompletedProcess { + $before_exec(&mut *self); self.cmd.run() } /// Run the constructed command and assert that it does not successfully run. #[track_caller] pub fn run_fail(&mut self) -> crate::command::CompletedProcess { + $before_exec(&mut *self); self.cmd.run_fail() } @@ -145,6 +153,7 @@ macro_rules! impl_common_helpers { /// whenever possible. #[track_caller] pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess { + $before_exec(&mut *self); self.cmd.run_unchecked() } diff --git a/tests/run-make/apple-deployment-target/rmake.rs b/tests/run-make/apple-deployment-target/rmake.rs index 839e21b7496d..7297a8622240 100644 --- a/tests/run-make/apple-deployment-target/rmake.rs +++ b/tests/run-make/apple-deployment-target/rmake.rs @@ -41,7 +41,6 @@ fn main() { // Remove env vars to get `rustc`'s default let output = rustc() - .target(target()) .env_remove("MACOSX_DEPLOYMENT_TARGET") .env_remove("IPHONEOS_DEPLOYMENT_TARGET") .env_remove("WATCHOS_DEPLOYMENT_TARGET") @@ -58,7 +57,6 @@ fn main() { run_in_tmpdir(|| { let rustc = || { let mut rustc = rustc(); - rustc.target(target()); rustc.crate_type("lib"); rustc.emit("obj"); rustc.input("foo.rs"); @@ -82,7 +80,6 @@ fn main() { let rustc = || { let mut rustc = rustc(); - rustc.target(target()); rustc.crate_type("dylib"); rustc.input("foo.rs"); rustc.output("libfoo.dylib"); @@ -108,7 +105,6 @@ fn main() { run_in_tmpdir(|| { let rustc = || { let mut rustc = rustc(); - rustc.target(target()); rustc.crate_type("bin"); rustc.input("foo.rs"); rustc.output("foo"); @@ -147,7 +143,6 @@ fn main() { run_in_tmpdir(|| { let rustc = || { let mut rustc = rustc(); - rustc.target(target()); rustc.incremental("incremental"); rustc.crate_type("lib"); rustc.emit("obj"); diff --git a/tests/run-make/apple-sdk-version/rmake.rs b/tests/run-make/apple-sdk-version/rmake.rs index 43e805772043..1f4f0ab8aef8 100644 --- a/tests/run-make/apple-sdk-version/rmake.rs +++ b/tests/run-make/apple-sdk-version/rmake.rs @@ -24,8 +24,7 @@ fn has_sdk_version(file: &str, version: &str) { fn main() { // Fetch rustc's inferred deployment target. - let current_deployment_target = - rustc().target(target()).print("deployment-target").run().stdout_utf8(); + let current_deployment_target = rustc().print("deployment-target").run().stdout_utf8(); let current_deployment_target = current_deployment_target.split('=').last().unwrap().trim(); // Fetch current SDK version via. xcrun. @@ -45,7 +44,7 @@ fn main() { let current_sdk_version = current_sdk_version.trim(); // Check the SDK version in the object file produced by the codegen backend. - rustc().target(target()).crate_type("lib").emit("obj").input("foo.rs").output("foo.o").run(); + rustc().crate_type("lib").emit("obj").input("foo.rs").output("foo.o").run(); // Set to 0, which means not set or "n/a". has_sdk_version("foo.o", "n/a"); @@ -53,7 +52,7 @@ fn main() { // // This is just to ensure that we don't set some odd version in `create_object_file`, // if the rmeta file is packed in a different way in the future, this can safely be removed. - rustc().target(target()).crate_type("rlib").input("foo.rs").output("libfoo.rlib").run(); + rustc().crate_type("rlib").input("foo.rs").output("libfoo.rlib").run(); // Extra .rmeta file (which is encoded as an object file). cmd("ar").arg("-x").arg("libfoo.rlib").arg("lib.rmeta").run(); has_sdk_version("lib.rmeta", "n/a"); @@ -69,7 +68,6 @@ fn main() { // Test with clang let file_name = format!("foo_cc{file_ext}"); rustc() - .target(target()) .crate_type("bin") .arg("-Clinker-flavor=gcc") .input("foo.rs") @@ -80,7 +78,6 @@ fn main() { // Test with ld64 let file_name = format!("foo_ld{file_ext}"); rustc() - .target(target()) .crate_type("bin") .arg("-Clinker-flavor=ld") .input("foo.rs") diff --git a/tests/run-make/mte-ffi/rmake.rs b/tests/run-make/mte-ffi/rmake.rs index 50f5f14191b4..a8da0dc0ee03 100644 --- a/tests/run-make/mte-ffi/rmake.rs +++ b/tests/run-make/mte-ffi/rmake.rs @@ -22,11 +22,7 @@ fn run_test(variant: &str) { flags }; println!("{variant} test..."); - rustc() - .input(format!("foo_{variant}.rs")) - .target(target()) - .linker("aarch64-linux-gnu-gcc") - .run(); + rustc().input(format!("foo_{variant}.rs")).linker("aarch64-linux-gnu-gcc").run(); gcc() .input(format!("bar_{variant}.c")) .input(dynamic_lib_name("foo")) diff --git a/tests/run-make/rustc-macro-dep-files/rmake.rs b/tests/run-make/rustc-macro-dep-files/rmake.rs index eb4771fea7a6..c01244824bb2 100644 --- a/tests/run-make/rustc-macro-dep-files/rmake.rs +++ b/tests/run-make/rustc-macro-dep-files/rmake.rs @@ -10,7 +10,7 @@ use run_make_support::{diff, rustc, target}; fn main() { rustc().input("foo.rs").run(); - rustc().input("bar.rs").target(target()).emit("dep-info").run(); + rustc().input("bar.rs").emit("dep-info").run(); // The emitted file should not contain "proc-macro source". diff().expected_file("correct.d").actual_file("bar.d").run(); } diff --git a/tests/run-make/static-pie/rmake.rs b/tests/run-make/static-pie/rmake.rs index 1557c170f56d..cb24c0495be8 100644 --- a/tests/run-make/static-pie/rmake.rs +++ b/tests/run-make/static-pie/rmake.rs @@ -49,7 +49,6 @@ fn test(compiler: &str) { rustc() .input("test-aslr.rs") - .target(target()) .linker(compiler) .arg("-Clinker-flavor=gcc") .arg("-Ctarget-feature=+crt-static") diff --git a/tests/run-make/sysroot-crates-are-unstable/rmake.rs b/tests/run-make/sysroot-crates-are-unstable/rmake.rs index c81c7fafdab0..20ad01bef61d 100644 --- a/tests/run-make/sysroot-crates-are-unstable/rmake.rs +++ b/tests/run-make/sysroot-crates-are-unstable/rmake.rs @@ -31,7 +31,6 @@ fn check_crate_is_unstable(cr: &Crate) { // Trying to use this crate from a user program should fail. let output = rustc() .crate_type("rlib") - .target(target()) .extern_(name, path) .input("-") .stdin_buf(format!("extern crate {name};")) From 49be6f32588e2eb276e9210b64f4927f609bbe96 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 2 Apr 2025 17:14:13 +0800 Subject: [PATCH 098/356] Enable `run-make-support` auto cross-compilation for `rustdoc` too --- .../src/external_deps/rustdoc.rs | 37 ++++++++++++++++--- src/tools/run-make-support/src/lib.rs | 2 +- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs index 7040fb667cfc..33e5f04d3034 100644 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs @@ -3,21 +3,36 @@ use std::path::Path; use crate::command::Command; use crate::env::env_var; +use crate::target; use crate::util::set_host_compiler_dylib_path; -/// Construct a new `rustdoc` invocation. This will configure the host compiler runtime libs. +/// Construct a new `rustdoc` invocation with target automatically set to cross-compile target and +/// with host compiler runtime libs configured. Use [`bare_rustdoc`] to avoid automatically setting +/// cross-compile target. #[track_caller] pub fn rustdoc() -> Rustdoc { Rustdoc::new() } +/// Bare `rustdoc` invocation, no args set. +#[track_caller] +pub fn bare_rustdoc() -> Rustdoc { + Rustdoc::bare() +} + #[derive(Debug)] #[must_use] pub struct Rustdoc { cmd: Command, + target: Option, } -crate::macros::impl_common_helpers!(Rustdoc); +// Only fill in the target just before execution, so that it can be overridden. +crate::macros::impl_common_helpers!(Rustdoc, |rustdoc: &mut Rustdoc| { + if let Some(target) = &rustdoc.target { + rustdoc.cmd.arg(&format!("--target={target}")); + } +}); #[track_caller] fn setup_common() -> Command { @@ -28,11 +43,20 @@ fn setup_common() -> Command { } impl Rustdoc { - /// Construct a bare `rustdoc` invocation. This will configure the host compiler runtime libs. + /// Construct a new `rustdoc` invocation with target automatically set to cross-compile target + /// and with host compiler runtime libs configured. Use [`bare_rustdoc`] to avoid automatically + /// setting cross-compile target. #[track_caller] pub fn new() -> Self { let cmd = setup_common(); - Self { cmd } + Self { cmd, target: Some(target()) } + } + + /// Bare `rustdoc` invocation, no args set. + #[track_caller] + pub fn bare() -> Self { + let cmd = setup_common(); + Self { cmd, target: None } } /// Specify where an external library is located. @@ -85,8 +109,9 @@ impl Rustdoc { /// Specify the target triple, or a path to a custom target json spec file. pub fn target>(&mut self, target: S) -> &mut Self { - let target = target.as_ref(); - self.cmd.arg(format!("--target={target}")); + // We store the target as a separate field, so that it can be specified multiple times. + // This is in particular useful to override the default target set in `Rustdoc::new()`. + self.target = Some(target.as_ref().to_string()); self } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index f37b38ac0b15..947f815fd697 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -68,7 +68,7 @@ pub use llvm::{ }; pub use python::python_command; pub use rustc::{bare_rustc, rustc, rustc_path, Rustc}; -pub use rustdoc::{rustdoc, Rustdoc}; +pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; /// [`diff`][mod@diff] is implemented in terms of the [similar] library. /// From b4f09d75e43076138129e3d0b08cf47144fdaa2d Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Wed, 18 Jun 2025 04:46:58 -0700 Subject: [PATCH 099/356] Add --color=always to test explorer command Fixes https://github.com/rust-lang/rust-analyzer/issues/20030 --- src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs index 9c0bc33af646..e7528dbc9396 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs @@ -103,6 +103,7 @@ impl CargoTestHandle { ) -> std::io::Result { let mut cmd = toolchain::command(Tool::Cargo.path(), root, &options.extra_env); cmd.env("RUSTC_BOOTSTRAP", "1"); + cmd.arg("--color=always"); cmd.arg("test"); cmd.arg("--package"); From b64fd13a04e03bd260b550430daa6fbdf1fb27c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 9 Mar 2025 23:46:47 +0100 Subject: [PATCH 100/356] convert the `optimize` attribute to a new parser --- .../src/attributes.rs | 6 ++- .../src/attributes/codegen_attrs.rs | 40 +++++++++++++++++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 2 + compiler/rustc_codegen_ssa/messages.ftl | 5 --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 29 +------------- compiler/rustc_codegen_ssa/src/errors.rs | 14 ------- .../src/error_codes/E0722.md | 8 +++- compiler/rustc_error_codes/src/lib.rs | 1 + compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 8 ++-- .../feature-gate-optimize_attribute.rs | 2 +- .../feature-gate-optimize_attribute.stderr | 13 +++--- 13 files changed, 72 insertions(+), 58 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d4c434560496..e0b0015f365c 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -38,7 +38,8 @@ pub enum InstructionSetAttr { ArmT32, } -#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic, Default)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, PrintAttribute)] +#[derive(Encodable, Decodable, HashStable_Generic)] pub enum OptimizeAttr { /// No `#[optimize(..)]` attribute #[default] @@ -226,7 +227,8 @@ pub enum AttributeKind { /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), - + /// Represents `#[optimize(size|speed)]` + Optimize(OptimizeAttr, Span), /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs new file mode 100644 index 000000000000..ddcf82cbf7cd --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -0,0 +1,40 @@ +use rustc_attr_data_structures::{AttributeKind, OptimizeAttr}; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::sym; + +use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct OptimizeParser; + +impl SingleAttributeParser for OptimizeParser { + const PATH: &[rustc_span::Symbol] = &[sym::optimize]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span); + return None; + }; + + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + + let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) { + Some(sym::size) => OptimizeAttr::Size, + Some(sym::speed) => OptimizeAttr::Speed, + Some(sym::none) => OptimizeAttr::DoNotOptimize, + _ => { + cx.expected_specific_argument(single.span(), vec!["size", "speed", "none"]); + OptimizeAttr::Default + } + }; + + Some(AttributeKind::Optimize(res, cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index fa2a6087506c..3bb4c163d326 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -28,6 +28,7 @@ use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; pub(crate) mod cfg; +pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod inline; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 51c1760da300..18ed98d4a259 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,6 +15,7 @@ use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; +use crate::attributes::codegen_attrs::OptimizeParser; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -107,6 +108,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, // tidy-alphabetical-end diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 5322fe58cf33..e4734b180935 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -48,8 +48,6 @@ codegen_ssa_error_writing_def_file = codegen_ssa_expected_name_value_pair = expected name value pair -codegen_ssa_expected_one_argument = expected one argument - codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified @@ -86,9 +84,6 @@ codegen_ssa_incorrect_cgu_reuse_type = codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. -codegen_ssa_invalid_argument = invalid argument - .help = valid inline arguments are `always` and `never` - codegen_ssa_invalid_instruction_set = invalid instruction set specified codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]` diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 188a9a98ce7a..33c457ead30a 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -465,33 +465,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.inline = InlineAttr::Never; } - codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::Default, |ia, attr| { - if !attr.has_name(sym::optimize) { - return ia; - } - if attr.is_word() { - tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() }); - return ia; - } - let Some(ref items) = attr.meta_item_list() else { - return OptimizeAttr::Default; - }; - - let [item] = &items[..] else { - tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() }); - return OptimizeAttr::Default; - }; - if item.has_name(sym::size) { - OptimizeAttr::Size - } else if item.has_name(sym::speed) { - OptimizeAttr::Speed - } else if item.has_name(sym::none) { - OptimizeAttr::DoNotOptimize - } else { - tcx.dcx().emit_err(errors::InvalidArgumentOptimize { span: item.span() }); - OptimizeAttr::Default - } - }); + codegen_fn_attrs.optimize = + find_attr!(attrs, AttributeKind::Optimize(i, _) => *i).unwrap_or(OptimizeAttr::Default); // #73631: closures inherit `#[target_feature]` annotations // diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 5387b2a7f818..c60661a1410c 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -208,20 +208,6 @@ pub(crate) struct OutOfRangeInteger { pub span: Span, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_expected_one_argument, code = E0722)] -pub(crate) struct ExpectedOneArgumentOptimize { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_invalid_argument, code = E0722)] -pub(crate) struct InvalidArgumentOptimize { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_copy_path_buf)] pub(crate) struct CopyPathBuf { diff --git a/compiler/rustc_error_codes/src/error_codes/E0722.md b/compiler/rustc_error_codes/src/error_codes/E0722.md index 570717a92bd7..1799458d46cb 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0722.md +++ b/compiler/rustc_error_codes/src/error_codes/E0722.md @@ -1,8 +1,14 @@ +#### Note: this error code is no longer emitted by the compiler + +This is because it was too specific to the `optimize` attribute. +Similar diagnostics occur for other attributes too. +The example here will now emit `E0539` + The `optimize` attribute was malformed. Erroneous code example: -```compile_fail,E0722 +```compile_fail,E0539 #![feature(optimize_attribute)] #[optimize(something)] // error: invalid argument diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 6f5e4829802e..22cc1e894da9 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -686,6 +686,7 @@ E0805: 0805, // E0707, // multiple elided lifetimes used in arguments of `async fn` // E0709, // multiple different lifetimes used in arguments of `async fn` // E0721, // `await` keyword +// E0722, // replaced with a generic attribute input check // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. // E0744, // merged into E0728 diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index b3096e46b09c..1fbc970e2a71 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -290,6 +290,7 @@ fn emit_malformed_attribute( | sym::rustc_confusables | sym::repr | sym::deprecated + | sym::optimize ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5ce803aa1f8a..98e8b47127b2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -128,6 +128,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => { self.check_inline(hir_id, *attr_span, span, kind, target) } + Attribute::Parsed(AttributeKind::Optimize(_, attr_span)) => { + self.check_optimize(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -163,7 +166,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) } [sym::coverage, ..] => self.check_coverage(attr, span, target), - [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target), [sym::no_sanitize, ..] => { self.check_no_sanitize(attr, span, target) } @@ -525,7 +527,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks that `#[optimize(..)]` is applied to a function/closure/method, /// or to an impl block or module. - fn check_optimize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_optimize(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { let is_valid = matches!( target, Target::Fn @@ -534,7 +536,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); if !is_valid { self.dcx().emit_err(errors::OptimizeInvalidTarget { - attr_span: attr.span(), + attr_span, defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.rs b/tests/ui/feature-gates/feature-gate-optimize_attribute.rs index 77cc307c9f45..ed5a11270f83 100644 --- a/tests/ui/feature-gates/feature-gate-optimize_attribute.rs +++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.rs @@ -11,5 +11,5 @@ fn none() {} #[optimize(banana)] //~^ ERROR the `#[optimize]` attribute is an experimental feature -//~| ERROR E0722 +//~| ERROR malformed `optimize` attribute input [E0539] fn not_known() {} diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr index 4e6e4ac2703a..e7e62b4f9899 100644 --- a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr +++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr @@ -38,13 +38,16 @@ LL | #[optimize(banana)] = help: add `#![feature(optimize_attribute)]` 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[E0722]: invalid argument - --> $DIR/feature-gate-optimize_attribute.rs:12:12 +error[E0539]: malformed `optimize` attribute input + --> $DIR/feature-gate-optimize_attribute.rs:12:1 | LL | #[optimize(banana)] - | ^^^^^^ + | ^^^^^^^^^^^------^^ + | | | + | | valid arguments are `size`, `speed` or `none` + | help: must be of the form: `#[optimize(size|speed|none)]` error: aborting due to 5 previous errors -Some errors have detailed explanations: E0658, E0722. -For more information about an error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0539, E0658. +For more information about an error, try `rustc --explain E0539`. From 815f0b71c70be3ee9d3ad714250d0a467a2e05ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 12 Jun 2025 13:25:37 +0200 Subject: [PATCH 101/356] better template for repr attributes --- compiler/rustc_attr_parsing/src/attributes/repr.rs | 3 ++- tests/ui/issues/issue-43988.stderr | 4 ++-- tests/ui/repr/repr.stderr | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index ae9e7871874d..83fabe14618a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -25,7 +25,8 @@ impl CombineAttributeParser for ReprParser { const PATH: &[Symbol] = &[sym::repr]; const CONVERT: ConvertFn = AttributeKind::Repr; // FIXME(jdonszelmann): never used - const TEMPLATE: AttributeTemplate = template!(List: "C"); + const TEMPLATE: AttributeTemplate = + template!(List: "C | Rust | align(...) | packed(...) | | transparent"); fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index bd4eb8bbed37..fe61e136a516 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -38,7 +38,7 @@ LL | #[repr] | ^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[repr(C)]` + | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` error[E0539]: malformed `inline` attribute input --> $DIR/issue-43988.rs:30:5 @@ -64,7 +64,7 @@ LL | let _z = #[repr] 1; | ^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[repr(C)]` + | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:5:5 diff --git a/tests/ui/repr/repr.stderr b/tests/ui/repr/repr.stderr index f3b11398eaa4..9e5813322783 100644 --- a/tests/ui/repr/repr.stderr +++ b/tests/ui/repr/repr.stderr @@ -5,7 +5,7 @@ LL | #[repr] | ^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[repr(C)]` + | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:4:1 @@ -14,7 +14,7 @@ LL | #[repr = "B"] | ^^^^^^^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[repr(C)]` + | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:7:1 @@ -23,7 +23,7 @@ LL | #[repr = "C"] | ^^^^^^^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[repr(C)]` + | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` error: aborting due to 3 previous errors From 5bd918fcd8be416600026a61df47a12c00788bfc Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 18 Jun 2025 11:51:40 +0000 Subject: [PATCH 102/356] vec_deque tests: remove static mut --- .../src/collections/linked_list/tests.rs | 18 +-------- .../alloc/src/collections/vec_deque/tests.rs | 38 ++++++------------- library/alloctests/testing/macros.rs | 17 +++++++++ library/alloctests/testing/mod.rs | 1 + 4 files changed, 31 insertions(+), 43 deletions(-) create mode 100644 library/alloctests/testing/macros.rs diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index 410e67d3fdb0..3d6c740e80b3 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -1,4 +1,3 @@ -use std::cell::Cell; use std::panic::{AssertUnwindSafe, catch_unwind}; use std::thread; @@ -6,6 +5,7 @@ use rand::RngCore; use super::*; use crate::testing::crash_test::{CrashTestDummy, Panic}; +use crate::testing::macros::struct_with_counted_drop; use crate::vec::Vec; #[test] @@ -1010,22 +1010,6 @@ fn extract_if_drop_panic_leak() { assert_eq!(d7.dropped(), 1); } -macro_rules! struct_with_counted_drop { - ($struct_name:ident$(($elt_ty:ty))?, $drop_counter:ident $(=> $drop_stmt:expr)?) => { - thread_local! {static $drop_counter: Cell = Cell::new(0);} - - struct $struct_name$(($elt_ty))?; - - impl Drop for $struct_name { - fn drop(&mut self) { - $drop_counter.set($drop_counter.get() + 1); - - $($drop_stmt(self))? - } - } - }; -} - #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn extract_if_pred_panic_leak() { diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index c90679f17977..ad76cb14deb8 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -1,9 +1,7 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] - use core::iter::TrustedLen; use super::*; +use crate::testing::macros::struct_with_counted_drop; #[bench] fn bench_push_back_100(b: &mut test::Bencher) { @@ -1086,36 +1084,24 @@ fn test_clone_from() { #[test] fn test_vec_deque_truncate_drop() { - static mut DROPS: u32 = 0; - #[derive(Clone)] - struct Elem(#[allow(dead_code)] i32); - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem, DROPS); - let v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; - for push_front in 0..=v.len() { - let v = v.clone(); - let mut tester = VecDeque::with_capacity(5); - for (index, elem) in v.into_iter().enumerate() { + const LEN: usize = 5; + for push_front in 0..=LEN { + let mut tester = VecDeque::with_capacity(LEN); + for index in 0..LEN { if index < push_front { - tester.push_front(elem); + tester.push_front(Elem); } else { - tester.push_back(elem); + tester.push_back(Elem); } } - assert_eq!(unsafe { DROPS }, 0); + assert_eq!(DROPS.get(), 0); tester.truncate(3); - assert_eq!(unsafe { DROPS }, 2); + assert_eq!(DROPS.get(), 2); tester.truncate(0); - assert_eq!(unsafe { DROPS }, 5); - unsafe { - DROPS = 0; - } + assert_eq!(DROPS.get(), 5); + DROPS.set(0); } } diff --git a/library/alloctests/testing/macros.rs b/library/alloctests/testing/macros.rs new file mode 100644 index 000000000000..37cf59bc1693 --- /dev/null +++ b/library/alloctests/testing/macros.rs @@ -0,0 +1,17 @@ +macro_rules! struct_with_counted_drop { + ($struct_name:ident$(($elt_ty:ty))?, $drop_counter:ident $(=> $drop_stmt:expr)?) => { + thread_local! {static $drop_counter: ::core::cell::Cell = ::core::cell::Cell::new(0);} + + struct $struct_name$(($elt_ty))?; + + impl ::std::ops::Drop for $struct_name { + fn drop(&mut self) { + $drop_counter.set($drop_counter.get() + 1); + + $($drop_stmt(self))? + } + } + }; +} + +pub(crate) use struct_with_counted_drop; diff --git a/library/alloctests/testing/mod.rs b/library/alloctests/testing/mod.rs index c8457daf93e5..66a4f6682b9f 100644 --- a/library/alloctests/testing/mod.rs +++ b/library/alloctests/testing/mod.rs @@ -1,3 +1,4 @@ pub(crate) mod crash_test; +pub(crate) mod macros; pub(crate) mod ord_chaos; pub(crate) mod rng; From 3c418ec505233927d562ff906d8eea309aee1905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 18 Jun 2025 14:04:54 +0200 Subject: [PATCH 103/356] bump rustdoc json format number for pretty print change of attribute --- src/rustdoc-json-types/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 1f93895ae076..d5de43feb588 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Pretty printing of inline attributes changed -pub const FORMAT_VERSION: u32 = 48; +// Latest feature: Pretty printing of optimize attributes changed +pub const FORMAT_VERSION: u32 = 49; /// The root of the emitted JSON blob. /// From 021bcb9b4c5d3b1c6cfa27226c221611e86fce2a Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 18 Jun 2025 12:29:22 +0000 Subject: [PATCH 104/356] fmt tests: remove static mut --- library/alloctests/tests/fmt.rs | 46 +++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/library/alloctests/tests/fmt.rs b/library/alloctests/tests/fmt.rs index dbcf0c3a1141..0989a56b5543 100644 --- a/library/alloctests/tests/fmt.rs +++ b/library/alloctests/tests/fmt.rs @@ -1,6 +1,4 @@ #![deny(warnings)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] #![allow(unnecessary_transmutes)] use std::cell::RefCell; @@ -285,19 +283,32 @@ fn test_format_args() { t!(s, "args were: hello world"); } +macro_rules! counter_fn { + ($name:ident) => { + fn $name() -> u32 { + thread_local! {static COUNTER: ::core::cell::Cell = ::core::cell::Cell::new(0);} + + COUNTER.set(COUNTER.get() + 1); + COUNTER.get() + } + }; +} + #[test] fn test_order() { - // Make sure format!() arguments are always evaluated in a left-to-right - // ordering - fn foo() -> isize { - static mut FOO: isize = 0; - unsafe { - FOO += 1; - FOO - } - } + // Make sure format!() arguments are always evaluated in a left-to-right ordering + counter_fn!(count); + assert_eq!( - format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()), + format!( + "{} {} {a} {b} {} {c}", + count(), + count(), + count(), + a = count(), + b = count(), + c = count() + ), "1 2 4 5 3 6".to_string() ); } @@ -306,14 +317,9 @@ fn test_order() { fn test_once() { // Make sure each argument are evaluated only once even though it may be // formatted multiple times - fn foo() -> isize { - static mut FOO: isize = 0; - unsafe { - FOO += 1; - FOO - } - } - assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string()); + counter_fn!(count); + + assert_eq!(format!("{0} {0} {0} {a} {a} {a}", count(), a = count()), "1 1 1 2 2 2".to_string()); } #[test] From 7f49de2cca902fe352cfba39f5e0f64b876f4524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 12 Jun 2025 13:08:05 +0200 Subject: [PATCH 105/356] fixup missing docs in attr parsing --- .../rustc_attr_parsing/src/attributes/mod.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index fa2a6087506c..e68f5060ec12 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -86,8 +86,19 @@ pub(crate) trait AttributeParser: Default + 'static { /// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. pub(crate) trait SingleAttributeParser: 'static { + /// The single path of the attribute this parser accepts. + /// + /// If you need the parser to accept more than one path, use [`AttributeParser`] instead const PATH: &[Symbol]; + + /// Configures the precedence of attributes with the same `PATH` on a syntax node. const ATTRIBUTE_ORDER: AttributeOrder; + + /// Configures what to do when when the same attribute is + /// applied more than once on the same syntax node. + /// + /// [`ATTRIBUTE_ORDER`](Self::ATTRIBUTE_ORDER) specified which one is assumed to be correct, + /// and this specified whether to, for example, warn or error on the other one. const ON_DUPLICATE: OnDuplicate; /// The template this attribute parser should implement. Used for diagnostics. @@ -97,6 +108,8 @@ pub(crate) trait SingleAttributeParser: 'static { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option; } +/// Use in combination with [`SingleAttributeParser`]. +/// `Single` implements [`AttributeParser`]. pub(crate) struct Single, S: Stage>( PhantomData<(S, T)>, Option<(AttributeKind, Span)>, @@ -229,6 +242,10 @@ pub(crate) trait CombineAttributeParser: 'static { const PATH: &[rustc_span::Symbol]; type Item; + /// A function that converts individual items (of type [`Item`](Self::Item)) into the final attribute. + /// + /// For example, individual representations fomr `#[repr(...)]` attributes into an `AttributeKind::Repr(x)`, + /// where `x` is a vec of these individual reprs. const CONVERT: ConvertFn; /// The template this attribute parser should implement. Used for diagnostics. @@ -241,6 +258,8 @@ pub(crate) trait CombineAttributeParser: 'static { ) -> impl IntoIterator + 'c; } +/// Use in combination with [`CombineAttributeParser`]. +/// `Combine` implements [`AttributeParser`]. pub(crate) struct Combine, S: Stage>( PhantomData<(S, T)>, ThinVec<>::Item>, From 8e266d999d47e40cc7e90fba5d1ea9a581fd5175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 18 Jun 2025 16:12:42 +0200 Subject: [PATCH 106/356] Preserve caches in a call to shrink_to_fit --- compiler/rustc_mir_transform/src/simplify.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index a54e548ad70a..db933da64137 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -82,7 +82,7 @@ pub(super) fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { remove_dead_blocks(body); // FIXME: Should probably be moved into some kind of pass manager - body.basic_blocks_mut().raw.shrink_to_fit(); + body.basic_blocks.as_mut_preserves_cfg().shrink_to_fit(); } impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg { From 2e57845de7b81dd984a8010e191b7b8fbb62a1f9 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 16 Jun 2025 15:40:40 +0200 Subject: [PATCH 107/356] actually use a doc comment --- .../rustc_type_ir/src/search_graph/mod.rs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index b59b4f928540..2bd0fa6866ea 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -1,16 +1,16 @@ -/// The search graph is responsible for caching and cycle detection in the trait -/// solver. Making sure that caching doesn't result in soundness bugs or unstable -/// query results is very challenging and makes this one of the most-involved -/// self-contained components of the compiler. -/// -/// We added fuzzing support to test its correctness. The fuzzers used to verify -/// the current implementation can be found in https://github.com/lcnr/search_graph_fuzz. -/// -/// This is just a quick overview of the general design, please check out the relevant -/// [rustc-dev-guide chapter](https://rustc-dev-guide.rust-lang.org/solve/caching.html) for -/// more details. Caching is split between a global cache and the per-cycle `provisional_cache`. -/// The global cache has to be completely unobservable, while the per-cycle cache may impact -/// behavior as long as the resulting behavior is still correct. +//! The search graph is responsible for caching and cycle detection in the trait +//! solver. Making sure that caching doesn't result in soundness bugs or unstable +//! query results is very challenging and makes this one of the most-involved +//! self-contained components of the compiler. +//! +//! We added fuzzing support to test its correctness. The fuzzers used to verify +//! the current implementation can be found in . +//! +//! This is just a quick overview of the general design, please check out the relevant +//! [rustc-dev-guide chapter](https://rustc-dev-guide.rust-lang.org/solve/caching.html) for +//! more details. Caching is split between a global cache and the per-cycle `provisional_cache`. +//! The global cache has to be completely unobservable, while the per-cycle cache may impact +//! behavior as long as the resulting behavior is still correct. use std::cmp::Ordering; use std::collections::BTreeMap; use std::collections::hash_map::Entry; From 8710c1fec9bb8d9a3f235c8143f8e94b98bed69c Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 17 Jun 2025 10:27:31 +0200 Subject: [PATCH 108/356] update comment --- compiler/rustc_type_ir/src/search_graph/mod.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 2bd0fa6866ea..953dc2d1bc84 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -381,18 +381,16 @@ impl PathsToNested { /// The nested goals of each stack entry and the path from the /// stack entry to that nested goal. /// +/// They are used when checking whether reevaluating a global cache +/// would encounter a cycle or use a provisional cache entry given the +/// currentl search graph state. We need to disable the global cache +/// in this case as it could otherwise result in behaviorial differences. +/// Cycles can impact behavior. The cycle ABA may have different final +/// results from a the cycle BAB depending on the cycle root. +/// /// We only start tracking nested goals once we've either encountered /// overflow or a solver cycle. This is a performance optimization to /// avoid tracking nested goals on the happy path. -/// -/// We use nested goals for two reasons: -/// - when rebasing provisional cache entries -/// - when checking whether we have to ignore a global cache entry as reevaluating -/// it would encounter a cycle or use a provisional cache entry. -/// -/// We need to disable the global cache if using it would hide a cycle, as -/// cycles can impact behavior. The cycle ABA may have different final -/// results from a the cycle BAB depending on the cycle root. #[derive_where(Debug, Default, Clone; X: Cx)] struct NestedGoals { nested_goals: HashMap, From 75da5c4c29048d388e89512164fff08a67f3abe4 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 17 Jun 2025 10:56:26 +0200 Subject: [PATCH 109/356] reevaluate: reset `encountered_overflow` also return `EvaluationResult` instead of the final `StackEntry` to make sure we correctly track information between reruns. --- .../src/search_graph/global_cache.rs | 17 ++- .../rustc_type_ir/src/search_graph/mod.rs | 117 +++++++++++++----- .../rustc_type_ir/src/search_graph/stack.rs | 8 +- 3 files changed, 97 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index a2442660259d..1b99cc820f1a 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -2,6 +2,7 @@ use derive_where::derive_where; use super::{AvailableDepth, Cx, NestedGoals}; use crate::data_structures::HashMap; +use crate::search_graph::EvaluationResult; struct Success { required_depth: usize, @@ -43,28 +44,26 @@ impl GlobalCache { &mut self, cx: X, input: X::Input, - - origin_result: X::Result, + evaluation_result: EvaluationResult, dep_node: X::DepNodeIndex, - - required_depth: usize, - encountered_overflow: bool, - nested_goals: NestedGoals, ) { - let result = cx.mk_tracked(origin_result, dep_node); + let EvaluationResult { encountered_overflow, required_depth, heads, nested_goals, result } = + evaluation_result; + debug_assert!(heads.is_empty()); + let result = cx.mk_tracked(result, dep_node); let entry = self.map.entry(input).or_default(); if encountered_overflow { let with_overflow = WithOverflow { nested_goals, result }; let prev = entry.with_overflow.insert(required_depth, with_overflow); if let Some(prev) = &prev { assert!(cx.evaluation_is_concurrent()); - assert_eq!(cx.get_tracked(&prev.result), origin_result); + assert_eq!(cx.get_tracked(&prev.result), evaluation_result.result); } } else { let prev = entry.success.replace(Success { required_depth, nested_goals, result }); if let Some(prev) = &prev { assert!(cx.evaluation_is_concurrent()); - assert_eq!(cx.get_tracked(&prev.result), origin_result); + assert_eq!(cx.get_tracked(&prev.result), evaluation_result.result); } } } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 953dc2d1bc84..1a7ccb5b916c 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -448,6 +448,43 @@ struct ProvisionalCacheEntry { result: X::Result, } +/// The final result of evaluating a goal. +/// +/// We reset `encountered_overflow` when reevaluating a goal, +/// but need to track whether we've hit the recursion limit at +/// all for correctness. +/// +/// We've previously simply returned the final `StackEntry` but this +/// made it easy to accidentally drop information from the previous +/// evaluation. +#[derive_where(Debug; X: Cx)] +struct EvaluationResult { + encountered_overflow: bool, + required_depth: usize, + heads: CycleHeads, + nested_goals: NestedGoals, + result: X::Result, +} + +impl EvaluationResult { + fn finalize( + final_entry: StackEntry, + encountered_overflow: bool, + result: X::Result, + ) -> EvaluationResult { + EvaluationResult { + encountered_overflow, + // Unlike `encountered_overflow`, we share `heads`, `required_depth`, + // and `nested_goals` between evaluations. + required_depth: final_entry.required_depth, + heads: final_entry.heads, + nested_goals: final_entry.nested_goals, + // We only care about the final result. + result, + } + } +} + pub struct SearchGraph, X: Cx = ::Cx> { root_depth: AvailableDepth, /// The stack of goals currently being computed. @@ -614,12 +651,12 @@ impl, X: Cx> SearchGraph { input, step_kind_from_parent, available_depth, + provisional_result: None, required_depth: 0, heads: Default::default(), encountered_overflow: false, has_been_used: None, nested_goals: Default::default(), - provisional_result: None, }); // This is for global caching, so we properly track query dependencies. @@ -628,7 +665,7 @@ impl, X: Cx> SearchGraph { // not tracked by the cache key and from outside of this anon task, it // must not be added to the global cache. Notably, this is the case for // trait solver cycles participants. - let ((final_entry, result), dep_node) = cx.with_cached_task(|| { + let (evaluation_result, dep_node) = cx.with_cached_task(|| { self.evaluate_goal_in_task(cx, input, inspect, &mut evaluate_goal) }); @@ -636,27 +673,34 @@ impl, X: Cx> SearchGraph { // lazily update its parent goal. Self::update_parent_goal( &mut self.stack, - final_entry.step_kind_from_parent, - final_entry.required_depth, - &final_entry.heads, - final_entry.encountered_overflow, - UpdateParentGoalCtxt::Ordinary(&final_entry.nested_goals), + step_kind_from_parent, + evaluation_result.required_depth, + &evaluation_result.heads, + evaluation_result.encountered_overflow, + UpdateParentGoalCtxt::Ordinary(&evaluation_result.nested_goals), ); + let result = evaluation_result.result; // We're now done with this goal. We only add the root of cycles to the global cache. // In case this goal is involved in a larger cycle add it to the provisional cache. - if final_entry.heads.is_empty() { + if evaluation_result.heads.is_empty() { if let Some((_scope, expected)) = validate_cache { // Do not try to move a goal into the cache again if we're testing // the global cache. - assert_eq!(result, expected, "input={input:?}"); + assert_eq!(evaluation_result.result, expected, "input={input:?}"); } else if D::inspect_is_noop(inspect) { - self.insert_global_cache(cx, final_entry, result, dep_node) + self.insert_global_cache(cx, input, evaluation_result, dep_node) } } else if D::ENABLE_PROVISIONAL_CACHE { debug_assert!(validate_cache.is_none(), "unexpected non-root: {input:?}"); let entry = self.provisional_cache.entry(input).or_default(); - let StackEntry { heads, encountered_overflow, .. } = final_entry; + let EvaluationResult { + encountered_overflow, + required_depth: _, + heads, + nested_goals: _, + result, + } = evaluation_result; let path_from_head = Self::cycle_path_kind( &self.stack, step_kind_from_parent, @@ -1022,18 +1066,24 @@ impl, X: Cx> SearchGraph { input: X::Input, inspect: &mut D::ProofTreeBuilder, mut evaluate_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, - ) -> (StackEntry, X::Result) { + ) -> EvaluationResult { + // We reset `encountered_overflow` each time we rerun this goal + // but need to make sure we currently propagate it to the global + // cache even if only some of the evaluations actually reach the + // recursion limit. + let mut encountered_overflow = false; let mut i = 0; loop { let result = evaluate_goal(self, inspect); let stack_entry = self.stack.pop(); + encountered_overflow |= stack_entry.encountered_overflow; debug_assert_eq!(stack_entry.input, input); // If the current goal is not the root of a cycle, we are done. // // There are no provisional cache entries which depend on this goal. let Some(usage_kind) = stack_entry.has_been_used else { - return (stack_entry, result); + return EvaluationResult::finalize(stack_entry, encountered_overflow, result); }; // If it is a cycle head, we have to keep trying to prove it until @@ -1049,7 +1099,7 @@ impl, X: Cx> SearchGraph { // final result is equal to the initial response for that case. if self.reached_fixpoint(cx, &stack_entry, usage_kind, result) { self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); - return (stack_entry, result); + return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } // If computing this goal results in ambiguity with no constraints, @@ -1068,7 +1118,7 @@ impl, X: Cx> SearchGraph { self.rebase_provisional_cache_entries(&stack_entry, |input, _| { D::propagate_ambiguity(cx, input, result) }); - return (stack_entry, result); + return EvaluationResult::finalize(stack_entry, encountered_overflow, result); }; // If we've reached the fixpoint step limit, we bail with overflow and taint all @@ -1080,7 +1130,7 @@ impl, X: Cx> SearchGraph { self.rebase_provisional_cache_entries(&stack_entry, |input, _| { D::on_fixpoint_overflow(cx, input) }); - return (stack_entry, result); + return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } // Clear all provisional cache entries which depend on a previous provisional @@ -1089,9 +1139,22 @@ impl, X: Cx> SearchGraph { debug!(?result, "fixpoint changed provisional results"); self.stack.push(StackEntry { - has_been_used: None, + input, + step_kind_from_parent: stack_entry.step_kind_from_parent, + available_depth: stack_entry.available_depth, provisional_result: Some(result), - ..stack_entry + // We can keep these goals from previous iterations as they are only + // ever read after finalizing this evaluation. + required_depth: stack_entry.required_depth, + heads: stack_entry.heads, + nested_goals: stack_entry.nested_goals, + // We reset these two fields when rerunning this goal. We could + // keep `encountered_overflow` as it's only used as a performance + // optimization. However, given that the proof tree will likely look + // similar to the previous iterations when reevaluating, it's better + // for caching if the reevaluation also starts out with `false`. + encountered_overflow: false, + has_been_used: None, }); } } @@ -1107,21 +1170,11 @@ impl, X: Cx> SearchGraph { fn insert_global_cache( &mut self, cx: X, - final_entry: StackEntry, - result: X::Result, + input: X::Input, + evaluation_result: EvaluationResult, dep_node: X::DepNodeIndex, ) { - debug!(?final_entry, ?result, "insert global cache"); - cx.with_global_cache(|cache| { - cache.insert( - cx, - final_entry.input, - result, - dep_node, - final_entry.required_depth, - final_entry.encountered_overflow, - final_entry.nested_goals, - ) - }) + debug!(?evaluation_result, "insert global cache"); + cx.with_global_cache(|cache| cache.insert(cx, input, evaluation_result, dep_node)) } } diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index 8bb247bf0554..e0fd934df698 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -26,6 +26,10 @@ pub(super) struct StackEntry { /// The available depth of a given goal, immutable. pub available_depth: AvailableDepth, + /// Starts out as `None` and gets set when rerunning this + /// goal in case we encounter a cycle. + pub provisional_result: Option, + /// The maximum depth required while evaluating this goal. pub required_depth: usize, @@ -42,10 +46,6 @@ pub(super) struct StackEntry { /// The nested goals of this goal, see the doc comment of the type. pub nested_goals: NestedGoals, - - /// Starts out as `None` and gets set when rerunning this - /// goal in case we encounter a cycle. - pub provisional_result: Option, } #[derive_where(Default; X: Cx)] From ecd65f870dc62352b15587d82e37a8e2b2480367 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 18 Jun 2025 17:22:04 +0200 Subject: [PATCH 110/356] `evaluate_goal`: accept different inputs --- .../src/solve/eval_ctxt/mod.rs | 2 +- compiler/rustc_type_ir/src/search_graph/mod.rs | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 7ead0a6d6b77..00fd3ba80465 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -430,7 +430,7 @@ where canonical_input, step_kind_from_parent, &mut canonical_goal_evaluation, - |search_graph, canonical_goal_evaluation| { + |search_graph, cx, canonical_input, canonical_goal_evaluation| { EvalCtxt::enter_canonical( cx, search_graph, diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 1a7ccb5b916c..a857da2fcd5e 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -597,7 +597,7 @@ impl, X: Cx> SearchGraph { input: X::Input, step_kind_from_parent: PathKind, inspect: &mut D::ProofTreeBuilder, - mut evaluate_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, + evaluate_goal: impl Fn(&mut Self, X, X::Input, &mut D::ProofTreeBuilder) -> X::Result + Copy, ) -> X::Result { let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::(self.root_depth, &self.stack) @@ -665,9 +665,8 @@ impl, X: Cx> SearchGraph { // not tracked by the cache key and from outside of this anon task, it // must not be added to the global cache. Notably, this is the case for // trait solver cycles participants. - let (evaluation_result, dep_node) = cx.with_cached_task(|| { - self.evaluate_goal_in_task(cx, input, inspect, &mut evaluate_goal) - }); + let (evaluation_result, dep_node) = + cx.with_cached_task(|| self.evaluate_goal_in_task(cx, input, inspect, evaluate_goal)); // We've finished computing the goal and have popped it from the stack, // lazily update its parent goal. @@ -1065,7 +1064,7 @@ impl, X: Cx> SearchGraph { cx: X, input: X::Input, inspect: &mut D::ProofTreeBuilder, - mut evaluate_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, + evaluate_goal: impl Fn(&mut Self, X, X::Input, &mut D::ProofTreeBuilder) -> X::Result + Copy, ) -> EvaluationResult { // We reset `encountered_overflow` each time we rerun this goal // but need to make sure we currently propagate it to the global @@ -1074,7 +1073,7 @@ impl, X: Cx> SearchGraph { let mut encountered_overflow = false; let mut i = 0; loop { - let result = evaluate_goal(self, inspect); + let result = evaluate_goal(self, cx, input, inspect); let stack_entry = self.stack.pop(); encountered_overflow |= stack_entry.encountered_overflow; debug_assert_eq!(stack_entry.input, input); From c6e77b3ba63cc9f824f99b7d356055e22bcf2ae2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 18 Jun 2025 15:14:48 +0000 Subject: [PATCH 111/356] Reduce uses of `hir_crate`. --- compiler/rustc_driver_impl/src/pretty.rs | 6 +++++- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_lint/src/expect.rs | 3 +-- compiler/rustc_middle/src/hir/map.rs | 16 ++++++++-------- compiler/rustc_middle/src/hir/mod.rs | 10 +++++++--- compiler/rustc_middle/src/ty/context.rs | 2 +- src/librustdoc/core.rs | 2 -- tests/ui/consts/const-unstable-intrinsic.stderr | 10 ++-------- ...stability-attribute-implies-no-feature.stderr | 5 +---- .../const-traits/staged-api-user-crate.stderr | 5 +---- 10 files changed, 27 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index ec77043cd128..688307a941f3 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -292,7 +292,11 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { } HirTree => { debug!("pretty printing HIR tree"); - format!("{:#?}", ex.tcx().hir_crate(())) + ex.tcx() + .hir_crate_items(()) + .owners() + .map(|owner| format!("{:#?} => {:#?}\n", owner, ex.tcx().hir_owner_nodes(owner))) + .collect() } Mir => { let mut out = Vec::new(); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 0238d6a39475..d29656fedd5b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1011,7 +1011,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // Prefetch this to prevent multiple threads from blocking on it later. // This is needed since the `hir_id_validator::check_crate` call above is not guaranteed // to use `hir_crate`. - tcx.ensure_done().hir_crate(()); + tcx.ensure_done().hir_crate_items(()); let sess = tcx.sess; sess.time("misc_checking_1", || { diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 4c2b82a9a23a..481e116d06e0 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_hir::CRATE_OWNER_ID; use rustc_middle::lint::LintExpectation; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; @@ -18,7 +17,7 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp let mut expectations = Vec::new(); - for owner in std::iter::once(CRATE_OWNER_ID).chain(krate.owners()) { + for owner in krate.owners() { let lints = tcx.shallow_lint_levels_on(owner); expectations.extend_from_slice(&lints.expectations); } diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 3de97c8c0d99..f75d75dd5b06 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -328,8 +328,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns an iterator of the `DefId`s for all body-owners in this - /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir_crate(()).body_ids.iter()`. + /// crate. #[inline] pub fn hir_body_owners(self) -> impl Iterator { self.hir_crate_items(()).body_owners.iter().copied() @@ -396,12 +395,11 @@ impl<'tcx> TyCtxt<'tcx> { where V: Visitor<'tcx>, { - let krate = self.hir_crate(()); - for info in krate.owners.iter() { - if let MaybeOwner::Owner(info) = info { - for attrs in info.attrs.map.values() { - walk_list!(visitor, visit_attribute, *attrs); - } + let krate = self.hir_crate_items(()); + for owner in krate.owners() { + let attrs = self.hir_attr_map(owner); + for attrs in attrs.map.values() { + walk_list!(visitor, visit_attribute, *attrs); } } V::Result::output() @@ -1225,6 +1223,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod .. } = collector; ModuleItems { + add_root: false, submodules: submodules.into_boxed_slice(), free_items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), @@ -1258,6 +1257,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { } = collector; ModuleItems { + add_root: true, submodules: submodules.into_boxed_slice(), free_items: items.into_boxed_slice(), trait_items: trait_items.into_boxed_slice(), diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index cb4760c18de5..bb36b2c93647 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -24,6 +24,9 @@ use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; /// bodies. The Ids are in visitor order. This is used to partition a pass between modules. #[derive(Debug, HashStable, Encodable, Decodable)] pub struct ModuleItems { + /// Whether this represents the whole crate, in which case we need to add `CRATE_OWNER_ID` to + /// the iterators if we want to account for the crate root. + add_root: bool, submodules: Box<[OwnerId]>, free_items: Box<[ItemId]>, trait_items: Box<[TraitItemId]>, @@ -60,9 +63,10 @@ impl ModuleItems { } pub fn owners(&self) -> impl Iterator { - self.free_items - .iter() - .map(|id| id.owner_id) + self.add_root + .then_some(CRATE_OWNER_ID) + .into_iter() + .chain(self.free_items.iter().map(|id| id.owner_id)) .chain(self.trait_items.iter().map(|id| id.owner_id)) .chain(self.impl_items.iter().map(|id| id.owner_id)) .chain(self.foreign_items.iter().map(|id| id.owner_id)) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b4d8b2e71763..7b1403c5e7ef 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2118,7 +2118,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap { // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. - self.ensure_ok().hir_crate(()); + self.ensure_ok().hir_crate_items(()); // Freeze definitions once we start iterating on them, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. self.untracked.definitions.freeze().def_path_hash_to_def_index_map() diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 204f8decffcc..d73600a46363 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -387,8 +387,6 @@ pub(crate) fn run_global_ctxt( ctxt.external_traits.insert(sized_trait_did, sized_trait); } - debug!("crate: {:?}", tcx.hir_crate(())); - let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt)); if krate.module.doc_value().is_empty() { diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 973c7bae5869..835113ccda51 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -24,10 +24,7 @@ error: `size_of_val` is not yet stable as a const intrinsic LL | unstable_intrinsic::size_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: add `#![feature(unstable)]` to the crate attributes to enable - | -LL + #![feature(unstable)] - | + = help: add `#![feature(unstable)]` to the crate attributes to enable error: `align_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:20:9 @@ -35,10 +32,7 @@ error: `align_of_val` is not yet stable as a const intrinsic LL | unstable_intrinsic::align_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: add `#![feature(unstable)]` to the crate attributes to enable - | -LL + #![feature(unstable)] - | + = help: add `#![feature(unstable)]` to the crate attributes to enable error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:24:9 diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr index 0f2006e932b3..0a5f58288fa3 100644 --- a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr +++ b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr @@ -4,10 +4,7 @@ error: `foobar` is not yet stable as a const fn LL | foobar(); | ^^^^^^^^ | -help: add `#![feature(const_foobar)]` to the crate attributes to enable - | -LL + #![feature(const_foobar)] - | + = help: add `#![feature(const_foobar)]` to the crate attributes to enable error: aborting due to 1 previous error 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 8ac83770cf7a..1365be7e3890 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -15,10 +15,7 @@ error: `staged_api::MyTrait` is not yet stable as a const trait LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: add `#![feature(unstable)]` to the crate attributes to enable - | -LL + #![feature(unstable)] - | + = help: add `#![feature(unstable)]` to the crate attributes to enable error: aborting due to 2 previous errors From 70f376d308c6d144c897be988427a13c9a276b00 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Thu, 19 Jun 2025 01:30:10 +0900 Subject: [PATCH 112/356] fix: Closure capturing for let exprs --- .../crates/hir-ty/src/infer/closure.rs | 6 +++++- .../hir-ty/src/tests/closure_captures.rs | 19 +++++++++++++++++++ .../src/handlers/moved_out_of_ref.rs | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index d1432cacf8d8..b756bb859d3e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -1230,11 +1230,15 @@ impl InferenceContext<'_> { self.select_from_expr(*expr); } } + Expr::Let { pat: _, expr } => { + self.walk_expr(*expr); + let place = self.place_of_expr(*expr); + self.ref_expr(*expr, place); + } Expr::UnaryOp { expr, op: _ } | Expr::Array(Array::Repeat { initializer: expr, repeat: _ }) | Expr::Await { expr } | Expr::Loop { body: expr, label: _ } - | Expr::Let { pat: _, expr } | Expr::Box { expr } | Expr::Cast { expr, type_ref: _ } => { self.consume_expr(*expr); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs index 88d21be81ea6..7fb981752de8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs @@ -444,3 +444,22 @@ fn main() { expect!["99..165;49..54;120..121,133..134 ByRef(Mut { kind: Default }) a &'? mut A"], ); } + +#[test] +fn let_binding_is_a_ref_capture() { + check_closure_captures( + r#" +//- minicore:copy +struct S; +fn main() { + let mut s = S; + let s_ref = &mut s; + let closure = || { + if let ref cb = s_ref { + } + }; +} +"#, + expect!["83..135;49..54;112..117 ByRef(Shared) s_ref &'? &'? mut S"], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index 7181d708fe33..0928262d22fa 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -220,4 +220,23 @@ fn test() { "#, ) } + + #[test] + fn regression_18201() { + check_diagnostics( + r#" +//- minicore: copy +struct NotCopy; +struct S(NotCopy); +impl S { + fn f(&mut self) { + || { + if let ref mut _cb = self.0 { + } + }; + } +} +"#, + ) + } } From 377d8fa4e3057838f20dd1eb1669d4ebaf8a561a Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 18 Jun 2025 15:04:03 +0100 Subject: [PATCH 113/356] Reviews --- compiler/rustc_type_ir/src/fast_reject.rs | 3 --- tests/ui/associated-inherent-types/bound_vars_in_args.rs | 4 ++-- .../ui/associated-inherent-types/candidate-with-alias-2.rs | 3 +++ .../associated-inherent-types/candidate-with-alias-2.stderr | 6 +++--- tests/ui/associated-inherent-types/candidate-with-alias.rs | 3 +++ .../multiple-candidates-in-adt-field-2.rs | 4 ++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index a5d461c57cd4..d88c88fc6f3f 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -241,9 +241,6 @@ impl bool { - if lhs == rhs { - return true; - } self.types_may_unify_inner(lhs, rhs, depth_limit) } diff --git a/tests/ui/associated-inherent-types/bound_vars_in_args.rs b/tests/ui/associated-inherent-types/bound_vars_in_args.rs index 0baa242af768..49a9ef31cd67 100644 --- a/tests/ui/associated-inherent-types/bound_vars_in_args.rs +++ b/tests/ui/associated-inherent-types/bound_vars_in_args.rs @@ -1,8 +1,8 @@ #![feature(non_lifetime_binders, inherent_associated_types)] #![expect(incomplete_features)] -// Test that we can resolve to the right IAT when the self type -// contains a bound type. +// Test whether we can resolve to the right IAT when the self type +// contains a bound type. This should ideally use the second impl. struct Foo(T); diff --git a/tests/ui/associated-inherent-types/candidate-with-alias-2.rs b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs index d7be825a9c22..551d30a8786e 100644 --- a/tests/ui/associated-inherent-types/candidate-with-alias-2.rs +++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.rs @@ -1,6 +1,9 @@ #![feature(inherent_associated_types)] #![expect(incomplete_features)] +// A behaviour test showcasing that we do not normalize associated types in +// the impl self ty when assembling IAT candidates + trait Identity { type Assoc; } diff --git a/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr b/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr index 335e35a95778..2b79b65f22ba 100644 --- a/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr +++ b/tests/ui/associated-inherent-types/candidate-with-alias-2.stderr @@ -1,16 +1,16 @@ error[E0034]: multiple applicable items in scope - --> $DIR/candidate-with-alias-2.rs:20:23 + --> $DIR/candidate-with-alias-2.rs:23:23 | LL | field: >::Inherent, | ^^^^^^^^ multiple `Inherent` found | note: candidate #1 is defined in an impl for the type `Foo<::Assoc>` - --> $DIR/candidate-with-alias-2.rs:13:5 + --> $DIR/candidate-with-alias-2.rs:16:5 | LL | type Inherent = u8; | ^^^^^^^^^^^^^ note: candidate #2 is defined in an impl for the type `Foo<::Assoc>` - --> $DIR/candidate-with-alias-2.rs:16:5 + --> $DIR/candidate-with-alias-2.rs:19:5 | LL | type Inherent = u32; | ^^^^^^^^^^^^^ diff --git a/tests/ui/associated-inherent-types/candidate-with-alias.rs b/tests/ui/associated-inherent-types/candidate-with-alias.rs index d4dd002a7741..a84da195c26b 100644 --- a/tests/ui/associated-inherent-types/candidate-with-alias.rs +++ b/tests/ui/associated-inherent-types/candidate-with-alias.rs @@ -3,6 +3,9 @@ #![feature(inherent_associated_types)] #![expect(incomplete_features)] +// A behaviour test showcasing that IAT resolution can pick the right +// candidate even if it has an alias, if it's the only candidate. + trait Identity { type Assoc; } diff --git a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs index b942c303d3e8..8a6d1896f7d2 100644 --- a/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs +++ b/tests/ui/associated-inherent-types/multiple-candidates-in-adt-field-2.rs @@ -1,8 +1,8 @@ #![feature(inherent_associated_types)] #![expect(incomplete_features)] -// Test that when we have an unnormalized projection we don't normalize it -// to determine which IAT to resolve to. +// Test that when we have an unnormalized projection in the IAT self ty +// we don't normalize it to determine which IAT to resolve to. struct Foo(T); impl Foo { From 7fa94af5565918146af0b86d3857321b097e956f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 18 Jun 2025 16:52:38 +0000 Subject: [PATCH 114/356] Make feature suggestion more consistent. --- .../src/check_consts/check.rs | 8 ----- .../rustc_const_eval/src/check_consts/ops.rs | 22 ++----------- compiler/rustc_const_eval/src/errors.rs | 4 +-- compiler/rustc_hir_analysis/src/check/mod.rs | 4 +-- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_typeck/src/errors.rs | 6 ---- compiler/rustc_hir_typeck/src/expr.rs | 21 +++--------- compiler/rustc_hir_typeck/src/method/probe.rs | 1 - compiler/rustc_middle/src/ty/context.rs | 33 +++++++------------ .../src/error_reporting/traits/suggestions.rs | 6 +--- .../ui/consts/const-unstable-intrinsic.stderr | 10 ++++-- ...bility-attribute-implies-no-feature.stderr | 5 ++- .../const-traits/staged-api-user-crate.stderr | 5 ++- 13 files changed, 40 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 4f252f3ccd48..576b174369d4 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -463,12 +463,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { ); } - fn crate_inject_span(&self) -> Option { - self.tcx.hir_crate_items(()).definitions().next().and_then(|id| { - self.tcx.crate_level_attribute_injection_span(self.tcx.local_def_id_to_hir_id(id)) - }) - } - /// Check the const stability of the given item (fn or trait). fn check_callee_stability(&mut self, def_id: DefId) { match self.tcx.lookup_const_stability(def_id) { @@ -543,7 +537,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { feature, feature_enabled, safe_to_expose_on_stable: callee_safe_to_expose_on_stable, - suggestion_span: self.crate_inject_span(), is_function_call: self.tcx.def_kind(def_id) != DefKind::Trait, }); } @@ -919,7 +912,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { name: intrinsic.name, feature, const_stable_indirect: is_const_stable, - suggestion: self.crate_inject_span(), }); } Some(attrs::ConstStability { diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 9c30dbff99eb..887275e7294d 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -1,8 +1,8 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use hir::{ConstContext, LangItem}; +use rustc_errors::Diag; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; @@ -384,7 +384,6 @@ pub(crate) struct CallUnstable { /// expose on stable. pub feature_enabled: bool, pub safe_to_expose_on_stable: bool, - pub suggestion_span: Option, /// true if `def_id` is the function we are calling, false if `def_id` is an unstable trait. pub is_function_call: bool, } @@ -412,20 +411,7 @@ impl<'tcx> NonConstOp<'tcx> for CallUnstable { def_path: ccx.tcx.def_path_str(self.def_id), }) }; - // FIXME: make this translatable - let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature); - #[allow(rustc::untranslatable_diagnostic)] - if let Some(span) = self.suggestion_span { - err.span_suggestion_verbose( - span, - msg, - format!("#![feature({})]\n", self.feature), - Applicability::MachineApplicable, - ); - } else { - err.help(msg); - } - + ccx.tcx.disabled_nightly_features(&mut err, [(String::new(), self.feature)]); err } } @@ -452,7 +438,6 @@ pub(crate) struct IntrinsicUnstable { pub name: Symbol, pub feature: Symbol, pub const_stable_indirect: bool, - pub suggestion: Option, } impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { @@ -472,8 +457,7 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { span, name: self.name, feature: self.feature, - suggestion: self.suggestion, - help: self.suggestion.is_none(), + suggestion: ccx.tcx.crate_level_attribute_injection_span(), }) } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 037cbf777e70..69c71aef9f33 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -136,9 +136,7 @@ pub(crate) struct UnstableIntrinsic { code = "#![feature({feature})]\n", applicability = "machine-applicable" )] - pub suggestion: Option, - #[help(const_eval_unstable_intrinsic_suggestion)] - pub help: bool, + pub suggestion: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index c5c7e6b2aa72..ed43a0b21e40 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -302,9 +302,7 @@ fn default_body_is_unstable( reason: reason_str, }); - let inject_span = item_did - .as_local() - .and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id))); + let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span()); rustc_session::parse::add_feature_diagnostics_for_issue( &mut err, &tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b8dc01cbc03c..8198c24a7f00 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1064,7 +1064,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]), }; if let Some(features) = may_suggest_feature { - tcx.disabled_nightly_features(&mut diag, Some(param.hir_id), features); + tcx.disabled_nightly_features(&mut diag, features); } Err(diag.emit()) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index abb8cdc1cdf3..5f59b3ad96e0 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -30,8 +30,6 @@ pub(crate) struct BaseExpressionDoubleDot { )] pub default_field_values_suggestion: Option, #[subdiagnostic] - pub default_field_values_help: Option, - #[subdiagnostic] pub add_expr: Option, #[subdiagnostic] pub remove_dots: Option, @@ -61,10 +59,6 @@ pub(crate) struct BaseExpressionDoubleDotAddExpr { pub span: Span, } -#[derive(Subdiagnostic)] -#[help(hir_typeck_base_expression_double_dot_enable_default_field_values)] -pub(crate) struct BaseExpressionDoubleDotEnableDefaultFieldValues; - #[derive(Diagnostic)] #[diag(hir_typeck_field_multiply_specified_in_initializer, code = E0062)] pub(crate) struct FieldMultiplySpecifiedInInitializer { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 30bf557dc93a..26370784f56c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -42,10 +42,9 @@ use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectatio use crate::coercion::{CoerceMany, DynamicCoerceMany}; use crate::errors::{ AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr, - BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove, - CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, - HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, NoFieldOnVariant, - ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, + BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer, + FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, + NoFieldOnVariant, ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo, YieldExprOutsideOfCoroutine, }; use crate::{ @@ -2133,7 +2132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if !self.tcx.features().default_field_values() { - let sugg = self.tcx.crate_level_attribute_injection_span(expr.hir_id); + let sugg = self.tcx.crate_level_attribute_injection_span(); self.dcx().emit_err(BaseExpressionDoubleDot { span: span.shrink_to_hi(), // We only mention enabling the feature if this is a nightly rustc *and* the @@ -2141,18 +2140,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { default_field_values_suggestion: if self.tcx.sess.is_nightly_build() && missing_mandatory_fields.is_empty() && !missing_optional_fields.is_empty() - && sugg.is_some() { - sugg - } else { - None - }, - default_field_values_help: if self.tcx.sess.is_nightly_build() - && missing_mandatory_fields.is_empty() - && !missing_optional_fields.is_empty() - && sugg.is_none() - { - Some(BaseExpressionDoubleDotEnableDefaultFieldValues) + Some(sugg) } else { None }, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index a3fdf200c8ea..589dbb531168 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1727,7 +1727,6 @@ impl<'tcx> Pick<'tcx> { } tcx.disabled_nightly_features( lint, - Some(scope_expr_id), self.unstable_candidates.iter().map(|(candidate, feature)| { (format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature) }), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7b1403c5e7ef..23056820bc67 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3165,42 +3165,33 @@ impl<'tcx> TyCtxt<'tcx> { lint_level(self.sess, lint, level, Some(span.into()), decorate); } - /// Find the crate root and the appropriate span where `use` and outer attributes can be - /// inserted at. - pub fn crate_level_attribute_injection_span(self, hir_id: HirId) -> Option { - for (_hir_id, node) in self.hir_parent_iter(hir_id) { - if let hir::Node::Crate(m) = node { - return Some(m.spans.inject_use_span.shrink_to_lo()); - } - } - None + /// Find the appropriate span where `use` and outer attributes can be inserted at. + pub fn crate_level_attribute_injection_span(self) -> Span { + let node = self.hir_node(hir::CRATE_HIR_ID); + let hir::Node::Crate(m) = node else { bug!() }; + m.spans.inject_use_span.shrink_to_lo() } pub fn disabled_nightly_features( self, diag: &mut Diag<'_, E>, - hir_id: Option, features: impl IntoIterator, ) { if !self.sess.is_nightly_build() { return; } - let span = hir_id.and_then(|id| self.crate_level_attribute_injection_span(id)); + let span = self.crate_level_attribute_injection_span(); for (desc, feature) in features { // FIXME: make this string translatable let msg = format!("add `#![feature({feature})]` to the crate attributes to enable{desc}"); - if let Some(span) = span { - diag.span_suggestion_verbose( - span, - msg, - format!("#![feature({feature})]\n"), - Applicability::MaybeIncorrect, - ); - } else { - diag.help(msg); - } + diag.span_suggestion_verbose( + span, + msg, + format!("#![feature({feature})]\n"), + Applicability::MaybeIncorrect, + ); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index ee5a5b247ce8..6d07ae021ae9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3575,11 +3575,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::TrivialBound => { err.help("see issue #48214"); - tcx.disabled_nightly_features( - err, - Some(tcx.local_def_id_to_hir_id(body_id)), - [(String::new(), sym::trivial_bounds)], - ); + tcx.disabled_nightly_features(err, [(String::new(), sym::trivial_bounds)]); } ObligationCauseCode::OpaqueReturnType(expr_info) => { let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info { diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 835113ccda51..973c7bae5869 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -24,7 +24,10 @@ error: `size_of_val` is not yet stable as a const intrinsic LL | unstable_intrinsic::size_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: add `#![feature(unstable)]` to the crate attributes to enable +help: add `#![feature(unstable)]` to the crate attributes to enable + | +LL + #![feature(unstable)] + | error: `align_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:20:9 @@ -32,7 +35,10 @@ error: `align_of_val` is not yet stable as a const intrinsic LL | unstable_intrinsic::align_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: add `#![feature(unstable)]` to the crate attributes to enable +help: add `#![feature(unstable)]` to the crate attributes to enable + | +LL + #![feature(unstable)] + | error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:24:9 diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr index 0a5f58288fa3..0f2006e932b3 100644 --- a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr +++ b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr @@ -4,7 +4,10 @@ error: `foobar` is not yet stable as a const fn LL | foobar(); | ^^^^^^^^ | - = help: add `#![feature(const_foobar)]` to the crate attributes to enable +help: add `#![feature(const_foobar)]` to the crate attributes to enable + | +LL + #![feature(const_foobar)] + | error: aborting due to 1 previous error 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 1365be7e3890..8ac83770cf7a 100644 --- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr +++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr @@ -15,7 +15,10 @@ error: `staged_api::MyTrait` is not yet stable as a const trait LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | - = help: add `#![feature(unstable)]` to the crate attributes to enable +help: add `#![feature(unstable)]` to the crate attributes to enable + | +LL + #![feature(unstable)] + | error: aborting due to 2 previous errors From 4df9f2f8412db164e787233d1fc56d2988f255c8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 18 Jun 2025 19:15:10 +0200 Subject: [PATCH 115/356] Emit the usages suggestions as tool-only suggestions --- compiler/rustc_lint/src/lints.rs | 15 ++++++++++- compiler/rustc_lint/src/nonstandard_style.rs | 24 ++++++++++-------- .../ui/lint/lint-non-uppercase-usages.stderr | 25 ------------------- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index d157bf6986ce..a20050a10b48 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1349,7 +1349,7 @@ pub(crate) struct NonUpperCaseGlobal<'a> { #[subdiagnostic] pub sub: NonUpperCaseGlobalSub, #[subdiagnostic] - pub usages: Vec, + pub usages: Vec, } #[derive(Subdiagnostic)] @@ -1367,6 +1367,19 @@ pub(crate) enum NonUpperCaseGlobalSub { }, } +#[derive(Subdiagnostic)] +#[suggestion( + lint_suggestion, + code = "{replace}", + applicability = "maybe-incorrect", + style = "tool-only" +)] +pub(crate) struct NonUpperCaseGlobalSubTool { + #[primary_span] + pub(crate) span: Span, + pub(crate) replace: String, +} + // noop_method_call.rs #[derive(LintDiagnostic)] #[diag(lint_noop_method_call)] diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index a5b3eb3f0ffb..e92e8e063829 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -14,7 +14,7 @@ use {rustc_ast as ast, rustc_hir as hir}; use crate::lints::{ NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub, - NonUpperCaseGlobal, NonUpperCaseGlobalSub, + NonUpperCaseGlobal, NonUpperCaseGlobalSub, NonUpperCaseGlobalSubTool, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -497,12 +497,10 @@ impl NonUpperCaseGlobals { // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". - let sub = |span| { - if *name != uc { - NonUpperCaseGlobalSub::Suggestion { span, replace: uc.clone() } - } else { - NonUpperCaseGlobalSub::Label { span } - } + let sub = if *name != uc { + NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc.clone() } + } else { + NonUpperCaseGlobalSub::Label { span: ident.span } }; struct UsageCollector<'a, 'tcx> { @@ -531,10 +529,16 @@ impl NonUpperCaseGlobals { } } - let usages = if let Some(did) = did { + let usages = if let Some(did) = did + && *name != uc + { let mut usage_collector = UsageCollector { cx, did, collected: Vec::new() }; cx.tcx.hir_walk_toplevel_module(&mut usage_collector); - usage_collector.collected.into_iter().map(|span| sub(span)).collect() + usage_collector + .collected + .into_iter() + .map(|span| NonUpperCaseGlobalSubTool { span, replace: uc.clone() }) + .collect() } else { vec![] }; @@ -542,7 +546,7 @@ impl NonUpperCaseGlobals { cx.emit_span_lint( NON_UPPER_CASE_GLOBALS, ident.span, - NonUpperCaseGlobal { sort, name, sub: sub(ident.span), usages }, + NonUpperCaseGlobal { sort, name, sub, usages }, ); } } diff --git a/tests/ui/lint/lint-non-uppercase-usages.stderr b/tests/ui/lint/lint-non-uppercase-usages.stderr index fa47b4ba6a8f..34a0a5b0ca68 100644 --- a/tests/ui/lint/lint-non-uppercase-usages.stderr +++ b/tests/ui/lint/lint-non-uppercase-usages.stderr @@ -10,16 +10,6 @@ help: convert the identifier to upper case LL - const my_static: u32 = 0; LL + const MY_STATIC: u32 = 0; | -help: convert the identifier to upper case - | -LL - const LOL: u32 = my_static + 0; -LL + const LOL: u32 = MY_STATIC + 0; - | -help: convert the identifier to upper case - | -LL - let _a = crate::my_static; -LL + let _a = crate::MY_STATIC; - | warning: constant `fooFOO` should have an upper case name --> $DIR/lint-non-uppercase-usages.rs:19:12 @@ -32,16 +22,6 @@ help: convert the identifier to upper case LL - static fooFOO: Cell = unreachable!(); LL + static FOO_FOO: Cell = unreachable!(); | -help: convert the identifier to upper case - | -LL - fooFOO.set(9); -LL + FOO_FOO.set(9); - | -help: convert the identifier to upper case - | -LL - println!("{}", fooFOO.get()); -LL + println!("{}", FOO_FOO.get()); - | warning: const parameter `foo` should have an upper case name --> $DIR/lint-non-uppercase-usages.rs:24:14 @@ -54,11 +34,6 @@ help: convert the identifier to upper case (notice the capitalization difference LL - fn foo() { LL + fn foo() { | -help: convert the identifier to upper case (notice the capitalization difference) - | -LL - let _a = foo + 1; -LL + let _a = FOO + 1; - | warning: 3 warnings emitted From 95cd989055b7b6ae1b37c7c2fd83c737a476f622 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 18 Jun 2025 19:59:11 +0300 Subject: [PATCH 116/356] expand: Remove some unnecessary generic parameters --- compiler/rustc_expand/src/expand.rs | 92 ++++++++++++++--------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 9fd524ef45cd..a1037ac0145f 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -86,7 +86,7 @@ macro_rules! ast_fragments { } } - fn make_from<'a>(self, result: Box) -> Option { + fn make_from(self, result: Box) -> Option { match self { AstFragmentKind::OptExpr => result.make_expr().map(Some).map(AstFragment::OptExpr), @@ -136,7 +136,7 @@ macro_rules! ast_fragments { T::fragment_to_output(self) } - pub(crate) fn mut_visit_with(&mut self, vis: &mut F) { + pub(crate) fn mut_visit_with(&mut self, vis: &mut impl MutVisitor) { match self { AstFragment::OptExpr(opt_expr) => { if let Some(expr) = opt_expr.take() { @@ -316,9 +316,9 @@ impl AstFragmentKind { } } - pub(crate) fn expect_from_annotatables>( + pub(crate) fn expect_from_annotatables( self, - items: I, + items: impl IntoIterator, ) -> AstFragment { let mut items = items.into_iter(); match self { @@ -1218,10 +1218,10 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn descr() -> &'static str { unreachable!() } - fn walk_flat_map(self, _visitor: &mut V) -> Self::OutputTy { + fn walk_flat_map(self, _collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { unreachable!() } - fn walk(&mut self, _visitor: &mut V) { + fn walk(&mut self, _collector: &mut InvocationCollector<'_, '_>) { unreachable!() } fn is_mac_call(&self) -> bool { @@ -1276,8 +1276,8 @@ impl InvocationCollectorNode for P { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_item(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_item(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ItemKind::MacCall(..)) @@ -1431,8 +1431,8 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_trait_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Trait) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Trait) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1472,8 +1472,8 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_impl_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl { of_trait: false }) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Impl { of_trait: false }) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1513,8 +1513,8 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitImplItem fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_trait_impl_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl { of_trait: true }) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Impl { of_trait: true }) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1551,8 +1551,8 @@ impl InvocationCollectorNode for P { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_foreign_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_foreign_item(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_foreign_item(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ForeignItemKind::MacCall(..)) @@ -1573,8 +1573,8 @@ impl InvocationCollectorNode for ast::Variant { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_variants() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_variant(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_variant(collector, self) } } @@ -1586,8 +1586,8 @@ impl InvocationCollectorNode for ast::WherePredicate { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_where_predicates() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_where_predicate(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_where_predicate(collector, self) } } @@ -1599,8 +1599,8 @@ impl InvocationCollectorNode for ast::FieldDef { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_field_defs() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_field_def(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_field_def(collector, self) } } @@ -1612,8 +1612,8 @@ impl InvocationCollectorNode for ast::PatField { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_pat_fields() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_pat_field(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_pat_field(collector, self) } } @@ -1625,8 +1625,8 @@ impl InvocationCollectorNode for ast::ExprField { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_expr_fields() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_expr_field(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_expr_field(collector, self) } } @@ -1638,8 +1638,8 @@ impl InvocationCollectorNode for ast::Param { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_params() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_param(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_param(collector, self) } } @@ -1651,8 +1651,8 @@ impl InvocationCollectorNode for ast::GenericParam { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_generic_params() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_generic_param(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_generic_param(collector, self) } } @@ -1664,8 +1664,8 @@ impl InvocationCollectorNode for ast::Arm { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_arms() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_arm(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_arm(collector, self) } } @@ -1677,8 +1677,8 @@ impl InvocationCollectorNode for ast::Stmt { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_stmts() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_stmt(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_stmt(collector, self) } fn is_mac_call(&self) -> bool { match &self.kind { @@ -1751,8 +1751,8 @@ impl InvocationCollectorNode for ast::Crate { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_crate() } - fn walk(&mut self, visitor: &mut V) { - walk_crate(visitor, self) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_crate(collector, self) } fn expand_cfg_false( &mut self, @@ -1777,8 +1777,8 @@ impl InvocationCollectorNode for ast::Ty { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_ty() } - fn walk(&mut self, visitor: &mut V) { - walk_ty(visitor, self) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_ty(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ast::TyKind::MacCall(..)) @@ -1800,8 +1800,8 @@ impl InvocationCollectorNode for ast::Pat { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_pat() } - fn walk(&mut self, visitor: &mut V) { - walk_pat(visitor, self) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_pat(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, PatKind::MacCall(..)) @@ -1826,8 +1826,8 @@ impl InvocationCollectorNode for ast::Expr { fn descr() -> &'static str { "an expression" } - fn walk(&mut self, visitor: &mut V) { - walk_expr(visitor, self) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_expr(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ExprKind::MacCall(..)) @@ -1850,8 +1850,8 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_opt_expr() } - fn walk_flat_map(mut self, visitor: &mut V) -> Self::OutputTy { - walk_expr(visitor, &mut self.wrapped); + fn walk_flat_map(mut self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_expr(collector, &mut self.wrapped); Some(self.wrapped) } fn is_mac_call(&self) -> bool { @@ -1885,8 +1885,8 @@ impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag) } - fn walk(&mut self, visitor: &mut V) { - walk_expr(visitor, &mut self.wrapped) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_expr(collector, &mut self.wrapped) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) From b47d36d8d1c22aa036021cc7a3c91f9edce043dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 17 Jun 2025 09:47:37 +0200 Subject: [PATCH 117/356] Remove `override_build_kind` It doesn't seem to be needed, we can just use `Kind::Check` explicitly. --- src/bootstrap/src/core/build_steps/check.rs | 26 +++----------------- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index f47873590a17..f5dae626a89b 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -199,13 +199,6 @@ pub struct Rustc { /// /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc crates: Vec, - /// Override `Builder::kind` on cargo invocations. - /// - /// By default, `Builder::kind` is propagated as the subcommand to the cargo invocations. - /// However, there are cases when this is not desirable. For example, when running `x clippy $tool_name`, - /// passing `Builder::kind` to cargo invocations would run clippy on the entire compiler and library, - /// which is not useful if we only want to lint a few crates with specific rules. - override_build_kind: Option, } impl Rustc { @@ -215,12 +208,7 @@ impl Rustc { .into_iter() .map(|krate| krate.name.to_string()) .collect(); - Self { target, crates, override_build_kind: None } - } - - pub fn build_kind(mut self, build_kind: Option) -> Self { - self.override_build_kind = build_kind; - self + Self { target, crates } } } @@ -235,7 +223,7 @@ impl Step for Rustc { fn make_run(run: RunConfig<'_>) { let crates = run.make_run_crates(Alias::Compiler); - run.builder.ensure(Rustc { target: run.target, crates, override_build_kind: None }); + run.builder.ensure(Rustc { target: run.target, crates }); } /// Builds the compiler. @@ -256,7 +244,7 @@ impl Step for Rustc { builder.ensure(crate::core::build_steps::compile::Std::new(compiler, compiler.host)); builder.ensure(crate::core::build_steps::compile::Std::new(compiler, target)); } else { - builder.ensure(Std::new(target).build_kind(self.override_build_kind)); + builder.ensure(Std::new(target)); } let mut cargo = builder::Cargo::new( @@ -265,17 +253,11 @@ impl Step for Rustc { Mode::Rustc, SourceType::InTree, target, - self.override_build_kind.unwrap_or(builder.kind), + Kind::Check, ); rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); - // For ./x.py clippy, don't run with --all-targets because - // linting tests and benchmarks can produce very noisy results - if builder.kind != Kind::Clippy { - cargo.arg("--all-targets"); - } - // Explicitly pass -p for all compiler crates -- this will force cargo // to also check the tests/benches/examples for these crates, rather // than just the leaf crate. diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 788a3b9601d9..f1932479d467 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -289,7 +289,7 @@ macro_rules! lint_any { let target = self.target; if !builder.download_rustc() { - builder.ensure(check::Rustc::new(target, builder).build_kind(Some(Kind::Check))); + builder.ensure(check::Rustc::new(target, builder)); }; let cargo = prepare_tool_cargo( From 887566881f92051cf29be482fae0b8c9cced1af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 17 Jun 2025 13:09:43 +0200 Subject: [PATCH 118/356] Remove useless conditions about Clippy We should always just use `Kind::Check` for the check steps, as Clippy now has an entirely separate set of steps. --- src/bootstrap/src/core/build_steps/check.rs | 51 ++++---------------- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- 2 files changed, 11 insertions(+), 42 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index f5dae626a89b..fcd4f4078adb 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -21,13 +21,6 @@ pub struct Std { /// /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc crates: Vec, - /// Override `Builder::kind` on cargo invocations. - /// - /// By default, `Builder::kind` is propagated as the subcommand to the cargo invocations. - /// However, there are cases when this is not desirable. For example, when running `x clippy $tool_name`, - /// passing `Builder::kind` to cargo invocations would run clippy on the entire compiler and library, - /// which is not useful if we only want to lint a few crates with specific rules. - override_build_kind: Option, /// Never use this from outside calls. It is intended for internal use only within `check::Std::make_run` /// and `check::Std::run`. custom_stage: Option, @@ -37,12 +30,7 @@ impl Std { const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"]; pub fn new(target: TargetSelection) -> Self { - Self { target, crates: vec![], override_build_kind: None, custom_stage: None } - } - - pub fn build_kind(mut self, kind: Option) -> Self { - self.override_build_kind = kind; - self + Self { target, crates: vec![], custom_stage: None } } } @@ -68,12 +56,7 @@ impl Step for Std { 1 }; - run.builder.ensure(Std { - target: run.target, - crates, - override_build_kind: None, - custom_stage: Some(stage), - }); + run.builder.ensure(Std { target: run.target, crates, custom_stage: Some(stage) }); } fn run(self, builder: &Builder<'_>) { @@ -116,7 +99,7 @@ impl Step for Std { Mode::Std, SourceType::InTree, target, - self.override_build_kind.unwrap_or(builder.kind), + Kind::Check, ); std_cargo(builder, target, compiler.stage, &mut cargo); @@ -147,9 +130,8 @@ impl Step for Std { } drop(_guard); - // don't run on std twice with x.py clippy // don't check test dependencies if we haven't built libtest - if builder.kind == Kind::Clippy || !self.crates.iter().any(|krate| krate == "test") { + if !self.crates.iter().any(|krate| krate == "test") { return; } @@ -165,7 +147,7 @@ impl Step for Std { Mode::Std, SourceType::InTree, target, - self.override_build_kind.unwrap_or(builder.kind), + Kind::Check, ); // If we're not in stage 0, tests and examples will fail to compile @@ -382,14 +364,9 @@ impl Step for RustAnalyzer { cargo.allow_features(crate::core::build_steps::tool::RustAnalyzer::ALLOW_FEATURES); - // For ./x.py clippy, don't check those targets because - // linting tests and benchmarks can produce very noisy results - if builder.kind != Kind::Clippy { - // can't use `--all-targets` because `--examples` doesn't work well - cargo.arg("--bins"); - cargo.arg("--tests"); - cargo.arg("--benches"); - } + cargo.arg("--bins"); + cargo.arg("--tests"); + cargo.arg("--benches"); // Cargo's output path in a given stage, compiled by a particular // compiler for the specified target. @@ -450,11 +427,7 @@ impl Step for Compiletest { cargo.allow_features(COMPILETEST_ALLOW_FEATURES); - // For ./x.py clippy, don't run with --all-targets because - // linting tests and benchmarks can produce very noisy results - if builder.kind != Kind::Clippy { - cargo.arg("--all-targets"); - } + cargo.arg("--all-targets"); let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target)) .with_prefix("compiletest-check"); @@ -528,11 +501,7 @@ fn run_tool_check_step( &[], ); - // For ./x.py clippy, don't run with --all-targets because - // linting tests and benchmarks can produce very noisy results - if builder.kind != Kind::Clippy { - cargo.arg("--all-targets"); - } + cargo.arg("--all-targets"); let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target)) .with_prefix(&format!("{}-check", step_type_name.to_lowercase())); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index f1932479d467..ebf0caccfbc9 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -217,7 +217,7 @@ impl Step for Rustc { builder.ensure(compile::Std::new(compiler, compiler.host)); builder.ensure(compile::Std::new(compiler, target)); } else { - builder.ensure(check::Std::new(target).build_kind(Some(Kind::Check))); + builder.ensure(check::Std::new(target)); } } From f3d42786434dca79521ee35d1c0c7c478a86dfaa Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 13 May 2025 21:12:47 -0500 Subject: [PATCH 119/356] Fix `core::iter::Fuse`'s `Default` impl to do what it's docs say it does. Add a doctest with a non-empty-by-default iterator. --- library/core/src/iter/adapters/fuse.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index e9765f911a25..0072a95e8dfe 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -198,8 +198,30 @@ impl Default for Fuse { /// let iter: Fuse> = Default::default(); /// assert_eq!(iter.len(), 0); /// ``` + /// + /// This is equivalent to `I::default().fuse()`[^fuse_note]; e.g. if + /// `I::default()` is not an empty iterator, then this will not be + /// an empty iterator. + /// + /// ``` + /// # use std::iter::Fuse; + /// #[derive(Default)] + /// struct Fourever; + /// + /// impl Iterator for Fourever { + /// type Item = u32; + /// fn next(&mut self) -> Option { + /// Some(4) + /// } + /// } + /// + /// let mut iter: Fuse = Default::default(); + /// assert_eq!(iter.next(), Some(4)); + /// ``` + /// + /// [^fuse_note]: if `I` does not override `Iterator::fuse`'s default implementation fn default() -> Self { - Fuse { iter: Default::default() } + Fuse { iter: Some(I::default()) } } } From 2beccc4d8e5066a42e6623d91e7991870d36feb2 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 16 Jun 2025 20:24:50 +0800 Subject: [PATCH 120/356] Adjust some run-make tests on cross-compile --- .../run-make/allow-warnings-cmdline-stability/rmake.rs | 2 +- tests/run-make/crate-circular-deps-link/rmake.rs | 4 ++-- tests/run-make/doctests-merge/rmake.rs | 3 ++- tests/run-make/doctests-runtool/rmake.rs | 4 ++-- tests/run-make/embed-metadata/rmake.rs | 5 +++-- tests/run-make/embed-source-dwarf/rmake.rs | 2 ++ tests/run-make/emit-shared-files/rmake.rs | 2 ++ tests/run-make/emit-stack-sizes/rmake.rs | 3 +-- tests/run-make/env-dep-info/rmake.rs | 6 ++++-- tests/run-make/exit-code/rmake.rs | 4 ++-- tests/run-make/export-executable-symbols/rmake.rs | 5 ++--- tests/run-make/export/disambiguator/rmake.rs | 6 +++++- tests/run-make/export/extern-opt/rmake.rs | 6 +++++- tests/run-make/export/simple/rmake.rs | 6 +++++- tests/run-make/extern-diff-internal-name/rmake.rs | 4 ++-- tests/run-make/extern-flag-fun/rmake.rs | 2 +- tests/run-make/extern-multiple-copies/rmake.rs | 4 ++-- tests/run-make/extern-multiple-copies2/rmake.rs | 4 ++-- tests/run-make/ice-dep-cannot-find-dep/rmake.rs | 1 + tests/run-make/include-all-symbols-linking/rmake.rs | 4 +++- tests/run-make/incr-prev-body-beyond-eof/rmake.rs | 2 +- tests/run-make/incr-test-moved-file/rmake.rs | 2 +- tests/run-make/intrinsic-unreachable/rmake.rs | 1 + tests/run-make/invalid-so/rmake.rs | 4 +++- tests/run-make/issue-125484-used-dependencies/rmake.rs | 4 ++-- tests/run-make/json-error-no-offset/rmake.rs | 4 ++-- tests/run-make/link-args-order/rmake.rs | 3 ++- tests/run-make/link-dedup/rmake.rs | 10 ++++++---- tests/run-make/linker-warning/rmake.rs | 3 ++- tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs | 2 +- tests/run-make/naked-symbol-visibility/rmake.rs | 3 +++ tests/run-make/native-lib-alt-naming/rmake.rs | 6 ++---- .../native-link-modifier-verbatim-linker/rmake.rs | 3 ++- .../run-make/no-builtins-attribute/filecheck.main.txt | 4 ++-- tests/run-make/no-builtins-attribute/rmake.rs | 2 +- tests/run-make/no-builtins-lto/rmake.rs | 4 ++-- tests/run-make/non-unicode-in-incremental-dir/rmake.rs | 2 +- tests/run-make/proc-macro-three-crates/rmake.rs | 6 ++++-- tests/run-make/relro-levels/rmake.rs | 1 + tests/run-make/repr128-dwarf/rmake.rs | 3 ++- tests/run-make/reproducible-build-2/rmake.rs | 2 +- .../rlib-format-packed-bundled-libs-2/rmake.rs | 4 ++-- tests/run-make/rustc-macro-dep-files/rmake.rs | 6 ++++-- tests/run-make/rustdoc-default-output/rmake.rs | 4 ++-- tests/run-make/rustdoc-dep-info/rmake.rs | 2 ++ tests/run-make/rustdoc-determinism/rmake.rs | 2 ++ tests/run-make/rustdoc-error-lines/rmake.rs | 2 ++ tests/run-make/rustdoc-io-error/rmake.rs | 1 + tests/run-make/rustdoc-map-file/rmake.rs | 2 ++ tests/run-make/rustdoc-output-path/rmake.rs | 2 ++ tests/run-make/rustdoc-output-stdout/rmake.rs | 2 ++ tests/run-make/rustdoc-test-args/rmake.rs | 2 ++ tests/run-make/rustdoc-themes/rmake.rs | 2 ++ tests/run-make/rustdoc-verify-output-files/rmake.rs | 2 ++ tests/run-make/rustdoc-with-out-dir-option/rmake.rs | 2 ++ tests/run-make/rustdoc-with-output-option/rmake.rs | 2 ++ tests/run-make/share-generics-dylib/rmake.rs | 6 ++++-- tests/run-make/staticlib-thin-archive/rmake.rs | 4 ++-- tests/run-make/stdin-rustc/rmake.rs | 10 +++------- tests/run-make/stdin-rustdoc/rmake.rs | 2 ++ tests/run-make/symbol-visibility/rmake.rs | 6 ++++-- tests/run-make/track-path-dep-info/rmake.rs | 6 ++++-- tests/run-make/used/rmake.rs | 3 ++- 63 files changed, 143 insertions(+), 79 deletions(-) diff --git a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs index 66ca3eb3383b..033a06741e22 100644 --- a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs +++ b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs @@ -1,4 +1,4 @@ -//@ needs-target-std +//@ ignore-cross-compile // Test that `-Awarnings` suppresses warnings for unstable APIs. use run_make_support::rustc; diff --git a/tests/run-make/crate-circular-deps-link/rmake.rs b/tests/run-make/crate-circular-deps-link/rmake.rs index 6771fdec7e8a..38b922c328f8 100644 --- a/tests/run-make/crate-circular-deps-link/rmake.rs +++ b/tests/run-make/crate-circular-deps-link/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // Test that previously triggered a linker failure with root cause // similar to one found in the issue #69368. // diff --git a/tests/run-make/doctests-merge/rmake.rs b/tests/run-make/doctests-merge/rmake.rs index 8236997d72d7..7893d4988ebb 100644 --- a/tests/run-make/doctests-merge/rmake.rs +++ b/tests/run-make/doctests-merge/rmake.rs @@ -1,4 +1,5 @@ -//@ needs-target-std +//@ ignore-cross-compile (needs to run doctests) + use std::path::Path; use run_make_support::{cwd, diff, rustc, rustdoc}; diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs index aaba41749102..bc406630932a 100644 --- a/tests/run-make/doctests-runtool/rmake.rs +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile (needs to run host tool binary) + // Tests behavior of rustdoc `--test-runtool`. use std::path::PathBuf; diff --git a/tests/run-make/embed-metadata/rmake.rs b/tests/run-make/embed-metadata/rmake.rs index a41716d15429..2de6575feb88 100644 --- a/tests/run-make/embed-metadata/rmake.rs +++ b/tests/run-make/embed-metadata/rmake.rs @@ -1,5 +1,6 @@ -//@ needs-target-std -// +//@ ignore-cross-compile +//@ needs-crate-type: dylib + // Tests the -Zembed-metadata compiler flag. // Tracking issue: https://github.com/rust-lang/rust/issues/139165 diff --git a/tests/run-make/embed-source-dwarf/rmake.rs b/tests/run-make/embed-source-dwarf/rmake.rs index 99fad359054b..f57e6aba13ed 100644 --- a/tests/run-make/embed-source-dwarf/rmake.rs +++ b/tests/run-make/embed-source-dwarf/rmake.rs @@ -1,6 +1,8 @@ //@ needs-target-std //@ ignore-windows //@ ignore-apple +//@ ignore-wasm (`object` doesn't handle wasm object files) +//@ ignore-cross-compile // This test should be replaced with one in tests/debuginfo once we can easily // tell via GDB or LLDB if debuginfo contains source code. Cheap tricks in LLDB diff --git a/tests/run-make/emit-shared-files/rmake.rs b/tests/run-make/emit-shared-files/rmake.rs index c8c113ce9445..f88fe69aa9cd 100644 --- a/tests/run-make/emit-shared-files/rmake.rs +++ b/tests/run-make/emit-shared-files/rmake.rs @@ -5,6 +5,8 @@ // `all-shared` should only emit files that can be shared between crates. // See https://github.com/rust-lang/rust/pull/83478 +//@ needs-target-std + use run_make_support::{has_extension, has_prefix, path, rustdoc, shallow_find_files}; fn main() { diff --git a/tests/run-make/emit-stack-sizes/rmake.rs b/tests/run-make/emit-stack-sizes/rmake.rs index 886e875cfae8..2e7f40896a5d 100644 --- a/tests/run-make/emit-stack-sizes/rmake.rs +++ b/tests/run-make/emit-stack-sizes/rmake.rs @@ -7,8 +7,7 @@ // See https://github.com/rust-lang/rust/pull/51946 //@ needs-target-std -//@ ignore-windows -//@ ignore-apple +//@ only-elf // Reason: this feature only works when the output object format is ELF. // This won't be the case on Windows/OSX - for example, OSX produces a Mach-O binary. diff --git a/tests/run-make/env-dep-info/rmake.rs b/tests/run-make/env-dep-info/rmake.rs index 97006a632057..18e6250d7d45 100644 --- a/tests/run-make/env-dep-info/rmake.rs +++ b/tests/run-make/env-dep-info/rmake.rs @@ -1,5 +1,7 @@ -//@ needs-target-std -// +//@ ignore-cross-compile +//@ needs-crate-type: proc-macro +//@ ignore-musl (FIXME: can't find `-lunwind`) + // Inside dep-info emit files, #71858 made it so all accessed environment // variables are usefully printed. This test checks that this feature works // as intended by checking if the environment variables used in compilation diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs index 5fdf920b55a6..21dea06a55af 100644 --- a/tests/run-make/exit-code/rmake.rs +++ b/tests/run-make/exit-code/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations use run_make_support::{rustc, rustdoc}; diff --git a/tests/run-make/export-executable-symbols/rmake.rs b/tests/run-make/export-executable-symbols/rmake.rs index dc8c59b9c742..884c7362822f 100644 --- a/tests/run-make/export-executable-symbols/rmake.rs +++ b/tests/run-make/export-executable-symbols/rmake.rs @@ -8,9 +8,8 @@ // Reason: the export-executable-symbols flag only works on Unix // due to hardcoded platform-specific implementation // (See #85673) -//@ ignore-wasm32 -//@ ignore-wasm64 -//@ needs-target-std +//@ ignore-cross-compile +//@ ignore-wasm use run_make_support::{bin_name, llvm_readobj, rustc}; diff --git a/tests/run-make/export/disambiguator/rmake.rs b/tests/run-make/export/disambiguator/rmake.rs index f855e42d08ee..afbe7f2cdbc3 100644 --- a/tests/run-make/export/disambiguator/rmake.rs +++ b/tests/run-make/export/disambiguator/rmake.rs @@ -1,4 +1,8 @@ -//@ needs-target-std +//@ ignore-cross-compile + +// NOTE: `sdylib`'s platform support is basically just `dylib`'s platform support. +//@ needs-crate-type: dylib + use run_make_support::rustc; fn main() { diff --git a/tests/run-make/export/extern-opt/rmake.rs b/tests/run-make/export/extern-opt/rmake.rs index a2f9ba28c2f5..2e3a70b251c6 100644 --- a/tests/run-make/export/extern-opt/rmake.rs +++ b/tests/run-make/export/extern-opt/rmake.rs @@ -1,4 +1,8 @@ -//@ needs-target-std +//@ ignore-cross-compile + +// NOTE: `sdylib`'s platform support is basically that of `dylib`. +//@ needs-crate-type: dylib + use run_make_support::{dynamic_lib_name, rustc}; fn main() { diff --git a/tests/run-make/export/simple/rmake.rs b/tests/run-make/export/simple/rmake.rs index f855e42d08ee..6468e38c69b5 100644 --- a/tests/run-make/export/simple/rmake.rs +++ b/tests/run-make/export/simple/rmake.rs @@ -1,4 +1,8 @@ -//@ needs-target-std +//@ ignore-cross-compile + +// NOTE: `sdylib`'s platform support is basically that of `dylib`. +//@ needs-crate-type: dylib + use run_make_support::rustc; fn main() { diff --git a/tests/run-make/extern-diff-internal-name/rmake.rs b/tests/run-make/extern-diff-internal-name/rmake.rs index 1bae8decb052..c905de1d9a8d 100644 --- a/tests/run-make/extern-diff-internal-name/rmake.rs +++ b/tests/run-make/extern-diff-internal-name/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // In the following scenario: // 1. The crate foo, is referenced multiple times // 2. --extern foo=./path/to/libbar.rlib is specified to rustc diff --git a/tests/run-make/extern-flag-fun/rmake.rs b/tests/run-make/extern-flag-fun/rmake.rs index 181a76b7cfa0..0b5e3c245c55 100644 --- a/tests/run-make/extern-flag-fun/rmake.rs +++ b/tests/run-make/extern-flag-fun/rmake.rs @@ -1,4 +1,4 @@ -//@ needs-target-std +//@ ignore-cross-compile // // The --extern flag can override the default crate search of // the compiler and directly fetch a given path. There are a few rules diff --git a/tests/run-make/extern-multiple-copies/rmake.rs b/tests/run-make/extern-multiple-copies/rmake.rs index d9d769d178c3..01e4beed1b5c 100644 --- a/tests/run-make/extern-multiple-copies/rmake.rs +++ b/tests/run-make/extern-multiple-copies/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // In this test, the rust library foo1 exists in two different locations, but only one // is required by the --extern flag. This test checks that the copy is ignored (as --extern // demands fetching only the original instance of foo1) and that no error is emitted, resulting diff --git a/tests/run-make/extern-multiple-copies2/rmake.rs b/tests/run-make/extern-multiple-copies2/rmake.rs index 4188d5bdc182..5937929a1f3e 100644 --- a/tests/run-make/extern-multiple-copies2/rmake.rs +++ b/tests/run-make/extern-multiple-copies2/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // Almost identical to `extern-multiple-copies`, but with a variation in the --extern calls // and the addition of #[macro_use] in the rust code files, which used to break --extern // until #33625. diff --git a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs index 1c136773f015..cb3cf39e436f 100644 --- a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs +++ b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs @@ -9,6 +9,7 @@ //@ only-x86_64 //@ only-linux +//@ ignore-cross-compile // Reason: This is a platform-independent issue, no need to waste time testing // everywhere. diff --git a/tests/run-make/include-all-symbols-linking/rmake.rs b/tests/run-make/include-all-symbols-linking/rmake.rs index 4f85ee179f5f..61b83e7a07fa 100644 --- a/tests/run-make/include-all-symbols-linking/rmake.rs +++ b/tests/run-make/include-all-symbols-linking/rmake.rs @@ -7,7 +7,9 @@ // See https://github.com/rust-lang/rust/pull/95604 // See https://github.com/rust-lang/rust/issues/47384 -//@ needs-target-std +//@ ignore-cross-compile +//@ needs-crate-type: cdylib +//@ needs-dynamic-linking //@ ignore-wasm differences in object file formats causes errors in the llvm_objdump step. //@ ignore-windows differences in object file formats causes errors in the llvm_objdump step. diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs index cfa8d5b46cd9..cdecf127a2c8 100644 --- a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs +++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs @@ -7,7 +7,7 @@ // was hashed by rustc in addition to the span length, and the fix still // works. -//@ needs-target-std +//@ ignore-cross-compile use run_make_support::{rfs, rustc}; diff --git a/tests/run-make/incr-test-moved-file/rmake.rs b/tests/run-make/incr-test-moved-file/rmake.rs index dfba95d3fedb..9a00a14ae955 100644 --- a/tests/run-make/incr-test-moved-file/rmake.rs +++ b/tests/run-make/incr-test-moved-file/rmake.rs @@ -9,7 +9,7 @@ // for successful compilation. // See https://github.com/rust-lang/rust/issues/83112 -//@ needs-target-std +//@ ignore-cross-compile use run_make_support::{rfs, rustc}; diff --git a/tests/run-make/intrinsic-unreachable/rmake.rs b/tests/run-make/intrinsic-unreachable/rmake.rs index bb189fbdcb5d..ea9c0a1434a3 100644 --- a/tests/run-make/intrinsic-unreachable/rmake.rs +++ b/tests/run-make/intrinsic-unreachable/rmake.rs @@ -4,6 +4,7 @@ // which means the emitted artifacts should be shorter in length. // See https://github.com/rust-lang/rust/pull/16970 +//@ needs-target-std //@ needs-asm-support //@ ignore-windows // Reason: Because of Windows exception handling, the code is not necessarily any shorter. diff --git a/tests/run-make/invalid-so/rmake.rs b/tests/run-make/invalid-so/rmake.rs index ee886b5ee3a6..9e5ce583ece2 100644 --- a/tests/run-make/invalid-so/rmake.rs +++ b/tests/run-make/invalid-so/rmake.rs @@ -1,5 +1,7 @@ //@ needs-target-std -// +//@ needs-crate-type: dylib +//@ needs-dynamic-linking + // When a fake library was given to the compiler, it would // result in an obscure and unhelpful error message. This test // creates a false "foo" dylib, and checks that the standard error diff --git a/tests/run-make/issue-125484-used-dependencies/rmake.rs b/tests/run-make/issue-125484-used-dependencies/rmake.rs index afcea34783f9..67b0b600b473 100644 --- a/tests/run-make/issue-125484-used-dependencies/rmake.rs +++ b/tests/run-make/issue-125484-used-dependencies/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // Non-regression test for issues #125474, #125484, #125646, with the repro taken from #125484. Some // queries use "used dependencies" while others use "speculatively loaded dependencies", and an // indexing ICE appeared in some cases when these were unexpectedly used in the same context. diff --git a/tests/run-make/json-error-no-offset/rmake.rs b/tests/run-make/json-error-no-offset/rmake.rs index 3f45778ca04a..296d968540a6 100644 --- a/tests/run-make/json-error-no-offset/rmake.rs +++ b/tests/run-make/json-error-no-offset/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // The byte positions in json format error logging used to have a small, difficult // to predict offset. This was changed to be the top of the file every time in #42973, // and this test checks that the measurements appearing in the standard error are correct. diff --git a/tests/run-make/link-args-order/rmake.rs b/tests/run-make/link-args-order/rmake.rs index a4591ea3949e..7a67c12f74c8 100644 --- a/tests/run-make/link-args-order/rmake.rs +++ b/tests/run-make/link-args-order/rmake.rs @@ -1,5 +1,6 @@ //@ needs-target-std -// +//@ ignore-wasm (explicit linker invocations) + // Passing linker arguments to the compiler used to be lost or reordered in a messy way // as they were passed further to the linker. This was fixed in #70665, and this test // checks that linker arguments remain intact and in the order they were originally passed in. diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs index 0148817f9878..874e6e0083bd 100644 --- a/tests/run-make/link-dedup/rmake.rs +++ b/tests/run-make/link-dedup/rmake.rs @@ -1,5 +1,5 @@ //@ needs-target-std -// +//@ ignore-musl (not passed consecutively) // When native libraries are passed to the linker, there used to be an annoyance // where multiple instances of the same library in a row would cause duplication in // outputs. This has been fixed, and this test checks that it stays fixed. @@ -9,7 +9,7 @@ use std::fmt::Write; -use run_make_support::{is_msvc, rustc}; +use run_make_support::{is_msvc, rustc, target}; fn main() { rustc().input("depa.rs").run(); @@ -33,9 +33,11 @@ fn needle_from_libs(libs: &[&str]) -> String { let mut needle = String::new(); for lib in libs { if is_msvc() { - let _ = needle.write_fmt(format_args!(r#""{lib}.lib" "#)); + needle.write_fmt(format_args!(r#""{lib}.lib" "#)).unwrap(); + } else if target().contains("wasm") { + needle.write_fmt(format_args!(r#""-l" "{lib}" "#)).unwrap(); } else { - let _ = needle.write_fmt(format_args!(r#""-l{lib}" "#)); + needle.write_fmt(format_args!(r#""-l{lib}" "#)).unwrap(); } } needle.pop(); // remove trailing space diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs index eb1bbbff8ef0..344b880faab9 100644 --- a/tests/run-make/linker-warning/rmake.rs +++ b/tests/run-make/linker-warning/rmake.rs @@ -1,4 +1,5 @@ -//@ needs-target-std +//@ ignore-cross-compile (need to run fake linker) + use run_make_support::{Rustc, diff, regex, rustc}; fn run_rustc() -> Rustc { diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs index 0d96b40e8a43..70a0853848cc 100644 --- a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs +++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs @@ -12,7 +12,7 @@ // sessions. // See https://github.com/rust-lang/rust/issues/85019 -//@ needs-target-std +//@ ignore-cross-compile use run_make_support::{rfs, rust_lib_name, rustc}; diff --git a/tests/run-make/naked-symbol-visibility/rmake.rs b/tests/run-make/naked-symbol-visibility/rmake.rs index c69a9ef9eeb0..d73eafcaefea 100644 --- a/tests/run-make/naked-symbol-visibility/rmake.rs +++ b/tests/run-make/naked-symbol-visibility/rmake.rs @@ -1,5 +1,8 @@ //@ ignore-windows //@ only-x86_64 +//@ needs-target-std +//@ needs-crate-type: dylib + use run_make_support::object::ObjectSymbol; use run_make_support::object::read::{File, Object, Symbol}; use run_make_support::targets::is_windows; diff --git a/tests/run-make/native-lib-alt-naming/rmake.rs b/tests/run-make/native-lib-alt-naming/rmake.rs index a1dc002533f5..e989cece6031 100644 --- a/tests/run-make/native-lib-alt-naming/rmake.rs +++ b/tests/run-make/native-lib-alt-naming/rmake.rs @@ -1,10 +1,8 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // On MSVC the alternative naming format for static libraries (`libfoo.a`) is accepted in addition // to the default format (`foo.lib`). -//REMOVE@ only-msvc - use run_make_support::rustc; fn main() { diff --git a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs index e06be13d9b95..4fb0690531a1 100644 --- a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs +++ b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs @@ -3,8 +3,9 @@ // This test is the same as native-link-modifier-rustc, but without rlibs. // See https://github.com/rust-lang/rust/issues/99425 -//@ needs-target-std +//@ ignore-cross-compile //@ ignore-apple +//@ ignore-wasm // Reason: linking fails due to the unusual ".ext" staticlib name. use run_make_support::rustc; diff --git a/tests/run-make/no-builtins-attribute/filecheck.main.txt b/tests/run-make/no-builtins-attribute/filecheck.main.txt index ecd650bdca80..7cbe94f57281 100644 --- a/tests/run-make/no-builtins-attribute/filecheck.main.txt +++ b/tests/run-make/no-builtins-attribute/filecheck.main.txt @@ -1,5 +1,5 @@ -CHECK: declare void @foo() +CHECK: declare{{.*}} void @foo() CHECK-SAME: #[[ATTR_3:[0-9]+]] -CHECK: attributes #[[ATTR_3]] +CHECK: attributes #[[ATTR_3]] CHECK-SAME: no-builtins diff --git a/tests/run-make/no-builtins-attribute/rmake.rs b/tests/run-make/no-builtins-attribute/rmake.rs index 038958f19ed9..f08316e14ce7 100644 --- a/tests/run-make/no-builtins-attribute/rmake.rs +++ b/tests/run-make/no-builtins-attribute/rmake.rs @@ -1,5 +1,4 @@ //@ needs-target-std -// // `no_builtins` is an attribute related to LLVM's optimizations. In order to ensure that it has an // effect on link-time optimizations (LTO), it should be added to function declarations in a crate. // This test uses the `llvm-filecheck` tool to determine that this attribute is successfully @@ -11,5 +10,6 @@ use run_make_support::{llvm_filecheck, rfs, rustc}; fn main() { rustc().input("no_builtins.rs").emit("link").run(); rustc().input("main.rs").emit("llvm-ir").run(); + llvm_filecheck().patterns("filecheck.main.txt").stdin_buf(rfs::read("main.ll")).run(); } diff --git a/tests/run-make/no-builtins-lto/rmake.rs b/tests/run-make/no-builtins-lto/rmake.rs index a1d9dc43e713..c7c075f1a66e 100644 --- a/tests/run-make/no-builtins-lto/rmake.rs +++ b/tests/run-make/no-builtins-lto/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // The rlib produced by a no_builtins crate should be explicitly linked // during compilation, and as a result be present in the linker arguments. // See the comments inside this file for more details. diff --git a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs index 5c437a3fe00c..aa6b83cf0621 100644 --- a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs +++ b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs @@ -1,4 +1,4 @@ -//@ needs-target-std +//@ ignore-cross-compile use run_make_support::{rfs, rustc}; fn main() { diff --git a/tests/run-make/proc-macro-three-crates/rmake.rs b/tests/run-make/proc-macro-three-crates/rmake.rs index e5a3385acbc5..4dfc32fe7e44 100644 --- a/tests/run-make/proc-macro-three-crates/rmake.rs +++ b/tests/run-make/proc-macro-three-crates/rmake.rs @@ -1,5 +1,7 @@ -//@ needs-target-std -// +//@ ignore-cross-compile +//@ needs-crate-type: proc-macro +//@ ignore-musl (FIXME: can't find `-lunwind`) + // A compiler bug caused the following issue: // If a crate A depends on crate B, and crate B // depends on crate C, and crate C contains a procedural diff --git a/tests/run-make/relro-levels/rmake.rs b/tests/run-make/relro-levels/rmake.rs index 91d106a03e4b..67aa7c155ea6 100644 --- a/tests/run-make/relro-levels/rmake.rs +++ b/tests/run-make/relro-levels/rmake.rs @@ -1,6 +1,7 @@ // This tests the different -Crelro-level values, and makes sure that they work properly. //@ only-linux +//@ ignore-cross-compile use run_make_support::{llvm_readobj, rustc}; diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index 1372d2bcc465..96c65d7d8977 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -1,4 +1,5 @@ -//@ needs-target-std +//@ ignore-cross-compile +//@ ignore-wasm (`object` can't handle wasm object files) //@ ignore-windows // This test should be replaced with one in tests/debuginfo once GDB or LLDB support 128-bit enums. diff --git a/tests/run-make/reproducible-build-2/rmake.rs b/tests/run-make/reproducible-build-2/rmake.rs index 0e1781dbfbe4..5971fa01f920 100644 --- a/tests/run-make/reproducible-build-2/rmake.rs +++ b/tests/run-make/reproducible-build-2/rmake.rs @@ -6,7 +6,7 @@ // Outputs should be identical. // See https://github.com/rust-lang/rust/issues/34902 -//@ needs-target-std +//@ ignore-cross-compile //@ ignore-windows // Reasons: // 1. The object files are reproducible, but their paths are not, which causes diff --git a/tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs b/tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs index 70d1ead85b5d..50c3f7f6df16 100644 --- a/tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs +++ b/tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // `-Z packed_bundled_libs` is an unstable rustc flag that makes the compiler // only require a native library and no supplementary object files to compile. // This test simply checks that this flag can be passed alongside verbatim syntax diff --git a/tests/run-make/rustc-macro-dep-files/rmake.rs b/tests/run-make/rustc-macro-dep-files/rmake.rs index c01244824bb2..2eb490e5d23a 100644 --- a/tests/run-make/rustc-macro-dep-files/rmake.rs +++ b/tests/run-make/rustc-macro-dep-files/rmake.rs @@ -1,5 +1,7 @@ -//@ needs-target-std -// +//@ ignore-cross-compile +//@ needs-crate-type: proc-macro +//@ ignore-musl (FIXME: can't find `-lunwind`) + // --emit dep-info used to print all macro-generated code it could // find as if it was part of a nonexistent file named "proc-macro source", // which is not a valid path. After this was fixed in #36776, this test checks diff --git a/tests/run-make/rustdoc-default-output/rmake.rs b/tests/run-make/rustdoc-default-output/rmake.rs index 5f9c501e5286..06720445a35c 100644 --- a/tests/run-make/rustdoc-default-output/rmake.rs +++ b/tests/run-make/rustdoc-default-output/rmake.rs @@ -3,10 +3,10 @@ // ensures the output of rustdoc's help menu is as expected. // See https://github.com/rust-lang/rust/issues/88756 -use run_make_support::{diff, rustdoc}; +use run_make_support::{bare_rustdoc, diff}; fn main() { - let out = rustdoc().run().stdout_utf8(); + let out = bare_rustdoc().run().stdout_utf8(); diff() .expected_file("output-default.stdout") .actual_text("actual", out) diff --git a/tests/run-make/rustdoc-dep-info/rmake.rs b/tests/run-make/rustdoc-dep-info/rmake.rs index 6902bfc21ca2..db7a00a5ce21 100644 --- a/tests/run-make/rustdoc-dep-info/rmake.rs +++ b/tests/run-make/rustdoc-dep-info/rmake.rs @@ -1,6 +1,8 @@ // This is a simple smoke test for rustdoc's `--emit dep-info` feature. It prints out // information about dependencies in a Makefile-compatible format, as a `.d` file. +//@ needs-target-std + use run_make_support::assertion_helpers::assert_contains; use run_make_support::{path, rfs, rustdoc}; diff --git a/tests/run-make/rustdoc-determinism/rmake.rs b/tests/run-make/rustdoc-determinism/rmake.rs index 5a030c6f496b..921baef4a979 100644 --- a/tests/run-make/rustdoc-determinism/rmake.rs +++ b/tests/run-make/rustdoc-determinism/rmake.rs @@ -1,6 +1,8 @@ // Assert that the search index is generated deterministically, regardless of the // order that crates are documented in. +//@ needs-target-std + use run_make_support::{diff, path, rustdoc}; fn main() { diff --git a/tests/run-make/rustdoc-error-lines/rmake.rs b/tests/run-make/rustdoc-error-lines/rmake.rs index 0d8c500ed1e0..e15d91e9387a 100644 --- a/tests/run-make/rustdoc-error-lines/rmake.rs +++ b/tests/run-make/rustdoc-error-lines/rmake.rs @@ -1,6 +1,8 @@ // Assert that the search index is generated deterministically, regardless of the // order that crates are documented in. +//@ needs-target-std + use run_make_support::rustdoc; fn main() { diff --git a/tests/run-make/rustdoc-io-error/rmake.rs b/tests/run-make/rustdoc-io-error/rmake.rs index 31441d7ebc5c..766091abf97c 100644 --- a/tests/run-make/rustdoc-io-error/rmake.rs +++ b/tests/run-make/rustdoc-io-error/rmake.rs @@ -13,6 +13,7 @@ // containers would use a non-root user, but this leads to issues with // `mkfs.ext4 -d`, as well as mounting a loop device for the rootfs. //@ ignore-windows - the `set_readonly` functions doesn't work on folders. +//@ needs-target-std use run_make_support::{path, rfs, rustdoc}; diff --git a/tests/run-make/rustdoc-map-file/rmake.rs b/tests/run-make/rustdoc-map-file/rmake.rs index 50dcc603c02f..802c924d580d 100644 --- a/tests/run-make/rustdoc-map-file/rmake.rs +++ b/tests/run-make/rustdoc-map-file/rmake.rs @@ -1,6 +1,8 @@ // This test ensures that all items from `foo` are correctly generated into the `redirect-map.json` // file with `--generate-redirect-map` rustdoc option. +//@ needs-target-std + use run_make_support::rfs::read_to_string; use run_make_support::{path, rustdoc, serde_json}; diff --git a/tests/run-make/rustdoc-output-path/rmake.rs b/tests/run-make/rustdoc-output-path/rmake.rs index 7f6accf26c21..cece914e947b 100644 --- a/tests/run-make/rustdoc-output-path/rmake.rs +++ b/tests/run-make/rustdoc-output-path/rmake.rs @@ -1,5 +1,7 @@ // Checks that if the output folder doesn't exist, rustdoc will create it. +//@ needs-target-std + use run_make_support::{path, rustdoc}; fn main() { diff --git a/tests/run-make/rustdoc-output-stdout/rmake.rs b/tests/run-make/rustdoc-output-stdout/rmake.rs index d2fd04511635..e6c007978bdc 100644 --- a/tests/run-make/rustdoc-output-stdout/rmake.rs +++ b/tests/run-make/rustdoc-output-stdout/rmake.rs @@ -1,6 +1,8 @@ // This test verifies that rustdoc `-o -` prints JSON on stdout and doesn't generate // a JSON file. +//@ needs-target-std + use run_make_support::path_helpers::{cwd, has_extension, read_dir_entries_recursive}; use run_make_support::{rustdoc, serde_json}; diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs index fddb3795402e..7c0223cf7329 100644 --- a/tests/run-make/rustdoc-test-args/rmake.rs +++ b/tests/run-make/rustdoc-test-args/rmake.rs @@ -1,3 +1,5 @@ +//@ ignore-cross-compile (needs to run doctest binary) + use std::iter; use std::path::Path; diff --git a/tests/run-make/rustdoc-themes/rmake.rs b/tests/run-make/rustdoc-themes/rmake.rs index 4577e47d47e7..681e6baaee36 100644 --- a/tests/run-make/rustdoc-themes/rmake.rs +++ b/tests/run-make/rustdoc-themes/rmake.rs @@ -1,5 +1,7 @@ // Test that rustdoc will properly load in a theme file and display it in the theme selector. +//@ needs-target-std + use std::path::Path; use run_make_support::{htmldocck, rfs, rustdoc, source_root}; diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs index a4d4050b7450..181d321997b0 100644 --- a/tests/run-make/rustdoc-verify-output-files/rmake.rs +++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs @@ -1,3 +1,5 @@ +//@ needs-target-std + use std::path::{Path, PathBuf}; use run_make_support::{assert_dirs_are_equal, rfs, rustdoc}; diff --git a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs index a82a1965a9c9..231a5b36600e 100644 --- a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs +++ b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs @@ -1,3 +1,5 @@ +//@ needs-target-std + use run_make_support::{htmldocck, rustdoc}; fn main() { diff --git a/tests/run-make/rustdoc-with-output-option/rmake.rs b/tests/run-make/rustdoc-with-output-option/rmake.rs index f7fbbec6986c..2c1b76f5b9cf 100644 --- a/tests/run-make/rustdoc-with-output-option/rmake.rs +++ b/tests/run-make/rustdoc-with-output-option/rmake.rs @@ -1,3 +1,5 @@ +//@ needs-target-std + use run_make_support::{htmldocck, rustdoc}; fn main() { diff --git a/tests/run-make/share-generics-dylib/rmake.rs b/tests/run-make/share-generics-dylib/rmake.rs index 2d52cd43db75..ae9e51abffd7 100644 --- a/tests/run-make/share-generics-dylib/rmake.rs +++ b/tests/run-make/share-generics-dylib/rmake.rs @@ -1,5 +1,7 @@ -//@ needs-target-std -// +//@ ignore-cross-compile +//@ needs-dynamic-linking +//@ needs-crate-type: dylib + // This test makes sure all generic instances get re-exported from Rust dylibs for use by // `-Zshare-generics`. There are two rlibs (`instance_provider_a` and `instance_provider_b`) // which both provide an instance of `Cell::set`. There is `instance_user_dylib` which is diff --git a/tests/run-make/staticlib-thin-archive/rmake.rs b/tests/run-make/staticlib-thin-archive/rmake.rs index 1fb56ac05381..5281e9f8c9cc 100644 --- a/tests/run-make/staticlib-thin-archive/rmake.rs +++ b/tests/run-make/staticlib-thin-archive/rmake.rs @@ -1,5 +1,5 @@ -//@ needs-target-std -// +//@ ignore-cross-compile + // Regression test for https://github.com/rust-lang/rust/issues/107407 which // checks that rustc can read thin archive. Before the object crate added thin // archive support rustc would add emit object files to the staticlib and after diff --git a/tests/run-make/stdin-rustc/rmake.rs b/tests/run-make/stdin-rustc/rmake.rs index 318d569a7605..6ae33766b90f 100644 --- a/tests/run-make/stdin-rustc/rmake.rs +++ b/tests/run-make/stdin-rustc/rmake.rs @@ -1,9 +1,9 @@ -//@ needs-target-std +//@ ignore-cross-compile //! This test checks rustc `-` (stdin) support use std::path::PathBuf; -use run_make_support::{is_windows, rustc}; +use run_make_support::{bin_name, rustc}; const HELLO_WORLD: &str = r#" fn main() { @@ -16,11 +16,7 @@ const NOT_UTF8: &[u8] = &[0xff, 0xff, 0xff]; fn main() { // echo $HELLO_WORLD | rustc - rustc().arg("-").stdin_buf(HELLO_WORLD).run(); - assert!( - PathBuf::from(if !is_windows() { "rust_out" } else { "rust_out.exe" }) - .try_exists() - .unwrap() - ); + assert!(PathBuf::from(bin_name("rust_out")).try_exists().unwrap()); // echo $NOT_UTF8 | rustc - rustc().arg("-").stdin_buf(NOT_UTF8).run_fail().assert_stderr_contains( diff --git a/tests/run-make/stdin-rustdoc/rmake.rs b/tests/run-make/stdin-rustdoc/rmake.rs index 30f97b8a2cd7..0420eac19932 100644 --- a/tests/run-make/stdin-rustdoc/rmake.rs +++ b/tests/run-make/stdin-rustdoc/rmake.rs @@ -1,3 +1,5 @@ +//@ ignore-cross-compile (needs to run doctests) + //! This test checks rustdoc `-` (stdin) handling use std::path::PathBuf; diff --git a/tests/run-make/symbol-visibility/rmake.rs b/tests/run-make/symbol-visibility/rmake.rs index 0175158d08b8..49c8e87707b6 100644 --- a/tests/run-make/symbol-visibility/rmake.rs +++ b/tests/run-make/symbol-visibility/rmake.rs @@ -1,5 +1,7 @@ -//@ needs-target-std -// +//@ ignore-cross-compile +//@ needs-crate-type: dylib, cdylib, proc-macro +//@ needs-dynamic-linking + // Dynamic libraries on Rust used to export a very high amount of symbols, // going as far as filling the output with mangled names and generic function // names. After the rework of #38117, this test checks that no mangled Rust symbols diff --git a/tests/run-make/track-path-dep-info/rmake.rs b/tests/run-make/track-path-dep-info/rmake.rs index 4b98a1b48d5f..955c46f7e682 100644 --- a/tests/run-make/track-path-dep-info/rmake.rs +++ b/tests/run-make/track-path-dep-info/rmake.rs @@ -1,5 +1,7 @@ -//@ needs-target-std -// +//@ ignore-cross-compile +//@ needs-crate-type: proc-macro +//@ ignore-musl (FIXME: can't find `-lunwind`) + // This test checks the functionality of `tracked_path::path`, a procedural macro // feature that adds a dependency to another file inside the procmacro. In this case, // the text file is added through this method, and the test checks that the compilation diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs index daed69c1b385..bcdb84132d3f 100644 --- a/tests/run-make/used/rmake.rs +++ b/tests/run-make/used/rmake.rs @@ -1,5 +1,6 @@ //@ needs-target-std -// +//@ ignore-wasm (`object` can't handle wasm object files) + // This test ensures that the compiler is keeping static variables, even if not referenced // by another part of the program, in the output object file. // From d70ec32ea7e03e3a082a45eeba6c8aa4c653efb4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 May 2025 22:53:38 +0200 Subject: [PATCH 121/356] move cfg(target_feature) computation into shared place --- compiler/rustc_codegen_gcc/src/lib.rs | 59 +++++------ compiler/rustc_codegen_llvm/src/llvm_util.rs | 87 ++-------------- .../rustc_codegen_ssa/src/target_features.rs | 99 ++++++++++++++++++- 3 files changed, 126 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index aa57655921d4..f5ad28681c79 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -103,7 +103,9 @@ use rustc_codegen_ssa::back::write::{ }; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods}; -use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; +use rustc_codegen_ssa::{ + CodegenResults, CompiledModule, ModuleCodegen, TargetConfig, target_features, +}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::DiagCtxtHandle; @@ -476,42 +478,25 @@ fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { /// Returns the features that should be set in `cfg(target_feature)`. fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig { - // TODO(antoyo): use global_gcc_features. - let f = |allow_unstable| { - sess.target - .rust_target_features() - .iter() - .filter_map(|&(feature, gate, _)| { - if allow_unstable - || (gate.in_cfg() - && (sess.is_nightly_build() || gate.requires_nightly().is_none())) - { - Some(feature) - } else { - None - } - }) - .filter(|feature| { - // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. - if *feature == "neon" { - return false; - } - target_info.cpu_supports(feature) - // cSpell:disable - /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, - avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, - bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, - sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves - */ - // cSpell:enable - }) - .map(Symbol::intern) - .collect() - }; - - let target_features = f(false); - let unstable_target_features = f(true); + let (unstable_target_features, target_features) = target_features::cfg_target_feature( + sess, + /* FIXME: we ignore `-Ctarget-feature` */ "", + |feature| { + // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. + if feature == "neon" { + return false; + } + target_info.cpu_supports(feature) + // cSpell:disable + /* + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, + avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, + bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, + sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves + */ + // cSpell:enable + }, + ); let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16); let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 0e77bc43df80..f9ebf8616344 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,9 +6,9 @@ use std::sync::Once; use std::{ptr, slice, str}; use libc::c_int; -use rustc_codegen_ssa::TargetConfig; use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::codegen_attrs::check_tied_features; +use rustc_codegen_ssa::{TargetConfig, target_features}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::unord::UnordSet; @@ -17,9 +17,8 @@ use rustc_middle::bug; use rustc_session::Session; use rustc_session::config::{PrintKind, PrintRequest}; use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; -use rustc_span::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; -use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; +use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; @@ -343,18 +342,11 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { // the target CPU, that is still expanded to target features (with all their implied features) // by LLVM. let target_machine = create_informational_target_machine(sess, true); - // Compute which of the known target features are enabled in the 'base' target machine. We only - // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. - let mut features: FxHashSet = sess - .target - .rust_target_features() - .iter() - .filter(|(feature, _, _)| { - // skip checking special features, as LLVM may not understand them - if RUSTC_SPECIAL_FEATURES.contains(feature) { - return true; - } + + let (unstable_target_features, target_features) = + target_features::cfg_target_feature(sess, &sess.opts.cg.target_feature, |feature| { if let Some(feat) = to_llvm_features(sess, feature) { + // All the LLVM features this expands to must be enabled. for llvm_feature in feat { let cstr = SmallCStr::new(llvm_feature); // `LLVMRustHasFeature` is moderately expensive. On targets with many @@ -368,73 +360,8 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { } else { false } - }) - .map(|(feature, _, _)| Symbol::intern(feature)) - .collect(); + }); - // Add enabled and remove disabled features. - for (enabled, feature) in - sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() { - Some('+') => Some((true, Symbol::intern(&s[1..]))), - Some('-') => Some((false, Symbol::intern(&s[1..]))), - _ => None, - }) - { - if enabled { - // Also add all transitively 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.extend( - sess.target - .implied_target_features(feature.as_str()) - .iter() - .map(|s| Symbol::intern(s)), - ); - } 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| { - if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) { - // 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 - } - }); - } - } - - // Filter enabled features based on feature gates. - let f = |allow_unstable| { - sess.target - .rust_target_features() - .iter() - .filter_map(|(feature, gate, _)| { - // The `allow_unstable` set is used by rustc internally to determined which target - // features are truly available, so we want to return even perma-unstable - // "forbidden" features. - if allow_unstable - || (gate.in_cfg() - && (sess.is_nightly_build() || gate.requires_nightly().is_none())) - { - Some(Symbol::intern(feature)) - } else { - None - } - }) - .filter(|feature| features.contains(&feature)) - .collect() - }; - - let target_features = f(false); - let unstable_target_features = f(true); let mut cfg = TargetConfig { target_features, unstable_target_features, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 640d197c219a..476671d68550 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::InstructionSetAttr; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -8,11 +8,12 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::Session; use rustc_session::features::StabilityExt; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{self, Stability}; +use rustc_target::target_features::{self, RUSTC_SPECIAL_FEATURES, Stability}; use crate::errors; @@ -156,6 +157,100 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, } } +/// Utility function for a codegen backend to compute `cfg(target_feature)`, or more specifically, +/// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and +/// 2nd component of the return value, respectively). +/// +/// `target_feature_flag` is the value of `-Ctarget-feature` (giving the caller a chance to override it). +/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is enabled +/// in the "base" target machine, i.e., without applying `-Ctarget-feature`. +/// +/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. +pub fn cfg_target_feature( + sess: &Session, + target_feature_flag: &str, + mut is_feature_enabled: impl FnMut(&str) -> bool, +) -> (Vec, Vec) { + // Compute which of the known target features are enabled in the 'base' target machine. We only + // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. + let mut features: FxHashSet = sess + .target + .rust_target_features() + .iter() + .filter(|(feature, _, _)| { + // Skip checking special features, those are not known to the backend. + if RUSTC_SPECIAL_FEATURES.contains(feature) { + return true; + } + is_feature_enabled(feature) + }) + .map(|(feature, _, _)| Symbol::intern(feature)) + .collect(); + + // Add enabled and remove disabled features. + for (enabled, feature) in + target_feature_flag.split(',').filter_map(|s| match s.chars().next() { + Some('+') => Some((true, Symbol::intern(&s[1..]))), + Some('-') => Some((false, Symbol::intern(&s[1..]))), + _ => None, + }) + { + if enabled { + // Also add all transitively 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.extend( + sess.target + .implied_target_features(feature.as_str()) + .iter() + .map(|s| Symbol::intern(s)), + ); + } 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| { + if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) { + // 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 + } + }); + } + } + + // Filter enabled features based on feature gates. + let f = |allow_unstable| { + sess.target + .rust_target_features() + .iter() + .filter_map(|(feature, gate, _)| { + // The `allow_unstable` set is used by rustc internally to determine which target + // features are truly available, so we want to return even perma-unstable + // "forbidden" features. + if allow_unstable + || (gate.in_cfg() + && (sess.is_nightly_build() || gate.requires_nightly().is_none())) + { + Some(Symbol::intern(feature)) + } else { + None + } + }) + .filter(|feature| features.contains(&feature)) + .collect() + }; + + (f(true), f(false)) +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { rust_target_features: |tcx, cnum| { From cd08652faa37a9119c2cf535b927129b1c4438b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 May 2025 08:07:42 +0200 Subject: [PATCH 122/356] move -Ctarget-feature handling into shared code --- compiler/rustc_codegen_gcc/messages.ftl | 16 -- compiler/rustc_codegen_gcc/src/errors.rs | 26 +-- compiler/rustc_codegen_gcc/src/gcc_util.rs | 122 +++---------- compiler/rustc_codegen_llvm/messages.ftl | 10 -- compiler/rustc_codegen_llvm/src/errors.rs | 26 +-- compiler/rustc_codegen_llvm/src/llvm_util.rs | 158 +++++------------ compiler/rustc_codegen_ssa/messages.ftl | 19 +++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 26 +-- compiler/rustc_codegen_ssa/src/errors.rs | 89 +++++++--- .../rustc_codegen_ssa/src/target_features.rs | 161 +++++++++++++++++- compiler/rustc_session/messages.ftl | 8 - compiler/rustc_session/src/errors.rs | 17 -- compiler/rustc_session/src/features.rs | 59 ------- compiler/rustc_session/src/lib.rs | 1 - compiler/rustc_session/src/options.rs | 8 - compiler/rustc_target/src/target_features.rs | 30 ++-- src/librustdoc/json/mod.rs | 5 +- tests/ui/check-cfg/target_feature.stderr | 3 - 18 files changed, 324 insertions(+), 460 deletions(-) delete mode 100644 compiler/rustc_session/src/features.rs diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index 18a8a5a1e048..55a28bc9493e 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -1,7 +1,3 @@ -codegen_gcc_unknown_ctarget_feature_prefix = - unknown feature specified for `-Ctarget-feature`: `{$feature}` - .note = features must begin with a `+` to enable or `-` to disable it - codegen_gcc_unwinding_inline_asm = GCC backend does not support unwinding from inline asm @@ -16,15 +12,3 @@ codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and st codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto` codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err}) - -codegen_gcc_unknown_ctarget_feature = - unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future - .possible_feature = you might have meant: `{$rust_feature}` - .consider_filing_feature_request = consider filing a feature request - -codegen_gcc_missing_features = - add the missing features in a `target_feature` attribute - -codegen_gcc_target_feature_disable_or_enable = - the target features {$features} must all be either enabled or disabled together diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 7786be9ae5de..b7e7343460fb 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -1,30 +1,6 @@ -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::Diagnostic; use rustc_span::Span; -#[derive(Diagnostic)] -#[diag(codegen_gcc_unknown_ctarget_feature_prefix)] -#[note] -pub(crate) struct UnknownCTargetFeaturePrefix<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_gcc_unknown_ctarget_feature)] -#[note] -pub(crate) struct UnknownCTargetFeature<'a> { - pub feature: &'a str, - #[subdiagnostic] - pub rust_feature: PossibleFeature<'a>, -} - -#[derive(Subdiagnostic)] -pub(crate) enum PossibleFeature<'a> { - #[help(codegen_gcc_possible_feature)] - Some { rust_feature: &'a str }, - #[help(codegen_gcc_consider_filing_feature_request)] - None, -} - #[derive(Diagnostic)] #[diag(codegen_gcc_unwinding_inline_asm)] pub(crate) struct UnwindingInlineAsm { diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 2e00d5fcb612..562f41248829 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -1,20 +1,11 @@ #[cfg(feature = "master")] use gccjit::Context; -use rustc_codegen_ssa::codegen_attrs::check_tied_features; -use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::unord::UnordSet; +use rustc_codegen_ssa::target_features; use rustc_session::Session; -use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; -use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; -use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; - -fn gcc_features_by_flags(sess: &Session) -> Vec<&str> { - let mut features: Vec<&str> = Vec::new(); - retpoline_features_by_flags(sess, &mut features); - features +fn gcc_features_by_flags(sess: &Session, features: &mut Vec) { + target_features::retpoline_features_by_flags(sess, features); } /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, @@ -44,98 +35,31 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec. - all_rust_features.push((false, feature)); - } else if !feature.is_empty() && diagnostics { - sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature }); - } - } - // Remove features that are meant for rustc, not codegen. - all_rust_features.retain(|&(_, feature)| { - // Retain if it is not a rustc feature - !RUSTC_SPECIFIC_FEATURES.contains(&feature) - }); - - // Check feature validity. - if diagnostics { - for &(enable, feature) in &all_rust_features { - let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); - match feature_state { - None => { - let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { - let gcc_features = to_gcc_features(sess, rust_feature); - if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) - { - Some(rust_feature) - } else { - None - } - }); - let unknown_feature = if let Some(rust_feature) = rust_feature { - UnknownCTargetFeature { - feature, - rust_feature: PossibleFeature::Some { rust_feature }, - } - } else { - UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } - }; - sess.dcx().emit_warn(unknown_feature); - } - Some(&(_, stability, _)) => { - stability.verify_feature_enabled_by_flag(sess, enable, feature); - } - } - - // FIXME(nagisa): figure out how to not allocate a full hashset here. - featsmap.insert(feature, enable); - } - } - - // Translate this into GCC features. - let feats = - all_rust_features.iter().flat_map(|&(enable, feature)| { - let enable_disable = if enable { '+' } else { '-' }; + target_features::flag_to_backend_features( + sess, + diagnostics, + |feature| to_gcc_features(sess, feature), + |feature, enable| { // We run through `to_gcc_features` when // passing requests down to GCC. This means that all in-language // features also work on the command line instead of having two // different names when the GCC name and the Rust name differ. - to_gcc_features(sess, feature) - .iter() - .flat_map(|feat| to_gcc_features(sess, feat).into_iter()) - .map(|feature| { - if enable_disable == '-' { - format!("-{}", feature) - } else { - feature.to_string() - } - }) - .collect::>() - }); - features.extend(feats); + features.extend( + to_gcc_features(sess, feature) + .iter() + .flat_map(|feat| to_gcc_features(sess, feat).into_iter()) + .map( + |feature| { + if !enable { format!("-{}", feature) } else { feature.to_string() } + }, + ), + ); + }, + ); - if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { - sess.dcx().emit_err(TargetFeatureDisableOrEnable { - features: f, - span: None, - missing_features: None, - }); - } + gcc_features_by_flags(sess, &mut features); + + // FIXME: LLVM also sets +reserve-x18 here under some conditions. features } diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 3faeb9b3b221..3885f18271f1 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -59,16 +59,6 @@ codegen_llvm_symbol_already_defined = codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple} codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err} -codegen_llvm_unknown_ctarget_feature = - unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future - .possible_feature = you might have meant: `{$rust_feature}` - .consider_filing_feature_request = consider filing a feature request - -codegen_llvm_unknown_ctarget_feature_prefix = - unknown feature specified for `-Ctarget-feature`: `{$feature}` - .note = features must begin with a `+` to enable or `-` to disable it - codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 8bc74fbec7ec..d50ad8a1a9cb 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -3,35 +3,11 @@ use std::path::Path; use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::Diagnostic; use rustc_span::Span; use crate::fluent_generated as fluent; -#[derive(Diagnostic)] -#[diag(codegen_llvm_unknown_ctarget_feature_prefix)] -#[note] -pub(crate) struct UnknownCTargetFeaturePrefix<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_llvm_unknown_ctarget_feature)] -#[note] -pub(crate) struct UnknownCTargetFeature<'a> { - pub feature: &'a str, - #[subdiagnostic] - pub rust_feature: PossibleFeature<'a>, -} - -#[derive(Subdiagnostic)] -pub(crate) enum PossibleFeature<'a> { - #[help(codegen_llvm_possible_feature)] - Some { rust_feature: &'a str }, - #[help(codegen_llvm_consider_filing_feature_request)] - None, -} - #[derive(Diagnostic)] #[diag(codegen_llvm_symbol_already_defined)] pub(crate) struct SymbolAlreadyDefined<'a> { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index f9ebf8616344..ee78c310b0df 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -7,25 +7,18 @@ use std::{ptr, slice, str}; use libc::c_int; use rustc_codegen_ssa::base::wants_wasm_eh; -use rustc_codegen_ssa::codegen_attrs::check_tied_features; use rustc_codegen_ssa::{TargetConfig, target_features}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_data_structures::unord::UnordSet; use rustc_fs_util::path_to_c_string; use rustc_middle::bug; use rustc_session::Session; use rustc_session::config::{PrintKind, PrintRequest}; -use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; -use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; -use crate::errors::{ - FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, -}; -use crate::llvm; +use crate::{errors, llvm}; static INIT: Once = Once::new(); @@ -194,15 +187,6 @@ impl<'a> LLVMFeature<'a> { ) -> Self { Self { llvm_feature_name, dependencies } } - - fn contains(&'a self, feat: &str) -> bool { - self.iter().any(|dep| dep == feat) - } - - fn iter(&'a self) -> impl Iterator { - let dependencies = self.dependencies.iter().map(|feat| feat.as_str()); - std::iter::once(self.llvm_feature_name).chain(dependencies) - } } impl<'a> IntoIterator for LLVMFeature<'a> { @@ -215,18 +199,22 @@ impl<'a> IntoIterator for LLVMFeature<'a> { } } -// WARNING: the features after applying `to_llvm_features` must be known -// to LLVM or the feature detection code will walk past the end of the feature -// array, leading to crashes. -// -// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td -// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. -// -// Check the current rustc fork of LLVM in the repo at https://github.com/rust-lang/llvm-project/. -// The commit in use can be found via the `llvm-project` submodule in -// https://github.com/rust-lang/rust/tree/master/src Though note that Rust can also be build with -// an external precompiled version of LLVM which might lead to failures if the oldest tested / -// supported LLVM version doesn't yet support the relevant intrinsics. +/// Convert a Rust feature name to an LLVM feature name. Returning `None` means the +/// feature should be skipped, usually because it is not supported by the current +/// LLVM version. +/// +/// WARNING: the features after applying `to_llvm_features` must be known +/// to LLVM or the feature detection code will walk past the end of the feature +/// array, leading to crashes. +/// +/// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td +/// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. +/// +/// Check the current rustc fork of LLVM in the repo at . +/// The commit in use can be found via the `llvm-project` submodule in +/// Though note that Rust can also be build with +/// an external precompiled version of LLVM which might lead to failures if the oldest tested / +/// supported LLVM version doesn't yet support the relevant intrinsics. pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option> { let arch = if sess.target.arch == "x86_64" { "x86" @@ -634,10 +622,9 @@ pub(crate) fn target_cpu(sess: &Session) -> &str { handle_native(cpu_name) } -fn llvm_features_by_flags(sess: &Session) -> Vec<&str> { - let mut features: Vec<&str> = Vec::new(); - retpoline_features_by_flags(sess, &mut features); - features +/// The target features for compiler flags other than `-Ctarget-features`. +fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { + target_features::retpoline_features_by_flags(sess, features); } /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, @@ -704,6 +691,8 @@ pub(crate) fn global_llvm_features( .split(',') .filter(|v| !v.is_empty()) // Drop +v8plus feature introduced in LLVM 20. + // (Hard-coded target features do not go through `to_llvm_feature` since they already + // are LLVM feature names, hence we need a special case here.) .filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0)) .map(String::from), ); @@ -714,86 +703,23 @@ pub(crate) fn global_llvm_features( // -Ctarget-features if !only_base_features { - let known_features = sess.target.rust_target_features(); - // Will only be filled when `diagnostics` is set! - let mut featsmap = FxHashMap::default(); - - // Compute implied features - let mut all_rust_features = vec![]; - for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) { - if let Some(feature) = feature.strip_prefix('+') { - all_rust_features.extend( - UnordSet::from(sess.target.implied_target_features(feature)) - .to_sorted_stable_ord() - .iter() - .map(|&&s| (true, s)), - ) - } else if let Some(feature) = feature.strip_prefix('-') { - // FIXME: Why do we not remove implied features on "-" here? - // We do the equivalent above in `target_config`. - // See . - all_rust_features.push((false, feature)); - } else if !feature.is_empty() { - if diagnostics { - sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature }); - } - } - } - // Remove features that are meant for rustc, not LLVM. - all_rust_features.retain(|(_, feature)| { - // Retain if it is not a rustc feature - !RUSTC_SPECIFIC_FEATURES.contains(feature) - }); - - // Check feature validity. - if diagnostics { - for &(enable, feature) in &all_rust_features { - let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); - match feature_state { - None => { - let rust_feature = - known_features.iter().find_map(|&(rust_feature, _, _)| { - let llvm_features = to_llvm_features(sess, rust_feature)?; - if llvm_features.contains(feature) - && !llvm_features.contains(rust_feature) - { - Some(rust_feature) - } else { - None - } - }); - let unknown_feature = if let Some(rust_feature) = rust_feature { - UnknownCTargetFeature { - feature, - rust_feature: PossibleFeature::Some { rust_feature }, - } - } else { - UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } - }; - sess.dcx().emit_warn(unknown_feature); - } - Some((_, stability, _)) => { - stability.verify_feature_enabled_by_flag(sess, enable, feature); - } - } - - // FIXME(nagisa): figure out how to not allocate a full hashset here. - featsmap.insert(feature, enable); - } - } - - // Translate this into LLVM features. - let feats = all_rust_features - .iter() - .filter_map(|&(enable, feature)| { + target_features::flag_to_backend_features( + sess, + diagnostics, + |feature| { + to_llvm_features(sess, feature) + .map(|f| SmallVec::<[&str; 2]>::from_iter(f.into_iter())) + .unwrap_or_default() + }, + |feature, enable| { let enable_disable = if enable { '+' } else { '-' }; // We run through `to_llvm_features` when // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two // different names when the LLVM name and the Rust name differ. - let llvm_feature = to_llvm_features(sess, feature)?; + let Some(llvm_feature) = to_llvm_features(sess, feature) else { return }; - Some( + features.extend( std::iter::once(format!( "{}{}", enable_disable, llvm_feature.llvm_feature_name @@ -808,23 +734,17 @@ pub(crate) fn global_llvm_features( }, )), ) - }) - .flatten(); - features.extend(feats); + }, + ); - if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) { - sess.dcx().emit_err(rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable { - features: f, - span: None, - missing_features: None, - }); - } + llvm_features_by_flags(sess, &mut features); } // -Zfixed-x18 + // FIXME: merge with `llvm_features_by_flags`. if sess.opts.unstable_opts.fixed_x18 { if sess.target.arch != "aarch64" { - sess.dcx().emit_fatal(FixedX18InvalidArch { arch: &sess.target.arch }); + sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch }); } else { features.push("+reserve-x18".into()); } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 5322fe58cf33..ffcce8b2ff4a 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -68,6 +68,11 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error} codegen_ssa_field_associated_value_expected = associated value expected for `{$name}` +codegen_ssa_forbidden_ctarget_feature = + target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} + .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +codegen_ssa_forbidden_ctarget_feature_issue = for more information, see issue #116344 + codegen_ssa_forbidden_target_feature_attr = target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason} @@ -368,8 +373,22 @@ codegen_ssa_unexpected_parameter_name = unexpected parameter name codegen_ssa_unknown_archive_kind = Don't know how to build archive of type: {$kind} +codegen_ssa_unknown_ctarget_feature = + unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}` + .note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future + .possible_feature = you might have meant: `{$rust_feature}` + .consider_filing_feature_request = consider filing a feature request + +codegen_ssa_unknown_ctarget_feature_prefix = + unknown feature specified for `-Ctarget-feature`: `{$feature}` + .note = features must begin with a `+` to enable or `-` to disable it + codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified +codegen_ssa_unstable_ctarget_feature = + unstable feature specified for `-Ctarget-feature`: `{$feature}` + .note = this feature is not stably supported; its behavior can change in the future + codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]` codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 188a9a98ce7a..78c8264eeb0d 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -7,7 +7,6 @@ use rustc_attr_data_structures::ReprAttr::ReprAlign; use rustc_attr_data_structures::{ AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr, }; -use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; @@ -19,13 +18,15 @@ use rustc_middle::mir::mono::Linkage; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{self as ty, TyCtxt}; +use rustc_session::lint; use rustc_session::parse::feature_err; -use rustc_session::{Session, lint}; use rustc_span::{Ident, Span, sym}; use rustc_target::spec::SanitizerSet; use crate::errors; -use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr}; +use crate::target_features::{ + check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr, +}; fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { use rustc_middle::mir::mono::Linkage::*; @@ -625,25 +626,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs } -/// Given a map from target_features to whether they are enabled or disabled, ensure only valid -/// combinations are allowed. -pub fn check_tied_features( - sess: &Session, - features: &FxHashMap<&str, bool>, -) -> Option<&'static [&'static str]> { - if !features.is_empty() { - for tied in sess.target.tied_target_features() { - // Tied features must be set to the same value, or not set at all - let mut tied_iter = tied.iter(); - let enabled = features.get(tied_iter.next().unwrap()); - if tied_iter.any(|f| enabled != features.get(f)) { - return Some(tied); - } - } - } - None -} - /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 5387b2a7f818..7c5d615aaff1 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1217,30 +1217,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> { pub error: String, } -pub struct TargetFeatureDisableOrEnable<'a> { - pub features: &'a [&'a str], - pub span: Option, - pub missing_features: Option, -} - -#[derive(Subdiagnostic)] -#[help(codegen_ssa_missing_features)] -pub struct MissingFeatures; - -impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { - let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable); - if let Some(span) = self.span { - diag.span(span); - }; - if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(missing_features); - } - diag.arg("features", self.features.join(", ")); - diag - } -} - #[derive(Diagnostic)] #[diag(codegen_ssa_aix_strip_not_used)] pub(crate) struct AixStripNotUsed; @@ -1283,3 +1259,68 @@ pub(crate) struct XcrunSdkPathWarning { #[derive(LintDiagnostic)] #[diag(codegen_ssa_aarch64_softfloat_neon)] pub(crate) struct Aarch64SoftfloatNeon; + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unknown_ctarget_feature_prefix)] +#[note] +pub(crate) struct UnknownCTargetFeaturePrefix<'a> { + pub feature: &'a str, +} + +#[derive(Subdiagnostic)] +pub(crate) enum PossibleFeature<'a> { + #[help(codegen_ssa_possible_feature)] + Some { rust_feature: &'a str }, + #[help(codegen_ssa_consider_filing_feature_request)] + None, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unknown_ctarget_feature)] +#[note] +pub(crate) struct UnknownCTargetFeature<'a> { + pub feature: &'a str, + #[subdiagnostic] + pub rust_feature: PossibleFeature<'a>, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unstable_ctarget_feature)] +#[note] +pub(crate) struct UnstableCTargetFeature<'a> { + pub feature: &'a str, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_forbidden_ctarget_feature)] +#[note] +#[note(codegen_ssa_forbidden_ctarget_feature_issue)] +pub(crate) struct ForbiddenCTargetFeature<'a> { + pub feature: &'a str, + pub enabled: &'a str, + pub reason: &'a str, +} + +pub struct TargetFeatureDisableOrEnable<'a> { + pub features: &'a [&'a str], + pub span: Option, + pub missing_features: Option, +} + +#[derive(Subdiagnostic)] +#[help(codegen_ssa_missing_features)] +pub struct MissingFeatures; + +impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { + let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable); + if let Some(span) = self.span { + diag.span(span); + }; + if let Some(missing_features) = self.missing_features { + diag.subdiagnostic(missing_features); + } + diag.arg("features", self.features.join(", ")); + diag + } +} diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 476671d68550..9cca6a3c72b1 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::InstructionSetAttr; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -9,11 +9,13 @@ use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_session::features::StabilityExt; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{self, RUSTC_SPECIAL_FEATURES, Stability}; +use rustc_target::target_features::{ + self, RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES, Stability, +}; +use smallvec::SmallVec; use crate::errors; @@ -68,7 +70,7 @@ pub(crate) fn from_target_feature_attr( // Only allow target features whose feature gates have been enabled // and which are permitted to be toggled. - if let Err(reason) = stability.is_toggle_permitted(tcx.sess) { + if let Err(reason) = stability.toggle_allowed() { tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { span: item.span(), feature, @@ -89,7 +91,7 @@ pub(crate) fn from_target_feature_attr( let feature_sym = Symbol::intern(feature); for &name in tcx.implied_target_features(feature_sym) { // But ensure the ABI does not forbid enabling this. - // Here we do assume that LLVM doesn't add even more implied features + // Here we do assume that the backend doesn't add even more implied features // we don't know about, at least no features that would have ABI effects! // We skip this logic in rustdoc, where we want to allow all target features of // all targets, so we can't check their ABI compatibility and anyway we are not @@ -251,6 +253,155 @@ pub fn cfg_target_feature( (f(true), f(false)) } +/// Given a map from target_features to whether they are enabled or disabled, ensure only valid +/// combinations are allowed. +pub fn check_tied_features( + sess: &Session, + features: &FxHashMap<&str, bool>, +) -> Option<&'static [&'static str]> { + if !features.is_empty() { + for tied in sess.target.tied_target_features() { + // Tied features must be set to the same value, or not set at all + let mut tied_iter = tied.iter(); + let enabled = features.get(tied_iter.next().unwrap()); + if tied_iter.any(|f| enabled != features.get(f)) { + return Some(tied); + } + } + } + None +} + +/// Translates the `-Ctarget-feature` flag into a backend target feature list. +/// +/// `to_backend_features` converts a Rust feature name into a list of backend feature names; this is +/// used for diagnostic purposes only. +/// +/// `extend_backend_features` extends the set of backend features (assumed to be in mutable state +/// accessible by that closure) to enable/disable the given Rust feature name. +pub fn flag_to_backend_features<'a, const N: usize>( + sess: &'a Session, + diagnostics: bool, + to_backend_features: impl Fn(&'a str) -> SmallVec<[&'a str; N]>, + mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool), +) { + let known_features = sess.target.rust_target_features(); + + // Compute implied features + let mut rust_features = vec![]; + for feature in sess.opts.cg.target_feature.split(',') { + if let Some(feature) = feature.strip_prefix('+') { + rust_features.extend( + UnordSet::from(sess.target.implied_target_features(feature)) + .to_sorted_stable_ord() + .iter() + .map(|&&s| (true, s)), + ) + } else if let Some(feature) = feature.strip_prefix('-') { + // FIXME: Why do we not remove implied features on "-" here? + // We do the equivalent above in `target_config`. + // See . + rust_features.push((false, feature)); + } else if !feature.is_empty() { + if diagnostics { + sess.dcx().emit_warn(errors::UnknownCTargetFeaturePrefix { feature }); + } + } + } + // Remove features that are meant for rustc, not the backend. + rust_features.retain(|(_, feature)| { + // Retain if it is not a rustc feature + !RUSTC_SPECIFIC_FEATURES.contains(feature) + }); + + // Check feature validity. + if diagnostics { + let mut featsmap = FxHashMap::default(); + + for &(enable, feature) in &rust_features { + let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); + match feature_state { + None => { + // This is definitely not a valid Rust feature name. Maybe it is a backend feature name? + // If so, give a better error message. + let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { + let backend_features = to_backend_features(rust_feature); + if backend_features.contains(&feature) + && !backend_features.contains(&rust_feature) + { + Some(rust_feature) + } else { + None + } + }); + let unknown_feature = if let Some(rust_feature) = rust_feature { + errors::UnknownCTargetFeature { + feature, + rust_feature: errors::PossibleFeature::Some { rust_feature }, + } + } else { + errors::UnknownCTargetFeature { + feature, + rust_feature: errors::PossibleFeature::None, + } + }; + sess.dcx().emit_warn(unknown_feature); + } + Some((_, stability, _)) => { + if let Err(reason) = stability.toggle_allowed() { + sess.dcx().emit_warn(errors::ForbiddenCTargetFeature { + feature, + enabled: if enable { "enabled" } else { "disabled" }, + reason, + }); + } else if stability.requires_nightly().is_some() { + // An unstable feature. Warn about using it. It makes little sense + // to hard-error here since we just warn about fully unknown + // features above. + sess.dcx().emit_warn(errors::UnstableCTargetFeature { feature }); + } + } + } + + // FIXME(nagisa): figure out how to not allocate a full hashset here. + featsmap.insert(feature, enable); + } + + if let Some(f) = check_tied_features(sess, &featsmap) { + sess.dcx().emit_err(errors::TargetFeatureDisableOrEnable { + features: f, + span: None, + missing_features: None, + }); + } + } + + // Add this to the backend features. + for (enable, feature) in rust_features { + extend_backend_features(feature, enable); + } +} + +/// Computes the backend target features to be added to account for retpoline flags. +/// Used by both LLVM and GCC since their target features are, conveniently, the same. +pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec) { + // -Zretpoline without -Zretpoline-external-thunk enables + // retpoline-indirect-branches and retpoline-indirect-calls target features + let unstable_opts = &sess.opts.unstable_opts; + if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk { + features.push("+retpoline-indirect-branches".into()); + features.push("+retpoline-indirect-calls".into()); + } + // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables + // retpoline-external-thunk, retpoline-indirect-branches and + // retpoline-indirect-calls target features + if unstable_opts.retpoline_external_thunk { + features.push("+retpoline-external-thunk".into()); + features.push("+retpoline-indirect-branches".into()); + features.push("+retpoline-indirect-calls".into()); + } +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { rust_target_features: |tcx, cnum| { diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 61953614c77e..528c52eace7c 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -40,11 +40,6 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it session_file_write_fail = failed to write `{$path}` due to error `{$err}` -session_forbidden_ctarget_feature = - target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} - .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -session_forbidden_ctarget_feature_issue = for more information, see issue #116344 - session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models @@ -137,9 +132,6 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote session_unleashed_feature_help_named = skipping check for `{$gate}` feature session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate -session_unstable_ctarget_feature = - unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = this feature is not stably supported; its behavior can change in the future session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` session_unsupported_crate_type_for_target = diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 9c591dcf619a..bf95014843d2 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -501,20 +501,3 @@ pub(crate) struct SoftFloatIgnored; #[note] #[note(session_soft_float_deprecated_issue)] pub(crate) struct SoftFloatDeprecated; - -#[derive(Diagnostic)] -#[diag(session_forbidden_ctarget_feature)] -#[note] -#[note(session_forbidden_ctarget_feature_issue)] -pub(crate) struct ForbiddenCTargetFeature<'a> { - pub feature: &'a str, - pub enabled: &'a str, - pub reason: &'a str, -} - -#[derive(Diagnostic)] -#[diag(session_unstable_ctarget_feature)] -#[note] -pub(crate) struct UnstableCTargetFeature<'a> { - pub feature: &'a str, -} diff --git a/compiler/rustc_session/src/features.rs b/compiler/rustc_session/src/features.rs deleted file mode 100644 index 70a088a236f7..000000000000 --- a/compiler/rustc_session/src/features.rs +++ /dev/null @@ -1,59 +0,0 @@ -use rustc_target::target_features::Stability; - -use crate::Session; -use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature}; - -pub trait StabilityExt { - /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. - /// Otherwise, some features also may only be enabled by flag (target modifier). - /// (It might still be nightly-only even if this returns `true`, so make sure to also check - /// `requires_nightly`.) - fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>; - - /// Check that feature is correctly enabled/disabled by command line flag (emits warnings) - fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str); -} - -impl StabilityExt for Stability { - fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> { - match self { - Stability::Forbidden { reason } => Err(reason), - Stability::TargetModifierOnly { reason, flag } => { - if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) } - } - _ => Ok(()), - } - } - fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) { - if let Err(reason) = self.is_toggle_permitted(sess) { - sess.dcx().emit_warn(ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if self.requires_nightly().is_some() { - // An unstable feature. Warn about using it. It makes little sense - // to hard-error here since we just warn about fully unknown - // features above. - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); - } - } -} - -pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) { - // -Zretpoline without -Zretpoline-external-thunk enables - // retpoline-indirect-branches and retpoline-indirect-calls target features - let unstable_opts = &sess.opts.unstable_opts; - if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk { - features.push("+retpoline-indirect-branches"); - features.push("+retpoline-indirect-calls"); - } - // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables - // retpoline-external-thunk, retpoline-indirect-branches and - // retpoline-indirect-calls target features - if unstable_opts.retpoline_external_thunk { - features.push("+retpoline-external-thunk"); - features.push("+retpoline-indirect-branches"); - features.push("+retpoline-indirect-calls"); - } -} diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 4added19e56e..5e5872ee0681 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -29,7 +29,6 @@ pub use session::*; pub mod output; pub use getopts; -pub mod features; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 31b4237d3b2e..7fef942525b9 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -290,14 +290,6 @@ macro_rules! top_level_options { mods.sort_by(|a, b| a.opt.cmp(&b.opt)); mods } - - pub fn target_feature_flag_enabled(&self, flag: &str) -> bool { - match flag { - "retpoline" => self.unstable_opts.retpoline, - "retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk, - _ => false, - } - } } ); } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index a1eac1fba25d..c18a2c1ebef5 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -34,9 +34,6 @@ pub enum Stability { /// particular for features are actually ABI configuration flags (not all targets are as nice as /// RISC-V and have an explicit way to set the ABI separate from target features). Forbidden { reason: &'static str }, - /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set - /// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules. - TargetModifierOnly { reason: &'static str, flag: &'static str }, } use Stability::*; @@ -52,7 +49,6 @@ impl HashStable for Stability { Stability::Forbidden { reason } => { reason.hash_stable(hcx, hasher); } - Stability::TargetModifierOnly { .. } => {} } } } @@ -62,7 +58,7 @@ impl Stability { /// (It might still be nightly-only even if this returns `true`, so make sure to also check /// `requires_nightly`.) pub fn in_cfg(&self) -> bool { - !matches!(self, Stability::Forbidden { .. }) + matches!(self, Stability::Stable | Stability::Unstable { .. }) } /// Returns the nightly feature that is required to toggle this target feature via @@ -78,7 +74,16 @@ impl Stability { Stability::Unstable(nightly_feature) => Some(nightly_feature), Stability::Stable { .. } => None, Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"), - Stability::TargetModifierOnly { .. } => None, + } + } + + /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. + /// (It might still be nightly-only even if this returns `true`, so make sure to also check + /// `requires_nightly`.) + pub fn toggle_allowed(&self) -> Result<(), &'static str> { + match self { + Stability::Unstable(_) | Stability::Stable { .. } => Ok(()), + Stability::Forbidden { reason } => Err(reason), } } } @@ -450,26 +455,19 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("rdseed", Stable, &[]), ( "retpoline-external-thunk", - Stability::TargetModifierOnly { + Stability::Forbidden { reason: "use `retpoline-external-thunk` target modifier flag instead", - flag: "retpoline-external-thunk", }, &[], ), ( "retpoline-indirect-branches", - Stability::TargetModifierOnly { - reason: "use `retpoline` target modifier flag instead", - flag: "retpoline", - }, + Stability::Forbidden { reason: "use `retpoline` target modifier flag instead" }, &[], ), ( "retpoline-indirect-calls", - Stability::TargetModifierOnly { - reason: "use `retpoline` target modifier flag instead", - flag: "retpoline", - }, + Stability::Forbidden { reason: "use `retpoline` target modifier flag instead" }, &[], ), ("rtm", Unstable(sym::rtm_target_feature), &[]), diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 2feadce26d09..29c63a391e21 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -18,7 +18,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_session::features::StabilityExt; use rustc_span::def_id::LOCAL_CRATE; use rustdoc_json_types as types; // It's important to use the FxHashMap from rustdoc_json_types here, instead of @@ -148,7 +147,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { .copied() .filter(|(_, stability, _)| { // Describe only target features which the user can toggle - stability.is_toggle_permitted(sess).is_ok() + stability.toggle_allowed().is_ok() }) .map(|(name, stability, implied_features)| { types::TargetFeature { @@ -164,7 +163,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { // Imply only target features which the user can toggle feature_stability .get(name) - .map(|stability| stability.is_toggle_permitted(sess).is_ok()) + .map(|stability| stability.toggle_allowed().is_ok()) .unwrap_or(false) }) .map(String::from) diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index f29a41d6a8e2..ec81ba2e3d89 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -212,9 +212,6 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `relax` `relaxed-simd` `reserve-x18` -`retpoline-external-thunk` -`retpoline-indirect-branches` -`retpoline-indirect-calls` `rtm` `sb` `scq` From e46c234ca4ccbad085f11de7ca1cd25a40431b22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 May 2025 11:18:48 +0200 Subject: [PATCH 123/356] unify two -Ctarget-feature parsers This does change the logic a bit: previously, we didn't forward reverse implications of negated features to the backend, instead relying on the backend to handle the implication itself. --- .../rustc_codegen_ssa/src/target_features.rs | 239 ++++++++++-------- .../target-feature-negative-implication.rs | 20 ++ tests/codegen/target-feature-overrides.rs | 5 +- tests/codegen/tied-features-strength.rs | 15 +- ...le-target-feature-flag-enable.riscv.stderr | 10 +- ...incompatible-target-feature-flag-enable.rs | 2 - 6 files changed, 170 insertions(+), 121 deletions(-) create mode 100644 tests/codegen/target-feature-negative-implication.rs diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 9cca6a3c72b1..41d8b8d8cbfe 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -159,6 +159,58 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, } } +/// Parse the value of `-Ctarget-feature`, also expanding implied features, +/// and call the closure for each (expanded) Rust feature. If the list contains +/// a syntactically invalid item (not starting with `+`/`-`), the error callback is invoked. +fn parse_rust_feature_flag<'a>( + sess: &Session, + target_feature_flag: &'a str, + err_callback: impl Fn(&'a str), + mut callback: impl FnMut( + /* base_feature */ &'a str, + /* with_implied */ FxHashSet<&'a str>, + /* enable */ bool, + ), +) { + // A cache for the backwards implication map. + let mut inverse_implied_features: Option>> = None; + + for feature in target_feature_flag.split(',') { + if let Some(base_feature) = feature.strip_prefix('+') { + callback(base_feature, sess.target.implied_target_features(base_feature), true) + } else if let Some(base_feature) = feature.strip_prefix('-') { + // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical contraposition. + // So we have to find all the reverse implications of `base_feature` and disable them, too. + + let inverse_implied_features = inverse_implied_features.get_or_insert_with(|| { + let mut set: FxHashMap<&str, FxHashSet<&str>> = FxHashMap::default(); + for (f, _, is) in sess.target.rust_target_features() { + for i in is.iter() { + set.entry(i).or_default().insert(f); + } + } + set + }); + + // Inverse mplied target features have their own inverse implied target features, so we + // traverse the map until there are no more features to add. + let mut features = FxHashSet::default(); + let mut new_features = vec![base_feature]; + while let Some(new_feature) = new_features.pop() { + if features.insert(new_feature) { + if let Some(implied_features) = inverse_implied_features.get(&new_feature) { + new_features.extend(implied_features) + } + } + } + + callback(base_feature, features, false) + } else if !feature.is_empty() { + err_callback(feature) + } + } +} + /// Utility function for a codegen backend to compute `cfg(target_feature)`, or more specifically, /// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and /// 2nd component of the return value, respectively). @@ -175,7 +227,7 @@ pub fn cfg_target_feature( ) -> (Vec, Vec) { // Compute which of the known target features are enabled in the 'base' target machine. We only // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. - let mut features: FxHashSet = sess + let mut features: UnordSet = sess .target .rust_target_features() .iter() @@ -190,43 +242,23 @@ pub fn cfg_target_feature( .collect(); // Add enabled and remove disabled features. - for (enabled, feature) in - target_feature_flag.split(',').filter_map(|s| match s.chars().next() { - Some('+') => Some((true, Symbol::intern(&s[1..]))), - Some('-') => Some((false, Symbol::intern(&s[1..]))), - _ => None, - }) - { - if enabled { - // Also add all transitively implied features. - - // We don't care about the order in `features` since the only thing we use it for is the - // `features.contains` below. + parse_rust_feature_flag( + sess, + target_feature_flag, + /* err_callback */ |_| {}, + |_base_feature, new_features, enabled| { + // Iteration order is irrelevant since this only influences an `UnordSet`. #[allow(rustc::potential_query_instability)] - features.extend( - sess.target - .implied_target_features(feature.as_str()) - .iter() - .map(|s| Symbol::intern(s)), - ); - } 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| { - if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) { - // 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 + if enabled { + features.extend(new_features.into_iter().map(|f| Symbol::intern(f))); + } else { + // Remove `new_features` from `features`. + for new in new_features { + features.remove(&Symbol::intern(new)); } - }); - } - } + } + }, + ); // Filter enabled features based on feature gates. let f = |allow_unstable| { @@ -289,85 +321,82 @@ pub fn flag_to_backend_features<'a, const N: usize>( // Compute implied features let mut rust_features = vec![]; - for feature in sess.opts.cg.target_feature.split(',') { - if let Some(feature) = feature.strip_prefix('+') { - rust_features.extend( - UnordSet::from(sess.target.implied_target_features(feature)) - .to_sorted_stable_ord() - .iter() - .map(|&&s| (true, s)), - ) - } else if let Some(feature) = feature.strip_prefix('-') { - // FIXME: Why do we not remove implied features on "-" here? - // We do the equivalent above in `target_config`. - // See . - rust_features.push((false, feature)); - } else if !feature.is_empty() { + parse_rust_feature_flag( + sess, + &sess.opts.cg.target_feature, + /* err_callback */ + |feature| { if diagnostics { sess.dcx().emit_warn(errors::UnknownCTargetFeaturePrefix { feature }); } - } - } - // Remove features that are meant for rustc, not the backend. - rust_features.retain(|(_, feature)| { - // Retain if it is not a rustc feature - !RUSTC_SPECIFIC_FEATURES.contains(feature) - }); + }, + |base_feature, new_features, enable| { + // Skip features that are meant for rustc, not the backend. + if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { + return; + } - // Check feature validity. - if diagnostics { - let mut featsmap = FxHashMap::default(); - - for &(enable, feature) in &rust_features { - let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature); - match feature_state { - None => { - // This is definitely not a valid Rust feature name. Maybe it is a backend feature name? - // If so, give a better error message. - let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { - let backend_features = to_backend_features(rust_feature); - if backend_features.contains(&feature) - && !backend_features.contains(&rust_feature) - { - Some(rust_feature) + rust_features.extend( + UnordSet::from(new_features).to_sorted_stable_ord().iter().map(|&&s| (enable, s)), + ); + // Check feature validity. + if diagnostics { + let feature_state = known_features.iter().find(|&&(v, _, _)| v == base_feature); + match feature_state { + None => { + // This is definitely not a valid Rust feature name. Maybe it is a backend feature name? + // If so, give a better error message. + let rust_feature = + known_features.iter().find_map(|&(rust_feature, _, _)| { + let backend_features = to_backend_features(rust_feature); + if backend_features.contains(&base_feature) + && !backend_features.contains(&rust_feature) + { + Some(rust_feature) + } else { + None + } + }); + let unknown_feature = if let Some(rust_feature) = rust_feature { + errors::UnknownCTargetFeature { + feature: base_feature, + rust_feature: errors::PossibleFeature::Some { rust_feature }, + } } else { - None + errors::UnknownCTargetFeature { + feature: base_feature, + rust_feature: errors::PossibleFeature::None, + } + }; + sess.dcx().emit_warn(unknown_feature); + } + Some((_, stability, _)) => { + if let Err(reason) = stability.toggle_allowed() { + sess.dcx().emit_warn(errors::ForbiddenCTargetFeature { + feature: base_feature, + enabled: if enable { "enabled" } else { "disabled" }, + reason, + }); + } else if stability.requires_nightly().is_some() { + // An unstable feature. Warn about using it. It makes little sense + // to hard-error here since we just warn about fully unknown + // features above. + sess.dcx().emit_warn(errors::UnstableCTargetFeature { + feature: base_feature, + }); } - }); - let unknown_feature = if let Some(rust_feature) = rust_feature { - errors::UnknownCTargetFeature { - feature, - rust_feature: errors::PossibleFeature::Some { rust_feature }, - } - } else { - errors::UnknownCTargetFeature { - feature, - rust_feature: errors::PossibleFeature::None, - } - }; - sess.dcx().emit_warn(unknown_feature); - } - Some((_, stability, _)) => { - if let Err(reason) = stability.toggle_allowed() { - sess.dcx().emit_warn(errors::ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. It makes little sense - // to hard-error here since we just warn about fully unknown - // features above. - sess.dcx().emit_warn(errors::UnstableCTargetFeature { feature }); } } } + }, + ); - // FIXME(nagisa): figure out how to not allocate a full hashset here. - featsmap.insert(feature, enable); - } - - if let Some(f) = check_tied_features(sess, &featsmap) { + if diagnostics { + // FIXME(nagisa): figure out how to not allocate a full hashmap here. + if let Some(f) = check_tied_features( + sess, + &FxHashMap::from_iter(rust_features.iter().map(|&(enable, feature)| (feature, enable))), + ) { sess.dcx().emit_err(errors::TargetFeatureDisableOrEnable { features: f, span: None, diff --git a/tests/codegen/target-feature-negative-implication.rs b/tests/codegen/target-feature-negative-implication.rs new file mode 100644 index 000000000000..36cd82dd8cf5 --- /dev/null +++ b/tests/codegen/target-feature-negative-implication.rs @@ -0,0 +1,20 @@ +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: --target=x86_64-unknown-linux-gnu +//@ compile-flags: -Ctarget-feature=-avx2 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub unsafe fn banana() { + // CHECK-LABEL: @banana() + // CHECK-SAME: [[BANANAATTRS:#[0-9]+]] { +} + +// CHECK: attributes [[BANANAATTRS]] +// CHECK-SAME: -avx512 diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs index 0fc1e0136b3f..eb19b0de2fa8 100644 --- a/tests/codegen/target-feature-overrides.rs +++ b/tests/codegen/target-feature-overrides.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength //@ add-core-stubs //@ revisions: COMPAT INCOMPAT //@ needs-llvm-components: x86 @@ -39,7 +40,7 @@ pub unsafe fn banana() -> u32 { // CHECK: attributes [[APPLEATTRS]] // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}" +// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}},+avx{{(,\+[^,]+)*}}" // CHECK: attributes [[BANANAATTRS]] // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}" -// INCOMPAT-SAME: "target-features"="-avx2,-avx" +// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}}" diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs index 6be0e21e0ef3..81499c070d19 100644 --- a/tests/codegen/tied-features-strength.rs +++ b/tests/codegen/tied-features-strength.rs @@ -4,14 +4,23 @@ //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 +// Rust made SVE require neon. //@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0 -// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" } +// ENABLE_SVE: attributes #0 +// ENABLE_SVE-SAME: +neon +// ENABLE_SVE-SAME: +sve +// However, disabling SVE does not disable neon. //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0 -// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-sve,?)|(\+neon,?))*}}" } +// DISABLE_SVE: attributes #0 +// DISABLE_SVE-NOT: -neon +// DISABLE_SVE-SAME: -sve +// OTOH, neon fn `fp-armv8` are fully tied; toggling neon must toggle `fp-armv8` the same way. //@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0 -// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-fp-armv8,?)|(-neon,?))*}}" } +// DISABLE_NEON: attributes #0 +// DISABLE_NEON-SAME: -neon +// DISABLE_NEON-SAME: -fp-armv8 //@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0 // ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}}" } diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr index 2dca0c220332..0b2d71f97d0d 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr +++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr @@ -7,13 +7,5 @@ warning: unstable feature specified for `-Ctarget-feature`: `d` | = note: this feature is not stably supported; its behavior can change in the future -warning: unstable feature specified for `-Ctarget-feature`: `f` - | - = note: this feature is not stably supported; its behavior can change in the future - -warning: unstable feature specified for `-Ctarget-feature`: `zicsr` - | - = note: this feature is not stably supported; its behavior can change in the future - -warning: 4 warnings emitted +warning: 2 warnings emitted diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs index 302cceccf693..1006b078bab3 100644 --- a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs +++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs @@ -24,5 +24,3 @@ pub trait Freeze {} //~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly //~? WARN unstable feature specified for `-Ctarget-feature` -//[riscv]~? WARN unstable feature specified for `-Ctarget-feature` -//[riscv]~? WARN unstable feature specified for `-Ctarget-feature` From 8bec5bb5adaa1f5a0bc3683fee5f77a5fdac539b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 May 2025 12:50:48 +0200 Subject: [PATCH 124/356] cg_gcc: properly populate cfg(target_features) with -Ctarget-features --- compiler/rustc_codegen_gcc/src/lib.rs | 39 ++++++++----------- compiler/rustc_codegen_llvm/src/llvm_util.rs | 32 +++++++-------- .../rustc_codegen_ssa/src/target_features.rs | 13 ++----- 3 files changed, 37 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f5ad28681c79..a912678ef2a1 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -102,10 +102,9 @@ use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, }; use rustc_codegen_ssa::base::codegen_crate; +use rustc_codegen_ssa::target_features::cfg_target_feature; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods}; -use rustc_codegen_ssa::{ - CodegenResults, CompiledModule, ModuleCodegen, TargetConfig, target_features, -}; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::DiagCtxtHandle; @@ -478,25 +477,21 @@ fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { /// Returns the features that should be set in `cfg(target_feature)`. fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig { - let (unstable_target_features, target_features) = target_features::cfg_target_feature( - sess, - /* FIXME: we ignore `-Ctarget-feature` */ "", - |feature| { - // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. - if feature == "neon" { - return false; - } - target_info.cpu_supports(feature) - // cSpell:disable - /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, - avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, - bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, - sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves - */ - // cSpell:enable - }, - ); + let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| { + // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. + if feature == "neon" { + return false; + } + target_info.cpu_supports(feature) + // cSpell:disable + /* + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, + avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, + bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, + sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves + */ + // cSpell:enable + }); let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16); let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ee78c310b0df..bc2165fa8290 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -7,6 +7,7 @@ use std::{ptr, slice, str}; use libc::c_int; use rustc_codegen_ssa::base::wants_wasm_eh; +use rustc_codegen_ssa::target_features::cfg_target_feature; use rustc_codegen_ssa::{TargetConfig, target_features}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::small_c_str::SmallCStr; @@ -331,24 +332,23 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { // by LLVM. let target_machine = create_informational_target_machine(sess, true); - let (unstable_target_features, target_features) = - target_features::cfg_target_feature(sess, &sess.opts.cg.target_feature, |feature| { - if let Some(feat) = to_llvm_features(sess, feature) { - // All the LLVM features this expands to must be enabled. - for llvm_feature in feat { - let cstr = SmallCStr::new(llvm_feature); - // `LLVMRustHasFeature` is moderately expensive. On targets with many - // features (e.g. x86) these calls take a non-trivial fraction of runtime - // when compiling very small programs. - if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } { - return false; - } + let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| { + if let Some(feat) = to_llvm_features(sess, feature) { + // All the LLVM features this expands to must be enabled. + for llvm_feature in feat { + let cstr = SmallCStr::new(llvm_feature); + // `LLVMRustHasFeature` is moderately expensive. On targets with many + // features (e.g. x86) these calls take a non-trivial fraction of runtime + // when compiling very small programs. + if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } { + return false; } - true - } else { - false } - }); + true + } else { + false + } + }); let mut cfg = TargetConfig { target_features, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 41d8b8d8cbfe..e29cdbb968ed 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -163,8 +163,7 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, /// and call the closure for each (expanded) Rust feature. If the list contains /// a syntactically invalid item (not starting with `+`/`-`), the error callback is invoked. fn parse_rust_feature_flag<'a>( - sess: &Session, - target_feature_flag: &'a str, + sess: &'a Session, err_callback: impl Fn(&'a str), mut callback: impl FnMut( /* base_feature */ &'a str, @@ -175,7 +174,7 @@ fn parse_rust_feature_flag<'a>( // A cache for the backwards implication map. let mut inverse_implied_features: Option>> = None; - for feature in target_feature_flag.split(',') { + for feature in sess.opts.cg.target_feature.split(',') { if let Some(base_feature) = feature.strip_prefix('+') { callback(base_feature, sess.target.implied_target_features(base_feature), true) } else if let Some(base_feature) = feature.strip_prefix('-') { @@ -215,15 +214,13 @@ fn parse_rust_feature_flag<'a>( /// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and /// 2nd component of the return value, respectively). /// -/// `target_feature_flag` is the value of `-Ctarget-feature` (giving the caller a chance to override it). /// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is enabled /// in the "base" target machine, i.e., without applying `-Ctarget-feature`. /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. pub fn cfg_target_feature( sess: &Session, - target_feature_flag: &str, - mut is_feature_enabled: impl FnMut(&str) -> bool, + mut target_base_has_feature: impl FnMut(&str) -> bool, ) -> (Vec, Vec) { // Compute which of the known target features are enabled in the 'base' target machine. We only // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. @@ -236,7 +233,7 @@ pub fn cfg_target_feature( if RUSTC_SPECIAL_FEATURES.contains(feature) { return true; } - is_feature_enabled(feature) + target_base_has_feature(feature) }) .map(|(feature, _, _)| Symbol::intern(feature)) .collect(); @@ -244,7 +241,6 @@ pub fn cfg_target_feature( // Add enabled and remove disabled features. parse_rust_feature_flag( sess, - target_feature_flag, /* err_callback */ |_| {}, |_base_feature, new_features, enabled| { // Iteration order is irrelevant since this only influences an `UnordSet`. @@ -323,7 +319,6 @@ pub fn flag_to_backend_features<'a, const N: usize>( let mut rust_features = vec![]; parse_rust_feature_flag( sess, - &sess.opts.cg.target_feature, /* err_callback */ |feature| { if diagnostics { From 0c4b0f57268b1e866eb7eb720caf815efcb85aeb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jun 2025 14:04:39 +0200 Subject: [PATCH 125/356] line-wrap and extend comments, typos --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 10 ++++---- .../rustc_codegen_ssa/src/target_features.rs | 25 ++++++++++++------- compiler/rustc_target/src/target_features.rs | 1 + 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index bc2165fa8290..676890b36ebf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -211,11 +211,11 @@ impl<'a> IntoIterator for LLVMFeature<'a> { /// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td /// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. /// -/// Check the current rustc fork of LLVM in the repo at . -/// The commit in use can be found via the `llvm-project` submodule in -/// Though note that Rust can also be build with -/// an external precompiled version of LLVM which might lead to failures if the oldest tested / -/// supported LLVM version doesn't yet support the relevant intrinsics. +/// Check the current rustc fork of LLVM in the repo at +/// . The commit in use can be found via the +/// `llvm-project` submodule in Though note that +/// Rust can also be build with an external precompiled version of LLVM which might lead to failures +/// if the oldest tested / supported LLVM version doesn't yet support the relevant intrinsics. pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option> { let arch = if sess.target.arch == "x86_64" { "x86" diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index e29cdbb968ed..f4f03c1a16bd 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -178,8 +178,9 @@ fn parse_rust_feature_flag<'a>( if let Some(base_feature) = feature.strip_prefix('+') { callback(base_feature, sess.target.implied_target_features(base_feature), true) } else if let Some(base_feature) = feature.strip_prefix('-') { - // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical contraposition. - // So we have to find all the reverse implications of `base_feature` and disable them, too. + // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical + // contraposition. So we have to find all the reverse implications of `base_feature` and + // disable them, too. let inverse_implied_features = inverse_implied_features.get_or_insert_with(|| { let mut set: FxHashMap<&str, FxHashSet<&str>> = FxHashMap::default(); @@ -191,7 +192,7 @@ fn parse_rust_feature_flag<'a>( set }); - // Inverse mplied target features have their own inverse implied target features, so we + // Inverse implied target features have their own inverse implied target features, so we // traverse the map until there are no more features to add. let mut features = FxHashSet::default(); let mut new_features = vec![base_feature]; @@ -214,8 +215,8 @@ fn parse_rust_feature_flag<'a>( /// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and /// 2nd component of the return value, respectively). /// -/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is enabled -/// in the "base" target machine, i.e., without applying `-Ctarget-feature`. +/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is +/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`. /// /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. pub fn cfg_target_feature( @@ -231,6 +232,8 @@ pub fn cfg_target_feature( .filter(|(feature, _, _)| { // Skip checking special features, those are not known to the backend. if RUSTC_SPECIAL_FEATURES.contains(feature) { + // FIXME: `true` here means we'll always think the feature is enabled. + // Does that really make sense? return true; } target_base_has_feature(feature) @@ -241,7 +244,10 @@ pub fn cfg_target_feature( // Add enabled and remove disabled features. parse_rust_feature_flag( sess, - /* err_callback */ |_| {}, + /* err_callback */ + |_| { + // Errors are already emitted in `flag_to_backend_features`; avoid duplicates. + }, |_base_feature, new_features, enabled| { // Iteration order is irrelevant since this only influences an `UnordSet`. #[allow(rustc::potential_query_instability)] @@ -339,8 +345,8 @@ pub fn flag_to_backend_features<'a, const N: usize>( let feature_state = known_features.iter().find(|&&(v, _, _)| v == base_feature); match feature_state { None => { - // This is definitely not a valid Rust feature name. Maybe it is a backend feature name? - // If so, give a better error message. + // This is definitely not a valid Rust feature name. Maybe it is a backend + // feature name? If so, give a better error message. let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| { let backend_features = to_backend_features(rust_feature); @@ -452,7 +458,8 @@ pub(crate) fn provide(providers: &mut Providers) { Stability::Unstable { .. } | Stability::Forbidden { .. }, ) | (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => { - // The stability in the entry is at least as good as the new one, just keep it. + // The stability in the entry is at least as good as the new + // one, just keep it. } _ => { // Overwrite stabilite. diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index c18a2c1ebef5..f7582f8a3440 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -730,6 +730,7 @@ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ #[rustfmt::skip] const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start + // For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker ("backchain", Unstable(sym::s390x_target_feature), &[]), ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]), ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]), From 342f07ab31d523c17eb1fb8fe8aee48674309e23 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 18 Jun 2025 20:55:52 -0400 Subject: [PATCH 126/356] Add a test for `concat_bytes!` with C strings Also ensure the suggestions are checked, since this will be updated. --- tests/ui/macros/concat-bytes-error.rs | 24 +++++++ tests/ui/macros/concat-bytes-error.stderr | 88 +++++++++++++++-------- 2 files changed, 83 insertions(+), 29 deletions(-) diff --git a/tests/ui/macros/concat-bytes-error.rs b/tests/ui/macros/concat-bytes-error.rs index db5d3cab0bd8..f7f291f446ff 100644 --- a/tests/ui/macros/concat-bytes-error.rs +++ b/tests/ui/macros/concat-bytes-error.rs @@ -1,20 +1,43 @@ +//@ edition: 2021 +// 2021 edition for C string literals + #![feature(concat_bytes)] fn main() { + // Identifiers concat_bytes!(pie); //~ ERROR expected a byte literal concat_bytes!(pie, pie); //~ ERROR expected a byte literal + + // String literals concat_bytes!("tnrsi", "tnri"); //~ ERROR cannot concatenate string literals + //~^ SUGGESTION b"tnrsi" + concat_bytes!(r"tnrsi", r"tnri"); //~ ERROR cannot concatenate string literals + //~^ SUGGESTION br"tnrsi" + concat_bytes!(r#"tnrsi"#, r###"tnri"###); //~ ERROR cannot concatenate string literals + //~^ SUGGESTION br#"tnrsi"# + concat_bytes!(c"tnrsi", c"tnri"); //~ ERROR cannot concatenate a C string literal + concat_bytes!(cr"tnrsi", cr"tnri"); //~ ERROR cannot concatenate a C string literal + concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); //~ ERROR cannot concatenate a C string literal + + // Other literals concat_bytes!(2.8); //~ ERROR cannot concatenate float literals concat_bytes!(300); //~ ERROR cannot concatenate numeric literals + //~^ SUGGESTION [300] concat_bytes!('a'); //~ ERROR cannot concatenate character literals + //~^ SUGGESTION b'a' concat_bytes!(true, false); //~ ERROR cannot concatenate boolean literals concat_bytes!(42, b"va", b'l'); //~ ERROR cannot concatenate numeric literals + //~^ SUGGESTION [42] concat_bytes!(42, b"va", b'l', [1, 2]); //~ ERROR cannot concatenate numeric literals + //~^ SUGGESTION [42] + + // Nested items concat_bytes!([ "hi", //~ ERROR cannot concatenate string literals ]); concat_bytes!([ 'a', //~ ERROR cannot concatenate character literals + //~^ SUGGESTION b'a' ]); concat_bytes!([ true, //~ ERROR cannot concatenate boolean literals @@ -38,6 +61,7 @@ fn main() { [5, 6, 7], //~ ERROR cannot concatenate doubly nested array ]); concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals + //~^ SUGGESTION [5u16] concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8` concat_bytes!([3; ()]); //~ ERROR repeat count is not a positive number concat_bytes!([3; -2]); //~ ERROR repeat count is not a positive number diff --git a/tests/ui/macros/concat-bytes-error.stderr b/tests/ui/macros/concat-bytes-error.stderr index 3f2c64922e34..fd498a023a18 100644 --- a/tests/ui/macros/concat-bytes-error.stderr +++ b/tests/ui/macros/concat-bytes-error.stderr @@ -1,5 +1,5 @@ error: expected a byte literal - --> $DIR/concat-bytes-error.rs:4:19 + --> $DIR/concat-bytes-error.rs:8:19 | LL | concat_bytes!(pie); | ^^^ @@ -7,7 +7,7 @@ LL | concat_bytes!(pie); = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: expected a byte literal - --> $DIR/concat-bytes-error.rs:5:19 + --> $DIR/concat-bytes-error.rs:9:19 | LL | concat_bytes!(pie, pie); | ^^^ ^^^ @@ -15,85 +15,115 @@ LL | concat_bytes!(pie, pie); = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate string literals - --> $DIR/concat-bytes-error.rs:6:19 + --> $DIR/concat-bytes-error.rs:12:19 | LL | concat_bytes!("tnrsi", "tnri"); | ^^^^^^^ help: try using a byte string: `b"tnrsi"` +error: cannot concatenate string literals + --> $DIR/concat-bytes-error.rs:14:19 + | +LL | concat_bytes!(r"tnrsi", r"tnri"); + | ^^^^^^^^ help: try using a byte string: `br"tnrsi"` + +error: cannot concatenate string literals + --> $DIR/concat-bytes-error.rs:16:19 + | +LL | concat_bytes!(r#"tnrsi"#, r###"tnri"###); + | ^^^^^^^^^^ help: try using a byte string: `br#"tnrsi"#` + +error: cannot concatenate a C string literal + --> $DIR/concat-bytes-error.rs:18:19 + | +LL | concat_bytes!(c"tnrsi", c"tnri"); + | ^^^^^^^^ + +error: cannot concatenate a C string literal + --> $DIR/concat-bytes-error.rs:19:19 + | +LL | concat_bytes!(cr"tnrsi", cr"tnri"); + | ^^^^^^^^^ + +error: cannot concatenate a C string literal + --> $DIR/concat-bytes-error.rs:20:19 + | +LL | concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); + | ^^^^^^^^^^^ + error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:7:19 + --> $DIR/concat-bytes-error.rs:23:19 | LL | concat_bytes!(2.8); | ^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:8:19 + --> $DIR/concat-bytes-error.rs:24:19 | LL | concat_bytes!(300); | ^^^ help: try wrapping the number in an array: `[300]` error: cannot concatenate character literals - --> $DIR/concat-bytes-error.rs:9:19 + --> $DIR/concat-bytes-error.rs:26:19 | LL | concat_bytes!('a'); | ^^^ help: try using a byte character: `b'a'` error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:10:19 + --> $DIR/concat-bytes-error.rs:28:19 | LL | concat_bytes!(true, false); | ^^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:11:19 + --> $DIR/concat-bytes-error.rs:29:19 | LL | concat_bytes!(42, b"va", b'l'); | ^^ help: try wrapping the number in an array: `[42]` error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:12:19 + --> $DIR/concat-bytes-error.rs:31:19 | LL | concat_bytes!(42, b"va", b'l', [1, 2]); | ^^ help: try wrapping the number in an array: `[42]` error: cannot concatenate string literals - --> $DIR/concat-bytes-error.rs:14:9 + --> $DIR/concat-bytes-error.rs:36:9 | LL | "hi", | ^^^^ error: cannot concatenate character literals - --> $DIR/concat-bytes-error.rs:17:9 + --> $DIR/concat-bytes-error.rs:39:9 | LL | 'a', | ^^^ help: try using a byte character: `b'a'` error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:20:9 + --> $DIR/concat-bytes-error.rs:43:9 | LL | true, | ^^^^ error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:23:9 + --> $DIR/concat-bytes-error.rs:46:9 | LL | false, | ^^^^^ error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:26:9 + --> $DIR/concat-bytes-error.rs:49:9 | LL | 2.6, | ^^^ error: numeric literal is out of bounds - --> $DIR/concat-bytes-error.rs:29:9 + --> $DIR/concat-bytes-error.rs:52:9 | LL | 265, | ^^^ error: expected a byte literal - --> $DIR/concat-bytes-error.rs:32:9 + --> $DIR/concat-bytes-error.rs:55:9 | LL | -33, | ^^^ @@ -101,7 +131,7 @@ LL | -33, = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:35:9 + --> $DIR/concat-bytes-error.rs:58:9 | LL | b"hi!", | ^^^^^^ @@ -110,43 +140,43 @@ LL | b"hi!", = help: try flattening the array error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:38:9 + --> $DIR/concat-bytes-error.rs:61:9 | LL | [5, 6, 7], | ^^^^^^^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:40:19 + --> $DIR/concat-bytes-error.rs:63:19 | LL | concat_bytes!(5u16); | ^^^^ help: try wrapping the number in an array: `[5u16]` error: numeric literal is not a `u8` - --> $DIR/concat-bytes-error.rs:41:20 + --> $DIR/concat-bytes-error.rs:65:20 | LL | concat_bytes!([5u16]); | ^^^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:42:23 + --> $DIR/concat-bytes-error.rs:66:23 | LL | concat_bytes!([3; ()]); | ^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:43:23 + --> $DIR/concat-bytes-error.rs:67:23 | LL | concat_bytes!([3; -2]); | ^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:44:25 + --> $DIR/concat-bytes-error.rs:68:25 | LL | concat_bytes!([pie; -2]); | ^^ error: expected a byte literal - --> $DIR/concat-bytes-error.rs:45:20 + --> $DIR/concat-bytes-error.rs:69:20 | LL | concat_bytes!([pie; 2]); | ^^^ @@ -154,28 +184,28 @@ LL | concat_bytes!([pie; 2]); = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:46:20 + --> $DIR/concat-bytes-error.rs:70:20 | LL | concat_bytes!([2.2; 0]); | ^^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:47:25 + --> $DIR/concat-bytes-error.rs:71:25 | LL | concat_bytes!([5.5; ()]); | ^^ error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:48:20 + --> $DIR/concat-bytes-error.rs:72:20 | LL | concat_bytes!([[1, 2, 3]; 3]); | ^^^^^^^^^ error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:49:20 + --> $DIR/concat-bytes-error.rs:73:20 | LL | concat_bytes!([[42; 2]; 3]); | ^^^^^^^ -error: aborting due to 28 previous errors +error: aborting due to 33 previous errors From a50a3b8e318594c41783294e440d864763e412ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Jun 2025 14:11:00 +0200 Subject: [PATCH 127/356] various minor target feature cleanups --- compiler/rustc_codegen_gcc/src/gcc_util.rs | 3 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 22 +++++++------- .../rustc_codegen_ssa/src/target_features.rs | 29 ++++++++----------- compiler/rustc_target/src/target_features.rs | 20 +++---------- tests/assembly/s390x-backchain-toggle.rs | 5 +++- tests/ui/check-cfg/target_feature.stderr | 1 - ...ine-target-feature-flag.by_feature1.stderr | 2 +- ...ine-target-feature-flag.by_feature2.stderr | 2 +- ...ine-target-feature-flag.by_feature3.stderr | 2 +- .../retpoline-target-feature-flag.rs | 6 ++-- 10 files changed, 38 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 562f41248829..42ba40692b75 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -6,6 +6,7 @@ use smallvec::{SmallVec, smallvec}; fn gcc_features_by_flags(sess: &Session, features: &mut Vec) { target_features::retpoline_features_by_flags(sess, features); + // FIXME: LLVM also sets +reserve-x18 here under some conditions. } /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, @@ -59,8 +60,6 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec &str { /// The target features for compiler flags other than `-Ctarget-features`. fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { target_features::retpoline_features_by_flags(sess, features); + + // -Zfixed-x18 + if sess.opts.unstable_opts.fixed_x18 { + if sess.target.arch != "aarch64" { + sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch }); + } else { + features.push("+reserve-x18".into()); + } + } } /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, @@ -736,19 +745,10 @@ pub(crate) fn global_llvm_features( ) }, ); - - llvm_features_by_flags(sess, &mut features); } - // -Zfixed-x18 - // FIXME: merge with `llvm_features_by_flags`. - if sess.opts.unstable_opts.fixed_x18 { - if sess.target.arch != "aarch64" { - sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch }); - } else { - features.push("+reserve-x18".into()); - } - } + // We add this in the "base target" so that these show up in `sess.unstable_target_features`. + llvm_features_by_flags(sess, &mut features); features } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index f4f03c1a16bd..67ac619091be 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -12,9 +12,7 @@ use rustc_session::Session; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{ - self, RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES, Stability, -}; +use rustc_target::target_features::{self, RUSTC_SPECIFIC_FEATURES, Stability}; use smallvec::SmallVec; use crate::errors; @@ -176,8 +174,18 @@ fn parse_rust_feature_flag<'a>( for feature in sess.opts.cg.target_feature.split(',') { if let Some(base_feature) = feature.strip_prefix('+') { + // Skip features that are not target features, but rustc features. + if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { + return; + } + callback(base_feature, sess.target.implied_target_features(base_feature), true) } else if let Some(base_feature) = feature.strip_prefix('-') { + // Skip features that are not target features, but rustc features. + if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { + return; + } + // If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical // contraposition. So we have to find all the reverse implications of `base_feature` and // disable them, too. @@ -229,15 +237,7 @@ pub fn cfg_target_feature( .target .rust_target_features() .iter() - .filter(|(feature, _, _)| { - // Skip checking special features, those are not known to the backend. - if RUSTC_SPECIAL_FEATURES.contains(feature) { - // FIXME: `true` here means we'll always think the feature is enabled. - // Does that really make sense? - return true; - } - target_base_has_feature(feature) - }) + .filter(|(feature, _, _)| target_base_has_feature(feature)) .map(|(feature, _, _)| Symbol::intern(feature)) .collect(); @@ -332,11 +332,6 @@ pub fn flag_to_backend_features<'a, const N: usize>( } }, |base_feature, new_features, enable| { - // Skip features that are meant for rustc, not the backend. - if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) { - return; - } - rust_features.extend( UnordSet::from(new_features).to_sorted_stable_ord().iter().map(|&&s| (enable, s)), ); diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index f7582f8a3440..3eea1e070a66 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -11,11 +11,6 @@ use crate::spec::{FloatAbi, RustcAbi, Target}; /// These exist globally and are not in the target-specific lists below. pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"]; -/// Features that require special handling when passing to LLVM: -/// these are target-specific (i.e., must also be listed in the target-specific list below) -/// but do not correspond to an LLVM target feature. -pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"]; - /// Stability information for target features. #[derive(Debug, Copy, Clone)] pub enum Stability { @@ -275,12 +270,7 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]), // FEAT_RDM ("rdm", Stable, &["neon"]), - // This is needed for inline assembly, but shouldn't be stabilized as-is - // since it should be enabled globally using -Zfixed-x18, not - // #[target_feature]. - // Note that cfg(target_feature = "reserve-x18") is currently not set for - // targets that reserve x18 by default. - ("reserve-x18", Unstable(sym::aarch64_unstable_target_feature), &[]), + ("reserve-x18", Forbidden { reason: "use `-Zfixed-x18` compiler flag instead" }, &[]), // FEAT_SB ("sb", Stable, &[]), // FEAT_SHA1 & FEAT_SHA256 @@ -455,19 +445,17 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("rdseed", Stable, &[]), ( "retpoline-external-thunk", - Stability::Forbidden { - reason: "use `retpoline-external-thunk` target modifier flag instead", - }, + Stability::Forbidden { reason: "use `-Zretpoline-external-thunk` compiler flag instead" }, &[], ), ( "retpoline-indirect-branches", - Stability::Forbidden { reason: "use `retpoline` target modifier flag instead" }, + Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" }, &[], ), ( "retpoline-indirect-calls", - Stability::Forbidden { reason: "use `retpoline` target modifier flag instead" }, + Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" }, &[], ), ("rtm", Unstable(sym::rtm_target_feature), &[]), diff --git a/tests/assembly/s390x-backchain-toggle.rs b/tests/assembly/s390x-backchain-toggle.rs index 83c7b82d0d4b..9bae15b7d11b 100644 --- a/tests/assembly/s390x-backchain-toggle.rs +++ b/tests/assembly/s390x-backchain-toggle.rs @@ -1,5 +1,5 @@ //@ add-core-stubs -//@ revisions: enable-backchain disable-backchain +//@ revisions: enable-backchain disable-backchain default-backchain //@ assembly-output: emit-asm //@ compile-flags: -Copt-level=3 --crate-type=lib --target=s390x-unknown-linux-gnu //@ needs-llvm-components: systemz @@ -26,6 +26,8 @@ extern "C" fn test_backchain() -> i32 { // enable-backchain: stg [[REG1]], 0(%r15) // disable-backchain: aghi %r15, -160 // disable-backchain-NOT: stg %r{{.*}}, 0(%r15) + // default-backchain: aghi %r15, -160 + // default-backchain-NOT: stg %r{{.*}}, 0(%r15) unsafe { extern_func(); } @@ -35,6 +37,7 @@ extern "C" fn test_backchain() -> i32 { // Make sure that the expected return value is written into %r2 (return register): // enable-backchain-NEXT: lghi %r2, 1 // disable-backchain: lghi %r2, 0 + // default-backchain: lghi %r2, 0 #[cfg(target_feature = "backchain")] { 1 diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index ec81ba2e3d89..f422919983b7 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -211,7 +211,6 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `reference-types` `relax` `relaxed-simd` -`reserve-x18` `rtm` `sb` `scq` diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr index 2a0f5f01aef6..79e89823c517 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr @@ -1,4 +1,4 @@ -warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead +warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline-external-thunk` compiler flag instead | = note: 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 #116344 diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr index f7b6cb164477..f5ff15df6329 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr @@ -1,4 +1,4 @@ -warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead | = note: 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 #116344 diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr index 4f2cd1d1a522..158cca08a762 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr @@ -1,4 +1,4 @@ -warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead | = note: 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 #116344 diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs index de3c44c3ed0e..05c85860385a 100644 --- a/tests/ui/target-feature/retpoline-target-feature-flag.rs +++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs @@ -16,6 +16,6 @@ #![no_core] extern crate minicore; -//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead -//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead -//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature` +//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature` +//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature` From f45ab4f742e39cd963b2d926f188c35049575859 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Thu, 19 Jun 2025 04:45:42 +0200 Subject: [PATCH 128/356] Update books --- src/doc/book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book b/src/doc/book index 4433c9f0cad8..8a6d44e45b7b 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 4433c9f0cad8460bee05ede040587f8a1fa3f1de +Subproject commit 8a6d44e45b7b564eeb6bae30507e1fbac439d72d diff --git a/src/doc/reference b/src/doc/reference index d4c66b346f4b..50fc1628f365 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit d4c66b346f4b72d29e70390a3fa3ea7d4e064db1 +Subproject commit 50fc1628f36563958399123829c73755fa7a8421 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 9baa9e863116..05c7d8bae65f 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 9baa9e863116cb9524a177d5a5c475baac18928a +Subproject commit 05c7d8bae65f23a1837430c5a19be129d414f5ec From 04a2eec304c687e8098f4d1d0e10a57b988924f2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Jun 2025 17:46:05 +0000 Subject: [PATCH 129/356] Cache instantiation of canonical binder --- .../src/infer/canonical/instantiate.rs | 187 ++++++++++++++++-- compiler/rustc_middle/src/ty/context.rs | 8 + 2 files changed, 176 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index 67f13192b522..2385c68ef6bb 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -7,8 +7,11 @@ //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use rustc_macros::extension; -use rustc_middle::bug; -use rustc_middle::ty::{self, FnMutDelegate, GenericArgKind, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, DelayedMap, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, + TypeVisitableExt, TypeVisitor, +}; +use rustc_type_ir::TypeVisitable; use crate::infer::canonical::{Canonical, CanonicalVarValues}; @@ -58,23 +61,169 @@ where T: TypeFoldable>, { if var_values.var_values.is_empty() { - value - } else { - let delegate = FnMutDelegate { - regions: &mut |br: ty::BoundRegion| match var_values[br.var].kind() { - GenericArgKind::Lifetime(l) => l, - r => bug!("{:?} is a region but value is {:?}", br, r), - }, - types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].kind() { - GenericArgKind::Type(ty) => ty, - r => bug!("{:?} is a type but value is {:?}", bound_ty, r), - }, - consts: &mut |bound_ct: ty::BoundVar| match var_values[bound_ct].kind() { - GenericArgKind::Const(ct) => ct, - c => bug!("{:?} is a const but value is {:?}", bound_ct, c), - }, - }; + return value; + } - tcx.replace_escaping_bound_vars_uncached(value, delegate) + value.fold_with(&mut CanonicalInstantiator { + tcx, + current_index: ty::INNERMOST, + var_values: var_values.var_values, + cache: Default::default(), + }) +} + +/// Replaces the bound vars in a canonical binder with var values. +struct CanonicalInstantiator<'tcx> { + tcx: TyCtxt<'tcx>, + + // The values that the bound vars are are being instantiated with. + var_values: ty::GenericArgsRef<'tcx>, + + /// As with `BoundVarReplacer`, represents the index of a binder *just outside* + /// the ones we have visited. + current_index: ty::DebruijnIndex, + + // Instantiation is a pure function of `DebruijnIndex` and `Ty`. + cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>, +} + +impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_binder>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match *t.kind() { + ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => { + self.var_values[bound_ty.var.as_usize()].expect_ty() + } + _ => { + if !t.has_vars_bound_at_or_above(self.current_index) { + t + } else if let Some(&t) = self.cache.get(&(self.current_index, t)) { + t + } else { + let res = t.super_fold_with(self); + assert!(self.cache.insert((self.current_index, t), res)); + res + } + } + } + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match r.kind() { + ty::ReBound(debruijn, br) if debruijn == self.current_index => { + self.var_values[br.var.as_usize()].expect_region() + } + _ => r, + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.kind() { + ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { + self.var_values[bound_const.as_usize()].expect_const() + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } + + fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { + if !c.has_vars_bound_at_or_above(self.current_index) { + return c; + } + + // Since instantiation is a function of `DebruijnIndex`, we don't want + // to have to cache more copies of clauses when we're inside of binders. + // Since we currently expect to only have clauses in the outermost + // debruijn index, we just fold if we're inside of a binder. + if self.current_index > ty::INNERMOST { + return c.super_fold_with(self); + } + + // Our cache key is `(clauses, var_values)`, but we also don't care about + // var values that aren't named in the clauses, since they can change without + // affecting the output. Since `ParamEnv`s are cached first, we compute the + // last var value that is mentioned in the clauses, and cut off the list so + // that we have more hits in the cache. + + // We also cache the computation of "highest var named by clauses" since that + // is both expensive (depending on the size of the clauses) and a pure function. + let index = *self + .tcx + .highest_var_in_clauses_cache + .lock() + .entry(c) + .or_insert_with(|| highest_var_in_clauses(c)); + let c_args = &self.var_values[..=index]; + + if let Some(c) = self.tcx.clauses_cache.lock().get(&(c, c_args)) { + c + } else { + let folded = c.super_fold_with(self); + self.tcx.clauses_cache.lock().insert((c, c_args), folded); + folded + } } } + +fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize { + struct HighestVarInClauses { + max_var: usize, + current_index: ty::DebruijnIndex, + } + impl<'tcx> TypeVisitor> for HighestVarInClauses { + fn visit_binder>>( + &mut self, + t: &ty::Binder<'tcx, T>, + ) -> Self::Result { + self.current_index.shift_in(1); + let t = t.super_visit_with(self); + self.current_index.shift_out(1); + t + } + fn visit_ty(&mut self, t: Ty<'tcx>) { + if let ty::Bound(debruijn, bound_ty) = *t.kind() + && debruijn == self.current_index + { + self.max_var = self.max_var.max(bound_ty.var.as_usize()); + } else if t.has_vars_bound_at_or_above(self.current_index) { + t.super_visit_with(self); + } + } + fn visit_region(&mut self, r: ty::Region<'tcx>) { + if let ty::ReBound(debruijn, bound_region) = r.kind() + && debruijn == self.current_index + { + self.max_var = self.max_var.max(bound_region.var.as_usize()); + } + } + fn visit_const(&mut self, ct: ty::Const<'tcx>) { + if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind() + && debruijn == self.current_index + { + self.max_var = self.max_var.max(bound_const.as_usize()); + } else if ct.has_vars_bound_at_or_above(self.current_index) { + ct.super_visit_with(self); + } + } + } + let mut visitor = HighestVarInClauses { max_var: 0, current_index: ty::INNERMOST }; + c.visit_with(&mut visitor); + visitor.max_var +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f1395c242f27..12eb626a1f68 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1479,6 +1479,12 @@ pub struct GlobalCtxt<'tcx> { pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>, + /// Caches the index of the highest bound var in clauses in a canonical binder. + pub highest_var_in_clauses_cache: Lock, usize>>, + /// Caches the instantiation of a canonical binder given a set of args. + pub clauses_cache: + Lock, &'tcx [ty::GenericArg<'tcx>]), ty::Clauses<'tcx>>>, + /// Data layout specification for the current target. pub data_layout: TargetDataLayout, @@ -1727,6 +1733,8 @@ impl<'tcx> TyCtxt<'tcx> { new_solver_evaluation_cache: Default::default(), new_solver_canonical_param_env_cache: Default::default(), canonical_param_env_cache: Default::default(), + highest_var_in_clauses_cache: Default::default(), + clauses_cache: Default::default(), data_layout, alloc_map: interpret::AllocMap::new(), current_gcx, From 8c281613739436582f979d228be4cc1d4f7afa3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 17 Jun 2025 16:09:30 +0200 Subject: [PATCH 130/356] Add `get_host_target` function --- src/bootstrap/src/core/config/config.rs | 4 ++-- src/bootstrap/src/utils/helpers.rs | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index ff0fda2d2e69..d3393afcae05 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -49,7 +49,7 @@ use crate::core::download::is_download_ci_available; use crate::utils::channel; use crate::utils::exec::command; use crate::utils::execution_context::ExecutionContext; -use crate::utils::helpers::exe; +use crate::utils::helpers::{exe, get_host_target}; use crate::{GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, t}; /// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic. @@ -349,7 +349,7 @@ impl Config { stderr_is_tty: std::io::stderr().is_terminal(), // set by build.rs - host_target: TargetSelection::from_user(env!("BUILD_TRIPLE")), + host_target: get_host_target(), src: { let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 2f18fb603182..3c5f612daa7d 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -178,6 +178,11 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result< } } +/// Return the host target on which we are currently running. +pub fn get_host_target() -> TargetSelection { + TargetSelection::from_user(env!("BUILD_TRIPLE")) +} + /// Rename a file if from and to are in the same filesystem or /// copy and remove the file otherwise pub fn move_file, Q: AsRef>(from: P, to: Q) -> io::Result<()> { From 21d21d5f81d6d0ac7e58275e40e982550951ec86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 17 Jun 2025 16:16:46 +0200 Subject: [PATCH 131/356] Normalize host target in snapshot tests --- src/bootstrap/src/core/builder/tests.rs | 50 ++++++++++++++++--------- src/bootstrap/src/utils/tests/mod.rs | 43 +++++++++++++++++++++ 2 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 6268a2b59d6c..f45afe0c789c 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -9,6 +9,7 @@ use crate::Flags; use crate::core::build_steps::doc::DocumentationFormat; use crate::core::config::Config; use crate::utils::cache::ExecutedStep; +use crate::utils::helpers::get_host_target; use crate::utils::tests::git::{GitCtx, git_test}; static TEST_TRIPLE_1: &str = "i686-unknown-haiku"; @@ -1236,24 +1237,38 @@ fn any_debug() { /// The staging tests use insta for snapshot testing. /// See bootstrap's README on how to bless the snapshots. mod staging { + use crate::Build; + use crate::core::builder::Builder; use crate::core::builder::tests::{ TEST_TRIPLE_1, configure, configure_with_args, render_steps, run_build, }; + use crate::utils::tests::ConfigBuilder; #[test] fn build_compiler_stage_1() { - let mut cache = run_build( - &["compiler".into()], - configure_with_args(&["build", "--stage", "1"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]), - ); - let steps = cache.into_executed_steps(); - insta::assert_snapshot!(render_steps(&steps), @r" - [build] rustc 0 -> std 0 - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> rustc 1 + insta::assert_snapshot!( + ConfigBuilder::build() + .path("compiler") + .stage(1) + .get_steps(), @r" + [build] rustc 0 -> std 0 + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 0 -> rustc 1 "); } + + impl ConfigBuilder { + fn get_steps(self) -> String { + let config = self.create_config(); + + let kind = config.cmd.kind(); + let build = Build::new(config); + let builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(kind), &builder.paths); + render_steps(&builder.cache.into_executed_steps()) + } + } } /// Renders the executed bootstrap steps for usage in snapshot tests with insta. @@ -1275,18 +1290,17 @@ fn render_steps(steps: &[ExecutedStep]) -> String { } let stage = if let Some(stage) = metadata.stage { format!("{stage} ") } else { "".to_string() }; - write!(record, "{} {stage}<{}>", metadata.name, metadata.target); + write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target)); Some(record) }) - .map(|line| { - line.replace(TEST_TRIPLE_1, "target1") - .replace(TEST_TRIPLE_2, "target2") - .replace(TEST_TRIPLE_3, "target3") - }) .collect::>() .join("\n") } -fn render_compiler(compiler: Compiler) -> String { - format!("rustc {} <{}>", compiler.stage, compiler.host) +fn normalize_target(target: TargetSelection) -> String { + target.to_string().replace(&get_host_target().to_string(), "host") +} + +fn render_compiler(compiler: Compiler) -> String { + format!("rustc {} <{}>", compiler.stage, normalize_target(compiler.host)) } diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index 73c500f6e369..ec6293f3c2c1 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -1,3 +1,46 @@ //! This module contains shared utilities for bootstrap tests. +use crate::core::builder::Builder; +use crate::core::config::DryRun; +use crate::{Build, Config, Flags}; + pub mod git; + +/// Used to configure an invocation of bootstrap. +/// Currently runs in the rustc checkout, long-term it should be switched +/// to run in a (cache-primed) temporary directory instead. +pub struct ConfigBuilder { + args: Vec, +} + +impl ConfigBuilder { + pub fn from_args(args: &[&str]) -> Self { + Self::new(args) + } + + pub fn build() -> Self { + Self::new(&["build"]) + } + + pub fn path(mut self, path: &str) -> Self { + self.args.push(path.to_string()); + self + } + + pub fn stage(mut self, stage: u32) -> Self { + self.args.push("--stage".to_string()); + self.args.push(stage.to_string()); + self + } + + fn new(args: &[&str]) -> Self { + Self { args: args.iter().copied().map(String::from).collect() } + } + + pub fn create_config(mut self) -> Config { + let mut config = Config::parse(Flags::parse(&self.args)); + // Run in dry-check, otherwise the test would be too slow + config.set_dry_run(DryRun::SelfCheck); + config + } +} From 718e475cb12094cb182a8271b1855d8f1663dc3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 18 Jun 2025 13:14:16 +0200 Subject: [PATCH 132/356] Clarify arrow in snapshot tests --- src/bootstrap/src/core/builder/tests.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index f45afe0c789c..1d1c315c1cfd 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1274,6 +1274,10 @@ mod staging { /// Renders the executed bootstrap steps for usage in snapshot tests with insta. /// Only renders certain important steps. /// Each value in `steps` should be a tuple of (Step, step output). +/// +/// The arrow in the rendered output (`X -> Y`) means `X builds Y`. +/// This is similar to the output printed by bootstrap to stdout, but here it is +/// generated purely for the purpose of tests. fn render_steps(steps: &[ExecutedStep]) -> String { steps .iter() From d41f48f3c3a7dba22ef56fe572bc93618d240db6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 19 Jun 2025 07:38:07 +0200 Subject: [PATCH 133/356] Revert "Turn `BlockId` into a `#[salsa::tracked]`" This reverts commit 8643a858dbaf12b37e90b603cdee64434576c229. --- .../rust-analyzer/crates/hir-def/src/db.rs | 17 ++++++++------- .../crates/hir-def/src/expr_store/lower.rs | 4 ++-- .../src/expr_store/tests/body/block.rs | 4 ++-- .../rust-analyzer/crates/hir-def/src/lib.rs | 21 +------------------ .../ide-completion/src/completions/postfix.rs | 12 ++++------- 5 files changed, 19 insertions(+), 39 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index c618e4bdce7d..00408e95ae6f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -11,12 +11,12 @@ use syntax::{AstPtr, ast}; use triomphe::Arc; use crate::{ - AssocItemId, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, - EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, - FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, - MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, - StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, - TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, + AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, + EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, + FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, + MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, + ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, + TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attr::{Attrs, AttrsWithOwner}, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes, @@ -90,7 +90,10 @@ pub trait InternDatabase: RootQueryDb { #[salsa::interned] fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId; - // // endregion: items + // endregion: items + + #[salsa::interned] + fn intern_block(&self, loc: BlockLoc) -> BlockId; } #[query_group::query_group] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 03683ec9203c..4ba31c1e20bf 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -11,7 +11,7 @@ use base_db::FxIndexSet; use cfg::CfgOptions; use either::Either; use hir_expand::{ - HirFileId, InFile, Intern, MacroDefId, + HirFileId, InFile, MacroDefId, mod_path::tool_path, name::{AsName, Name}, span_map::SpanMapRef, @@ -2148,7 +2148,7 @@ impl ExprCollector<'_> { ) -> ExprId { let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| { let ast_id = self.expander.in_file(file_local_id); - BlockLoc { ast_id, module: self.module }.intern(self.db) + self.db.intern_block(BlockLoc { ast_id, module: self.module }) }); let (module, def_map) = diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs index bb0b70bc5bf2..c7707378a5b3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs @@ -189,8 +189,8 @@ fn f() { } "#, expect![[r#" - BlockIdLt { [salsa id]: Id(3c01) } in BlockRelativeModuleId { block: Some(BlockIdLt { [salsa id]: Id(3c00) }), local_id: Idx::(1) } - BlockIdLt { [salsa id]: Id(3c00) } in BlockRelativeModuleId { block: None, local_id: Idx::(0) } + BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::(1) } + BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::(0) } crate scope "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index a542214d3031..a562f2d0af2f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -384,26 +384,7 @@ pub struct BlockLoc { /// The containing module. pub module: ModuleId, } -#[salsa_macros::tracked(debug)] -#[derive(PartialOrd, Ord)] -pub struct BlockIdLt<'db> { - pub loc: BlockLoc, -} -pub type BlockId = BlockIdLt<'static>; -impl hir_expand::Intern for BlockLoc { - type Database = dyn DefDatabase; - type ID = BlockId; - fn intern(self, db: &Self::Database) -> Self::ID { - unsafe { std::mem::transmute::, BlockId>(BlockIdLt::new(db, self)) } - } -} -impl hir_expand::Lookup for BlockId { - type Database = dyn DefDatabase; - type Data = BlockLoc; - fn lookup(&self, db: &Self::Database) -> Self::Data { - self.loc(db) - } -} +impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block); /// A `ModuleId` that is always a crate's root module. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 2e2a3e83cc75..d0023852acf9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -283,16 +283,12 @@ pub(crate) fn complete_postfix( let (open_brace, close_brace) = if block_should_be_wrapped { ("{ ", " }") } else { ("", "") }; let (open_paren, close_paren) = if is_in_cond { ("(", ")") } else { ("", "") }; - let unsafe_completion_string = format!( - "{}unsafe {}{receiver_text}{}{}", - open_paren, open_brace, close_brace, close_paren - ); + let unsafe_completion_string = + format!("{open_paren}unsafe {open_brace}{receiver_text}{close_brace}{close_paren}"); postfix_snippet("unsafe", "unsafe {}", &unsafe_completion_string).add_to(acc, ctx.db); - let const_completion_string = format!( - "{}const {}{receiver_text}{}{}", - open_paren, open_brace, close_brace, close_paren - ); + let const_completion_string = + format!("{open_paren}const {open_brace}{receiver_text}{close_brace}{close_paren}"); postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db); } From 4eaca5d1def1347e3c31bd549f419258a2bd6004 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 11 Jun 2025 22:20:28 +0800 Subject: [PATCH 134/356] remove `walk_item_kind` from `MutVisitor` just using `walk_item` instead would be okay. --- compiler/rustc_ast/src/mut_visit.rs | 46 ------------------- .../rustc_builtin_macros/src/test_harness.rs | 6 +-- 2 files changed, 3 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 07fbe8045fc2..960800b09270 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -79,14 +79,6 @@ pub trait MutVisitor: Sized + MutVisitorResult { walk_crate(self, c) } - fn visit_meta_list_item(&mut self, list_item: &mut MetaItemInner) { - walk_meta_list_item(self, list_item); - } - - fn visit_meta_item(&mut self, meta_item: &mut MetaItem) { - walk_meta_item(self, meta_item); - } - fn visit_use_tree(&mut self, use_tree: &mut UseTree) { walk_use_tree(self, use_tree); } @@ -398,16 +390,6 @@ generate_flat_map_visitor_fns! { visit_arms, Arm, flat_map_arm; } -#[inline] -fn visit_thin_vec(elems: &mut ThinVec, mut visit_elem: F) -where - F: FnMut(&mut T), -{ - for elem in elems { - visit_elem(elem); - } -} - fn visit_attrs(vis: &mut T, attrs: &mut AttrVec) { for attr in attrs.iter_mut() { vis.visit_attribute(attr); @@ -444,23 +426,6 @@ pub fn walk_flat_map_variant( smallvec![variant] } -fn walk_meta_list_item(vis: &mut T, li: &mut MetaItemInner) { - match li { - MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi), - MetaItemInner::Lit(_lit) => {} - } -} - -fn walk_meta_item(vis: &mut T, mi: &mut MetaItem) { - let MetaItem { unsafety: _, path: _, kind, span } = mi; - match kind { - MetaItemKind::Word => {} - MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)), - MetaItemKind::NameValue(_s) => {} - } - vis.visit_span(span); -} - pub fn walk_flat_map_param(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> { vis.visit_param(&mut param); smallvec![param] @@ -506,17 +471,6 @@ pub fn walk_flat_map_expr_field( smallvec![f] } -pub fn walk_item_kind( - kind: &mut K, - span: Span, - id: NodeId, - visibility: &mut Visibility, - ctxt: K::Ctxt, - vis: &mut impl MutVisitor, -) { - kind.walk(span, id, visibility, ctxt, vis) -} - pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P) -> SmallVec<[P; 1]> { vis.visit_item(&mut item); smallvec![item] diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 0bc313cbdacb..a2440afb9d80 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -6,7 +6,7 @@ use rustc_ast as ast; use rustc_ast::entry::EntryPointType; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_ast::visit::{Visitor, walk_item}; +use rustc_ast::visit::Visitor; use rustc_ast::{ModKind, attr}; use rustc_errors::DiagCtxtHandle; use rustc_expand::base::{ExtCtxt, ResolverExpand}; @@ -146,11 +146,11 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { ) = item.kind { let prev_tests = mem::take(&mut self.tests); - walk_item_kind(&mut item.kind, item.span, item.id, &mut item.vis, (), self); + ast::mut_visit::walk_item(self, item); self.add_test_cases(item.id, span, prev_tests); } else { // But in those cases, we emit a lint to warn the user of these missing tests. - walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item); + ast::visit::walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item); } } } From 80bd8a436c8eb187edd451e2fa72e00ed9cfccb1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 19 Jun 2025 08:29:50 +0200 Subject: [PATCH 135/356] fix: Temporarily disable `+` typing handler as it moves the cursor position --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- .../rust-analyzer/docs/book/src/configuration_generated.md | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 32560bb26f12..76a4a26af645 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -344,7 +344,7 @@ config_data! { /// - typing `{` in a use item adds a closing `}` in the right place /// - typing `>` to complete a return type `->` will insert a whitespace after it /// - typing `<` in a path or type position inserts a closing `>` after the path or type. - typing_triggerChars: Option = Some("=.+".to_owned()), + typing_triggerChars: Option = Some("=.".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 119b60725a92..54a624d25abe 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -1417,7 +1417,7 @@ Show documentation. ## rust-analyzer.typing.triggerChars {#typing.triggerChars} -Default: `"=.+"` +Default: `"=."` Specify the characters allowed to invoke special on typing triggers. - typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index acac54e53a61..fb41225ca0dc 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2846,7 +2846,7 @@ "properties": { "rust-analyzer.typing.triggerChars": { "markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.", - "default": "=.+", + "default": "=.", "type": [ "null", "string" From 8dea73acfd76a38173975ff1e60b7770af677768 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 19 Jun 2025 09:28:38 +0000 Subject: [PATCH 136/356] Rustup to rustc 1.89.0-nightly (c68340350 2025-06-18) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index a9ca0f23d8be..f09a2628777d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-17" +channel = "nightly-2025-06-19" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 3da58e673a723378942fc1828e45956025c97569 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 11 Jun 2025 23:14:10 +0800 Subject: [PATCH 137/356] completely deduplicate `Visitor` and `MutVisitor` --- compiler/rustc_ast/src/ast_traits.rs | 7 + compiler/rustc_ast/src/mut_visit.rs | 444 +----------- compiler/rustc_ast/src/visit.rs | 653 +++++++++++------- compiler/rustc_builtin_macros/src/cfg_eval.rs | 2 +- compiler/rustc_expand/src/expand.rs | 12 +- compiler/rustc_expand/src/placeholders.rs | 4 +- compiler/rustc_resolve/src/late.rs | 13 +- .../rustc-dev-remap.only-remap.stderr | 1 + .../rustc-dev-remap.remap-unremap.stderr | 5 +- 9 files changed, 465 insertions(+), 676 deletions(-) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 797ab297319b..9d91f41d6c79 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -321,6 +321,13 @@ impl AstNodeWrapper { } } +// FIXME: remove after `stmt_expr_attributes` is stabilized. +impl From, Tag>> for AstNodeWrapper { + fn from(value: AstNodeWrapper, Tag>) -> Self { + AstNodeWrapper { wrapped: *value.wrapped, tag: value.tag } + } +} + impl HasNodeId for AstNodeWrapper { fn node_id(&self) -> NodeId { self.wrapped.node_id() diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 960800b09270..3eae19f4daa1 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -13,7 +13,7 @@ use std::panic; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span}; -use smallvec::{Array, SmallVec, smallvec}; +use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use crate::ast::*; @@ -21,17 +21,6 @@ use crate::ptr::P; use crate::tokenstream::*; use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list}; -pub trait ExpectOne { - fn expect_one(self, err: &'static str) -> A::Item; -} - -impl ExpectOne
for SmallVec { - fn expect_one(self, err: &'static str) -> A::Item { - assert!(self.len() == 1, "{}", err); - self.into_iter().next().unwrap() - } -} - mod sealed { use rustc_ast_ir::visit::VisitorResult; @@ -47,315 +36,6 @@ mod sealed { use sealed::MutVisitorResult; -pub trait MutVisitor: Sized + MutVisitorResult { - // Methods in this trait have one of three forms: - // - // fn visit_t(&mut self, t: &mut T); // common - // fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>; // rare - // fn filter_map_t(&mut self, t: T) -> Option; // rarest - // - // When writing these methods, it is better to use destructuring like this: - // - // fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) { - // visit_a(a); - // visit_b(b); - // } - // - // than to use field access like this: - // - // fn visit_abc(&mut self, abc: &mut ABC) { - // visit_a(&mut abc.a); - // visit_b(&mut abc.b); - // // ignore abc.c - // } - // - // As well as being more concise, the former is explicit about which fields - // are skipped. Furthermore, if a new field is added, the destructuring - // version will cause a compile error, which is good. In comparison, the - // field access version will continue working and it would be easy to - // forget to add handling for it. - - fn visit_crate(&mut self, c: &mut Crate) { - walk_crate(self, c) - } - - fn visit_use_tree(&mut self, use_tree: &mut UseTree) { - walk_use_tree(self, use_tree); - } - - fn visit_foreign_item(&mut self, ni: &mut ForeignItem) { - walk_item(self, ni); - } - - fn flat_map_foreign_item(&mut self, ni: P) -> SmallVec<[P; 1]> { - walk_flat_map_foreign_item(self, ni) - } - - fn visit_item(&mut self, i: &mut Item) { - walk_item(self, i); - } - - fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { - walk_flat_map_item(self, i) - } - - fn visit_fn_header(&mut self, header: &mut FnHeader) { - walk_fn_header(self, header); - } - - fn visit_field_def(&mut self, fd: &mut FieldDef) { - walk_field_def(self, fd); - } - - fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> { - walk_flat_map_field_def(self, fd) - } - - fn visit_assoc_item(&mut self, i: &mut AssocItem, ctxt: AssocCtxt) { - walk_assoc_item(self, i, ctxt) - } - - fn flat_map_assoc_item( - &mut self, - i: P, - ctxt: AssocCtxt, - ) -> SmallVec<[P; 1]> { - walk_flat_map_assoc_item(self, i, ctxt) - } - - fn visit_contract(&mut self, c: &mut FnContract) { - walk_contract(self, c); - } - - fn visit_fn_decl(&mut self, d: &mut FnDecl) { - walk_fn_decl(self, d); - } - - /// `Span` and `NodeId` are mutated at the caller site. - fn visit_fn(&mut self, fk: FnKind<'_>, _: Span, _: NodeId) { - walk_fn(self, fk) - } - - fn visit_coroutine_kind(&mut self, a: &mut CoroutineKind) { - walk_coroutine_kind(self, a); - } - - fn visit_closure_binder(&mut self, b: &mut ClosureBinder) { - walk_closure_binder(self, b); - } - - fn visit_block(&mut self, b: &mut Block) { - walk_block(self, b); - } - - fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> { - walk_flat_map_stmt(self, s) - } - - fn visit_arm(&mut self, arm: &mut Arm) { - walk_arm(self, arm); - } - - fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { - walk_flat_map_arm(self, arm) - } - - fn visit_pat(&mut self, p: &mut Pat) { - walk_pat(self, p); - } - - fn visit_anon_const(&mut self, c: &mut AnonConst) { - walk_anon_const(self, c); - } - - fn visit_expr(&mut self, e: &mut Expr) { - walk_expr(self, e); - } - - /// This method is a hack to workaround unstable of `stmt_expr_attributes`. - /// It can be removed once that feature is stabilized. - fn visit_method_receiver_expr(&mut self, ex: &mut P) { - self.visit_expr(ex) - } - - fn filter_map_expr(&mut self, e: P) -> Option> { - walk_filter_map_expr(self, e) - } - - fn visit_generic_arg(&mut self, arg: &mut GenericArg) { - walk_generic_arg(self, arg); - } - - fn visit_ty(&mut self, t: &mut Ty) { - walk_ty(self, t); - } - - fn visit_ty_pat(&mut self, t: &mut TyPat) { - walk_ty_pat(self, t); - } - - fn visit_lifetime(&mut self, l: &mut Lifetime) { - walk_lifetime(self, l); - } - - fn visit_assoc_item_constraint(&mut self, c: &mut AssocItemConstraint) { - walk_assoc_item_constraint(self, c); - } - - fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) { - walk_foreign_mod(self, nm); - } - - fn visit_variant(&mut self, v: &mut Variant) { - walk_variant(self, v); - } - - fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { - walk_flat_map_variant(self, v) - } - - fn visit_ident(&mut self, i: &mut Ident) { - self.visit_span(&mut i.span); - } - - fn visit_path(&mut self, p: &mut Path) { - walk_path(self, p); - } - - fn visit_path_segment(&mut self, p: &mut PathSegment) { - walk_path_segment(self, p) - } - - fn visit_qself(&mut self, qs: &mut Option>) { - walk_qself(self, qs); - } - - fn visit_generic_args(&mut self, p: &mut GenericArgs) { - walk_generic_args(self, p); - } - - fn visit_local(&mut self, l: &mut Local) { - walk_local(self, l); - } - - fn visit_mac_call(&mut self, mac: &mut MacCall) { - walk_mac(self, mac); - } - - fn visit_macro_def(&mut self, def: &mut MacroDef) { - walk_macro_def(self, def); - } - - fn visit_label(&mut self, label: &mut Label) { - walk_label(self, label); - } - - fn visit_attribute(&mut self, at: &mut Attribute) { - walk_attribute(self, at); - } - - fn visit_param(&mut self, param: &mut Param) { - walk_param(self, param); - } - - fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { - walk_flat_map_param(self, param) - } - - fn visit_generics(&mut self, generics: &mut Generics) { - walk_generics(self, generics); - } - - fn visit_trait_ref(&mut self, tr: &mut TraitRef) { - walk_trait_ref(self, tr); - } - - fn visit_poly_trait_ref(&mut self, p: &mut PolyTraitRef) { - walk_poly_trait_ref(self, p); - } - - fn visit_variant_data(&mut self, vdata: &mut VariantData) { - walk_variant_data(self, vdata); - } - - fn visit_generic_param(&mut self, param: &mut GenericParam) { - walk_generic_param(self, param) - } - - fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { - walk_flat_map_generic_param(self, param) - } - - fn visit_param_bound(&mut self, tpb: &mut GenericBound, _ctxt: BoundKind) { - walk_param_bound(self, tpb); - } - - fn visit_precise_capturing_arg(&mut self, arg: &mut PreciseCapturingArg) { - walk_precise_capturing_arg(self, arg); - } - - fn visit_expr_field(&mut self, f: &mut ExprField) { - walk_expr_field(self, f); - } - - fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> { - walk_flat_map_expr_field(self, f) - } - - fn flat_map_where_predicate( - &mut self, - where_predicate: WherePredicate, - ) -> SmallVec<[WherePredicate; 1]> { - walk_flat_map_where_predicate(self, where_predicate) - } - - fn visit_where_predicate_kind(&mut self, kind: &mut WherePredicateKind) { - walk_where_predicate_kind(self, kind) - } - - fn visit_vis(&mut self, vis: &mut Visibility) { - walk_vis(self, vis); - } - - fn visit_id(&mut self, _id: &mut NodeId) { - // Do nothing. - } - - // Span visiting is no longer used, but we keep it for now, - // in case it's needed for something like #127241. - fn visit_span(&mut self, _sp: &mut Span) { - // Do nothing. - } - - fn visit_pat_field(&mut self, fp: &mut PatField) { - walk_pat_field(self, fp) - } - - fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> { - walk_flat_map_pat_field(self, fp) - } - - fn visit_inline_asm(&mut self, asm: &mut InlineAsm) { - walk_inline_asm(self, asm) - } - - fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) { - walk_inline_asm_sym(self, sym) - } - - fn visit_format_args(&mut self, fmt: &mut FormatArgs) { - walk_format_args(self, fmt) - } - - fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) { - walk_capture_by(self, capture_by) - } - - fn visit_fn_ret_ty(&mut self, fn_ret_ty: &mut FnRetTy) { - walk_fn_ret_ty(self, fn_ret_ty) - } -} - super::common_visitor_and_walkers!((mut) MutVisitor); macro_rules! generate_flat_map_visitor_fns { @@ -390,12 +70,6 @@ generate_flat_map_visitor_fns! { visit_arms, Arm, flat_map_arm; } -fn visit_attrs(vis: &mut T, attrs: &mut AttrVec) { - for attr in attrs.iter_mut() { - vis.visit_attribute(attr); - } -} - pub fn walk_flat_map_pat_field( vis: &mut T, mut fp: PatField, @@ -413,30 +87,26 @@ fn visit_nested_use_tree( vis.visit_use_tree(nested_tree); } -pub fn walk_flat_map_arm(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> { - vis.visit_arm(&mut arm); - smallvec![arm] +macro_rules! generate_walk_flat_map_fns { + ($($fn_name:ident($Ty:ty$(,$extra_name:ident: $ExtraTy:ty)*) => $visit_fn_name:ident;)+) => {$( + pub fn $fn_name(vis: &mut V, mut value: $Ty$(,$extra_name: $ExtraTy)*) -> SmallVec<[$Ty; 1]> { + vis.$visit_fn_name(&mut value$(,$extra_name)*); + smallvec![value] + } + )+}; } -pub fn walk_flat_map_variant( - vis: &mut T, - mut variant: Variant, -) -> SmallVec<[Variant; 1]> { - vis.visit_variant(&mut variant); - smallvec![variant] -} - -pub fn walk_flat_map_param(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> { - vis.visit_param(&mut param); - smallvec![param] -} - -pub fn walk_flat_map_generic_param( - vis: &mut T, - mut param: GenericParam, -) -> SmallVec<[GenericParam; 1]> { - vis.visit_generic_param(&mut param); - smallvec![param] +generate_walk_flat_map_fns! { + walk_flat_map_arm(Arm) => visit_arm; + walk_flat_map_variant(Variant) => visit_variant; + walk_flat_map_param(Param) => visit_param; + walk_flat_map_generic_param(GenericParam) => visit_generic_param; + walk_flat_map_where_predicate(WherePredicate) => visit_where_predicate; + walk_flat_map_field_def(FieldDef) => visit_field_def; + walk_flat_map_expr_field(ExprField) => visit_expr_field; + walk_flat_map_item(P) => visit_item; + walk_flat_map_foreign_item(P) => visit_foreign_item; + walk_flat_map_assoc_item(P, ctxt: AssocCtxt) => visit_assoc_item; } fn walk_ty_alias_where_clauses(vis: &mut T, tawcs: &mut TyAliasWhereClauses) { @@ -447,52 +117,6 @@ fn walk_ty_alias_where_clauses(vis: &mut T, tawcs: &mut TyAliasWh vis.visit_span(span_after); } -pub fn walk_flat_map_where_predicate( - vis: &mut T, - mut pred: WherePredicate, -) -> SmallVec<[WherePredicate; 1]> { - walk_where_predicate(vis, &mut pred); - smallvec![pred] -} - -pub fn walk_flat_map_field_def( - vis: &mut T, - mut fd: FieldDef, -) -> SmallVec<[FieldDef; 1]> { - vis.visit_field_def(&mut fd); - smallvec![fd] -} - -pub fn walk_flat_map_expr_field( - vis: &mut T, - mut f: ExprField, -) -> SmallVec<[ExprField; 1]> { - vis.visit_expr_field(&mut f); - smallvec![f] -} - -pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P) -> SmallVec<[P; 1]> { - vis.visit_item(&mut item); - smallvec![item] -} - -pub fn walk_flat_map_foreign_item( - vis: &mut impl MutVisitor, - mut item: P, -) -> SmallVec<[P; 1]> { - vis.visit_foreign_item(&mut item); - smallvec![item] -} - -pub fn walk_flat_map_assoc_item( - vis: &mut impl MutVisitor, - mut item: P, - ctxt: AssocCtxt, -) -> SmallVec<[P; 1]> { - vis.visit_assoc_item(&mut item, ctxt); - smallvec![item] -} - pub fn walk_filter_map_expr(vis: &mut T, mut e: P) -> Option> { vis.visit_expr(&mut e); Some(e) @@ -530,35 +154,11 @@ fn walk_flat_map_stmt_kind(vis: &mut T, kind: StmtKind) -> SmallV StmtKind::Empty => smallvec![StmtKind::Empty], StmtKind::MacCall(mut mac) => { let MacCallStmt { mac: mac_, style: _, attrs, tokens: _ } = mac.deref_mut(); - visit_attrs(vis, attrs); + for attr in attrs { + vis.visit_attribute(attr); + } vis.visit_mac_call(mac_); smallvec![StmtKind::MacCall(mac)] } } } - -fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { - match capture_by { - CaptureBy::Ref => {} - CaptureBy::Value { move_kw } => { - vis.visit_span(move_kw); - } - CaptureBy::Use { use_kw } => { - vis.visit_span(use_kw); - } - } -} - -#[derive(Debug)] -pub enum FnKind<'a> { - /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, &'a mut Visibility, &'a mut Fn), - - /// E.g., `|x, y| body`. - Closure( - &'a mut ClosureBinder, - &'a mut Option, - &'a mut P, - &'a mut P, - ), -} diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index bd2ab34bfc19..1d437e5c2af0 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -65,45 +65,6 @@ impl BoundKind { } } -#[derive(Copy, Clone, Debug)] -pub enum FnKind<'a> { - /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. - Fn(FnCtxt, &'a Visibility, &'a Fn), - - /// E.g., `|x, y| body`. - Closure(&'a ClosureBinder, &'a Option, &'a FnDecl, &'a Expr), -} - -impl<'a> FnKind<'a> { - pub fn header(&self) -> Option<&'a FnHeader> { - match *self { - FnKind::Fn(_, _, Fn { sig, .. }) => Some(&sig.header), - FnKind::Closure(..) => None, - } - } - - pub fn ident(&self) -> Option<&Ident> { - match self { - FnKind::Fn(_, _, Fn { ident, .. }) => Some(ident), - _ => None, - } - } - - pub fn decl(&self) -> &'a FnDecl { - match self { - FnKind::Fn(_, _, Fn { sig, .. }) => &sig.decl, - FnKind::Closure(_, _, decl, _) => decl, - } - } - - pub fn ctxt(&self) -> Option { - match self { - FnKind::Fn(ctxt, ..) => Some(*ctxt), - FnKind::Closure(..) => None, - } - } -} - #[derive(Copy, Clone, Debug)] pub enum LifetimeCtxt { /// Appears in a reference type. @@ -114,206 +75,405 @@ pub enum LifetimeCtxt { GenericArg, } -/// Each method of the `Visitor` trait is a hook to be potentially -/// overridden. Each method's default implementation recursively visits -/// the substructure of the input via the corresponding `walk` method; -/// e.g., the `visit_item` method by default calls `visit::walk_item`. -/// -/// If you want to ensure that your code handles every variant -/// explicitly, you need to override each method. (And you also need -/// to monitor future changes to `Visitor` in case a new method with a -/// new default implementation gets introduced.) -/// -/// Every `walk_*` method uses deconstruction to access fields of structs and -/// enums. This will result in a compile error if a field is added, which makes -/// it more likely the appropriate visit call will be added for it. -pub trait Visitor<'ast>: Sized { - /// The result type of the `visit_*` methods. Can be either `()`, - /// or `ControlFlow`. - type Result: VisitorResult = (); - - fn visit_ident(&mut self, _ident: &'ast Ident) -> Self::Result { - Self::Result::output() - } - fn visit_foreign_mod(&mut self, nm: &'ast ForeignMod) -> Self::Result { - walk_foreign_mod(self, nm) - } - fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result { - walk_item(self, i) - } - fn visit_item(&mut self, i: &'ast Item) -> Self::Result { - walk_item(self, i) - } - fn visit_local(&mut self, l: &'ast Local) -> Self::Result { - walk_local(self, l) - } - fn visit_block(&mut self, b: &'ast Block) -> Self::Result { - walk_block(self, b) - } - fn visit_stmt(&mut self, s: &'ast Stmt) -> Self::Result { - walk_stmt(self, s) - } - fn visit_param(&mut self, param: &'ast Param) -> Self::Result { - walk_param(self, param) - } - fn visit_arm(&mut self, a: &'ast Arm) -> Self::Result { - walk_arm(self, a) - } - fn visit_pat(&mut self, p: &'ast Pat) -> Self::Result { - walk_pat(self, p) - } - fn visit_anon_const(&mut self, c: &'ast AnonConst) -> Self::Result { - walk_anon_const(self, c) - } - fn visit_expr(&mut self, ex: &'ast Expr) -> Self::Result { - walk_expr(self, ex) - } - /// This method is a hack to workaround unstable of `stmt_expr_attributes`. - /// It can be removed once that feature is stabilized. - fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) -> Self::Result { - self.visit_expr(ex) - } - fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result { - walk_ty(self, t) - } - fn visit_ty_pat(&mut self, t: &'ast TyPat) -> Self::Result { - walk_ty_pat(self, t) - } - fn visit_generic_param(&mut self, param: &'ast GenericParam) -> Self::Result { - walk_generic_param(self, param) - } - fn visit_generics(&mut self, g: &'ast Generics) -> Self::Result { - walk_generics(self, g) - } - fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) -> Self::Result { - walk_closure_binder(self, b) - } - fn visit_contract(&mut self, c: &'ast FnContract) -> Self::Result { - walk_contract(self, c) - } - fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result { - walk_where_predicate(self, p) - } - fn visit_where_predicate_kind(&mut self, k: &'ast WherePredicateKind) -> Self::Result { - walk_where_predicate_kind(self, k) - } - fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) -> Self::Result { - walk_fn(self, fk) - } - fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) -> Self::Result { - walk_assoc_item(self, i, ctxt) - } - fn visit_trait_ref(&mut self, t: &'ast TraitRef) -> Self::Result { - walk_trait_ref(self, t) - } - fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result { - walk_param_bound(self, bounds) - } - fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) -> Self::Result { - walk_precise_capturing_arg(self, arg) - } - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result { - walk_poly_trait_ref(self, t) - } - fn visit_variant_data(&mut self, s: &'ast VariantData) -> Self::Result { - walk_variant_data(self, s) - } - fn visit_field_def(&mut self, s: &'ast FieldDef) -> Self::Result { - walk_field_def(self, s) - } - fn visit_variant(&mut self, v: &'ast Variant) -> Self::Result { - walk_variant(self, v) - } - fn visit_variant_discr(&mut self, discr: &'ast AnonConst) -> Self::Result { - self.visit_anon_const(discr) - } - fn visit_label(&mut self, label: &'ast Label) -> Self::Result { - walk_label(self, label) - } - fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) -> Self::Result { - walk_lifetime(self, lifetime) - } - fn visit_mac_call(&mut self, mac: &'ast MacCall) -> Self::Result { - walk_mac(self, mac) - } - fn visit_id(&mut self, _id: NodeId) -> Self::Result { - Self::Result::output() - } - fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) -> Self::Result { - walk_macro_def(self, macro_def) - } - fn visit_path(&mut self, path: &'ast Path) -> Self::Result { - walk_path(self, path) - } - fn visit_use_tree(&mut self, use_tree: &'ast UseTree) -> Self::Result { - walk_use_tree(self, use_tree) - } - fn visit_nested_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId) -> Self::Result { - try_visit!(self.visit_id(id)); - self.visit_use_tree(use_tree) - } - fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) -> Self::Result { - walk_path_segment(self, path_segment) - } - fn visit_generic_args(&mut self, generic_args: &'ast GenericArgs) -> Self::Result { - walk_generic_args(self, generic_args) - } - fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) -> Self::Result { - walk_generic_arg(self, generic_arg) - } - fn visit_assoc_item_constraint( - &mut self, - constraint: &'ast AssocItemConstraint, - ) -> Self::Result { - walk_assoc_item_constraint(self, constraint) - } - fn visit_attribute(&mut self, attr: &'ast Attribute) -> Self::Result { - walk_attribute(self, attr) - } - fn visit_vis(&mut self, vis: &'ast Visibility) -> Self::Result { - walk_vis(self, vis) - } - fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result { - walk_fn_ret_ty(self, ret_ty) - } - fn visit_fn_header(&mut self, header: &'ast FnHeader) -> Self::Result { - walk_fn_header(self, header) - } - fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result { - walk_expr_field(self, f) - } - fn visit_pat_field(&mut self, fp: &'ast PatField) -> Self::Result { - walk_pat_field(self, fp) - } - fn visit_crate(&mut self, krate: &'ast Crate) -> Self::Result { - walk_crate(self, krate) - } - fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) -> Self::Result { - walk_inline_asm(self, asm) - } - fn visit_format_args(&mut self, fmt: &'ast FormatArgs) -> Self::Result { - walk_format_args(self, fmt) - } - fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) -> Self::Result { - walk_inline_asm_sym(self, sym) - } - fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result { - Self::Result::output() - } - fn visit_coroutine_kind(&mut self, coroutine_kind: &'ast CoroutineKind) -> Self::Result { - walk_coroutine_kind(self, coroutine_kind) - } - fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result { - walk_fn_decl(self, fn_decl) - } - fn visit_qself(&mut self, qs: &'ast Option>) -> Self::Result { - walk_qself(self, qs) - } -} - #[macro_export] macro_rules! common_visitor_and_walkers { ($(($mut: ident))? $Visitor:ident$(<$lt:lifetime>)?) => { + $(${ignore($lt)} + #[derive(Copy, Clone)] + )? + #[derive(Debug)] + pub enum FnKind<'a> { + /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`. + Fn(FnCtxt, &'a $($mut)? Visibility, &'a $($mut)? Fn), + + /// E.g., `|x, y| body`. + Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option, &'a $($mut)? P, &'a $($mut)? P), + } + + impl<'a> FnKind<'a> { + pub fn header(&'a $($mut)? self) -> Option<&'a $($mut)? FnHeader> { + match *self { + FnKind::Fn(_, _, Fn { sig, .. }) => Some(&$($mut)? sig.header), + FnKind::Closure(..) => None, + } + } + + pub fn ident(&'a $($mut)? self) -> Option<&'a $($mut)? Ident> { + match self { + FnKind::Fn(_, _, Fn { ident, .. }) => Some(ident), + _ => None, + } + } + + pub fn decl(&'a $($mut)? self) -> &'a $($mut)? FnDecl { + match self { + FnKind::Fn(_, _, Fn { sig, .. }) => &$($mut)? sig.decl, + FnKind::Closure(_, _, decl, _) => decl, + } + } + + pub fn ctxt(&self) -> Option { + match self { + FnKind::Fn(ctxt, ..) => Some(*ctxt), + FnKind::Closure(..) => None, + } + } + } + + /// Each method of this trait is a hook to be potentially + /// overridden. Each method's default implementation recursively visits + /// the substructure of the input via the corresponding `walk` method; + #[doc = concat!(" e.g., the `visit_item` method by default calls `visit"$(, "_", stringify!($mut))?, "::walk_item`.")] + /// + /// If you want to ensure that your code handles every variant + /// explicitly, you need to override each method. (And you also need + /// to monitor future changes to this trait in case a new method with a + /// new default implementation gets introduced.) + /// + /// Every `walk_*` method uses deconstruction to access fields of structs and + /// enums. This will result in a compile error if a field is added, which makes + /// it more likely the appropriate visit call will be added for it. + pub trait $Visitor<$($lt)?> : Sized $(${ignore($mut)} + MutVisitorResult)? { + $( + ${ignore($lt)} + /// The result type of the `visit_*` methods. Can be either `()`, + /// or `ControlFlow`. + type Result: VisitorResult = (); + )? + + // Methods in this trait have one of three forms, with the last two forms + // only occuring on `MutVisitor`: + // + // fn visit_t(&mut self, t: &mut T); // common + // fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>; // rare + // fn filter_map_t(&mut self, t: T) -> Option; // rarest + // + // When writing these methods, it is better to use destructuring like this: + // + // fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) { + // visit_a(a); + // visit_b(b); + // } + // + // than to use field access like this: + // + // fn visit_abc(&mut self, abc: &mut ABC) { + // visit_a(&mut abc.a); + // visit_b(&mut abc.b); + // // ignore abc.c + // } + // + // As well as being more concise, the former is explicit about which fields + // are skipped. Furthermore, if a new field is added, the destructuring + // version will cause a compile error, which is good. In comparison, the + // field access version will continue working and it would be easy to + // forget to add handling for it. + fn visit_ident(&mut self, Ident { name: _, span }: &$($lt)? $($mut)? Ident) -> Self::Result { + visit_span(self, span) + } + + fn visit_foreign_mod(&mut self, nm: &$($lt)? $($mut)? ForeignMod) -> Self::Result { + walk_foreign_mod(self, nm) + } + + fn visit_foreign_item(&mut self, i: &$($lt)? $($mut)? ForeignItem) -> Self::Result { + walk_item(self, i) + } + + fn visit_item(&mut self, i: &$($lt)? $($mut)? Item) -> Self::Result { + walk_item(self, i) + } + + fn visit_local(&mut self, l: &$($lt)? $($mut)? Local) -> Self::Result { + walk_local(self, l) + } + + fn visit_block(&mut self, b: &$($lt)? $($mut)? Block) -> Self::Result { + walk_block(self, b) + } + + fn visit_param(&mut self, param: &$($lt)? $($mut)? Param) -> Self::Result { + walk_param(self, param) + } + + fn visit_arm(&mut self, a: &$($lt)? $($mut)? Arm) -> Self::Result { + walk_arm(self, a) + } + + fn visit_pat(&mut self, p: &$($lt)? $($mut)? Pat) -> Self::Result { + walk_pat(self, p) + } + + fn visit_anon_const(&mut self, c: &$($lt)? $($mut)? AnonConst) -> Self::Result { + walk_anon_const(self, c) + } + + fn visit_expr(&mut self, ex: &$($lt)? $($mut)? Expr) -> Self::Result { + walk_expr(self, ex) + } + + /// This method is a hack to workaround unstable of `stmt_expr_attributes`. + /// It can be removed once that feature is stabilized. + fn visit_method_receiver_expr(&mut self, ex: &$($lt)? $($mut)? Expr) -> Self::Result { + self.visit_expr(ex) + } + + fn visit_ty(&mut self, t: &$($lt)? $($mut)? Ty) -> Self::Result { + walk_ty(self, t) + } + + fn visit_ty_pat(&mut self, t: &$($lt)? $($mut)? TyPat) -> Self::Result { + walk_ty_pat(self, t) + } + + fn visit_generic_param(&mut self, param: &$($lt)? $($mut)? GenericParam) -> Self::Result { + walk_generic_param(self, param) + } + + fn visit_generics(&mut self, g: &$($lt)? $($mut)? Generics) -> Self::Result { + walk_generics(self, g) + } + fn visit_closure_binder(&mut self, b: &$($lt)? $($mut)? ClosureBinder) -> Self::Result { + walk_closure_binder(self, b) + } + fn visit_contract(&mut self, c: &$($lt)? $($mut)? FnContract) -> Self::Result { + walk_contract(self, c) + } + + fn visit_where_predicate(&mut self, p: &$($lt)? $($mut)? WherePredicate) -> Self::Result { + walk_where_predicate(self, p) + } + + fn visit_where_predicate_kind(&mut self, k: &$($lt)? $($mut)? WherePredicateKind) -> Self::Result { + walk_where_predicate_kind(self, k) + } + + // for `MutVisitor`: `Span` and `NodeId` are mutated at the caller site. + fn visit_fn( + &mut self, + fk: FnKind<$($lt)? $(${ignore($mut)} '_)?>, + _: Span, + _: NodeId + ) -> Self::Result { + walk_fn(self, fk) + } + + fn visit_assoc_item(&mut self, i: &$($lt)? $($mut)? AssocItem, ctxt: AssocCtxt) -> Self::Result { + walk_assoc_item(self, i, ctxt) + } + + fn visit_trait_ref(&mut self, t: &$($lt)? $($mut)? TraitRef) -> Self::Result { + walk_trait_ref(self, t) + } + + fn visit_param_bound(&mut self, bounds: &$($lt)? $($mut)? GenericBound, _ctxt: BoundKind) -> Self::Result { + walk_param_bound(self, bounds) + } + + fn visit_precise_capturing_arg(&mut self, arg: &$($lt)? $($mut)? PreciseCapturingArg) -> Self::Result { + walk_precise_capturing_arg(self, arg) + } + + fn visit_poly_trait_ref(&mut self, t: &$($lt)? $($mut)? PolyTraitRef) -> Self::Result { + walk_poly_trait_ref(self, t) + } + + fn visit_variant_data(&mut self, s: &$($lt)? $($mut)? VariantData) -> Self::Result { + walk_variant_data(self, s) + } + + fn visit_field_def(&mut self, s: &$($lt)? $($mut)? FieldDef) -> Self::Result { + walk_field_def(self, s) + } + + fn visit_variant(&mut self, v: &$($lt)? $($mut)? Variant) -> Self::Result { + walk_variant(self, v) + } + + fn visit_label(&mut self, label: &$($lt)? $($mut)? Label) -> Self::Result { + walk_label(self, label) + } + + fn visit_lifetime(&mut self, lifetime: &$($lt)? $($mut)? Lifetime, $(${ignore($lt)} _: LifetimeCtxt )?) -> Self::Result { + walk_lifetime(self, lifetime) + } + + fn visit_mac_call(&mut self, mac: &$($lt)? $($mut)? MacCall) -> Self::Result { + walk_mac(self, mac) + } + + fn visit_id(&mut self, _id: $(&$mut)? NodeId) -> Self::Result { + Self::Result::output() + } + + fn visit_macro_def(&mut self, macro_def: &$($lt)? $($mut)? MacroDef) -> Self::Result { + walk_macro_def(self, macro_def) + } + + fn visit_path(&mut self, path: &$($lt)? $($mut)? Path) -> Self::Result { + walk_path(self, path) + } + + fn visit_use_tree(&mut self, use_tree: &$($lt)? $($mut)? UseTree) -> Self::Result { + walk_use_tree(self, use_tree) + } + + fn visit_path_segment(&mut self, path_segment: &$($lt)? $($mut)? PathSegment) -> Self::Result { + walk_path_segment(self, path_segment) + } + + fn visit_generic_args(&mut self, generic_args: &$($lt)? $($mut)? GenericArgs) -> Self::Result { + walk_generic_args(self, generic_args) + } + + fn visit_generic_arg(&mut self, generic_arg: &$($lt)? $($mut)? GenericArg) -> Self::Result { + walk_generic_arg(self, generic_arg) + } + + fn visit_assoc_item_constraint( + &mut self, + constraint: &$($lt)? $($mut)? AssocItemConstraint, + ) -> Self::Result { + walk_assoc_item_constraint(self, constraint) + } + + fn visit_attribute(&mut self, attr: &$($lt)? $($mut)? Attribute) -> Self::Result { + walk_attribute(self, attr) + } + + fn visit_vis(&mut self, vis: &$($lt)? $($mut)? Visibility) -> Self::Result { + walk_vis(self, vis) + } + + fn visit_fn_ret_ty(&mut self, ret_ty: &$($lt)? $($mut)? FnRetTy) -> Self::Result { + walk_fn_ret_ty(self, ret_ty) + } + + fn visit_fn_header(&mut self, header: &$($lt)? $($mut)? FnHeader) -> Self::Result { + walk_fn_header(self, header) + } + + fn visit_expr_field(&mut self, f: &$($lt)? $($mut)? ExprField) -> Self::Result { + walk_expr_field(self, f) + } + + fn visit_pat_field(&mut self, fp: &$($lt)? $($mut)? PatField) -> Self::Result { + walk_pat_field(self, fp) + } + + fn visit_crate(&mut self, krate: &$($lt)? $($mut)? Crate) -> Self::Result { + walk_crate(self, krate) + } + + fn visit_inline_asm(&mut self, asm: &$($lt)? $($mut)? InlineAsm) -> Self::Result { + walk_inline_asm(self, asm) + } + + fn visit_format_args(&mut self, fmt: &$($lt)? $($mut)? FormatArgs) -> Self::Result { + walk_format_args(self, fmt) + } + + fn visit_inline_asm_sym(&mut self, sym: &$($lt)? $($mut)? InlineAsmSym) -> Self::Result { + walk_inline_asm_sym(self, sym) + } + + fn visit_capture_by(&mut self, capture_by: &$($lt)? $($mut)? CaptureBy) -> Self::Result { + walk_capture_by(self, capture_by) + } + + fn visit_coroutine_kind(&mut self, coroutine_kind: &$($lt)? $($mut)? CoroutineKind) -> Self::Result { + walk_coroutine_kind(self, coroutine_kind) + } + + fn visit_fn_decl(&mut self, fn_decl: &$($lt)? $($mut)? FnDecl) -> Self::Result { + walk_fn_decl(self, fn_decl) + } + + fn visit_qself(&mut self, qs: &$($lt)? $($mut)? Option>) -> Self::Result { + walk_qself(self, qs) + } + + // (non-mut) `Visitor`-only methods + $( + fn visit_stmt(&mut self, s: &$lt Stmt) -> Self::Result { + walk_stmt(self, s) + } + + fn visit_nested_use_tree(&mut self, use_tree: &$lt UseTree, id: NodeId) -> Self::Result { + try_visit!(self.visit_id(id)); + self.visit_use_tree(use_tree) + } + )? + + // `MutVisitor`-only methods + $( + fn flat_map_foreign_item(&mut self, ni: P) -> SmallVec<[P; 1]> { + walk_flat_map_foreign_item(self, ni) + } + + fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { + walk_flat_map_item(self, i) + } + + fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> { + walk_flat_map_field_def(self, fd) + } + + fn flat_map_assoc_item( + &mut self, + i: P, + ctxt: AssocCtxt, + ) -> SmallVec<[P; 1]> { + walk_flat_map_assoc_item(self, i, ctxt) + } + + fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> { + walk_flat_map_stmt(self, s) + } + + fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { + walk_flat_map_arm(self, arm) + } + + fn filter_map_expr(&mut self, e: P) -> Option> { + walk_filter_map_expr(self, e) + } + + fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { + walk_flat_map_variant(self, v) + } + + fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { + walk_flat_map_param(self, param) + } + + fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { + walk_flat_map_generic_param(self, param) + } + + fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> { + walk_flat_map_expr_field(self, f) + } + + fn flat_map_where_predicate( + &mut self, + where_predicate: WherePredicate, + ) -> SmallVec<[WherePredicate; 1]> { + walk_flat_map_where_predicate(self, where_predicate) + } + + // Span visiting is no longer used, but we keep it for now, + // in case it's needed for something like #127241. + fn visit_span(&mut self, _sp: &$mut Span) { + // Do nothing. + } + + fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> { + walk_flat_map_pat_field(self, fp) + } + )? + } + pub trait WalkItemKind { type Ctxt; fn walk<$($lt,)? V: $Visitor$(<$lt>)?>( @@ -409,6 +569,24 @@ macro_rules! common_visitor_and_walkers { V::Result::output() } + $(${ignore($lt)} + #[inline] + )? + fn walk_capture_by<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + capture_by: &$($lt)? $($mut)? CaptureBy + ) -> V::Result { + match capture_by { + CaptureBy::Ref => { V::Result::output() } + CaptureBy::Value { move_kw } => { + visit_span(vis, move_kw) + } + CaptureBy::Use { use_kw } => { + visit_span(vis, use_kw) + } + } + } + fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) -> V::Result { walk_list!(visitor, visit_param_bound, bounds, ctxt); V::Result::output() @@ -989,8 +1167,7 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_vis(visibility)); try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_variant_data(data)); - $(${ignore($lt)} visit_opt!(vis, visit_variant_discr, disr_expr); )? - $(${ignore($mut)} visit_opt!(vis, visit_anon_const, disr_expr); )? + visit_opt!(vis, visit_anon_const, disr_expr); visit_span(vis, span) } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index fe44350863c9..ec3b87467a9b 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -161,7 +161,7 @@ impl MutVisitor for CfgEval<'_> { } #[instrument(level = "trace", skip(self))] - fn visit_method_receiver_expr(&mut self, expr: &mut P) { + fn visit_method_receiver_expr(&mut self, expr: &mut ast::Expr) { self.0.configure_expr(expr, true); mut_visit::walk_expr(self, expr); } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 9fd524ef45cd..b3d7f77940e4 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1873,14 +1873,14 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { /// It can be removed once that feature is stabilized. struct MethodReceiverTag; -impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> { - type OutputTy = Self; +impl InvocationCollectorNode for AstNodeWrapper { + type OutputTy = AstNodeWrapper, MethodReceiverTag>; const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr; fn descr() -> &'static str { "an expression" } fn to_annotatable(self) -> Annotatable { - Annotatable::Expr(self.wrapped) + Annotatable::Expr(P(self.wrapped)) } fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag) @@ -1983,9 +1983,9 @@ impl DummyAstNode for ast::Expr { } } -impl DummyAstNode for AstNodeWrapper, MethodReceiverTag> { +impl DummyAstNode for AstNodeWrapper { fn dummy() -> Self { - AstNodeWrapper::new(P(ast::Expr::dummy()), MethodReceiverTag) + AstNodeWrapper::new(ast::Expr::dummy(), MethodReceiverTag) } } @@ -2431,7 +2431,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.visit_node(node) } - fn visit_method_receiver_expr(&mut self, node: &mut P) { + fn visit_method_receiver_expr(&mut self, node: &mut ast::Expr) { self.visit_node(AstNodeWrapper::from_mut(node, MethodReceiverTag)) } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 2c486a02bdf1..6e1c6df4bcb4 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -339,9 +339,9 @@ impl MutVisitor for PlaceholderExpander { } } - fn visit_method_receiver_expr(&mut self, expr: &mut P) { + fn visit_method_receiver_expr(&mut self, expr: &mut ast::Expr) { match expr.kind { - ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(), + ast::ExprKind::MacCall(_) => *expr = *self.remove(expr.id).make_method_receiver_expr(), _ => walk_expr(self, expr), } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 338d9edcd22f..a965b38b9e8d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1432,11 +1432,14 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc fn visit_variant(&mut self, v: &'ast Variant) { self.resolve_doc_links(&v.attrs, MaybeExported::Ok(v.id)); - visit::walk_variant(self, v) - } - - fn visit_variant_discr(&mut self, discr: &'ast AnonConst) { - self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant); + self.visit_id(v.id); + walk_list!(self, visit_attribute, &v.attrs); + self.visit_vis(&v.vis); + self.visit_ident(&v.ident); + self.visit_variant_data(&v.data); + if let Some(discr) = &v.disr_expr { + self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant); + } } fn visit_field_def(&mut self, f: &'ast FieldDef) { diff --git a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr index f54b6803b346..0c969b9c6d82 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr @@ -9,6 +9,7 @@ LL | type Result = NotAValidResultType; ControlFlow note: required by a bound in `rustc_ast::visit::Visitor::Result` --> /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL + = note: this error originates in the macro `common_visitor_and_walkers` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr index 438c23458e2f..6ac8c3046f62 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr @@ -10,8 +10,9 @@ LL | type Result = NotAValidResultType; note: required by a bound in `rustc_ast::visit::Visitor::Result` --> $COMPILER_DIR_REAL/rustc_ast/src/visit.rs:LL:COL | -LL | type Result: VisitorResult = (); - | ^^^^^^^^^^^^^ required by this bound in `Visitor::Result` +LL | common_visitor_and_walkers!(Visitor<'a>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Visitor::Result` + = note: this error originates in the macro `common_visitor_and_walkers` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error From 867c1d5ebf15b1c710cf892c032ad5ec047b34b9 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 24 May 2025 12:10:55 +0000 Subject: [PATCH 138/356] one less pathbuf allocation --- src/librustdoc/html/render/write_shared.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 09b2b01486ec..7433c6276749 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -446,13 +446,13 @@ impl CratesIndexPart { /// Might return parts that are duplicate with ones in prexisting index.html fn get(crate_name: &str, external_crates: &[String]) -> Result, Error> { let mut ret = PartsAndLocations::default(); - let path = PathBuf::from("index.html"); + let path = Path::new("index.html"); for crate_name in external_crates.iter().map(|s| s.as_str()).chain(once(crate_name)) { let part = format!( "
  • {crate_name}
  • ", trailing_slash = ensure_trailing_slash(crate_name), ); - ret.push(path.clone(), part); + ret.push(path.to_path_buf(), part); } Ok(ret) } From 569aa26e7bf7f3742fbd6ab3ea3e3c5f9b8d8a75 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Wed, 18 Jun 2025 09:49:12 +0000 Subject: [PATCH 139/356] avoid intermediately collecting into vectors --- src/librustdoc/html/render/write_shared.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 7433c6276749..fc8111fffdca 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -733,7 +733,7 @@ impl TraitAliasPart { }, }; - let implementors = imps + let mut implementors = imps .iter() .filter_map(|imp| { // If the trait and implementation are in the same crate, then @@ -755,12 +755,12 @@ impl TraitAliasPart { }) } }) - .collect::>(); + .peekable(); // Only create a js file if we have impls to add to it. If the trait is // documented locally though we always create the file to avoid dead // links. - if implementors.is_empty() && !cache.paths.contains_key(&did) { + if implementors.peek().is_none() && !cache.paths.contains_key(&did) { continue; } @@ -771,11 +771,7 @@ impl TraitAliasPart { path.push(format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1])); let part = OrderedJson::array_sorted( - implementors - .iter() - .map(OrderedJson::serialize) - .collect::, _>>() - .unwrap(), + implementors.map(|implementor| OrderedJson::serialize(implementor).unwrap()), ); path_parts.push(path, OrderedJson::array_unsorted([crate_name_json, &part])); } From 2bf66e3887f8ef915a1f92496b1ddf27d847b1ee Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Wed, 18 Jun 2025 10:28:32 +0000 Subject: [PATCH 140/356] `Option`s are `Iterator`s --- src/librustdoc/html/render/write_shared.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index fc8111fffdca..606a91139087 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -866,9 +866,8 @@ impl<'item> DocVisitor<'item> for TypeImplCollector<'_, '_, 'item> { let impl_ = cache .impls .get(&target_did) - .map(|v| &v[..]) - .unwrap_or_default() - .iter() + .into_iter() + .flatten() .map(|impl_| { (impl_.impl_item.item_id, AliasedTypeImpl { impl_, type_aliases: Vec::new() }) }) @@ -883,14 +882,8 @@ impl<'item> DocVisitor<'item> for TypeImplCollector<'_, '_, 'item> { // Exclude impls that are directly on this type. They're already in the HTML. // Some inlining scenarios can cause there to be two versions of the same // impl: one on the type alias and one on the underlying target type. - let mut seen_impls: FxHashSet = cache - .impls - .get(&self_did) - .map(|s| &s[..]) - .unwrap_or_default() - .iter() - .map(|i| i.impl_item.item_id) - .collect(); + let mut seen_impls: FxHashSet = + cache.impls.get(&self_did).into_iter().flatten().map(|i| i.impl_item.item_id).collect(); for (impl_item_id, aliased_type_impl) in &mut aliased_type.impl_ { // Only include this impl if it actually unifies with this alias. // Synthetic impls are not included; those are also included in the HTML. From 7760f8ec4297fc9a8bf319ffefff02ba9b17458c Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 19 Jun 2025 18:31:56 +0800 Subject: [PATCH 141/356] add comment to `src/bootstrap/build.rs` --- src/bootstrap/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs index e0e32d313535..d9810e899a04 100644 --- a/src/bootstrap/build.rs +++ b/src/bootstrap/build.rs @@ -1,6 +1,7 @@ use std::env; fn main() { + // this is needed because `HOST` is only available to build scripts. let host = env::var("HOST").unwrap(); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-env=BUILD_TRIPLE={host}"); From 41ca0cb020fd2440a015f053f675303869bd17c6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 19 Jun 2025 20:32:17 +1000 Subject: [PATCH 142/356] Adjust `with_generic_param_rib`. Currently all of its call sites construct a `LifetimeRibKind::Generics` value, which `with_generic_param_rib` then deconstructs (and panics if it's a different `LifetimeRibKind` variant). This commit makes the code simpler and shorter: the call sites just pass in the three values and `with_generic_param_rib` constructs the `LifetimeRibKind::Generics` value from them. --- compiler/rustc_resolve/src/late.rs | 196 ++++++++++++----------------- 1 file changed, 77 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 338d9edcd22f..67dd87b0ae9e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -869,11 +869,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.with_generic_param_rib( &[], RibKind::Normal, - LifetimeRibKind::Generics { - binder: ty.id, - kind: LifetimeBinderKind::PolyTrait, - span, - }, + ty.id, + LifetimeBinderKind::PolyTrait, + span, |this| this.visit_path(path), ); } else { @@ -907,11 +905,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.with_generic_param_rib( &bare_fn.generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: ty.id, - kind: LifetimeBinderKind::BareFnType, - span, - }, + ty.id, + LifetimeBinderKind::BareFnType, + span, |this| { this.visit_generic_params(&bare_fn.generic_params, false); this.with_lifetime_rib( @@ -942,11 +938,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.with_generic_param_rib( &unsafe_binder.generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: ty.id, - kind: LifetimeBinderKind::BareFnType, - span, - }, + ty.id, + LifetimeBinderKind::BareFnType, + span, |this| { this.visit_generic_params(&unsafe_binder.generic_params, false); this.with_lifetime_rib( @@ -995,11 +989,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.with_generic_param_rib( &tref.bound_generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: tref.trait_ref.ref_id, - kind: LifetimeBinderKind::PolyTrait, - span, - }, + tref.trait_ref.ref_id, + LifetimeBinderKind::PolyTrait, + span, |this| { this.visit_generic_params(&tref.bound_generic_params, false); this.smart_resolve_path( @@ -1020,11 +1012,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: foreign_item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + foreign_item.id, + LifetimeBinderKind::Item, + generics.span, |this| visit::walk_item(this, foreign_item), ); } @@ -1032,11 +1022,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: foreign_item.id, - kind: LifetimeBinderKind::Function, - span: generics.span, - }, + foreign_item.id, + LifetimeBinderKind::Function, + generics.span, |this| visit::walk_item(this, foreign_item), ); } @@ -1374,11 +1362,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc this.with_generic_param_rib( bound_generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: bounded_ty.id, - kind: LifetimeBinderKind::WhereBound, - span, - }, + bounded_ty.id, + LifetimeBinderKind::WhereBound, + span, |this| { this.visit_generic_params(bound_generic_params, false); this.visit_ty(bounded_ty); @@ -2555,11 +2541,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); this.with_self_rib( @@ -2632,11 +2616,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| visit::walk_item(this, item), ); } @@ -2645,11 +2627,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Function, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Function, + generics.span, |this| visit::walk_item(this, item), ); self.resolve_define_opaques(define_opaque); @@ -2685,11 +2665,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| { let local_def_id = this.r.local_def_id(item.id).to_def_id(); this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { @@ -2706,11 +2684,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Item, - span: generics.span, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| { let local_def_id = this.r.local_def_id(item.id).to_def_id(); this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { @@ -2776,11 +2752,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, def_kind, ), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::ConstItem, - span: generics.span, - }, + item.id, + LifetimeBinderKind::ConstItem, + generics.span, |this| { this.visit_generics(generics); @@ -2825,11 +2799,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &[], RibKind::Item(HasGenericParams::Yes(span), def_kind), - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Function, - span, - }, + item.id, + LifetimeBinderKind::Function, + span, |this| this.resolve_delegation(delegation), ); } @@ -2846,17 +2818,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &'c mut self, params: &'c [GenericParam], kind: RibKind<'ra>, - lifetime_kind: LifetimeRibKind, + binder: NodeId, + generics_kind: LifetimeBinderKind, + generics_span: Span, f: F, ) where F: FnOnce(&mut Self), { debug!("with_generic_param_rib"); - let LifetimeRibKind::Generics { binder, span: generics_span, kind: generics_kind, .. } = - lifetime_kind - else { - panic!() - }; + let lifetime_kind = + LifetimeRibKind::Generics { binder, span: generics_span, kind: generics_kind }; let mut function_type_rib = Rib::new(kind); let mut function_value_rib = Rib::new(kind); @@ -3086,7 +3057,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind }, + item.id, + kind, + generics.span, |this| visit::walk_assoc_item(this, item, AssocCtxt::Trait), ); }; @@ -3104,11 +3077,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind: LifetimeBinderKind::ConstItem, - }, + item.id, + LifetimeBinderKind::ConstItem, + generics.span, |this| { this.with_lifetime_rib( LifetimeRibKind::StaticIfNoLifetimeInScope { @@ -3145,11 +3116,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &[], RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Function, - span: delegation.path.segments.last().unwrap().ident.span, - }, + item.id, + LifetimeBinderKind::Function, + delegation.path.segments.last().unwrap().ident.span, |this| this.resolve_delegation(delegation), ); } @@ -3227,11 +3196,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), self.r.local_def_kind(item_id)), - LifetimeRibKind::Generics { - span: generics.span, - binder: item_id, - kind: LifetimeBinderKind::ImplBlock, - }, + item_id, + LifetimeBinderKind::ImplBlock, + generics.span, |this| { // Dummy self type for better errors if `Self` is used in the trait path. this.with_self_rib(Res::SelfTyParam { trait_: LOCAL_CRATE.as_def_id() }, |this| { @@ -3316,15 +3283,14 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind: LifetimeBinderKind::ConstItem, - }, + item.id, + LifetimeBinderKind::ConstItem, + generics.span, |this| { this.with_lifetime_rib( - // Until these are a hard error, we need to create them within the correct binder, - // Otherwise the lifetimes of this assoc const think they are lifetimes of the trait. + // Until these are a hard error, we need to create them within the + // correct binder, Otherwise the lifetimes of this assoc const think + // they are lifetimes of the trait. LifetimeRibKind::AnonymousCreateParameter { binder: item.id, report_in_path: true, @@ -3373,11 +3339,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind: LifetimeBinderKind::Function, - }, + item.id, + LifetimeBinderKind::Function, + generics.span, |this| { // If this is a trait impl, ensure the method // exists in trait @@ -3404,11 +3368,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &generics.params, RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind: LifetimeBinderKind::Item, - }, + item.id, + LifetimeBinderKind::Item, + generics.span, |this| { this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { // If this is a trait impl, ensure the type @@ -3434,11 +3396,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( &[], RibKind::AssocItem, - LifetimeRibKind::Generics { - binder: item.id, - kind: LifetimeBinderKind::Function, - span: delegation.path.segments.last().unwrap().ident.span, - }, + item.id, + LifetimeBinderKind::Function, + delegation.path.segments.last().unwrap().ident.span, |this| { this.check_trait_item( item.id, @@ -4951,11 +4911,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.with_generic_param_rib( generic_params, RibKind::Normal, - LifetimeRibKind::Generics { - binder: expr.id, - kind: LifetimeBinderKind::Closure, - span, - }, + expr.id, + LifetimeBinderKind::Closure, + span, |this| visit::walk_expr(this, expr), ); } From ede48910fdb8956f4a23a3bb29ded754206a3ef2 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 19 Jun 2025 13:18:33 +0200 Subject: [PATCH 143/356] Update compiler/rustc_interface/src/passes.rs Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- compiler/rustc_interface/src/passes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d29656fedd5b..21bb8b152711 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1010,7 +1010,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // Prefetch this to prevent multiple threads from blocking on it later. // This is needed since the `hir_id_validator::check_crate` call above is not guaranteed - // to use `hir_crate`. + // to use `hir_crate_items`. tcx.ensure_done().hir_crate_items(()); let sess = tcx.sess; From ecdf220dbcd19ba15a2707231df4f25eef498906 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 19 Jun 2025 11:39:21 +0000 Subject: [PATCH 144/356] vec tests: remove static mut --- library/alloctests/testing/macros.rs | 24 ++++- library/alloctests/tests/testing/mod.rs | 2 + library/alloctests/tests/vec.rs | 119 ++++++------------------ 3 files changed, 53 insertions(+), 92 deletions(-) diff --git a/library/alloctests/testing/macros.rs b/library/alloctests/testing/macros.rs index 37cf59bc1693..2433e53ca895 100644 --- a/library/alloctests/testing/macros.rs +++ b/library/alloctests/testing/macros.rs @@ -1,13 +1,33 @@ macro_rules! struct_with_counted_drop { - ($struct_name:ident$(($elt_ty:ty))?, $drop_counter:ident $(=> $drop_stmt:expr)?) => { + ($struct_name:ident $(( $( $elt_ty:ty ),+ ))?, $drop_counter:ident $( => $drop_stmt:expr )? ) => { thread_local! {static $drop_counter: ::core::cell::Cell = ::core::cell::Cell::new(0);} - struct $struct_name$(($elt_ty))?; + #[derive(Clone, Debug, PartialEq)] + struct $struct_name $(( $( $elt_ty ),+ ))?; impl ::std::ops::Drop for $struct_name { fn drop(&mut self) { $drop_counter.set($drop_counter.get() + 1); + $($drop_stmt(self))? + } + } + }; + ($struct_name:ident $(( $( $elt_ty:ty ),+ ))?, $drop_counter:ident[ $drop_key:expr,$key_ty:ty ] $( => $drop_stmt:expr )? ) => { + thread_local! { + static $drop_counter: ::core::cell::RefCell<::std::collections::HashMap<$key_ty, u32>> = + ::core::cell::RefCell::new(::std::collections::HashMap::new()); + } + + #[derive(Clone, Debug, PartialEq)] + struct $struct_name $(( $( $elt_ty ),+ ))?; + + impl ::std::ops::Drop for $struct_name { + fn drop(&mut self) { + $drop_counter.with_borrow_mut(|counter| { + *counter.entry($drop_key(self)).or_default() += 1; + }); + $($drop_stmt(self))? } } diff --git a/library/alloctests/tests/testing/mod.rs b/library/alloctests/tests/testing/mod.rs index 0a3dd191dc89..f0911406cf99 100644 --- a/library/alloctests/tests/testing/mod.rs +++ b/library/alloctests/tests/testing/mod.rs @@ -1 +1,3 @@ pub mod crash_test; +#[path = "../../testing/macros.rs"] +pub mod macros; diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 51b49b8edb3f..00f640cd17ea 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -1,6 +1,3 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] - use core::alloc::{Allocator, Layout}; use core::num::NonZero; use core::ptr::NonNull; @@ -20,6 +17,8 @@ use std::rc::Rc; use std::sync::atomic::{AtomicU32, Ordering}; use std::vec::{Drain, IntoIter}; +use crate::testing::macros::struct_with_counted_drop; + struct DropCounter<'a> { count: &'a mut u32, } @@ -548,32 +547,25 @@ fn test_cmp() { #[test] fn test_vec_truncate_drop() { - static mut DROPS: u32 = 0; - struct Elem(#[allow(dead_code)] i32); - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem(i32), DROPS); let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; - assert_eq!(unsafe { DROPS }, 0); + + assert_eq!(DROPS.get(), 0); v.truncate(3); - assert_eq!(unsafe { DROPS }, 2); + assert_eq!(DROPS.get(), 2); v.truncate(0); - assert_eq!(unsafe { DROPS }, 5); + assert_eq!(DROPS.get(), 5); } #[test] #[should_panic] fn test_vec_truncate_fail() { struct BadElem(i32); + impl Drop for BadElem { fn drop(&mut self) { - let BadElem(ref mut x) = *self; - if *x == 0xbadbeef { + if let BadElem(0xbadbeef) = self { panic!("BadElem panic: 0xbadbeef") } } @@ -812,22 +804,7 @@ fn test_drain_end_overflow() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_leak() { - static mut DROPS: i32 = 0; - - #[derive(Debug, PartialEq)] - struct D(u32, bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.1 { - panic!("panic in `drop`"); - } - } - } + struct_with_counted_drop!(D(u32, bool), DROPS => |this: &D| if this.1 { panic!("panic in `drop`"); }); let mut v = vec![ D(0, false), @@ -844,7 +821,7 @@ fn test_drain_leak() { })) .ok(); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]); } @@ -1057,27 +1034,13 @@ fn test_into_iter_clone() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_into_iter_leak() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } + struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); }); let v = vec![D(false), D(true), D(false)]; catch_unwind(move || drop(v.into_iter())).ok(); - assert_eq!(unsafe { DROPS }, 3); + assert_eq!(DROPS.get(), 3); } #[test] @@ -1274,55 +1237,31 @@ fn test_from_iter_specialization_panic_during_iteration_drops() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#[allow(static_mut_refs)] fn test_from_iter_specialization_panic_during_drop_doesnt_leak() { - static mut DROP_COUNTER_OLD: [usize; 5] = [0; 5]; - static mut DROP_COUNTER_NEW: [usize; 2] = [0; 2]; - - #[derive(Debug)] - struct Old(usize); - - impl Drop for Old { - fn drop(&mut self) { - unsafe { - DROP_COUNTER_OLD[self.0] += 1; + struct_with_counted_drop!( + Old(usize), DROP_COUNTER_OLD[|this: &Old| this.0, usize] => + |this: &Old| { + if this.0 == 3 { panic!(); } println!("Dropped Old: {}", this.0) } - - if self.0 == 3 { - panic!(); - } - - println!("Dropped Old: {}", self.0); - } - } - - #[derive(Debug)] - struct New(usize); - - impl Drop for New { - fn drop(&mut self) { - unsafe { - DROP_COUNTER_NEW[self.0] += 1; - } - - println!("Dropped New: {}", self.0); - } - } + ); + struct_with_counted_drop!( + New(usize), DROP_COUNTER_NEW[|this: &New| this.0, usize] => + |this: &New| println!("Dropped New: {}", this.0) + ); let _ = std::panic::catch_unwind(AssertUnwindSafe(|| { let v = vec![Old(0), Old(1), Old(2), Old(3), Old(4)]; let _ = v.into_iter().map(|x| New(x.0)).take(2).collect::>(); })); - assert_eq!(unsafe { DROP_COUNTER_OLD[0] }, 1); - assert_eq!(unsafe { DROP_COUNTER_OLD[1] }, 1); - assert_eq!(unsafe { DROP_COUNTER_OLD[2] }, 1); - assert_eq!(unsafe { DROP_COUNTER_OLD[3] }, 1); - assert_eq!(unsafe { DROP_COUNTER_OLD[4] }, 1); + DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&0), Some(&1))); + DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&1), Some(&1))); + DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&2), Some(&1))); + DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&3), Some(&1))); + DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&4), Some(&1))); - assert_eq!(unsafe { DROP_COUNTER_NEW[0] }, 1); - assert_eq!(unsafe { DROP_COUNTER_NEW[1] }, 1); + DROP_COUNTER_NEW.with_borrow(|c| assert_eq!(c.get(&0), Some(&1))); + DROP_COUNTER_NEW.with_borrow(|c| assert_eq!(c.get(&1), Some(&1))); } // regression test for issue #85322. Peekable previously implemented InPlaceIterable, From 456c9da45a7ccb0903f4d462d93ecffcb51b9d65 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 19 Jun 2025 11:51:47 +0000 Subject: [PATCH 145/356] vec_deque alloctests: remove static mut --- library/alloctests/tests/vec_deque.rs | 119 ++++---------------------- 1 file changed, 18 insertions(+), 101 deletions(-) diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index b77ea3a312be..a82906d55e5d 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -1,6 +1,3 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#![allow(static_mut_refs)] - use core::num::NonZero; use std::assert_matches::assert_matches; use std::collections::TryReserveErrorKind::*; @@ -14,6 +11,7 @@ use Taggy::*; use Taggypar::*; use crate::hash; +use crate::testing::macros::struct_with_counted_drop; #[test] fn test_simple() { @@ -719,15 +717,7 @@ fn test_show() { #[test] fn test_drop() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem, DROPS); let mut ring = VecDeque::new(); ring.push_back(Elem); @@ -736,20 +726,12 @@ fn test_drop() { ring.push_front(Elem); drop(ring); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); } #[test] fn test_drop_with_pop() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem, DROPS); let mut ring = VecDeque::new(); ring.push_back(Elem); @@ -759,23 +741,15 @@ fn test_drop_with_pop() { drop(ring.pop_back()); drop(ring.pop_front()); - assert_eq!(unsafe { DROPS }, 2); + assert_eq!(DROPS.get(), 2); drop(ring); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); } #[test] fn test_drop_clear() { - static mut DROPS: i32 = 0; - struct Elem; - impl Drop for Elem { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - } - } + struct_with_counted_drop!(Elem, DROPS); let mut ring = VecDeque::new(); ring.push_back(Elem); @@ -783,30 +757,16 @@ fn test_drop_clear() { ring.push_back(Elem); ring.push_front(Elem); ring.clear(); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); drop(ring); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); } #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drop_panic() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } + struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } ); let mut q = VecDeque::new(); q.push_back(D(false)); @@ -820,7 +780,7 @@ fn test_drop_panic() { catch_unwind(move || drop(q)).ok(); - assert_eq!(unsafe { DROPS }, 8); + assert_eq!(DROPS.get(), 8); } #[test] @@ -1655,21 +1615,7 @@ fn test_try_rfold_moves_iter() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn truncate_leak() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } + struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } ); let mut q = VecDeque::new(); q.push_back(D(false)); @@ -1683,27 +1629,13 @@ fn truncate_leak() { catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok(); - assert_eq!(unsafe { DROPS }, 7); + assert_eq!(DROPS.get(), 7); } #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn truncate_front_leak() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } + struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } ); let mut q = VecDeque::new(); q.push_back(D(false)); @@ -1717,28 +1649,13 @@ fn truncate_front_leak() { catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok(); - assert_eq!(unsafe { DROPS }, 7); + assert_eq!(DROPS.get(), 7); } #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_leak() { - static mut DROPS: i32 = 0; - - #[derive(Debug, PartialEq)] - struct D(u32, bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.1 { - panic!("panic in `drop`"); - } - } - } + struct_with_counted_drop!(D(u32, bool), DROPS => |this: &D| if this.1 { panic!("panic in `drop`"); } ); let mut v = VecDeque::new(); v.push_back(D(4, false)); @@ -1754,10 +1671,10 @@ fn test_drain_leak() { })) .ok(); - assert_eq!(unsafe { DROPS }, 4); + assert_eq!(DROPS.get(), 4); assert_eq!(v.len(), 3); drop(v); - assert_eq!(unsafe { DROPS }, 7); + assert_eq!(DROPS.get(), 7); } #[test] From eefd59872565330fc5905dc5903a56ce93fca47e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 19 Jun 2025 12:40:50 +0200 Subject: [PATCH 146/356] correct template for `#[align]` it should not suggest just `#[align]` --- .../rustc_attr_parsing/src/attributes/repr.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 2 +- .../compiler-flags/min-function-alignment.md | 2 +- tests/ui/attributes/malformed-fn-align.rs | 5 +- tests/ui/attributes/malformed-fn-align.stderr | 47 ++++++++++--------- .../feature-gate-fn_align.stderr | 10 ++-- 6 files changed, 35 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index c9f9f34bdb7c..eb16c3f95f0c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -273,7 +273,7 @@ pub(crate) struct AlignParser(Option<(Align, Span)>); impl AlignParser { const PATH: &'static [Symbol] = &[sym::align]; - const TEMPLATE: AttributeTemplate = template!(Word, List: ""); + const TEMPLATE: AttributeTemplate = template!(List: ""); fn parse<'c, S: Stage>( &mut self, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a7bc6207149f..91715851226b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -510,7 +510,7 @@ declare_features! ( (unstable, ffi_pure, "1.45.0", Some(58329)), /// Controlling the behavior of fmt::Debug (unstable, fmt_debug, "1.82.0", Some(129709)), - /// Allows using `#[repr(align(...))]` on function items + /// Allows using `#[align(...)]` on function items (unstable, fn_align, "1.53.0", Some(82232)), /// Support delegating implementation of functions to other already implemented functions. (incomplete, fn_delegation, "1.76.0", Some(118212)), diff --git a/src/doc/unstable-book/src/compiler-flags/min-function-alignment.md b/src/doc/unstable-book/src/compiler-flags/min-function-alignment.md index b7a3aa71fc4c..03e576e3e300 100644 --- a/src/doc/unstable-book/src/compiler-flags/min-function-alignment.md +++ b/src/doc/unstable-book/src/compiler-flags/min-function-alignment.md @@ -15,7 +15,7 @@ This flag is equivalent to: - `-fmin-function-alignment` for [GCC](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fmin-function-alignment_003dn) - `-falign-functions` for [Clang](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang1-falign-functions) -The specified alignment is a minimum. A higher alignment can be specified for specific functions by using the [`repr(align(...))`](https://github.com/rust-lang/rust/issues/82232) feature and annotating the function with a `#[repr(align())]` attribute. The attribute's value is ignored when it is lower than the value passed to `min-function-alignment`. +The specified alignment is a minimum. A higher alignment can be specified for specific functions by using the [`align(...)`](https://github.com/rust-lang/rust/issues/82232) feature and annotating the function with a `#[align()]` attribute. The attribute's value is ignored when it is lower than the value passed to `min-function-alignment`. There are two additional edge cases for this flag: diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs index 35ffd6d8acce..f5ab9555e561 100644 --- a/tests/ui/attributes/malformed-fn-align.rs +++ b/tests/ui/attributes/malformed-fn-align.rs @@ -3,7 +3,10 @@ trait MyTrait { #[align] //~ ERROR malformed `align` attribute input - fn myfun(); + fn myfun1(); + + #[align(1, 2)] //~ ERROR malformed `align` attribute input + fn myfun2(); } #[align = 16] //~ ERROR malformed `align` attribute input diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr index 765255c2c3a9..b769d0b457dd 100644 --- a/tests/ui/attributes/malformed-fn-align.stderr +++ b/tests/ui/attributes/malformed-fn-align.stderr @@ -2,54 +2,55 @@ error[E0539]: malformed `align` attribute input --> $DIR/malformed-fn-align.rs:5:5 | LL | #[align] - | ^^^^^^^^ expected this to be a list + | ^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[align()]` + +error[E0805]: malformed `align` attribute input + --> $DIR/malformed-fn-align.rs:8:5 | -help: try changing it to one of the following valid forms of the attribute - | -LL | #[align()] - | ++++++++++++++++++++++ +LL | #[align(1, 2)] + | ^^^^^^^------^ + | | | + | | expected a single argument here + | help: must be of the form: `#[align()]` error[E0539]: malformed `align` attribute input - --> $DIR/malformed-fn-align.rs:9:1 + --> $DIR/malformed-fn-align.rs:12:1 | LL | #[align = 16] - | ^^^^^^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL - #[align = 16] -LL + #[align()] - | -LL - #[align = 16] -LL + #[align] - | + | ^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[align()]` error[E0589]: invalid alignment value: not an unsuffixed integer - --> $DIR/malformed-fn-align.rs:12:9 + --> $DIR/malformed-fn-align.rs:15:9 | LL | #[align("hello")] | ^^^^^^^ error[E0589]: invalid alignment value: not a power of two - --> $DIR/malformed-fn-align.rs:15:9 + --> $DIR/malformed-fn-align.rs:18:9 | LL | #[align(0)] | ^ error: `#[repr(align(...))]` is not supported on function items - --> $DIR/malformed-fn-align.rs:18:8 + --> $DIR/malformed-fn-align.rs:21:8 | LL | #[repr(align(16))] | ^^^^^^^^^ | help: use `#[align(...)]` instead - --> $DIR/malformed-fn-align.rs:18:8 + --> $DIR/malformed-fn-align.rs:21:8 | LL | #[repr(align(16))] | ^^^^^^^^^ error: `#[align(...)]` is not supported on struct items - --> $DIR/malformed-fn-align.rs:21:1 + --> $DIR/malformed-fn-align.rs:24:1 | LL | #[align(16)] | ^^^^^^^^^^^^ @@ -60,7 +61,7 @@ LL - #[align(16)] LL + #[repr(align(16))] | -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0539, E0589. +Some errors have detailed explanations: E0539, E0589, E0805. For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/feature-gates/feature-gate-fn_align.stderr b/tests/ui/feature-gates/feature-gate-fn_align.stderr index 93ef136dc73c..921cf08435c2 100644 --- a/tests/ui/feature-gates/feature-gate-fn_align.stderr +++ b/tests/ui/feature-gates/feature-gate-fn_align.stderr @@ -22,12 +22,10 @@ error[E0539]: malformed `align` attribute input --> $DIR/feature-gate-fn_align.rs:8:5 | LL | #[align] - | ^^^^^^^^ expected this to be a list - | -help: try changing it to one of the following valid forms of the attribute - | -LL | #[align()] - | ++++++++++++++++++++++ + | ^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[align()]` error: aborting due to 3 previous errors From 2da3a66c5525a860f3aacd50877db4a0772b9023 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 19 Jun 2025 14:08:20 +0200 Subject: [PATCH 147/356] Use expr_ref. --- compiler/rustc_ast_lowering/src/format.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 7a4e056175c0..12f0af754868 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -551,8 +551,7 @@ fn expand_format_args<'hir>( // Generate: // &args - let args = - ctx.expr(macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, args)); + let args = ctx.expr_ref(macsp, args); let call = if let Some(format_options) = format_options { // Generate: From 9c2276818369d20e683497459b85e93d9c5aee84 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 19 Jun 2025 12:08:24 +0000 Subject: [PATCH 148/356] atomic tests: remove static mut --- library/coretests/tests/atomic.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/library/coretests/tests/atomic.rs b/library/coretests/tests/atomic.rs index e0c0fe4790c0..b1ab443aa6e5 100644 --- a/library/coretests/tests/atomic.rs +++ b/library/coretests/tests/atomic.rs @@ -228,24 +228,20 @@ fn static_init() { } #[test] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#[allow(static_mut_refs)] fn atomic_access_bool() { - static mut ATOMIC: AtomicBool = AtomicBool::new(false); + let mut atom = AtomicBool::new(false); - unsafe { - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.store(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_or(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_and(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.fetch_nand(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_xor(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - } + assert_eq!(*atom.get_mut(), false); + atom.store(true, SeqCst); + assert_eq!(*atom.get_mut(), true); + atom.fetch_or(false, SeqCst); + assert_eq!(*atom.get_mut(), true); + atom.fetch_and(false, SeqCst); + assert_eq!(*atom.get_mut(), false); + atom.fetch_nand(true, SeqCst); + assert_eq!(*atom.get_mut(), true); + atom.fetch_xor(true, SeqCst); + assert_eq!(*atom.get_mut(), false); } #[test] From b4f2cac097504a0728206b08fd4f8cb3d0946a3c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 19 Jun 2025 14:08:29 +0200 Subject: [PATCH 149/356] Remove old format_args diagnostic. --- .../src/diagnostics/conflict_errors.rs | 38 ++++++------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 34d368499397..98dc898db232 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3201,14 +3201,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let expr_ty: Option> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); - let is_format_arguments_item = if let Some(expr_ty) = expr_ty - && let ty::Adt(adt, _) = expr_ty.kind() - { - self.infcx.tcx.is_lang_item(adt.did(), LangItem::FormatArguments) - } else { - false - }; - if visitor.found == 0 && stmt.span.contains(proper_span) && let Some(p) = sm.span_to_margin(stmt.span) @@ -3236,25 +3228,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { "" }; - if !is_format_arguments_item { - let addition = format!( - "let {}binding = {};\n{}", - mutability, - s, - " ".repeat(p) - ); - err.multipart_suggestion_verbose( - msg, - vec![ - (stmt.span.shrink_to_lo(), addition), - (proper_span, "binding".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } else { - err.note("the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used"); - err.note("to learn more, visit "); - } + let addition = + format!("let {}binding = {};\n{}", mutability, s, " ".repeat(p)); + err.multipart_suggestion_verbose( + msg, + vec![ + (stmt.span.shrink_to_lo(), addition), + (proper_span, "binding".to_string()), + ], + Applicability::MaybeIncorrect, + ); + suggested = true; break; } From aca0688a1dd16e0bc41ac41c5b861384c418427e Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Thu, 19 Jun 2025 13:50:54 +0000 Subject: [PATCH 150/356] De-dup common code from `ExternalCrate` methods --- src/librustdoc/clean/types.rs | 118 ++++++++----------- src/librustdoc/clean/utils.rs | 4 +- src/librustdoc/passes/collect_trait_impls.rs | 2 +- 3 files changed, 53 insertions(+), 71 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2d9670a3d10c..408ef611ee52 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -4,6 +4,7 @@ use std::sync::{Arc, OnceLock as OnceCell}; use std::{fmt, iter}; use arrayvec::ArrayVec; +use itertools::Either; use rustc_abi::{ExternAbi, VariantIdx}; use rustc_attr_data_structures::{ AttributeKind, ConstStability, Deprecation, Stability, StableSince, @@ -199,49 +200,49 @@ impl ExternalCrate { .unwrap_or(Unknown) // Well, at least we tried. } - pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> { + fn mapped_root_modules( + &self, + tcx: TyCtxt<'_>, + f: impl Fn(DefId, TyCtxt<'_>) -> Option<(DefId, T)>, + ) -> impl Iterator { let root = self.def_id(); - let as_keyword = |res: Res| { - if let Res::Def(DefKind::Mod, def_id) = res { - let mut keyword = None; - let meta_items = tcx - .get_attrs(def_id, sym::doc) - .flat_map(|attr| attr.meta_item_list().unwrap_or_default()); - for meta in meta_items { - if meta.has_name(sym::keyword) - && let Some(v) = meta.value_str() - { - keyword = Some(v); - break; - } - } - return keyword.map(|p| (def_id, p)); - } - None - }; if root.is_local() { - tcx.hir_root_module() - .item_ids - .iter() - .filter_map(|&id| { - let item = tcx.hir_item(id); - match item.kind { - hir::ItemKind::Mod(..) => { - as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id())) - } - _ => None, - } - }) - .collect() + Either::Left( + tcx.hir_root_module() + .item_ids + .iter() + .filter(move |&&id| matches!(tcx.hir_item(id).kind, hir::ItemKind::Mod(..))) + .filter_map(move |&id| f(id.owner_id.into(), tcx)), + ) } else { - tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect() + Either::Right( + tcx.module_children(root) + .iter() + .filter_map(|item| { + if let Res::Def(DefKind::Mod, did) = item.res { Some(did) } else { None } + }) + .filter_map(move |did| f(did, tcx)), + ) } } - pub(crate) fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> { - let root = self.def_id(); + pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator { + fn as_keyword(did: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, Symbol)> { + tcx.get_attrs(did, sym::doc) + .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) + .filter(|meta| meta.has_name(sym::keyword)) + .find_map(|meta| meta.value_str()) + .map(|value| (did, value)) + } + self.mapped_root_modules(tcx, as_keyword) + } + + pub(crate) fn primitives( + &self, + tcx: TyCtxt<'_>, + ) -> impl Iterator { // Collect all inner modules which are tagged as implementations of // primitives. // @@ -259,40 +260,21 @@ impl ExternalCrate { // Also note that this does not attempt to deal with modules tagged // duplicately for the same primitive. This is handled later on when // rendering by delegating everything to a hash map. - let as_primitive = |res: Res| { - let Res::Def(DefKind::Mod, def_id) = res else { return None }; - tcx.get_attrs(def_id, sym::rustc_doc_primitive) - .map(|attr| { - let attr_value = attr.value_str().expect("syntax should already be validated"); - let Some(prim) = PrimitiveType::from_symbol(attr_value) else { - span_bug!( - attr.span(), - "primitive `{attr_value}` is not a member of `PrimitiveType`" - ); - }; + fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, PrimitiveType)> { + tcx.get_attrs(def_id, sym::rustc_doc_primitive).next().map(|attr| { + let attr_value = attr.value_str().expect("syntax should already be validated"); + let Some(prim) = PrimitiveType::from_symbol(attr_value) else { + span_bug!( + attr.span(), + "primitive `{attr_value}` is not a member of `PrimitiveType`" + ); + }; - (def_id, prim) - }) - .next() - }; - - if root.is_local() { - tcx.hir_root_module() - .item_ids - .iter() - .filter_map(|&id| { - let item = tcx.hir_item(id); - match item.kind { - hir::ItemKind::Mod(..) => { - as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id())) - } - _ => None, - } - }) - .collect() - } else { - tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect() + (def_id, prim) + }) } + + self.mapped_root_modules(tcx, as_primitive) } } @@ -1966,7 +1948,7 @@ impl PrimitiveType { let e = ExternalCrate { crate_num }; let crate_name = e.name(tcx); debug!(?crate_num, ?crate_name); - for &(def_id, prim) in &e.primitives(tcx) { + for (def_id, prim) in e.primitives(tcx) { // HACK: try to link to std instead where possible if crate_name == sym::core && primitive_locations.contains_key(&prim) { continue; diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c58b07a5b673..2c9878636abf 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -61,7 +61,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { let keywords = local_crate.keywords(cx.tcx); { let ItemKind::ModuleItem(m) = &mut module.inner.kind else { unreachable!() }; - m.items.extend(primitives.iter().map(|&(def_id, prim)| { + m.items.extend(primitives.map(|(def_id, prim)| { Item::from_def_id_and_parts( def_id, Some(prim.as_sym()), @@ -69,7 +69,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { cx, ) })); - m.items.extend(keywords.into_iter().map(|(def_id, kw)| { + m.items.extend(keywords.map(|(def_id, kw)| { Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem, cx) })); } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index f4e4cd924f7f..2339a6b69cd8 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -35,7 +35,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> }); let local_crate = ExternalCrate { crate_num: LOCAL_CRATE }; - let prims: FxHashSet = local_crate.primitives(tcx).iter().map(|p| p.1).collect(); + let prims: FxHashSet = local_crate.primitives(tcx).map(|(_, p)| p).collect(); let crate_items = { let mut coll = ItemAndAliasCollector::new(&cx.cache); From b26dfa175c302f7752192ac20844fbff0c1d06c2 Mon Sep 17 00:00:00 2001 From: Kornel Date: Thu, 19 Jun 2025 16:55:09 +0100 Subject: [PATCH 151/356] Let String pass #[track_caller] to its Vec calls --- library/alloc/src/string.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 7c71594c4303..1b24118660f7 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1105,6 +1105,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("append", "push")] #[rustc_diagnostic_item = "string_push_str"] @@ -1135,6 +1136,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "string_extend_from_within", since = "1.87.0")] + #[track_caller] pub fn extend_from_within(&mut self, src: R) where R: RangeBounds, @@ -1206,6 +1208,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { self.vec.reserve(additional) @@ -1257,6 +1260,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn reserve_exact(&mut self, additional: usize) { self.vec.reserve_exact(additional) } @@ -1352,6 +1356,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { self.vec.shrink_to_fit() @@ -1379,6 +1384,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { self.vec.shrink_to(min_capacity) @@ -1400,6 +1406,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn push(&mut self, ch: char) { let len = self.len(); let ch_len = ch.len_utf8(); @@ -1889,6 +1896,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "string_split_off", since = "1.16.0")] #[must_use = "use `.truncate()` if you don't need the other half"] pub fn split_off(&mut self, at: usize) -> String { @@ -2101,6 +2109,7 @@ impl String { #[stable(feature = "box_str", since = "1.4.0")] #[must_use = "`self` will be dropped if the result is not used"] #[inline] + #[track_caller] pub fn into_boxed_str(self) -> Box { let slice = self.vec.into_boxed_slice(); unsafe { from_boxed_utf8_unchecked(slice) } @@ -2288,6 +2297,7 @@ impl Error for FromUtf16Error { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for String { + #[track_caller] fn clone(&self) -> Self { String { vec: self.vec.clone() } } @@ -2296,6 +2306,7 @@ impl Clone for String { /// /// This method is preferred over simply assigning `source.clone()` to `self`, /// as it avoids reallocation if possible. + #[track_caller] fn clone_from(&mut self, source: &Self) { self.vec.clone_from(&source.vec); } @@ -2469,11 +2480,14 @@ impl<'a> Extend> for String { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "ascii_char", issue = "110998")] impl Extend for String { + #[inline] + #[track_caller] fn extend>(&mut self, iter: I) { self.vec.extend(iter.into_iter().map(|c| c.to_u8())); } #[inline] + #[track_caller] fn extend_one(&mut self, c: core::ascii::Char) { self.vec.push(c.to_u8()); } @@ -2482,11 +2496,14 @@ impl Extend for String { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "ascii_char", issue = "110998")] impl<'a> Extend<&'a core::ascii::Char> for String { + #[inline] + #[track_caller] fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } #[inline] + #[track_caller] fn extend_one(&mut self, c: &'a core::ascii::Char) { self.vec.push(c.to_u8()); } From c109b28ac403dc1943b117eeef5e9a125cf26a69 Mon Sep 17 00:00:00 2001 From: Kornel Date: Thu, 19 Jun 2025 16:55:33 +0100 Subject: [PATCH 152/356] Add #[track_caller] to String methods that assert inputs --- library/alloc/src/string.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 1b24118660f7..0f89186aaa4d 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1463,6 +1463,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn truncate(&mut self, new_len: usize) { if new_len <= self.len() { assert!(self.is_char_boundary(new_len)); @@ -1518,6 +1519,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] #[rustc_confusables("delete", "take")] pub fn remove(&mut self, idx: usize) -> char { let ch = match self[idx..].chars().next() { @@ -1712,6 +1714,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("set")] pub fn insert(&mut self, idx: usize, ch: char) { @@ -1768,6 +1771,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[inline] + #[track_caller] #[stable(feature = "insert_str", since = "1.16.0")] #[rustc_diagnostic_item = "string_insert_str"] pub fn insert_str(&mut self, idx: usize, string: &str) { @@ -1961,6 +1965,7 @@ impl String { /// assert_eq!(s, ""); /// ``` #[stable(feature = "drain", since = "1.6.0")] + #[track_caller] pub fn drain(&mut self, range: R) -> Drain<'_> where R: RangeBounds, @@ -2060,6 +2065,7 @@ impl String { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "splice", since = "1.27.0")] + #[track_caller] pub fn replace_range(&mut self, range: R, replace_with: &str) where R: RangeBounds, From 77858696ac864a3a6d6f2601fe398a86895c7144 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Thu, 19 Jun 2025 18:01:32 +0200 Subject: [PATCH 153/356] Add `fn parent(self, db) -> GenericDef` to `hir::TypeParam` --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c4f5a7ef588b..3b39707cf609 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -4150,6 +4150,10 @@ impl TypeParam { self.merge().name(db) } + pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { + self.id.parent().into() + } + pub fn module(self, db: &dyn HirDatabase) -> Module { self.id.parent().module(db).into() } From 044c99df78da9464e2ad0a90494af1e584123ab4 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 18 Jun 2025 20:08:15 -0400 Subject: [PATCH 154/356] Improve diagnostics for `concat_bytes!` with C string literals Use the same error as other invalid types for `concat_bytes!`, rather than using `ConcatCStrLit` from `concat!`. Also add more information with a note about why this doesn't work, and a suggestion to use a null-terminated byte string instead. --- compiler/rustc_builtin_macros/messages.ftl | 2 + .../rustc_builtin_macros/src/concat_bytes.rs | 40 ++++++++--- compiler/rustc_builtin_macros/src/errors.rs | 9 +++ tests/ui/macros/concat-bytes-error.rs | 7 +- tests/ui/macros/concat-bytes-error.stderr | 71 +++++++++++-------- 5 files changed, 86 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index d32e6f1558e4..c5d1f2ad2de8 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -104,6 +104,8 @@ builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals .byte_char = try using a byte character .byte_str = try using a byte string + .c_str = try using a null-terminated byte string + .c_str_note = concatenating C strings is ambiguous about including the '\0' .number_array = try wrapping the number in an array builtin_macros_concat_bytes_missing_literal = expected a byte literal diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 456f2b9ab31d..92d011fb9d1f 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ExprKind, LitIntType, LitKind, UintTy, token}; +use rustc_ast::{ExprKind, LitIntType, LitKind, StrStyle, UintTy, token}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_session::errors::report_lit_error; use rustc_span::{ErrorGuaranteed, Span}; @@ -21,15 +21,32 @@ fn invalid_type_err( let snippet = cx.sess.source_map().span_to_snippet(span).ok(); let dcx = cx.dcx(); match LitKind::from_token_lit(token_lit) { - Ok(LitKind::CStr(_, _)) => { + Ok(LitKind::CStr(_, style)) => { // Avoid ambiguity in handling of terminal `NUL` by refusing to // concatenate C string literals as bytes. - dcx.emit_err(errors::ConcatCStrLit { span }) + let sugg = if let Some(mut as_bstr) = snippet + && style == StrStyle::Cooked + && as_bstr.starts_with('c') + && as_bstr.ends_with('"') + { + // Suggest`c"foo"` -> `b"foo\0"` if we can + as_bstr.replace_range(0..1, "b"); + as_bstr.pop(); + as_bstr.push_str(r#"\0""#); + Some(ConcatBytesInvalidSuggestion::CStrLit { span, as_bstr }) + } else { + // No suggestion for a missing snippet, raw strings, or if for some reason we have + // a span that doesn't match `c"foo"` (possible if a proc macro assigns a span + // that doesn't actually point to a C string). + None + }; + // We can only provide a suggestion if we have a snip and it is not a raw string + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "C string", sugg, cs_note: Some(()) }) } Ok(LitKind::Char(_)) => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }) + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg, cs_note: None }) } Ok(LitKind::Str(_, _)) => { // suggestion would be invalid if we are nested @@ -38,18 +55,21 @@ fn invalid_type_err( } else { None }; - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }) + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg, cs_note: None }) } Ok(LitKind::Float(_, _)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }) - } - Ok(LitKind::Bool(_)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }) + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None, cs_note: None }) } + Ok(LitKind::Bool(_)) => dcx.emit_err(ConcatBytesInvalid { + span, + lit_kind: "boolean", + sugg: None, + cs_note: None, + }), Ok(LitKind::Int(_, _)) if !is_nested => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg, cs_note: None }) } Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => { assert!(val.get() > u8::MAX.into()); // must be an error diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 3a2e96a5e5af..b7ecfd2285ce 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -215,6 +215,8 @@ pub(crate) struct ConcatBytesInvalid { pub(crate) lit_kind: &'static str, #[subdiagnostic] pub(crate) sugg: Option, + #[note(builtin_macros_c_str_note)] + pub(crate) cs_note: Option<()>, } #[derive(Subdiagnostic)] @@ -239,6 +241,13 @@ pub(crate) enum ConcatBytesInvalidSuggestion { span: Span, snippet: String, }, + #[note(builtin_macros_c_str_note)] + #[suggestion(builtin_macros_c_str, code = "{as_bstr}", applicability = "machine-applicable")] + CStrLit { + #[primary_span] + span: Span, + as_bstr: String, + }, #[suggestion( builtin_macros_number_array, code = "[{snippet}]", diff --git a/tests/ui/macros/concat-bytes-error.rs b/tests/ui/macros/concat-bytes-error.rs index f7f291f446ff..8130fc54d8d5 100644 --- a/tests/ui/macros/concat-bytes-error.rs +++ b/tests/ui/macros/concat-bytes-error.rs @@ -15,9 +15,10 @@ fn main() { //~^ SUGGESTION br"tnrsi" concat_bytes!(r#"tnrsi"#, r###"tnri"###); //~ ERROR cannot concatenate string literals //~^ SUGGESTION br#"tnrsi"# - concat_bytes!(c"tnrsi", c"tnri"); //~ ERROR cannot concatenate a C string literal - concat_bytes!(cr"tnrsi", cr"tnri"); //~ ERROR cannot concatenate a C string literal - concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); //~ ERROR cannot concatenate a C string literal + concat_bytes!(c"tnrsi", c"tnri"); //~ ERROR cannot concatenate C string literals + //~^ SUGGESTION b"tnrsi\0" + concat_bytes!(cr"tnrsi", cr"tnri"); //~ ERROR cannot concatenate C string literals + concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); //~ ERROR cannot concatenate C string literals // Other literals concat_bytes!(2.8); //~ ERROR cannot concatenate float literals diff --git a/tests/ui/macros/concat-bytes-error.stderr b/tests/ui/macros/concat-bytes-error.stderr index fd498a023a18..447d7a663fdc 100644 --- a/tests/ui/macros/concat-bytes-error.stderr +++ b/tests/ui/macros/concat-bytes-error.stderr @@ -32,98 +32,109 @@ error: cannot concatenate string literals LL | concat_bytes!(r#"tnrsi"#, r###"tnri"###); | ^^^^^^^^^^ help: try using a byte string: `br#"tnrsi"#` -error: cannot concatenate a C string literal +error: cannot concatenate C string literals + --> $DIR/concat-bytes-error.rs:18:19 + | +LL | concat_bytes!(c"tnrsi", c"tnri"); + | ^^^^^^^^ help: try using a null-terminated byte string: `b"tnrsi\0"` + | +note: concatenating C strings is ambiguous about including the '\0' --> $DIR/concat-bytes-error.rs:18:19 | LL | concat_bytes!(c"tnrsi", c"tnri"); | ^^^^^^^^ + = note: concatenating C strings is ambiguous about including the '\0' -error: cannot concatenate a C string literal - --> $DIR/concat-bytes-error.rs:19:19 +error: cannot concatenate C string literals + --> $DIR/concat-bytes-error.rs:20:19 | LL | concat_bytes!(cr"tnrsi", cr"tnri"); | ^^^^^^^^^ + | + = note: concatenating C strings is ambiguous about including the '\0' -error: cannot concatenate a C string literal - --> $DIR/concat-bytes-error.rs:20:19 +error: cannot concatenate C string literals + --> $DIR/concat-bytes-error.rs:21:19 | LL | concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); | ^^^^^^^^^^^ + | + = note: concatenating C strings is ambiguous about including the '\0' error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:23:19 + --> $DIR/concat-bytes-error.rs:24:19 | LL | concat_bytes!(2.8); | ^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:24:19 + --> $DIR/concat-bytes-error.rs:25:19 | LL | concat_bytes!(300); | ^^^ help: try wrapping the number in an array: `[300]` error: cannot concatenate character literals - --> $DIR/concat-bytes-error.rs:26:19 + --> $DIR/concat-bytes-error.rs:27:19 | LL | concat_bytes!('a'); | ^^^ help: try using a byte character: `b'a'` error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:28:19 + --> $DIR/concat-bytes-error.rs:29:19 | LL | concat_bytes!(true, false); | ^^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:29:19 + --> $DIR/concat-bytes-error.rs:30:19 | LL | concat_bytes!(42, b"va", b'l'); | ^^ help: try wrapping the number in an array: `[42]` error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:31:19 + --> $DIR/concat-bytes-error.rs:32:19 | LL | concat_bytes!(42, b"va", b'l', [1, 2]); | ^^ help: try wrapping the number in an array: `[42]` error: cannot concatenate string literals - --> $DIR/concat-bytes-error.rs:36:9 + --> $DIR/concat-bytes-error.rs:37:9 | LL | "hi", | ^^^^ error: cannot concatenate character literals - --> $DIR/concat-bytes-error.rs:39:9 + --> $DIR/concat-bytes-error.rs:40:9 | LL | 'a', | ^^^ help: try using a byte character: `b'a'` error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:43:9 + --> $DIR/concat-bytes-error.rs:44:9 | LL | true, | ^^^^ error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:46:9 + --> $DIR/concat-bytes-error.rs:47:9 | LL | false, | ^^^^^ error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:49:9 + --> $DIR/concat-bytes-error.rs:50:9 | LL | 2.6, | ^^^ error: numeric literal is out of bounds - --> $DIR/concat-bytes-error.rs:52:9 + --> $DIR/concat-bytes-error.rs:53:9 | LL | 265, | ^^^ error: expected a byte literal - --> $DIR/concat-bytes-error.rs:55:9 + --> $DIR/concat-bytes-error.rs:56:9 | LL | -33, | ^^^ @@ -131,7 +142,7 @@ LL | -33, = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:58:9 + --> $DIR/concat-bytes-error.rs:59:9 | LL | b"hi!", | ^^^^^^ @@ -140,43 +151,43 @@ LL | b"hi!", = help: try flattening the array error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:61:9 + --> $DIR/concat-bytes-error.rs:62:9 | LL | [5, 6, 7], | ^^^^^^^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:63:19 + --> $DIR/concat-bytes-error.rs:64:19 | LL | concat_bytes!(5u16); | ^^^^ help: try wrapping the number in an array: `[5u16]` error: numeric literal is not a `u8` - --> $DIR/concat-bytes-error.rs:65:20 + --> $DIR/concat-bytes-error.rs:66:20 | LL | concat_bytes!([5u16]); | ^^^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:66:23 + --> $DIR/concat-bytes-error.rs:67:23 | LL | concat_bytes!([3; ()]); | ^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:67:23 + --> $DIR/concat-bytes-error.rs:68:23 | LL | concat_bytes!([3; -2]); | ^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:68:25 + --> $DIR/concat-bytes-error.rs:69:25 | LL | concat_bytes!([pie; -2]); | ^^ error: expected a byte literal - --> $DIR/concat-bytes-error.rs:69:20 + --> $DIR/concat-bytes-error.rs:70:20 | LL | concat_bytes!([pie; 2]); | ^^^ @@ -184,25 +195,25 @@ LL | concat_bytes!([pie; 2]); = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:70:20 + --> $DIR/concat-bytes-error.rs:71:20 | LL | concat_bytes!([2.2; 0]); | ^^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:71:25 + --> $DIR/concat-bytes-error.rs:72:25 | LL | concat_bytes!([5.5; ()]); | ^^ error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:72:20 + --> $DIR/concat-bytes-error.rs:73:20 | LL | concat_bytes!([[1, 2, 3]; 3]); | ^^^^^^^^^ error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:73:20 + --> $DIR/concat-bytes-error.rs:74:20 | LL | concat_bytes!([[42; 2]; 3]); | ^^^^^^^ From 496cbe1aa93f99b9988ab9b272426e9706be3fc9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Jun 2025 16:27:33 +0000 Subject: [PATCH 155/356] mbe: Move `transcribe_metavar_expr` directly after `transcribe` Be more consistent with the otherwise top-down organization of this file. --- compiler/rustc_expand/src/mbe/transcribe.rs | 192 ++++++++++---------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 2d3fd7702da5..d1393a240cc4 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -450,6 +450,102 @@ pub(super) fn transcribe<'a>( } } +fn transcribe_metavar_expr<'a>( + dcx: DiagCtxtHandle<'a>, + expr: &MetaVarExpr, + interp: &FxHashMap, + marker: &mut Marker, + repeats: &[(usize, usize)], + result: &mut Vec, + sp: &DelimSpan, + symbol_gallery: &SymbolGallery, +) -> PResult<'a, ()> { + let mut visited_span = || { + let mut span = sp.entire(); + marker.mark_span(&mut span); + span + }; + match *expr { + MetaVarExpr::Concat(ref elements) => { + let mut concatenated = String::new(); + for element in elements.into_iter() { + let symbol = match element { + MetaVarExprConcatElem::Ident(elem) => elem.name, + MetaVarExprConcatElem::Literal(elem) => *elem, + MetaVarExprConcatElem::Var(ident) => { + match matched_from_ident(dcx, *ident, interp)? { + NamedMatch::MatchedSeq(named_matches) => { + let Some((curr_idx, _)) = repeats.last() else { + return Err(dcx.struct_span_err(sp.entire(), "invalid syntax")); + }; + match &named_matches[*curr_idx] { + // FIXME(c410-f3r) Nested repetitions are unimplemented + MatchedSeq(_) => unimplemented!(), + MatchedSingle(pnr) => { + extract_symbol_from_pnr(dcx, pnr, ident.span)? + } + } + } + NamedMatch::MatchedSingle(pnr) => { + extract_symbol_from_pnr(dcx, pnr, ident.span)? + } + } + } + }; + concatenated.push_str(symbol.as_str()); + } + let symbol = nfc_normalize(&concatenated); + let concatenated_span = visited_span(); + if !rustc_lexer::is_ident(symbol.as_str()) { + return Err(dcx.struct_span_err( + concatenated_span, + "`${concat(..)}` is not generating a valid identifier", + )); + } + symbol_gallery.insert(symbol, concatenated_span); + // The current implementation marks the span as coming from the macro regardless of + // contexts of the concatenated identifiers but this behavior may change in the + // future. + result.push(TokenTree::Token( + Token::from_ast_ident(Ident::new(symbol, concatenated_span)), + Spacing::Alone, + )); + } + MetaVarExpr::Count(original_ident, depth) => { + let matched = matched_from_ident(dcx, original_ident, interp)?; + let count = count_repetitions(dcx, depth, matched, repeats, sp)?; + let tt = TokenTree::token_alone( + TokenKind::lit(token::Integer, sym::integer(count), None), + visited_span(), + ); + result.push(tt); + } + MetaVarExpr::Ignore(original_ident) => { + // Used to ensure that `original_ident` is present in the LHS + let _ = matched_from_ident(dcx, original_ident, interp)?; + } + MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) { + Some((index, _)) => { + result.push(TokenTree::token_alone( + TokenKind::lit(token::Integer, sym::integer(*index), None), + visited_span(), + )); + } + None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "index")), + }, + MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) { + Some((_, length)) => { + result.push(TokenTree::token_alone( + TokenKind::lit(token::Integer, sym::integer(*length), None), + visited_span(), + )); + } + None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "len")), + }, + } + Ok(()) +} + /// Store the metavariable span for this original span into a side table. /// FIXME: Try to put the metavariable span into `SpanData` instead of a side table (#118517). /// An optimal encoding for inlined spans will need to be selected to minimize regressions. @@ -762,102 +858,6 @@ fn out_of_bounds_err<'a>(dcx: DiagCtxtHandle<'a>, max: usize, span: Span, ty: &s dcx.struct_span_err(span, msg) } -fn transcribe_metavar_expr<'a>( - dcx: DiagCtxtHandle<'a>, - expr: &MetaVarExpr, - interp: &FxHashMap, - marker: &mut Marker, - repeats: &[(usize, usize)], - result: &mut Vec, - sp: &DelimSpan, - symbol_gallery: &SymbolGallery, -) -> PResult<'a, ()> { - let mut visited_span = || { - let mut span = sp.entire(); - marker.mark_span(&mut span); - span - }; - match *expr { - MetaVarExpr::Concat(ref elements) => { - let mut concatenated = String::new(); - for element in elements.into_iter() { - let symbol = match element { - MetaVarExprConcatElem::Ident(elem) => elem.name, - MetaVarExprConcatElem::Literal(elem) => *elem, - MetaVarExprConcatElem::Var(ident) => { - match matched_from_ident(dcx, *ident, interp)? { - NamedMatch::MatchedSeq(named_matches) => { - let Some((curr_idx, _)) = repeats.last() else { - return Err(dcx.struct_span_err(sp.entire(), "invalid syntax")); - }; - match &named_matches[*curr_idx] { - // FIXME(c410-f3r) Nested repetitions are unimplemented - MatchedSeq(_) => unimplemented!(), - MatchedSingle(pnr) => { - extract_symbol_from_pnr(dcx, pnr, ident.span)? - } - } - } - NamedMatch::MatchedSingle(pnr) => { - extract_symbol_from_pnr(dcx, pnr, ident.span)? - } - } - } - }; - concatenated.push_str(symbol.as_str()); - } - let symbol = nfc_normalize(&concatenated); - let concatenated_span = visited_span(); - if !rustc_lexer::is_ident(symbol.as_str()) { - return Err(dcx.struct_span_err( - concatenated_span, - "`${concat(..)}` is not generating a valid identifier", - )); - } - symbol_gallery.insert(symbol, concatenated_span); - // The current implementation marks the span as coming from the macro regardless of - // contexts of the concatenated identifiers but this behavior may change in the - // future. - result.push(TokenTree::Token( - Token::from_ast_ident(Ident::new(symbol, concatenated_span)), - Spacing::Alone, - )); - } - MetaVarExpr::Count(original_ident, depth) => { - let matched = matched_from_ident(dcx, original_ident, interp)?; - let count = count_repetitions(dcx, depth, matched, repeats, sp)?; - let tt = TokenTree::token_alone( - TokenKind::lit(token::Integer, sym::integer(count), None), - visited_span(), - ); - result.push(tt); - } - MetaVarExpr::Ignore(original_ident) => { - // Used to ensure that `original_ident` is present in the LHS - let _ = matched_from_ident(dcx, original_ident, interp)?; - } - MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) { - Some((index, _)) => { - result.push(TokenTree::token_alone( - TokenKind::lit(token::Integer, sym::integer(*index), None), - visited_span(), - )); - } - None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "index")), - }, - MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) { - Some((_, length)) => { - result.push(TokenTree::token_alone( - TokenKind::lit(token::Integer, sym::integer(*length), None), - visited_span(), - )); - } - None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "len")), - }, - } - Ok(()) -} - /// Extracts an metavariable symbol that can be an identifier, a token tree or a literal. fn extract_symbol_from_pnr<'a>( dcx: DiagCtxtHandle<'a>, From 67a9fb2fb7703ffe2148ba30462b1dbcf559649b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Jun 2025 07:53:22 +0000 Subject: [PATCH 156/356] mbe: Refactor transcription Introduce `MacroTcbCtx` that holds everything relevant to transcription. This allows for the following changes: * Split `transcribe_sequence` and `transcribe_metavar` out of the heavily nested `transcribe` * Split `metavar_expr_concat` out of `transcribe_metavar_expr` This is a nonfunctional change. --- compiler/rustc_expand/src/mbe/transcribe.rs | 737 +++++++++++--------- 1 file changed, 389 insertions(+), 348 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index d1393a240cc4..0520be5fbaee 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parser::ParseNtResult; -use rustc_session::parse::{ParseSess, SymbolGallery}; +use rustc_session::parse::ParseSess; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::{ Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, sym, with_metavar_spans, @@ -25,20 +25,77 @@ use crate::mbe::macro_parser::NamedMatch::*; use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR}; use crate::mbe::{self, KleeneOp, MetaVarExpr}; -// A Marker adds the given mark to the syntax context. -struct Marker(LocalExpnId, Transparency, FxHashMap); +/// Context needed to perform transcription of metavariable expressions. +struct TranscrCtx<'psess, 'itp> { + psess: &'psess ParseSess, + + /// Map from metavars to matched tokens + interp: &'itp FxHashMap, + + /// Allow marking spans. + marker: Marker, + + /// The stack of things yet to be completely expanded. + /// + /// We descend into the RHS (`src`), expanding things as we go. This stack contains the things + /// we have yet to expand/are still expanding. We start the stack off with the whole RHS. The + /// choice of spacing values doesn't matter. + stack: SmallVec<[Frame<'itp>; 1]>, + + /// A stack of where we are in the repeat expansion. + /// + /// As we descend in the RHS, we will need to be able to match nested sequences of matchers. + /// `repeats` keeps track of where we are in matching at each level, with the last element + /// being the most deeply nested sequence. This is used as a stack. + repeats: Vec<(usize, usize)>, + + /// The resulting token stream from the `TokenTree` we just finished processing. + /// + /// At the end, this will contain the full result of transcription, but at arbitrary points + /// during `transcribe`, `result` will contain subsets of the final result. + /// + /// Specifically, as we descend into each TokenTree, we will push the existing results onto the + /// `result_stack` and clear `results`. We will then produce the results of transcribing the + /// TokenTree into `results`. Then, as we unwind back out of the `TokenTree`, we will pop the + /// `result_stack` and append `results` too it to produce the new `results` up to that point. + /// + /// Thus, if we try to pop the `result_stack` and it is empty, we have reached the top-level + /// again, and we are done transcribing. + result: Vec, + + /// The in-progress `result` lives at the top of this stack. Each entered `TokenTree` adds a + /// new entry. + result_stack: Vec>, +} + +impl<'psess> TranscrCtx<'psess, '_> { + /// Span marked with the correct expansion and transparency. + fn visited_dspan(&mut self, dspan: DelimSpan) -> Span { + let mut span = dspan.entire(); + self.marker.mark_span(&mut span); + span + } +} + +/// A Marker adds the given mark to the syntax context. +struct Marker { + expand_id: LocalExpnId, + transparency: Transparency, + cache: FxHashMap, +} impl Marker { + /// Mark a span with the stored expansion ID and transparency. fn mark_span(&mut self, span: &mut Span) { // `apply_mark` is a relatively expensive operation, both due to taking hygiene lock, and // by itself. All tokens in a macro body typically have the same syntactic context, unless // it's some advanced case with macro-generated macros. So if we cache the marked version // of that context once, we'll typically have a 100% cache hit rate after that. - let Marker(expn_id, transparency, ref mut cache) = *self; *span = span.map_ctxt(|ctxt| { - *cache + *self + .cache .entry(ctxt) - .or_insert_with(|| ctxt.apply_mark(expn_id.to_expn_id(), transparency)) + .or_insert_with(|| ctxt.apply_mark(self.expand_id.to_expn_id(), self.transparency)) }); } } @@ -116,52 +173,36 @@ pub(super) fn transcribe<'a>( return Ok(TokenStream::default()); } - // We descend into the RHS (`src`), expanding things as we go. This stack contains the things - // we have yet to expand/are still expanding. We start the stack off with the whole RHS. The - // choice of spacing values doesn't matter. - let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new_delimited( - src, - src_span, - DelimSpacing::new(Spacing::Alone, Spacing::Alone) - )]; + let mut tscx = TranscrCtx { + psess, + interp, + marker: Marker { expand_id, transparency, cache: Default::default() }, + repeats: Vec::new(), + stack: smallvec![Frame::new_delimited( + src, + src_span, + DelimSpacing::new(Spacing::Alone, Spacing::Alone) + )], + result: Vec::new(), + result_stack: Vec::new(), + }; - // As we descend in the RHS, we will need to be able to match nested sequences of matchers. - // `repeats` keeps track of where we are in matching at each level, with the last element being - // the most deeply nested sequence. This is used as a stack. - let mut repeats: Vec<(usize, usize)> = Vec::new(); - - // `result` contains resulting token stream from the TokenTree we just finished processing. At - // the end, this will contain the full result of transcription, but at arbitrary points during - // `transcribe`, `result` will contain subsets of the final result. - // - // Specifically, as we descend into each TokenTree, we will push the existing results onto the - // `result_stack` and clear `results`. We will then produce the results of transcribing the - // TokenTree into `results`. Then, as we unwind back out of the `TokenTree`, we will pop the - // `result_stack` and append `results` too it to produce the new `results` up to that point. - // - // Thus, if we try to pop the `result_stack` and it is empty, we have reached the top-level - // again, and we are done transcribing. - let mut result: Vec = Vec::new(); - let mut result_stack = Vec::new(); - let mut marker = Marker(expand_id, transparency, Default::default()); - - let dcx = psess.dcx(); loop { // Look at the last frame on the stack. // If it still has a TokenTree we have not looked at yet, use that tree. - let Some(tree) = stack.last_mut().unwrap().next() else { + let Some(tree) = tscx.stack.last_mut().unwrap().next() else { // This else-case never produces a value for `tree` (it `continue`s or `return`s). // Otherwise, if we have just reached the end of a sequence and we can keep repeating, // go back to the beginning of the sequence. - let frame = stack.last_mut().unwrap(); + let frame = tscx.stack.last_mut().unwrap(); if let FrameKind::Sequence { sep, .. } = &frame.kind { - let (repeat_idx, repeat_len) = repeats.last_mut().unwrap(); + let (repeat_idx, repeat_len) = tscx.repeats.last_mut().unwrap(); *repeat_idx += 1; if repeat_idx < repeat_len { frame.idx = 0; if let Some(sep) = sep { - result.push(TokenTree::Token(*sep, Spacing::Alone)); + tscx.result.push(TokenTree::Token(*sep, Spacing::Alone)); } continue; } @@ -170,10 +211,10 @@ pub(super) fn transcribe<'a>( // We are done with the top of the stack. Pop it. Depending on what it was, we do // different things. Note that the outermost item must be the delimited, wrapped RHS // that was passed in originally to `transcribe`. - match stack.pop().unwrap().kind { + match tscx.stack.pop().unwrap().kind { // Done with a sequence. Pop from repeats. FrameKind::Sequence { .. } => { - repeats.pop(); + tscx.repeats.pop(); } // We are done processing a Delimited. If this is the top-level delimited, we are @@ -185,15 +226,16 @@ pub(super) fn transcribe<'a>( if delim == Delimiter::Bracket { spacing.close = Spacing::Alone; } - if result_stack.is_empty() { + if tscx.result_stack.is_empty() { // No results left to compute! We are back at the top-level. - return Ok(TokenStream::new(result)); + return Ok(TokenStream::new(tscx.result)); } // Step back into the parent Delimited. - let tree = TokenTree::Delimited(span, spacing, delim, TokenStream::new(result)); - result = result_stack.pop().unwrap(); - result.push(tree); + let tree = + TokenTree::Delimited(span, spacing, delim, TokenStream::new(tscx.result)); + tscx.result = tscx.result_stack.pop().unwrap(); + tscx.result.push(tree); } } continue; @@ -202,223 +244,19 @@ pub(super) fn transcribe<'a>( // At this point, we know we are in the middle of a TokenTree (the last one on `stack`). // `tree` contains the next `TokenTree` to be processed. match tree { - // We are descending into a sequence. We first make sure that the matchers in the RHS - // and the matches in `interp` have the same shape. Otherwise, either the caller or the - // macro writer has made a mistake. + // Replace the sequence with its expansion. seq @ mbe::TokenTree::Sequence(_, seq_rep) => { - match lockstep_iter_size(seq, interp, &repeats) { - LockstepIterSize::Unconstrained => { - return Err(dcx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() })); - } - - LockstepIterSize::Contradiction(msg) => { - // FIXME: this really ought to be caught at macro definition time... It - // happens when two meta-variables are used in the same repetition in a - // sequence, but they come from different sequence matchers and repeat - // different amounts. - return Err( - dcx.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg }) - ); - } - - LockstepIterSize::Constraint(len, _) => { - // We do this to avoid an extra clone above. We know that this is a - // sequence already. - let mbe::TokenTree::Sequence(sp, seq) = seq else { unreachable!() }; - - // Is the repetition empty? - if len == 0 { - if seq.kleene.op == KleeneOp::OneOrMore { - // FIXME: this really ought to be caught at macro definition - // time... It happens when the Kleene operator in the matcher and - // the body for the same meta-variable do not match. - return Err(dcx.create_err(MustRepeatOnce { span: sp.entire() })); - } - } else { - // 0 is the initial counter (we have done 0 repetitions so far). `len` - // is the total number of repetitions we should generate. - repeats.push((0, len)); - - // The first time we encounter the sequence we push it to the stack. It - // then gets reused (see the beginning of the loop) until we are done - // repeating. - stack.push(Frame::new_sequence( - seq_rep, - seq.separator.clone(), - seq.kleene.op, - )); - } - } - } + transcribe_sequence(&mut tscx, seq, seq_rep)?; } // Replace the meta-var with the matched token tree from the invocation. - &mbe::TokenTree::MetaVar(mut sp, mut original_ident) => { - // Find the matched nonterminal from the macro invocation, and use it to replace - // the meta-var. - // - // We use `Spacing::Alone` everywhere here, because that's the conservative choice - // and spacing of declarative macros is tricky. E.g. in this macro: - // ``` - // macro_rules! idents { - // ($($a:ident,)*) => { stringify!($($a)*) } - // } - // ``` - // `$a` has no whitespace after it and will be marked `JointHidden`. If you then - // call `idents!(x,y,z,)`, each of `x`, `y`, and `z` will be marked as `Joint`. So - // if you choose to use `$x`'s spacing or the identifier's spacing, you'll end up - // producing "xyz", which is bad because it effectively merges tokens. - // `Spacing::Alone` is the safer option. Fortunately, `space_between` will avoid - // some of the unnecessary whitespace. - let ident = MacroRulesNormalizedIdent::new(original_ident); - if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { - // We wrap the tokens in invisible delimiters, unless they are already wrapped - // in invisible delimiters with the same `MetaVarKind`. Because some proc - // macros can't handle multiple layers of invisible delimiters of the same - // `MetaVarKind`. This loses some span info, though it hopefully won't matter. - let mut mk_delimited = |mk_span, mv_kind, mut stream: TokenStream| { - if stream.len() == 1 { - let tree = stream.iter().next().unwrap(); - if let TokenTree::Delimited(_, _, delim, inner) = tree - && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mvk)) = delim - && mv_kind == *mvk - { - stream = inner.clone(); - } - } - - // Emit as a token stream within `Delimiter::Invisible` to maintain - // parsing priorities. - marker.mark_span(&mut sp); - with_metavar_spans(|mspans| mspans.insert(mk_span, sp)); - // Both the open delim and close delim get the same span, which covers the - // `$foo` in the decl macro RHS. - TokenTree::Delimited( - DelimSpan::from_single(sp), - DelimSpacing::new(Spacing::Alone, Spacing::Alone), - Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)), - stream, - ) - }; - let tt = match cur_matched { - MatchedSingle(ParseNtResult::Tt(tt)) => { - // `tt`s are emitted into the output stream directly as "raw tokens", - // without wrapping them into groups. Other variables are emitted into - // the output stream as groups with `Delimiter::Invisible` to maintain - // parsing priorities. - maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker) - } - MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { - marker.mark_span(&mut sp); - with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); - let kind = token::NtIdent(*ident, *is_raw); - TokenTree::token_alone(kind, sp) - } - MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => { - marker.mark_span(&mut sp); - with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); - let kind = token::NtLifetime(*ident, *is_raw); - TokenTree::token_alone(kind, sp) - } - MatchedSingle(ParseNtResult::Item(item)) => { - mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item)) - } - MatchedSingle(ParseNtResult::Block(block)) => mk_delimited( - block.span, - MetaVarKind::Block, - TokenStream::from_ast(block), - ), - MatchedSingle(ParseNtResult::Stmt(stmt)) => { - let stream = if let StmtKind::Empty = stmt.kind { - // FIXME: Properly collect tokens for empty statements. - TokenStream::token_alone(token::Semi, stmt.span) - } else { - TokenStream::from_ast(stmt) - }; - mk_delimited(stmt.span, MetaVarKind::Stmt, stream) - } - MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => mk_delimited( - pat.span, - MetaVarKind::Pat(*pat_kind), - TokenStream::from_ast(pat), - ), - MatchedSingle(ParseNtResult::Expr(expr, kind)) => { - let (can_begin_literal_maybe_minus, can_begin_string_literal) = - match &expr.kind { - ExprKind::Lit(_) => (true, true), - ExprKind::Unary(UnOp::Neg, e) - if matches!(&e.kind, ExprKind::Lit(_)) => - { - (true, false) - } - _ => (false, false), - }; - mk_delimited( - expr.span, - MetaVarKind::Expr { - kind: *kind, - can_begin_literal_maybe_minus, - can_begin_string_literal, - }, - TokenStream::from_ast(expr), - ) - } - MatchedSingle(ParseNtResult::Literal(lit)) => { - mk_delimited(lit.span, MetaVarKind::Literal, TokenStream::from_ast(lit)) - } - MatchedSingle(ParseNtResult::Ty(ty)) => { - let is_path = matches!(&ty.kind, TyKind::Path(None, _path)); - mk_delimited( - ty.span, - MetaVarKind::Ty { is_path }, - TokenStream::from_ast(ty), - ) - } - MatchedSingle(ParseNtResult::Meta(attr_item)) => { - let has_meta_form = attr_item.meta_kind().is_some(); - mk_delimited( - attr_item.span(), - MetaVarKind::Meta { has_meta_form }, - TokenStream::from_ast(attr_item), - ) - } - MatchedSingle(ParseNtResult::Path(path)) => { - mk_delimited(path.span, MetaVarKind::Path, TokenStream::from_ast(path)) - } - MatchedSingle(ParseNtResult::Vis(vis)) => { - mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) - } - MatchedSeq(..) => { - // We were unable to descend far enough. This is an error. - return Err(dcx.create_err(VarStillRepeating { span: sp, ident })); - } - }; - result.push(tt) - } else { - // If we aren't able to match the meta-var, we push it back into the result but - // with modified syntax context. (I believe this supports nested macros). - marker.mark_span(&mut sp); - marker.mark_span(&mut original_ident.span); - result.push(TokenTree::token_joint_hidden(token::Dollar, sp)); - result.push(TokenTree::Token( - Token::from_ast_ident(original_ident), - Spacing::Alone, - )); - } + &mbe::TokenTree::MetaVar(sp, original_ident) => { + transcribe_metavar(&mut tscx, sp, original_ident)?; } // Replace meta-variable expressions with the result of their expansion. - mbe::TokenTree::MetaVarExpr(sp, expr) => { - transcribe_metavar_expr( - dcx, - expr, - interp, - &mut marker, - &repeats, - &mut result, - sp, - &psess.symbol_gallery, - )?; + mbe::TokenTree::MetaVarExpr(dspan, expr) => { + transcribe_metavar_expr(&mut tscx, *dspan, expr)?; } // If we are entering a new delimiter, we push its contents to the `stack` to be @@ -427,21 +265,21 @@ pub(super) fn transcribe<'a>( // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). &mbe::TokenTree::Delimited(mut span, ref spacing, ref delimited) => { - marker.mark_span(&mut span.open); - marker.mark_span(&mut span.close); - stack.push(Frame::new_delimited(delimited, span, *spacing)); - result_stack.push(mem::take(&mut result)); + tscx.marker.mark_span(&mut span.open); + tscx.marker.mark_span(&mut span.close); + tscx.stack.push(Frame::new_delimited(delimited, span, *spacing)); + tscx.result_stack.push(mem::take(&mut tscx.result)); } // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. &mbe::TokenTree::Token(mut token) => { - marker.mark_span(&mut token.span); + tscx.marker.mark_span(&mut token.span); if let token::NtIdent(ident, _) | token::NtLifetime(ident, _) = &mut token.kind { - marker.mark_span(&mut ident.span); + tscx.marker.mark_span(&mut ident.span); } let tt = TokenTree::Token(token, Spacing::Alone); - result.push(tt); + tscx.result.push(tt); } // There should be no meta-var declarations in the invocation of a macro. @@ -450,102 +288,305 @@ pub(super) fn transcribe<'a>( } } -fn transcribe_metavar_expr<'a>( - dcx: DiagCtxtHandle<'a>, - expr: &MetaVarExpr, - interp: &FxHashMap, - marker: &mut Marker, - repeats: &[(usize, usize)], - result: &mut Vec, - sp: &DelimSpan, - symbol_gallery: &SymbolGallery, -) -> PResult<'a, ()> { - let mut visited_span = || { - let mut span = sp.entire(); - marker.mark_span(&mut span); - span - }; - match *expr { - MetaVarExpr::Concat(ref elements) => { - let mut concatenated = String::new(); - for element in elements.into_iter() { - let symbol = match element { - MetaVarExprConcatElem::Ident(elem) => elem.name, - MetaVarExprConcatElem::Literal(elem) => *elem, - MetaVarExprConcatElem::Var(ident) => { - match matched_from_ident(dcx, *ident, interp)? { - NamedMatch::MatchedSeq(named_matches) => { - let Some((curr_idx, _)) = repeats.last() else { - return Err(dcx.struct_span_err(sp.entire(), "invalid syntax")); - }; - match &named_matches[*curr_idx] { - // FIXME(c410-f3r) Nested repetitions are unimplemented - MatchedSeq(_) => unimplemented!(), - MatchedSingle(pnr) => { - extract_symbol_from_pnr(dcx, pnr, ident.span)? - } - } - } - NamedMatch::MatchedSingle(pnr) => { - extract_symbol_from_pnr(dcx, pnr, ident.span)? - } - } - } - }; - concatenated.push_str(symbol.as_str()); - } - let symbol = nfc_normalize(&concatenated); - let concatenated_span = visited_span(); - if !rustc_lexer::is_ident(symbol.as_str()) { - return Err(dcx.struct_span_err( - concatenated_span, - "`${concat(..)}` is not generating a valid identifier", - )); - } - symbol_gallery.insert(symbol, concatenated_span); - // The current implementation marks the span as coming from the macro regardless of - // contexts of the concatenated identifiers but this behavior may change in the - // future. - result.push(TokenTree::Token( - Token::from_ast_ident(Ident::new(symbol, concatenated_span)), - Spacing::Alone, - )); +/// Turn `$(...)*` sequences into tokens. +fn transcribe_sequence<'tx, 'itp>( + tscx: &mut TranscrCtx<'tx, 'itp>, + seq: &mbe::TokenTree, + seq_rep: &'itp mbe::SequenceRepetition, +) -> PResult<'tx, ()> { + let dcx = tscx.psess.dcx(); + + // We are descending into a sequence. We first make sure that the matchers in the RHS + // and the matches in `interp` have the same shape. Otherwise, either the caller or the + // macro writer has made a mistake. + match lockstep_iter_size(seq, tscx.interp, &tscx.repeats) { + LockstepIterSize::Unconstrained => { + return Err(dcx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() })); } + + LockstepIterSize::Contradiction(msg) => { + // FIXME: this really ought to be caught at macro definition time... It + // happens when two meta-variables are used in the same repetition in a + // sequence, but they come from different sequence matchers and repeat + // different amounts. + return Err(dcx.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg })); + } + + LockstepIterSize::Constraint(len, _) => { + // We do this to avoid an extra clone above. We know that this is a + // sequence already. + let mbe::TokenTree::Sequence(sp, seq) = seq else { unreachable!() }; + + // Is the repetition empty? + if len == 0 { + if seq.kleene.op == KleeneOp::OneOrMore { + // FIXME: this really ought to be caught at macro definition + // time... It happens when the Kleene operator in the matcher and + // the body for the same meta-variable do not match. + return Err(dcx.create_err(MustRepeatOnce { span: sp.entire() })); + } + } else { + // 0 is the initial counter (we have done 0 repetitions so far). `len` + // is the total number of repetitions we should generate. + tscx.repeats.push((0, len)); + + // The first time we encounter the sequence we push it to the stack. It + // then gets reused (see the beginning of the loop) until we are done + // repeating. + tscx.stack.push(Frame::new_sequence(seq_rep, seq.separator.clone(), seq.kleene.op)); + } + } + } + + Ok(()) +} + +/// Find the matched nonterminal from the macro invocation, and use it to replace +/// the meta-var. +/// +/// We use `Spacing::Alone` everywhere here, because that's the conservative choice +/// and spacing of declarative macros is tricky. E.g. in this macro: +/// ``` +/// macro_rules! idents { +/// ($($a:ident,)*) => { stringify!($($a)*) } +/// } +/// ``` +/// `$a` has no whitespace after it and will be marked `JointHidden`. If you then +/// call `idents!(x,y,z,)`, each of `x`, `y`, and `z` will be marked as `Joint`. So +/// if you choose to use `$x`'s spacing or the identifier's spacing, you'll end up +/// producing "xyz", which is bad because it effectively merges tokens. +/// `Spacing::Alone` is the safer option. Fortunately, `space_between` will avoid +/// some of the unnecessary whitespace. +fn transcribe_metavar<'tx>( + tscx: &mut TranscrCtx<'tx, '_>, + mut sp: Span, + mut original_ident: Ident, +) -> PResult<'tx, ()> { + let dcx = tscx.psess.dcx(); + + let ident = MacroRulesNormalizedIdent::new(original_ident); + let Some(cur_matched) = lookup_cur_matched(ident, tscx.interp, &tscx.repeats) else { + // If we aren't able to match the meta-var, we push it back into the result but + // with modified syntax context. (I believe this supports nested macros). + tscx.marker.mark_span(&mut sp); + tscx.marker.mark_span(&mut original_ident.span); + tscx.result.push(TokenTree::token_joint_hidden(token::Dollar, sp)); + tscx.result.push(TokenTree::Token(Token::from_ast_ident(original_ident), Spacing::Alone)); + return Ok(()); + }; + + // We wrap the tokens in invisible delimiters, unless they are already wrapped + // in invisible delimiters with the same `MetaVarKind`. Because some proc + // macros can't handle multiple layers of invisible delimiters of the same + // `MetaVarKind`. This loses some span info, though it hopefully won't matter. + let mut mk_delimited = |mk_span, mv_kind, mut stream: TokenStream| { + if stream.len() == 1 { + let tree = stream.iter().next().unwrap(); + if let TokenTree::Delimited(_, _, delim, inner) = tree + && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mvk)) = delim + && mv_kind == *mvk + { + stream = inner.clone(); + } + } + + // Emit as a token stream within `Delimiter::Invisible` to maintain + // parsing priorities. + tscx.marker.mark_span(&mut sp); + with_metavar_spans(|mspans| mspans.insert(mk_span, sp)); + // Both the open delim and close delim get the same span, which covers the + // `$foo` in the decl macro RHS. + TokenTree::Delimited( + DelimSpan::from_single(sp), + DelimSpacing::new(Spacing::Alone, Spacing::Alone), + Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)), + stream, + ) + }; + + let tt = match cur_matched { + MatchedSingle(ParseNtResult::Tt(tt)) => { + // `tt`s are emitted into the output stream directly as "raw tokens", + // without wrapping them into groups. Other variables are emitted into + // the output stream as groups with `Delimiter::Invisible` to maintain + // parsing priorities. + maybe_use_metavar_location(tscx.psess, &tscx.stack, sp, tt, &mut tscx.marker) + } + MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { + tscx.marker.mark_span(&mut sp); + with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); + let kind = token::NtIdent(*ident, *is_raw); + TokenTree::token_alone(kind, sp) + } + MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => { + tscx.marker.mark_span(&mut sp); + with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); + let kind = token::NtLifetime(*ident, *is_raw); + TokenTree::token_alone(kind, sp) + } + MatchedSingle(ParseNtResult::Item(item)) => { + mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item)) + } + MatchedSingle(ParseNtResult::Block(block)) => { + mk_delimited(block.span, MetaVarKind::Block, TokenStream::from_ast(block)) + } + MatchedSingle(ParseNtResult::Stmt(stmt)) => { + let stream = if let StmtKind::Empty = stmt.kind { + // FIXME: Properly collect tokens for empty statements. + TokenStream::token_alone(token::Semi, stmt.span) + } else { + TokenStream::from_ast(stmt) + }; + mk_delimited(stmt.span, MetaVarKind::Stmt, stream) + } + MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => { + mk_delimited(pat.span, MetaVarKind::Pat(*pat_kind), TokenStream::from_ast(pat)) + } + MatchedSingle(ParseNtResult::Expr(expr, kind)) => { + let (can_begin_literal_maybe_minus, can_begin_string_literal) = match &expr.kind { + ExprKind::Lit(_) => (true, true), + ExprKind::Unary(UnOp::Neg, e) if matches!(&e.kind, ExprKind::Lit(_)) => { + (true, false) + } + _ => (false, false), + }; + mk_delimited( + expr.span, + MetaVarKind::Expr { + kind: *kind, + can_begin_literal_maybe_minus, + can_begin_string_literal, + }, + TokenStream::from_ast(expr), + ) + } + MatchedSingle(ParseNtResult::Literal(lit)) => { + mk_delimited(lit.span, MetaVarKind::Literal, TokenStream::from_ast(lit)) + } + MatchedSingle(ParseNtResult::Ty(ty)) => { + let is_path = matches!(&ty.kind, TyKind::Path(None, _path)); + mk_delimited(ty.span, MetaVarKind::Ty { is_path }, TokenStream::from_ast(ty)) + } + MatchedSingle(ParseNtResult::Meta(attr_item)) => { + let has_meta_form = attr_item.meta_kind().is_some(); + mk_delimited( + attr_item.span(), + MetaVarKind::Meta { has_meta_form }, + TokenStream::from_ast(attr_item), + ) + } + MatchedSingle(ParseNtResult::Path(path)) => { + mk_delimited(path.span, MetaVarKind::Path, TokenStream::from_ast(path)) + } + MatchedSingle(ParseNtResult::Vis(vis)) => { + mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) + } + MatchedSeq(..) => { + // We were unable to descend far enough. This is an error. + return Err(dcx.create_err(VarStillRepeating { span: sp, ident })); + } + }; + + tscx.result.push(tt); + Ok(()) +} + +/// Turn `${expr(...)}` metavariable expressionss into tokens. +fn transcribe_metavar_expr<'tx>( + tscx: &mut TranscrCtx<'tx, '_>, + dspan: DelimSpan, + expr: &MetaVarExpr, +) -> PResult<'tx, ()> { + let dcx = tscx.psess.dcx(); + let tt = match *expr { + MetaVarExpr::Concat(ref elements) => metavar_expr_concat(tscx, dspan, elements)?, MetaVarExpr::Count(original_ident, depth) => { - let matched = matched_from_ident(dcx, original_ident, interp)?; - let count = count_repetitions(dcx, depth, matched, repeats, sp)?; - let tt = TokenTree::token_alone( + let matched = matched_from_ident(dcx, original_ident, tscx.interp)?; + let count = count_repetitions(dcx, depth, matched, &tscx.repeats, &dspan)?; + TokenTree::token_alone( TokenKind::lit(token::Integer, sym::integer(count), None), - visited_span(), - ); - result.push(tt); + tscx.visited_dspan(dspan), + ) } MetaVarExpr::Ignore(original_ident) => { // Used to ensure that `original_ident` is present in the LHS - let _ = matched_from_ident(dcx, original_ident, interp)?; + let _ = matched_from_ident(dcx, original_ident, tscx.interp)?; + return Ok(()); } - MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) { - Some((index, _)) => { - result.push(TokenTree::token_alone( - TokenKind::lit(token::Integer, sym::integer(*index), None), - visited_span(), - )); + MetaVarExpr::Index(depth) => match tscx.repeats.iter().nth_back(depth) { + Some((index, _)) => TokenTree::token_alone( + TokenKind::lit(token::Integer, sym::integer(*index), None), + tscx.visited_dspan(dspan), + ), + None => { + return Err(out_of_bounds_err(dcx, tscx.repeats.len(), dspan.entire(), "index")); } - None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "index")), }, - MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) { - Some((_, length)) => { - result.push(TokenTree::token_alone( - TokenKind::lit(token::Integer, sym::integer(*length), None), - visited_span(), - )); + MetaVarExpr::Len(depth) => match tscx.repeats.iter().nth_back(depth) { + Some((_, length)) => TokenTree::token_alone( + TokenKind::lit(token::Integer, sym::integer(*length), None), + tscx.visited_dspan(dspan), + ), + None => { + return Err(out_of_bounds_err(dcx, tscx.repeats.len(), dspan.entire(), "len")); } - None => return Err(out_of_bounds_err(dcx, repeats.len(), sp.entire(), "len")), }, - } + }; + tscx.result.push(tt); Ok(()) } +/// Handle the `${concat(...)}` metavariable expression. +fn metavar_expr_concat<'tx>( + tscx: &mut TranscrCtx<'tx, '_>, + dspan: DelimSpan, + elements: &[MetaVarExprConcatElem], +) -> PResult<'tx, TokenTree> { + let dcx = tscx.psess.dcx(); + let mut concatenated = String::new(); + for element in elements.into_iter() { + let symbol = match element { + MetaVarExprConcatElem::Ident(elem) => elem.name, + MetaVarExprConcatElem::Literal(elem) => *elem, + MetaVarExprConcatElem::Var(ident) => { + match matched_from_ident(dcx, *ident, tscx.interp)? { + NamedMatch::MatchedSeq(named_matches) => { + let Some((curr_idx, _)) = tscx.repeats.last() else { + return Err(dcx.struct_span_err(dspan.entire(), "invalid syntax")); + }; + match &named_matches[*curr_idx] { + // FIXME(c410-f3r) Nested repetitions are unimplemented + MatchedSeq(_) => unimplemented!(), + MatchedSingle(pnr) => extract_symbol_from_pnr(dcx, pnr, ident.span)?, + } + } + NamedMatch::MatchedSingle(pnr) => { + extract_symbol_from_pnr(dcx, pnr, ident.span)? + } + } + } + }; + concatenated.push_str(symbol.as_str()); + } + let symbol = nfc_normalize(&concatenated); + let concatenated_span = tscx.visited_dspan(dspan); + if !rustc_lexer::is_ident(symbol.as_str()) { + return Err(dcx.struct_span_err( + concatenated_span, + "`${concat(..)}` is not generating a valid identifier", + )); + } + tscx.psess.symbol_gallery.insert(symbol, concatenated_span); + + // The current implementation marks the span as coming from the macro regardless of + // contexts of the concatenated identifiers but this behavior may change in the + // future. + Ok(TokenTree::Token( + Token::from_ast_ident(Ident::new(symbol, concatenated_span)), + Spacing::Alone, + )) +} + /// Store the metavariable span for this original span into a side table. /// FIXME: Try to put the metavariable span into `SpanData` instead of a side table (#118517). /// An optimal encoding for inlined spans will need to be selected to minimize regressions. @@ -767,13 +808,13 @@ fn lockstep_iter_size( /// * `[ $( ${count(foo, 0)} ),* ]` will be the same as `[ $( ${count(foo)} ),* ]` /// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is /// declared inside a single repetition and the index `1` implies two nested repetitions. -fn count_repetitions<'a>( - dcx: DiagCtxtHandle<'a>, +fn count_repetitions<'dx>( + dcx: DiagCtxtHandle<'dx>, depth_user: usize, mut matched: &NamedMatch, repeats: &[(usize, usize)], sp: &DelimSpan, -) -> PResult<'a, usize> { +) -> PResult<'dx, usize> { // Recursively count the number of matches in `matched` at given depth // (or at the top-level of `matched` if no depth is given). fn count<'a>(depth_curr: usize, depth_max: usize, matched: &NamedMatch) -> PResult<'a, usize> { From 07b9bb1855596ac84a80d898b40c4b403f1dcc3f Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 19 Jun 2025 13:02:04 -0500 Subject: [PATCH 157/356] Extract Translator struct --- compiler/rustc_codegen_ssa/src/back/write.rs | 20 ++---- compiler/rustc_driver_impl/src/lib.rs | 10 ++- compiler/rustc_error_messages/src/lib.rs | 10 +-- .../src/annotate_snippet_emitter_writer.rs | 36 +++------- compiler/rustc_errors/src/emitter.rs | 67 +++++++++---------- compiler/rustc_errors/src/json.rs | 40 ++++------- compiler/rustc_errors/src/json/tests.rs | 6 +- compiler/rustc_errors/src/lib.rs | 15 ++--- compiler/rustc_errors/src/tests.rs | 43 +++++------- compiler/rustc_errors/src/translation.rs | 43 ++++++++---- compiler/rustc_parse/src/parser/tests.rs | 6 +- compiler/rustc_session/src/parse.rs | 12 ++-- compiler/rustc_session/src/session.rs | 44 ++++++------ src/librustdoc/core.rs | 9 +-- src/librustdoc/doctest/make.rs | 9 +-- .../passes/lint/check_code_block_syntax.rs | 28 +++----- .../src/doc/needless_doctest_main.rs | 5 +- src/tools/rustfmt/src/parse/session.rs | 37 +++------- 18 files changed, 190 insertions(+), 250 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index bbf9cceef2a0..c3bfe4c13cdf 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -14,10 +14,10 @@ use rustc_data_structures::jobserver::{self, Acquired}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_errors::emitter::Emitter; -use rustc_errors::translation::Translate; +use rustc_errors::translation::Translator; use rustc_errors::{ - Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, FluentBundle, Level, MultiSpan, - Style, Suggestions, + Diag, DiagArgMap, DiagCtxt, DiagMessage, ErrCode, FatalError, Level, MultiSpan, Style, + Suggestions, }; use rustc_fs_util::link_or_copy; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; @@ -1889,16 +1889,6 @@ impl SharedEmitter { } } -impl Translate for SharedEmitter { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - None - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - panic!("shared emitter attempted to translate a diagnostic"); - } -} - impl Emitter for SharedEmitter { fn emit_diagnostic( &mut self, @@ -1932,6 +1922,10 @@ impl Emitter for SharedEmitter { fn source_map(&self) -> Option<&SourceMap> { None } + + fn translator(&self) -> &Translator { + panic!("shared emitter attempted to translate a diagnostic"); + } } impl SharedEmitterMain { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index d53126d04143..daeca43169d4 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -38,6 +38,7 @@ use rustc_data_structures::profiling::{ }; use rustc_errors::emitter::stderr_destination; use rustc_errors::registry::Registry; +use rustc_errors::translation::Translator; use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown}; use rustc_feature::find_gated_cfg; // This avoids a false positive with `-Wunused_crate_dependencies`. @@ -109,6 +110,10 @@ use crate::session_diagnostics::{ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } +pub fn default_translator() -> Translator { + Translator::with_fallback_bundle(DEFAULT_LOCALE_RESOURCES.to_vec(), false) +} + pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ // tidy-alphabetical-start crate::DEFAULT_LOCALE_RESOURCE, @@ -1413,11 +1418,10 @@ fn report_ice( extra_info: fn(&DiagCtxt), using_internal_features: &AtomicBool, ) { - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false); + let translator = default_translator(); let emitter = Box::new(rustc_errors::emitter::HumanEmitter::new( stderr_destination(rustc_errors::ColorConfig::Auto), - fallback_bundle, + translator, )); let dcx = rustc_errors::DiagCtxt::new(emitter); let dcx = dcx.handle(); diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 1d3b5b20751a..194fc2450ba4 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -18,7 +18,7 @@ pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue}; use fluent_syntax::parser::ParserError; use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; use intl_memoizer::concurrent::IntlLangMemoizer; -use rustc_data_structures::sync::IntoDynSyncSend; +use rustc_data_structures::sync::{DynSend, IntoDynSyncSend}; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; use smallvec::SmallVec; @@ -204,16 +204,16 @@ fn register_functions(bundle: &mut FluentBundle) { /// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily /// evaluated fluent bundle. -pub type LazyFallbackBundle = Arc FluentBundle>>; +pub type LazyFallbackBundle = + Arc FluentBundle + DynSend>>>; /// Return the default `FluentBundle` with standard "en-US" diagnostic messages. #[instrument(level = "trace", skip(resources))] -#[define_opaque(LazyFallbackBundle)] pub fn fallback_fluent_bundle( resources: Vec<&'static str>, with_directionality_markers: bool, ) -> LazyFallbackBundle { - Arc::new(LazyLock::new(move || { + Arc::new(LazyLock::new(Box::new(move || { let mut fallback_bundle = new_bundle(vec![langid!("en-US")]); register_functions(&mut fallback_bundle); @@ -228,7 +228,7 @@ pub fn fallback_fluent_bundle( } fallback_bundle - })) + }))) } /// Identifier for the Fluent message/attribute corresponding to a diagnostic message. diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index f3aeb8d224b9..2eb3c23259ff 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -15,17 +15,15 @@ use rustc_span::source_map::SourceMap; use crate::emitter::FileWithAnnotatedLines; use crate::registry::Registry; use crate::snippet::Line; -use crate::translation::{Translate, to_fluent_args}; +use crate::translation::{Translator, to_fluent_args}; use crate::{ - CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, FluentBundle, LazyFallbackBundle, - Level, MultiSpan, Style, Subdiag, + CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, Level, MultiSpan, Style, Subdiag, }; /// Generates diagnostics using annotate-snippet pub struct AnnotateSnippetEmitter { source_map: Option>, - fluent_bundle: Option>, - fallback_bundle: LazyFallbackBundle, + translator: Translator, /// If true, hides the longer explanation text short_message: bool, @@ -35,16 +33,6 @@ pub struct AnnotateSnippetEmitter { macro_backtrace: bool, } -impl Translate for AnnotateSnippetEmitter { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - self.fluent_bundle.as_deref() - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &self.fallback_bundle - } -} - impl Emitter for AnnotateSnippetEmitter { /// The entry point for the diagnostics generation fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) { @@ -78,6 +66,10 @@ impl Emitter for AnnotateSnippetEmitter { fn should_show_explain(&self) -> bool { !self.short_message } + + fn translator(&self) -> &Translator { + &self.translator + } } /// Provides the source string for the given `line` of `file` @@ -104,19 +96,11 @@ fn annotation_level_for_level(level: Level) -> annotate_snippets::Level { impl AnnotateSnippetEmitter { pub fn new( source_map: Option>, - fluent_bundle: Option>, - fallback_bundle: LazyFallbackBundle, + translator: Translator, short_message: bool, macro_backtrace: bool, ) -> Self { - Self { - source_map, - fluent_bundle, - fallback_bundle, - short_message, - ui_testing: false, - macro_backtrace, - } + Self { source_map, translator, short_message, ui_testing: false, macro_backtrace } } /// Allows to modify `Self` to enable or disable the `ui_testing` flag. @@ -137,7 +121,7 @@ impl AnnotateSnippetEmitter { _children: &[Subdiag], _suggestions: &[CodeSuggestion], ) { - let message = self.translate_messages(messages, args); + let message = self.translator.translate_messages(messages, args); if let Some(source_map) = &self.source_map { // Make sure our primary file comes first let primary_lo = if let Some(primary_span) = msp.primary_span().as_ref() { diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 6ab6f96079eb..494f15cc6390 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -35,10 +35,10 @@ use crate::snippet::{ }; use crate::styled_buffer::StyledBuffer; use crate::timings::TimingRecord; -use crate::translation::{Translate, to_fluent_args}; +use crate::translation::{Translator, to_fluent_args}; use crate::{ - CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level, - MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl, + CodeSuggestion, DiagInner, DiagMessage, ErrCode, Level, MultiSpan, Subdiag, + SubstitutionHighlight, SuggestionStyle, TerminalUrl, }; /// Default column width, used in tests and when terminal dimensions cannot be determined. @@ -175,7 +175,7 @@ const ANONYMIZED_LINE_NUM: &str = "LL"; pub type DynEmitter = dyn Emitter + DynSend; /// Emitter trait for emitting errors and other structured information. -pub trait Emitter: Translate { +pub trait Emitter { /// Emit a structured diagnostic. fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry); @@ -212,6 +212,8 @@ pub trait Emitter: Translate { fn source_map(&self) -> Option<&SourceMap>; + fn translator(&self) -> &Translator; + /// Formats the substitutions of the primary_span /// /// There are a lot of conditions to this method, but in short: @@ -224,13 +226,17 @@ pub trait Emitter: Translate { /// * If the current `DiagInner` has multiple suggestions, /// we leave `primary_span` and the suggestions untouched. fn primary_span_formatted( - &mut self, + &self, primary_span: &mut MultiSpan, suggestions: &mut Vec, fluent_args: &FluentArgs<'_>, ) { if let Some((sugg, rest)) = suggestions.split_first() { - let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap(); + let msg = self + .translator() + .translate_message(&sugg.msg, fluent_args) + .map_err(Report::new) + .unwrap(); if rest.is_empty() // ^ if there is only one suggestion // don't display multi-suggestions as labels @@ -491,16 +497,6 @@ pub trait Emitter: Translate { } } -impl Translate for HumanEmitter { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - self.fluent_bundle.as_deref() - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &self.fallback_bundle - } -} - impl Emitter for HumanEmitter { fn source_map(&self) -> Option<&SourceMap> { self.sm.as_deref() @@ -538,6 +534,10 @@ impl Emitter for HumanEmitter { fn supports_color(&self) -> bool { self.dst.supports_color() } + + fn translator(&self) -> &Translator { + &self.translator + } } /// An emitter that does nothing when emitting a non-fatal diagnostic. @@ -549,16 +549,6 @@ pub struct SilentEmitter { pub emit_fatal_diagnostic: bool, } -impl Translate for SilentEmitter { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - None - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - self.fatal_emitter.fallback_fluent_bundle() - } -} - impl Emitter for SilentEmitter { fn source_map(&self) -> Option<&SourceMap> { None @@ -572,6 +562,10 @@ impl Emitter for SilentEmitter { self.fatal_emitter.emit_diagnostic(diag, registry); } } + + fn translator(&self) -> &Translator { + self.fatal_emitter.translator() + } } /// Maximum number of suggestions to be shown @@ -615,9 +609,8 @@ pub struct HumanEmitter { #[setters(skip)] dst: IntoDynSyncSend, sm: Option>, - fluent_bundle: Option>, #[setters(skip)] - fallback_bundle: LazyFallbackBundle, + translator: Translator, short_message: bool, ui_testing: bool, ignored_directories_in_source_blocks: Vec, @@ -637,12 +630,11 @@ pub(crate) struct FileWithAnnotatedLines { } impl HumanEmitter { - pub fn new(dst: Destination, fallback_bundle: LazyFallbackBundle) -> HumanEmitter { + pub fn new(dst: Destination, translator: Translator) -> HumanEmitter { HumanEmitter { dst: IntoDynSyncSend(dst), sm: None, - fluent_bundle: None, - fallback_bundle, + translator, short_message: false, ui_testing: false, ignored_directories_in_source_blocks: Vec::new(), @@ -1433,7 +1425,7 @@ impl HumanEmitter { // very *weird* formats // see? for (text, style) in msgs.iter() { - let text = self.translate_message(text, args).map_err(Report::new).unwrap(); + let text = self.translator.translate_message(text, args).map_err(Report::new).unwrap(); let text = &normalize_whitespace(&text); let lines = text.split('\n').collect::>(); if lines.len() > 1 { @@ -1528,7 +1520,8 @@ impl HumanEmitter { } let mut line = 0; for (text, style) in msgs.iter() { - let text = self.translate_message(text, args).map_err(Report::new).unwrap(); + let text = + self.translator.translate_message(text, args).map_err(Report::new).unwrap(); // Account for newlines to align output to its label. for text in normalize_whitespace(&text).lines() { buffer.append( @@ -1560,7 +1553,7 @@ impl HumanEmitter { .into_iter() .filter_map(|label| match label.label { Some(msg) if label.is_primary => { - let text = self.translate_message(&msg, args).ok()?; + let text = self.translator.translate_message(&msg, args).ok()?; if !text.trim().is_empty() { Some(text.to_string()) } else { None } } _ => None, @@ -3104,7 +3097,11 @@ impl FileWithAnnotatedLines { let label = label.as_ref().map(|m| { normalize_whitespace( - &emitter.translate_message(m, args).map_err(Report::new).unwrap(), + &emitter + .translator() + .translate_message(m, args) + .map_err(Report::new) + .unwrap(), ) }); diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index d67e2ba2d60e..6d600f896a0f 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -32,11 +32,8 @@ use crate::emitter::{ }; use crate::registry::Registry; use crate::timings::{TimingRecord, TimingSection}; -use crate::translation::{Translate, to_fluent_args}; -use crate::{ - CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, Subdiag, Suggestions, - TerminalUrl, -}; +use crate::translation::{Translator, to_fluent_args}; +use crate::{CodeSuggestion, MultiSpan, SpanLabel, Subdiag, Suggestions, TerminalUrl}; #[cfg(test)] mod tests; @@ -47,9 +44,8 @@ pub struct JsonEmitter { dst: IntoDynSyncSend>, #[setters(skip)] sm: Option>, - fluent_bundle: Option>, #[setters(skip)] - fallback_bundle: LazyFallbackBundle, + translator: Translator, #[setters(skip)] pretty: bool, ui_testing: bool, @@ -67,7 +63,7 @@ impl JsonEmitter { pub fn new( dst: Box, sm: Option>, - fallback_bundle: LazyFallbackBundle, + translator: Translator, pretty: bool, json_rendered: HumanReadableErrorType, color_config: ColorConfig, @@ -75,8 +71,7 @@ impl JsonEmitter { JsonEmitter { dst: IntoDynSyncSend(dst), sm, - fluent_bundle: None, - fallback_bundle, + translator, pretty, ui_testing: false, ignored_directories_in_source_blocks: Vec::new(), @@ -110,16 +105,6 @@ enum EmitTyped<'a> { UnusedExtern(UnusedExterns<'a>), } -impl Translate for JsonEmitter { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - self.fluent_bundle.as_deref() - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &self.fallback_bundle - } -} - impl Emitter for JsonEmitter { fn emit_diagnostic(&mut self, diag: crate::DiagInner, registry: &Registry) { let data = Diagnostic::from_errors_diagnostic(diag, self, registry); @@ -194,6 +179,10 @@ impl Emitter for JsonEmitter { fn should_show_explain(&self) -> bool { !self.json_rendered.short() } + + fn translator(&self) -> &Translator { + &self.translator + } } // The following data types are provided just for serialisation. @@ -324,7 +313,7 @@ impl Diagnostic { let args = to_fluent_args(diag.args.iter()); let sugg_to_diag = |sugg: &CodeSuggestion| { let translated_message = - je.translate_message(&sugg.msg, &args).map_err(Report::new).unwrap(); + je.translator.translate_message(&sugg.msg, &args).map_err(Report::new).unwrap(); Diagnostic { message: translated_message.to_string(), code: None, @@ -368,7 +357,7 @@ impl Diagnostic { } } - let translated_message = je.translate_messages(&diag.messages, &args); + let translated_message = je.translator.translate_messages(&diag.messages, &args); let code = if let Some(code) = diag.code { Some(DiagnosticCode { @@ -396,10 +385,9 @@ impl Diagnostic { ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)), ColorConfig::Never => {} } - HumanEmitter::new(dst, Arc::clone(&je.fallback_bundle)) + HumanEmitter::new(dst, je.translator.clone()) .short_message(short) .sm(je.sm.clone()) - .fluent_bundle(je.fluent_bundle.clone()) .diagnostic_width(je.diagnostic_width) .macro_backtrace(je.macro_backtrace) .track_diagnostics(je.track_diagnostics) @@ -430,7 +418,7 @@ impl Diagnostic { args: &FluentArgs<'_>, je: &JsonEmitter, ) -> Diagnostic { - let translated_message = je.translate_messages(&subdiag.messages, args); + let translated_message = je.translator.translate_messages(&subdiag.messages, args); Diagnostic { message: translated_message.to_string(), code: None, @@ -454,7 +442,7 @@ impl DiagnosticSpan { span.is_primary, span.label .as_ref() - .map(|m| je.translate_message(m, args).unwrap()) + .map(|m| je.translator.translate_message(m, args).unwrap()) .map(|m| m.to_string()), suggestion, je, diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index 40973e8e5d8a..8cf81f467d84 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -41,14 +41,14 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { rustc_span::create_default_session_globals_then(|| { let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned()); - let fallback_bundle = - crate::fallback_fluent_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); + let translator = + Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); let output = Arc::new(Mutex::new(Vec::new())); let je = JsonEmitter::new( Box::new(Shared { data: output.clone() }), Some(sm), - fallback_bundle, + translator, true, // pretty HumanReadableErrorType::Short, ColorConfig::Never, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 0bd259366def..70f294b696a2 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -761,14 +761,8 @@ impl DiagCtxt { fn source_map(&self) -> Option<&SourceMap> { unimplemented!("false emitter must only used during `make_silent`") } - } - impl translation::Translate for FalseEmitter { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - unimplemented!("false emitter must only used during `make_silent`") - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { + fn translator(&self) -> &translation::Translator { unimplemented!("false emitter must only used during `make_silent`") } } @@ -1771,7 +1765,12 @@ impl DiagCtxtInner { args: impl Iterator>, ) -> String { let args = crate::translation::to_fluent_args(args); - self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string() + self.emitter + .translator() + .translate_message(&message, &args) + .map_err(Report::new) + .unwrap() + .to_string() } fn eagerly_translate_for_subdiag( diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 376fd24d57ba..34ebac0fde11 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, LazyLock}; + use rustc_data_structures::sync::IntoDynSyncSend; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::{DiagMessage, langid}; @@ -5,23 +7,9 @@ use rustc_error_messages::{DiagMessage, langid}; use crate::FluentBundle; use crate::error::{TranslateError, TranslateErrorKind}; use crate::fluent_bundle::*; -use crate::translation::Translate; +use crate::translation::Translator; -struct Dummy { - bundle: FluentBundle, -} - -impl Translate for Dummy { - fn fluent_bundle(&self) -> Option<&FluentBundle> { - None - } - - fn fallback_fluent_bundle(&self) -> &FluentBundle { - &self.bundle - } -} - -fn make_dummy(ftl: &'static str) -> Dummy { +fn make_translator(ftl: &'static str) -> Translator { let resource = FluentResource::try_new(ftl.into()).expect("Failed to parse an FTL string."); let langid_en = langid!("en-US"); @@ -33,12 +21,15 @@ fn make_dummy(ftl: &'static str) -> Dummy { bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle."); - Dummy { bundle } + Translator { + fluent_bundle: None, + fallback_fluent_bundle: Arc::new(LazyLock::new(Box::new(|| bundle))), + } } #[test] fn wellformed_fluent() { - let dummy = make_dummy("mir_build_borrow_of_moved_value = borrow of moved value + let translator = make_translator("mir_build_borrow_of_moved_value = borrow of moved value .label = value moved into `{$name}` here .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait .value_borrowed_label = value borrowed here after move @@ -54,7 +45,7 @@ fn wellformed_fluent() { ); assert_eq!( - dummy.translate_message(&message, &args).unwrap(), + translator.translate_message(&message, &args).unwrap(), "borrow this binding in the pattern to avoid moving the value" ); } @@ -66,7 +57,7 @@ fn wellformed_fluent() { ); assert_eq!( - dummy.translate_message(&message, &args).unwrap(), + translator.translate_message(&message, &args).unwrap(), "value borrowed here after move" ); } @@ -78,7 +69,7 @@ fn wellformed_fluent() { ); assert_eq!( - dummy.translate_message(&message, &args).unwrap(), + translator.translate_message(&message, &args).unwrap(), "move occurs because `\u{2068}Foo\u{2069}` has type `\u{2068}std::string::String\u{2069}` which does not implement the `Copy` trait" ); @@ -89,7 +80,7 @@ fn wellformed_fluent() { ); assert_eq!( - dummy.translate_message(&message, &args).unwrap(), + translator.translate_message(&message, &args).unwrap(), "value moved into `\u{2068}Foo\u{2069}` here" ); } @@ -98,7 +89,7 @@ fn wellformed_fluent() { #[test] fn misformed_fluent() { - let dummy = make_dummy("mir_build_borrow_of_moved_value = borrow of moved value + let translator = make_translator("mir_build_borrow_of_moved_value = borrow of moved value .label = value moved into `{name}` here .occurs_because_label = move occurs because `{$oops}` has type `{$ty}` which does not implement the `Copy` trait .suggestion = borrow this binding in the pattern to avoid moving the value"); @@ -112,7 +103,7 @@ fn misformed_fluent() { Some("value_borrowed_label".into()), ); - let err = dummy.translate_message(&message, &args).unwrap_err(); + let err = translator.translate_message(&message, &args).unwrap_err(); assert!( matches!( &err, @@ -141,7 +132,7 @@ fn misformed_fluent() { Some("label".into()), ); - let err = dummy.translate_message(&message, &args).unwrap_err(); + let err = translator.translate_message(&message, &args).unwrap_err(); if let TranslateError::Two { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, @@ -168,7 +159,7 @@ fn misformed_fluent() { Some("occurs_because_label".into()), ); - let err = dummy.translate_message(&message, &args).unwrap_err(); + let err = translator.translate_message(&message, &args).unwrap_err(); if let TranslateError::Two { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index 156f5e5d26e6..c0bcec093c7e 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -1,8 +1,9 @@ use std::borrow::Cow; use std::env; use std::error::Report; +use std::sync::Arc; -pub use rustc_error_messages::FluentArgs; +pub use rustc_error_messages::{FluentArgs, LazyFallbackBundle}; use tracing::{debug, trace}; use crate::error::{TranslateError, TranslateErrorKind}; @@ -28,19 +29,33 @@ pub fn to_fluent_args<'iter>(iter: impl Iterator>) -> Flue args } -pub trait Translate { - /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no - /// language was requested by the user then this will be `None` and `fallback_fluent_bundle` - /// should be used. - fn fluent_bundle(&self) -> Option<&FluentBundle>; - +#[derive(Clone)] +pub struct Translator { + /// Localized diagnostics for the locale requested by the user. If no language was requested by + /// the user then this will be `None` and `fallback_fluent_bundle` should be used. + pub fluent_bundle: Option>, /// Return `FluentBundle` with localized diagnostics for the default locale of the compiler. /// Used when the user has not requested a specific language or when a localized diagnostic is /// unavailable for the requested locale. - fn fallback_fluent_bundle(&self) -> &FluentBundle; + pub fallback_fluent_bundle: LazyFallbackBundle, +} + +impl Translator { + pub fn with_fallback_bundle( + resources: Vec<&'static str>, + with_directionality_markers: bool, + ) -> Translator { + Translator { + fluent_bundle: None, + fallback_fluent_bundle: crate::fallback_fluent_bundle( + resources, + with_directionality_markers, + ), + } + } /// Convert `DiagMessage`s to a string, performing translation if necessary. - fn translate_messages( + pub fn translate_messages( &self, messages: &[(DiagMessage, Style)], args: &FluentArgs<'_>, @@ -54,7 +69,7 @@ pub trait Translate { } /// Convert a `DiagMessage` to a string, performing translation if necessary. - fn translate_message<'a>( + pub fn translate_message<'a>( &'a self, message: &'a DiagMessage, args: &'a FluentArgs<'_>, @@ -91,7 +106,7 @@ pub trait Translate { }; try { - match self.fluent_bundle().map(|b| translate_with_bundle(b)) { + match self.fluent_bundle.as_ref().map(|b| translate_with_bundle(b)) { // The primary bundle was present and translation succeeded Some(Ok(t)) => t, @@ -102,7 +117,7 @@ pub trait Translate { primary @ TranslateError::One { kind: TranslateErrorKind::MessageMissing, .. }, - )) => translate_with_bundle(self.fallback_fluent_bundle()) + )) => translate_with_bundle(&self.fallback_fluent_bundle) .map_err(|fallback| primary.and(fallback))?, // Always yeet out for errors on debug (unless @@ -118,11 +133,11 @@ pub trait Translate { // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so // just hide it and try with the fallback bundle. - Some(Err(primary)) => translate_with_bundle(self.fallback_fluent_bundle()) + Some(Err(primary)) => translate_with_bundle(&self.fallback_fluent_bundle) .map_err(|fallback| primary.and(fallback))?, // The primary bundle is missing, proceed to the fallback bundle - None => translate_with_bundle(self.fallback_fluent_bundle()) + None => translate_with_bundle(&self.fallback_fluent_bundle) .map_err(|fallback| TranslateError::primary(identifier, args).and(fallback))?, } } diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 2a44c90abc17..15679d23bc56 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -14,6 +14,7 @@ use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, Toke use rustc_ast::{self as ast, PatKind, visit}; use rustc_ast_pretty::pprust::item_to_string; use rustc_errors::emitter::{HumanEmitter, OutputTheme}; +use rustc_errors::translation::Translator; use rustc_errors::{DiagCtxt, MultiSpan, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; @@ -41,9 +42,8 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Arc, Arc>>) { let output = Arc::new(Mutex::new(Vec::new())); let source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); - let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) + let translator = Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); + let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), translator) .sm(Some(source_map.clone())) .diagnostic_width(Some(140)); emitter = emitter.theme(theme); diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 87c848cf857f..30a61cb411bb 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -9,9 +9,10 @@ use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock}; use rustc_errors::emitter::{HumanEmitter, SilentEmitter, stderr_destination}; +use rustc_errors::translation::Translator; use rustc_errors::{ ColorConfig, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, EmissionGuarantee, MultiSpan, - StashKey, fallback_fluent_bundle, + StashKey, }; use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue}; use rustc_span::edition::Edition; @@ -242,10 +243,10 @@ pub struct ParseSess { impl ParseSess { /// Used for testing. pub fn new(locale_resources: Vec<&'static str>) -> Self { - let fallback_bundle = fallback_fluent_bundle(locale_resources, false); + let translator = Translator::with_fallback_bundle(locale_resources, false); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new( - HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle) + HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator) .sm(Some(Arc::clone(&sm))), ); let dcx = DiagCtxt::new(emitter); @@ -277,12 +278,13 @@ impl ParseSess { pub fn with_silent_emitter( locale_resources: Vec<&'static str>, fatal_note: String, + emit_fatal_diagnostic: bool, ) -> Self { - let fallback_bundle = fallback_fluent_bundle(locale_resources, false); + let translator = Translator::with_fallback_bundle(locale_resources, false); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let fatal_emitter = - Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle)); + Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator)); let dcx = DiagCtxt::new(Box::new(SilentEmitter { fatal_emitter, fatal_note: Some(fatal_note), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ca42c5a42566..ad58c3c8f7d8 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -19,9 +19,10 @@ use rustc_errors::emitter::{ }; use rustc_errors::json::JsonEmitter; use rustc_errors::timings::TimingSectionHandler; +use rustc_errors::translation::Translator; use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort, - FluentBundle, LazyFallbackBundle, TerminalUrl, fallback_fluent_bundle, + TerminalUrl, fallback_fluent_bundle, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -948,8 +949,7 @@ impl Session { fn default_emitter( sopts: &config::Options, source_map: Arc, - bundle: Option>, - fallback_bundle: LazyFallbackBundle, + translator: Translator, ) -> Box { let macro_backtrace = sopts.unstable_opts.macro_backtrace; let track_diagnostics = sopts.unstable_opts.track_diagnostics; @@ -974,17 +974,11 @@ fn default_emitter( let short = kind.short(); if let HumanReadableErrorType::AnnotateSnippet = kind { - let emitter = AnnotateSnippetEmitter::new( - source_map, - bundle, - fallback_bundle, - short, - macro_backtrace, - ); + let emitter = + AnnotateSnippetEmitter::new(source_map, translator, short, macro_backtrace); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } else { - let emitter = HumanEmitter::new(stderr_destination(color_config), fallback_bundle) - .fluent_bundle(bundle) + let emitter = HumanEmitter::new(stderr_destination(color_config), translator) .sm(source_map) .short_message(short) .diagnostic_width(sopts.diagnostic_width) @@ -1006,12 +1000,11 @@ fn default_emitter( JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), source_map, - fallback_bundle, + translator, pretty, json_rendered, color_config, ) - .fluent_bundle(bundle) .ui_testing(sopts.unstable_opts.ui_testing) .ignored_directories_in_source_blocks( sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(), @@ -1030,7 +1023,7 @@ fn default_emitter( pub fn build_session( sopts: config::Options, io: CompilerIO, - bundle: Option>, + fluent_bundle: Option>, registry: rustc_errors::registry::Registry, fluent_resources: Vec<&'static str>, driver_lint_caps: FxHashMap, @@ -1052,12 +1045,15 @@ pub fn build_session( let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow); let can_emit_warnings = !(warnings_allow || cap_lints_allow); - let fallback_bundle = fallback_fluent_bundle( - fluent_resources, - sopts.unstable_opts.translate_directionality_markers, - ); + let translator = Translator { + fluent_bundle, + fallback_fluent_bundle: fallback_fluent_bundle( + fluent_resources, + sopts.unstable_opts.translate_directionality_markers, + ), + }; let source_map = rustc_span::source_map::get_source_map().unwrap(); - let emitter = default_emitter(&sopts, Arc::clone(&source_map), bundle, fallback_bundle); + let emitter = default_emitter(&sopts, Arc::clone(&source_map), translator); let mut dcx = DiagCtxt::new(emitter) .with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings)) @@ -1500,13 +1496,13 @@ impl EarlyDiagCtxt { fn mk_emitter(output: ErrorOutputType) -> Box { // FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will // need to reference every crate that might emit an early error for translation to work. - let fallback_bundle = - fallback_fluent_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false); + let translator = + Translator::with_fallback_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false); let emitter: Box = match output { config::ErrorOutputType::HumanReadable { kind, color_config } => { let short = kind.short(); Box::new( - HumanEmitter::new(stderr_destination(color_config), fallback_bundle) + HumanEmitter::new(stderr_destination(color_config), translator) .theme(if let HumanReadableErrorType::Unicode = kind { OutputTheme::Unicode } else { @@ -1519,7 +1515,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box { Box::new(JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), Some(Arc::new(SourceMap::new(FilePathMapping::empty()))), - fallback_bundle, + translator, pretty, json_rendered, color_config, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 204f8decffcc..3b1d89bbecd9 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -149,15 +149,12 @@ pub(crate) fn new_dcx( diagnostic_width: Option, unstable_opts: &UnstableOptions, ) -> rustc_errors::DiagCtxt { - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); + let translator = rustc_driver::default_translator(); let emitter: Box = match error_format { ErrorOutputType::HumanReadable { kind, color_config } => { let short = kind.short(); Box::new( - HumanEmitter::new(stderr_destination(color_config), fallback_bundle) + HumanEmitter::new(stderr_destination(color_config), translator) .sm(source_map.map(|sm| sm as _)) .short_message(short) .diagnostic_width(diagnostic_width) @@ -178,7 +175,7 @@ pub(crate) fn new_dcx( JsonEmitter::new( Box::new(io::BufWriter::new(io::stderr())), Some(source_map), - fallback_bundle, + translator, pretty, json_rendered, color_config, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 3ff6828e52f9..f229f77c9784 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -456,16 +456,13 @@ fn parse_source( let filename = FileName::anon_source_code(&wrapped_source); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); + let translator = rustc_driver::default_translator(); info.supports_color = - HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle.clone()) + HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator.clone()) .supports_color(); // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that the parser emits directly into a `Sink` instead of stderr. - let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); + let emitter = HumanEmitter::new(Box::new(io::sink()), translator); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 9662dd85d678..91cddbe5a5bc 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -6,8 +6,8 @@ use std::sync::Arc; use rustc_data_structures::sync::Lock; use rustc_errors::emitter::Emitter; use rustc_errors::registry::Registry; -use rustc_errors::translation::{Translate, to_fluent_args}; -use rustc_errors::{Applicability, DiagCtxt, DiagInner, LazyFallbackBundle}; +use rustc_errors::translation::{Translator, to_fluent_args}; +use rustc_errors::{Applicability, DiagCtxt, DiagInner}; use rustc_parse::{source_str_to_stream, unwrap_or_emit_fatal}; use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_session::parse::ParseSess; @@ -36,11 +36,8 @@ fn check_rust_syntax( code_block: RustCodeBlock, ) { let buffer = Arc::new(Lock::new(Buffer::default())); - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); - let emitter = BufferEmitter { buffer: Arc::clone(&buffer), fallback_bundle }; + let translator = rustc_driver::default_translator(); + let emitter = BufferEmitter { buffer: Arc::clone(&buffer), translator }; let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); @@ -149,17 +146,7 @@ struct Buffer { struct BufferEmitter { buffer: Arc>, - fallback_bundle: LazyFallbackBundle, -} - -impl Translate for BufferEmitter { - fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { - None - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - &self.fallback_bundle - } + translator: Translator, } impl Emitter for BufferEmitter { @@ -168,6 +155,7 @@ impl Emitter for BufferEmitter { let fluent_args = to_fluent_args(diag.args.iter()); let translated_main_message = self + .translator .translate_message(&diag.messages[0].0, &fluent_args) .unwrap_or_else(|e| panic!("{e}")); @@ -180,4 +168,8 @@ impl Emitter for BufferEmitter { fn source_map(&self) -> Option<&SourceMap> { None } + + fn translator(&self) -> &Translator { + &self.translator + } } diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index ec4538039a91..7ba11c20f456 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -42,9 +42,8 @@ pub fn check( let mut test_attr_spans = vec![]; let filename = FileName::anon_source_code(&code); - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); - let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); + let translator = rustc_driver::default_translator(); + let emitter = HumanEmitter::new(Box::new(io::sink()), translator); let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); #[expect(clippy::arc_with_non_send_sync)] // `Arc` is expected by with_dcx let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index afd847f95157..73a89072f146 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination}; use rustc_errors::registry::Registry; -use rustc_errors::translation::Translate; +use rustc_errors::translation::Translator; use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel}; use rustc_session::parse::ParseSess as RawParseSess; use rustc_span::{ @@ -47,16 +47,6 @@ impl SilentOnIgnoredFilesEmitter { } } -impl Translate for SilentOnIgnoredFilesEmitter { - fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { - self.emitter.fluent_bundle() - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - self.emitter.fallback_fluent_bundle() - } -} - impl Emitter for SilentOnIgnoredFilesEmitter { fn source_map(&self) -> Option<&SourceMap> { None @@ -84,6 +74,10 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } self.handle_non_ignoreable_error(diag, registry); } + + fn translator(&self) -> &Translator { + self.emitter.translator() + } } impl From for ColorConfig { @@ -110,12 +104,9 @@ fn default_dcx( ColorConfig::Never }; - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); + let translator = rustc_driver::default_translator(); let emitter = Box::new( - HumanEmitter::new(stderr_destination(emit_color), fallback_bundle) + HumanEmitter::new(stderr_destination(emit_color), translator) .sm(Some(source_map.clone())), ); @@ -335,16 +326,6 @@ mod tests { num_emitted_errors: Arc, } - impl Translate for TestEmitter { - fn fluent_bundle(&self) -> Option<&rustc_errors::FluentBundle> { - None - } - - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { - panic!("test emitter attempted to translate a diagnostic"); - } - } - impl Emitter for TestEmitter { fn source_map(&self) -> Option<&SourceMap> { None @@ -353,6 +334,10 @@ mod tests { fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) { self.num_emitted_errors.fetch_add(1, Ordering::Release); } + + fn translator(&self) -> &Translator { + panic!("test emitter attempted to translate a diagnostic"); + } } fn build_diagnostic(level: DiagnosticLevel, span: Option) -> DiagInner { From 316f63bc48a9bfe26b2a8fc06e7eeef45ac2b7aa Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 17 Jun 2025 16:59:57 -0500 Subject: [PATCH 158/356] Rename SilentEmitter -> FatalOnlyEmitter --- compiler/rustc_errors/src/emitter.rs | 4 ++-- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_interface/src/interface.rs | 4 ++-- compiler/rustc_session/src/parse.rs | 6 +++--- src/tools/rustfmt/src/parse/session.rs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 494f15cc6390..4464b45775ad 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -543,13 +543,13 @@ impl Emitter for HumanEmitter { /// An emitter that does nothing when emitting a non-fatal diagnostic. /// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent /// failures of rustc, as witnessed e.g. in issue #89358. -pub struct SilentEmitter { +pub struct FatalOnlyEmitter { pub fatal_emitter: Box, pub fatal_note: Option, pub emit_fatal_diagnostic: bool, } -impl Emitter for SilentEmitter { +impl Emitter for FatalOnlyEmitter { fn source_map(&self) -> Option<&SourceMap> { None } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 70f294b696a2..831a50efa27d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -770,7 +770,7 @@ impl DiagCtxt { let mut inner = self.inner.borrow_mut(); let mut prev_emitter = Box::new(FalseEmitter) as Box; std::mem::swap(&mut inner.emitter, &mut prev_emitter); - let new_emitter = Box::new(emitter::SilentEmitter { + let new_emitter = Box::new(emitter::FatalOnlyEmitter { fatal_emitter: prev_emitter, fatal_note, emit_fatal_diagnostic, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index e824e9d4aa91..ffac9cbdec1a 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -52,7 +52,7 @@ pub struct Compiler { pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec) -> Cfg { cfgs.into_iter() .map(|s| { - let psess = ParseSess::with_silent_emitter( + let psess = ParseSess::with_fatal_emitter( vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], format!("this error occurred on the command line: `--cfg={s}`"), true, @@ -116,7 +116,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() }; for s in specs { - let psess = ParseSess::with_silent_emitter( + let psess = ParseSess::with_fatal_emitter( vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], format!("this error occurred on the command line: `--check-cfg={s}`"), true, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 30a61cb411bb..154bed8b809a 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -8,7 +8,7 @@ use rustc_ast::attr::AttrIdGenerator; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock}; -use rustc_errors::emitter::{HumanEmitter, SilentEmitter, stderr_destination}; +use rustc_errors::emitter::{FatalOnlyEmitter, HumanEmitter, stderr_destination}; use rustc_errors::translation::Translator; use rustc_errors::{ ColorConfig, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, EmissionGuarantee, MultiSpan, @@ -275,7 +275,7 @@ impl ParseSess { } } - pub fn with_silent_emitter( + pub fn with_fatal_emitter( locale_resources: Vec<&'static str>, fatal_note: String, @@ -285,7 +285,7 @@ impl ParseSess { let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let fatal_emitter = Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), translator)); - let dcx = DiagCtxt::new(Box::new(SilentEmitter { + let dcx = DiagCtxt::new(Box::new(FatalOnlyEmitter { fatal_emitter, fatal_note: Some(fatal_note), emit_fatal_diagnostic, diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 73a89072f146..c50d4ef04890 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination}; +use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, FatalOnlyEmitter, stderr_destination}; use rustc_errors::registry::Registry; use rustc_errors::translation::Translator; use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel}; @@ -111,7 +111,7 @@ fn default_dcx( ); let emitter: Box = if !show_parse_errors { - Box::new(SilentEmitter { + Box::new(FatalOnlyEmitter { fatal_emitter: emitter, fatal_note: None, emit_fatal_diagnostic: false, From 3388d837850eebca505350bc25f017276551a955 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 19 Jun 2025 13:05:01 -0500 Subject: [PATCH 159/356] Extract SilentEmitter --- compiler/rustc_errors/src/emitter.rs | 19 ++++++++++++-- compiler/rustc_errors/src/lib.rs | 30 +++-------------------- compiler/rustc_interface/src/interface.rs | 2 -- compiler/rustc_session/src/parse.rs | 8 +----- src/tools/rustfmt/src/parse/session.rs | 21 ++++++---------- 5 files changed, 29 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 4464b45775ad..e333de4b660b 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -546,7 +546,6 @@ impl Emitter for HumanEmitter { pub struct FatalOnlyEmitter { pub fatal_emitter: Box, pub fatal_note: Option, - pub emit_fatal_diagnostic: bool, } impl Emitter for FatalOnlyEmitter { @@ -555,7 +554,7 @@ impl Emitter for FatalOnlyEmitter { } fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) { - if self.emit_fatal_diagnostic && diag.level == Level::Fatal { + if diag.level == Level::Fatal { if let Some(fatal_note) = &self.fatal_note { diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new()); } @@ -568,6 +567,22 @@ impl Emitter for FatalOnlyEmitter { } } +pub struct SilentEmitter { + pub translator: Translator, +} + +impl Emitter for SilentEmitter { + fn source_map(&self) -> Option<&SourceMap> { + None + } + + fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) {} + + fn translator(&self) -> &Translator { + &self.translator + } +} + /// Maximum number of suggestions to be shown /// /// Arbitrary, but taken from trait import suggestion limit diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 831a50efa27d..207aed8c7554 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -748,34 +748,10 @@ impl DiagCtxt { Self { inner: Lock::new(DiagCtxtInner::new(emitter)) } } - pub fn make_silent(&self, fatal_note: Option, emit_fatal_diagnostic: bool) { - // An empty type that implements `Emitter` to temporarily swap in place of the real one, - // which will be used in constructing its replacement. - struct FalseEmitter; - - impl Emitter for FalseEmitter { - fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) { - unimplemented!("false emitter must only used during `make_silent`") - } - - fn source_map(&self) -> Option<&SourceMap> { - unimplemented!("false emitter must only used during `make_silent`") - } - - fn translator(&self) -> &translation::Translator { - unimplemented!("false emitter must only used during `make_silent`") - } - } - + pub fn make_silent(&self) { let mut inner = self.inner.borrow_mut(); - let mut prev_emitter = Box::new(FalseEmitter) as Box; - std::mem::swap(&mut inner.emitter, &mut prev_emitter); - let new_emitter = Box::new(emitter::FatalOnlyEmitter { - fatal_emitter: prev_emitter, - fatal_note, - emit_fatal_diagnostic, - }); - inner.emitter = new_emitter; + let translator = inner.emitter.translator().clone(); + inner.emitter = Box::new(emitter::SilentEmitter { translator }); } pub fn set_emitter(&self, emitter: Box) { diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index ffac9cbdec1a..d62bf7f85e0e 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -55,7 +55,6 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec) -> Cfg { let psess = ParseSess::with_fatal_emitter( vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], format!("this error occurred on the command line: `--cfg={s}`"), - true, ); let filename = FileName::cfg_spec_source_code(&s); @@ -119,7 +118,6 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch let psess = ParseSess::with_fatal_emitter( vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], format!("this error occurred on the command line: `--check-cfg={s}`"), - true, ); let filename = FileName::cfg_spec_source_code(&s); diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 154bed8b809a..0118cdb1fc27 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -275,12 +275,7 @@ impl ParseSess { } } - pub fn with_fatal_emitter( - locale_resources: Vec<&'static str>, - fatal_note: String, - - emit_fatal_diagnostic: bool, - ) -> Self { + pub fn with_fatal_emitter(locale_resources: Vec<&'static str>, fatal_note: String) -> Self { let translator = Translator::with_fallback_bundle(locale_resources, false); let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let fatal_emitter = @@ -288,7 +283,6 @@ impl ParseSess { let dcx = DiagCtxt::new(Box::new(FatalOnlyEmitter { fatal_emitter, fatal_note: Some(fatal_note), - emit_fatal_diagnostic, })) .disable_warnings(); ParseSess::with_dcx(dcx, sm) diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index c50d4ef04890..10e2809e58bf 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, FatalOnlyEmitter, stderr_destination}; +use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination}; use rustc_errors::registry::Registry; use rustc_errors::translation::Translator; use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel}; @@ -105,19 +105,14 @@ fn default_dcx( }; let translator = rustc_driver::default_translator(); - let emitter = Box::new( - HumanEmitter::new(stderr_destination(emit_color), translator) - .sm(Some(source_map.clone())), - ); - let emitter: Box = if !show_parse_errors { - Box::new(FatalOnlyEmitter { - fatal_emitter: emitter, - fatal_note: None, - emit_fatal_diagnostic: false, - }) + let emitter: Box = if show_parse_errors { + Box::new( + HumanEmitter::new(stderr_destination(emit_color), translator) + .sm(Some(source_map.clone())), + ) } else { - emitter + Box::new(SilentEmitter { translator }) }; DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter { has_non_ignorable_parser_errors: false, @@ -196,7 +191,7 @@ impl ParseSess { } pub(crate) fn set_silent_emitter(&mut self) { - self.raw_psess.dcx().make_silent(None, false); + self.raw_psess.dcx().make_silent(); } pub(crate) fn span_to_filename(&self, span: Span) -> FileName { From 1ed0cbf698bbed4135eb4e47c4ac22a907dd41e9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 13 Jun 2025 12:59:25 -0700 Subject: [PATCH 160/356] Preserve Paren expression's attributes during Unparenthesize --- tests/ui-fulldeps/pprust-parenthesis-insertion.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index 90e07bed40e7..6ac079ae4342 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -158,7 +158,12 @@ struct Unparenthesize; impl MutVisitor for Unparenthesize { fn visit_expr(&mut self, e: &mut Expr) { while let ExprKind::Paren(paren) = &mut e.kind { + let paren_attrs = mem::take(&mut e.attrs); *e = mem::replace(paren, Expr::dummy()); + if !paren_attrs.is_empty() { + assert!(e.attrs.is_empty()); + e.attrs = paren_attrs; + } } mut_visit::walk_expr(self, e); } From 24ea06cbe8e5b735a4807d08da14b5925db896cc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 19 Jun 2025 21:03:10 +0000 Subject: [PATCH 161/356] Apply impl_super_outlives optimization to new trait solver --- compiler/rustc_middle/src/ty/context.rs | 7 +++++++ .../src/solve/trait_goals.rs | 15 ++++++--------- compiler/rustc_type_ir/src/interner.rs | 7 +++++++ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f1395c242f27..b1dd25d39b43 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -432,6 +432,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied()) } + fn impl_super_outlives( + self, + impl_def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { + self.impl_super_outlives(impl_def_id) + } + fn impl_is_const(self, def_id: DefId) -> bool { debug_assert_matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true }); self.is_conditionally_const(def_id) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 8ee116b090dc..8aaa8e9ca87e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -103,15 +103,12 @@ where // We currently elaborate all supertrait outlives obligations from impls. // This can be removed when we actually do coinduction correctly, and prove // all supertrait obligations unconditionally. - let goal_clause: I::Clause = goal.predicate.upcast(cx); - for clause in elaborate::elaborate(cx, [goal_clause]) { - if matches!( - clause.kind().skip_binder(), - ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..) - ) { - ecx.add_goal(GoalSource::Misc, goal.with(cx, clause)); - } - } + ecx.add_goals( + GoalSource::Misc, + cx.impl_super_outlives(impl_def_id) + .iter_instantiated(cx, impl_args) + .map(|pred| goal.with(cx, pred)), + ); ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) }) diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 033d2579678c..ffc2903ad1ca 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -271,6 +271,13 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder>; + /// This is equivalent to computing the super-predicates of the trait for this impl + /// and filtering them to the outlives predicates. This is purely for performance. + fn impl_super_outlives( + self, + impl_def_id: Self::DefId, + ) -> ty::EarlyBinder>; + fn impl_is_const(self, def_id: Self::DefId) -> bool; fn fn_is_const(self, def_id: Self::DefId) -> bool; fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool; From dfaa6220e22cfed43ea36d958d239c67896a9ceb Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 19 Jun 2025 13:40:02 -0500 Subject: [PATCH 162/356] add issue template for rustdoc --- .github/ISSUE_TEMPLATE/rustdoc.md | 54 +++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/rustdoc.md diff --git a/.github/ISSUE_TEMPLATE/rustdoc.md b/.github/ISSUE_TEMPLATE/rustdoc.md new file mode 100644 index 000000000000..130d5f67102a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rustdoc.md @@ -0,0 +1,54 @@ +--- +name: Problem with rustdoc +about: Report an issue with how docs get generated. +labels: C-bug, T-rustdoc +--- + + +# Code + + +```rust + +``` + +# Reproduction Steps + + +# Expected Outcome + + +# Actual Output + +```console + +``` + + +# Version + + +# Additional Details + From e14e137b9d486868e041c030581cb750b0d05bcb Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Jun 2025 18:39:08 -0400 Subject: [PATCH 163/356] Update library dependencies This bumps to the latest versions of `r-efi` and `r-efi-alloc`, which drop the dependency on `compiler_builtins` via crates.io. Part of [#142265]. [#142265]: https://www.github.com/rust-lang/rust/issues/142265 --- library/Cargo.lock | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 34012d6943b7..4f0e7aed217c 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -219,21 +219,19 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] [[package]] name = "r-efi-alloc" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203" +checksum = "dc2f58ef3ca9bb0f9c44d9aa8537601bcd3df94cc9314a40178cadf7d4466354" dependencies = [ - "compiler_builtins", "r-efi", "rustc-std-workspace-core", ] From 240dc05371a5a7894cb87ebe45a12a3b1fd701fa Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 19 Jun 2025 16:49:22 -0400 Subject: [PATCH 164/356] Add a mailmap entry for y21 --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index b9fb7be0403c..f55200c3fe97 100644 --- a/.mailmap +++ b/.mailmap @@ -698,3 +698,4 @@ Zach Pomerantz Zack Corr Zack Slayton Zbigniew Siciarz Zbigniew Siciarz +y21 <30553356+y21@users.noreply.github.com> From aab941ff303e6795f0d1ea03ef825809ae4bd871 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Thu, 19 Jun 2025 23:21:38 +0000 Subject: [PATCH 165/356] rustdoc: Remove `FormatRenderer::cache` We only called it it one place, which isn't generic and can be replaced with a field access. --- src/librustdoc/formats/renderer.rs | 2 -- src/librustdoc/html/render/context.rs | 4 ---- src/librustdoc/json/conversions.rs | 3 +-- src/librustdoc/json/mod.rs | 4 ---- 4 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 48626171404f..79ff1fa38c38 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -68,8 +68,6 @@ pub(crate) trait FormatRenderer<'tcx>: Sized { /// Post processing hook for cleanup and dumping output to files. fn after_krate(self) -> Result<(), Error>; - - fn cache(&self) -> &Cache; } fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 382144516575..3b4dae841ee7 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -875,8 +875,4 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { Ok(()) } - - fn cache(&self) -> &Cache { - &self.shared.cache - } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 6bdf3b5fe387..8b4be107ace6 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -16,7 +16,6 @@ use rustdoc_json_types::*; use thin_vec::ThinVec; use crate::clean::{self, ItemId}; -use crate::formats::FormatRenderer; use crate::formats::item_type::ItemType; use crate::json::JsonRenderer; use crate::passes::collect_intra_doc_links::UrlFragment; @@ -41,7 +40,7 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes_and_repr(self.tcx, self.cache(), true); + let attrs = item.attributes_and_repr(self.tcx, &self.cache, true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 2feadce26d09..0f62c8bc347b 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -377,8 +377,4 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "") } } - - fn cache(&self) -> &Cache { - &self.cache - } } From 91851432c874bacc8e5c4e2a5c4c846ce81289d6 Mon Sep 17 00:00:00 2001 From: Daniel Bloom <7810950-Daniel.Aaron.Bloom@users.noreply.gitlab.com> Date: Thu, 19 Jun 2025 16:21:49 -0700 Subject: [PATCH 166/356] Make `Clone` a `const_trait` --- library/core/src/clone.rs | 9 +++++++-- library/core/src/lib.rs | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 57de507a73e8..a34d1b4a0649 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -36,7 +36,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::marker::PointeeSized; +use crate::marker::{Destruct, PointeeSized}; mod uninit; @@ -157,6 +157,8 @@ mod uninit; #[lang = "clone"] #[rustc_diagnostic_item = "Clone"] #[rustc_trivial_field_reads] +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +#[const_trait] pub trait Clone: Sized { /// Returns a duplicate of the value. /// @@ -208,7 +210,10 @@ pub trait Clone: Sized { /// allocations. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn clone_from(&mut self, source: &Self) { + fn clone_from(&mut self, source: &Self) + where + Self: ~const Destruct, + { *self = source.clone() } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 88855831788d..72132d365cc0 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -103,6 +103,7 @@ #![feature(cfg_select)] #![feature(cfg_target_has_reliable_f16_f128)] #![feature(const_carrying_mul_add)] +#![feature(const_destruct)] #![feature(const_eval_select)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] From fca6e81735c7d31fcfd39aa10126f3e5041dbecb Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 20 Jun 2025 07:44:18 +0800 Subject: [PATCH 167/356] Make sure to rebuild rustdoc if `src/rustdoc-json-types` is changed --- src/bootstrap/src/core/build_steps/tool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 0088e851d397..41f83da13f4f 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -716,7 +716,7 @@ impl Step for Rustdoc { && target_compiler.stage > 0 && builder.rust_info().is_managed_git_subrepository() { - let files_to_track = &["src/librustdoc", "src/tools/rustdoc"]; + let files_to_track = &["src/librustdoc", "src/tools/rustdoc", "src/rustdoc-json-types"]; // Check if unchanged if !builder.config.has_changes_from_upstream(files_to_track) { From 867d0016e5199a30630d1ca7e8585c3be883c97e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 17 Jun 2025 13:57:06 -0700 Subject: [PATCH 168/356] rustc_target: document public AbiMap-related fn and variants --- compiler/rustc_target/src/spec/abi_map.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index 4659bbdb8909..42ec10a8e157 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -12,16 +12,19 @@ pub struct AbiMap { os: OsKind, } +/// result from trying to map an ABI #[derive(Copy, Clone, Debug)] pub enum AbiMapping { /// this ABI is exactly mapped for this platform Direct(CanonAbi), /// we don't yet warn on this, but we will Deprecated(CanonAbi), + /// ABI we do not map for this platform: it must not reach codegen Invalid, } impl AbiMapping { + /// optionally get a [CanonAbi], even if Deprecated pub fn into_option(self) -> Option { match self { Self::Direct(abi) | Self::Deprecated(abi) => Some(abi), @@ -29,6 +32,7 @@ impl AbiMapping { } } + /// get a [CanonAbi] even if Deprecated, panicking if Invalid #[track_caller] pub fn unwrap(self) -> CanonAbi { self.into_option().unwrap() @@ -40,6 +44,7 @@ impl AbiMapping { } impl AbiMap { + /// create an AbiMap according to arbitrary fields on the [Target] pub fn from_target(target: &Target) -> Self { // the purpose of this little exercise is to force listing what affects these mappings let arch = match &*target.arch { @@ -59,6 +64,7 @@ impl AbiMap { AbiMap { arch, os } } + /// lower an [ExternAbi] to a [CanonAbi] if this AbiMap allows pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping { let AbiMap { os, arch } = *self; From 42b02019dc9beaffc424719c6afa9c64f1f4e10e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 14:51:42 +1000 Subject: [PATCH 169/356] Fix `tests/ui/asm/naked-invalid-attr.stderr`. `{{root}}` is supposed to be an internal-only name but it shows up in the output. (I'm working towards a more general fix -- a universal "joiner" function that can be used all over the place -- but I'm not there yet, so let's fix this one in-place for now.) --- compiler/rustc_passes/src/check_attr.rs | 7 +++++-- tests/ui/asm/naked-invalid-attr.stderr | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5ce803aa1f8a..c6a581123716 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, kw, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; @@ -715,7 +715,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { && !matches!(other_attr.path().as_slice(), [sym::rustfmt, ..]) { let path = other_attr.path(); - let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); + let path: Vec<_> = path + .iter() + .map(|s| if *s == kw::PathRoot { "" } else { s.as_str() }) + .collect(); let other_attr_name = path.join("::"); self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index ef389e7d921b..6661084861ee 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -37,7 +37,7 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-invalid-attr.rs:56:1 | LL | #[::a] - | ^^^^^^ the `{{root}}::a` attribute is incompatible with `#[unsafe(naked)]` + | ^^^^^^ the `::a` attribute is incompatible with `#[unsafe(naked)]` ... LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here From 4a1f445142e2446d8139f91cf85d4e93083b33ef Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 30 May 2025 00:37:27 +1000 Subject: [PATCH 170/356] Use a symbol for `ExpansionConfig::crate_name`. This avoids some symbol interning and `to_string` conversions. --- .../rustc_builtin_macros/src/proc_macro_harness.rs | 2 +- .../src/standard_library_imports.rs | 2 +- compiler/rustc_builtin_macros/src/test_harness.rs | 2 +- compiler/rustc_expand/src/errors.rs | 4 ++-- compiler/rustc_expand/src/expand.rs | 10 +++++----- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index daf480a9ce47..42b7e0e06d1f 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -56,7 +56,7 @@ pub fn inject( is_test_crate: bool, dcx: DiagCtxtHandle<'_>, ) { - let ecfg = ExpansionConfig::default("proc_macro".to_string(), features); + let ecfg = ExpansionConfig::default(sym::proc_macro, features); let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); let mut collect = CollectProcMacros { diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index a1ee53b7ca21..682e7c9b17ae 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -36,7 +36,7 @@ pub fn inject( let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id()); let call_site = DUMMY_SP.with_call_site_ctxt(expn_id.to_expn_id()); - let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features); + let ecfg = ExpansionConfig::default(sym::std_lib_injection, features); let cx = ExtCtxt::new(sess, ecfg, resolver, None); let ident_span = if edition >= Edition2018 { span } else { call_site }; diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 0bc313cbdacb..77aafd3469a0 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -227,7 +227,7 @@ fn generate_test_harness( panic_strategy: PanicStrategy, test_runner: Option, ) { - let econfig = ExpansionConfig::default("test".to_string(), features); + let econfig = ExpansionConfig::default(sym::test, features); let ext_cx = ExtCtxt::new(sess, econfig, resolver, None); let expn_id = ext_cx.resolver.expansion_for_ast_pass( diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index ec0af67c0463..714ba3bf0f4f 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -183,12 +183,12 @@ pub(crate) struct FeatureNotAllowed { #[derive(Diagnostic)] #[diag(expand_recursion_limit_reached)] #[help] -pub(crate) struct RecursionLimitReached<'a> { +pub(crate) struct RecursionLimitReached { #[primary_span] pub span: Span, pub descr: String, pub suggested_limit: Limit, - pub crate_name: &'a str, + pub crate_name: Symbol, } #[derive(Diagnostic)] diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 9fd524ef45cd..37010700fab8 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -26,7 +26,7 @@ use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; use rustc_session::parse::feature_err; use rustc_session::{Limit, Session}; use rustc_span::hygiene::SyntaxContext; -use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, sym}; +use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym}; use smallvec::SmallVec; use crate::base::*; @@ -473,7 +473,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let dir_path = file_path.parent().unwrap_or(&file_path).to_owned(); self.cx.root_path = dir_path.clone(); self.cx.current_expansion.module = Rc::new(ModuleData { - mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)], + mod_path: vec![Ident::with_dummy_span(self.cx.ecfg.crate_name)], file_path_stack: vec![file_path], dir_path, }); @@ -689,7 +689,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { span: expn_data.call_site, descr: expn_data.kind.descr(), suggested_limit, - crate_name: &self.cx.ecfg.crate_name, + crate_name: self.cx.ecfg.crate_name, }); self.cx.trace_macros_diag(); @@ -2458,7 +2458,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } pub struct ExpansionConfig<'feat> { - pub crate_name: String, + pub crate_name: Symbol, pub features: &'feat Features, pub recursion_limit: Limit, pub trace_mac: bool, @@ -2471,7 +2471,7 @@ pub struct ExpansionConfig<'feat> { } impl ExpansionConfig<'_> { - pub fn default(crate_name: String, features: &Features) -> ExpansionConfig<'_> { + pub fn default(crate_name: Symbol, features: &Features) -> ExpansionConfig<'_> { ExpansionConfig { crate_name, features, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 02d1ebdb31a9..b2d7383b987a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -192,7 +192,7 @@ fn configure_and_expand( // Create the config for macro expansion let recursion_limit = get_recursion_limit(pre_configured_attrs, sess); let cfg = rustc_expand::expand::ExpansionConfig { - crate_name: crate_name.to_string(), + crate_name, features, recursion_limit, trace_mac: sess.opts.unstable_opts.trace_macros, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index baadff16120f..60f3d5fecb0c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2052,6 +2052,7 @@ symbols! { static_recursion, staticlib, std, + std_lib_injection, std_panic, std_panic_2015_macro, std_panic_macro, From 1edf2019370356b81ac60d43899bf7b828771470 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 30 May 2025 02:29:06 +1000 Subject: [PATCH 171/356] Avoid some unnecessary symbol interning. - `Ident::from_str_and_span` -> `Ident::new` when the string is pre-interned. - `Ident::from_str` -> `Ident::with_dummy_span` when the string is pre-interned. - `_d` and `_e` are unused. --- compiler/rustc_builtin_macros/src/alloc_error_handler.rs | 4 ++-- compiler/rustc_builtin_macros/src/autodiff.rs | 6 ++++-- compiler/rustc_hir_pretty/src/lib.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 3 +-- src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index ea406e706660..e75bc944d7ec 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -62,8 +62,8 @@ pub(crate) fn expand( fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt { let usize = cx.path_ident(span, Ident::new(sym::usize, span)); let ty_usize = cx.ty_path(usize); - let size = Ident::from_str_and_span("size", span); - let align = Ident::from_str_and_span("align", span); + let size = Ident::new(sym::size, span); + let align = Ident::new(sym::align, span); let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); let layout_new = cx.expr_path(cx.path(span, layout_new)); diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index dc3bb8ab52a5..df1b1eb60e18 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -652,8 +652,10 @@ mod llvm_enzyme { exprs = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![exprs]); } else { let q = QSelf { ty: d_ret_ty, path_span: span, position: 0 }; - let y = - ExprKind::Path(Some(P(q)), ecx.path_ident(span, Ident::from_str("default"))); + let y = ExprKind::Path( + Some(P(q)), + ecx.path_ident(span, Ident::with_dummy_span(kw::Default)), + ); let default_call_expr = ecx.expr(span, y); let default_call_expr = ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index fc507285860e..233bb5cd5b85 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -22,7 +22,7 @@ use rustc_hir::{ TyPatKind, }; use rustc_span::source_map::SourceMap; -use rustc_span::{FileName, Ident, Span, Symbol, kw}; +use rustc_span::{FileName, Ident, Span, Symbol, kw, sym}; use {rustc_ast as ast, rustc_hir as hir}; pub fn id_to_string(cx: &dyn rustc_hir::intravisit::HirTyCtxt<'_>, hir_id: HirId) -> String { @@ -1517,7 +1517,7 @@ impl<'a> State<'a> { self.bopen(ib); // Print `let _t = $init;`: - let temp = Ident::from_str("_t"); + let temp = Ident::with_dummy_span(sym::_t); self.print_local(false, Some(init), None, |this| this.print_ident(temp)); self.word(";"); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 60f3d5fecb0c..9924322ae9de 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -396,8 +396,7 @@ symbols! { __S, __awaitee, __try_var, - _d, - _e, + _t, _task_context, a32, aarch64_target_feature, diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index ae36bb76117d..8f95e44bf853 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -56,7 +56,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - .and_then(|trait_id| { cx.tcx.associated_items(trait_id).find_by_ident_and_kind( cx.tcx, - Ident::from_str("Output"), + Ident::with_dummy_span(sym::Output), ty::AssocTag::Type, trait_id, ) From b95d39d37ae99bca1e9938738ec2c0e3724eefb1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 27 May 2025 15:06:56 +1000 Subject: [PATCH 172/356] Remove an unnecessary check in rustfmt. "{{root}}" is an internal-only name, and cannot appear in Rust code being formatted. --- src/tools/rustfmt/src/imports.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs index b741dd9b5da5..788fed013ad2 100644 --- a/src/tools/rustfmt/src/imports.rs +++ b/src/tools/rustfmt/src/imports.rs @@ -184,7 +184,7 @@ impl UseSegment { modsep: bool, ) -> Option { let name = rewrite_ident(context, path_seg.ident); - if name.is_empty() || name == "{{root}}" { + if name.is_empty() { return None; } let kind = match name { From 5d16a7b88450624971004ffc2ce6dbde0bb03871 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 19 Jun 2025 21:44:01 -0700 Subject: [PATCH 173/356] Avoid a bitcast FFI call in transmuting For things that only change the valid ranges, we can just skip the `LLVMBuildBitCast` call. I tried to tweak this a bit more and broke stuff, so I also added some extra tests for that as we apparently didn't have coverage. --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 10 ++++- tests/codegen/transmute-scalar.rs | 45 ++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e1d8b7546cf4..db5ac6a514fb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1123,7 +1123,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // While optimizations will remove no-op transmutes, they might still be // there in debug or things that aren't no-op in MIR because they change // the Rust type but not the underlying layout/niche. - if from_scalar == to_scalar && from_backend_ty == to_backend_ty { + if from_scalar == to_scalar { return imm; } @@ -1142,7 +1142,13 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { - (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty), + (Int(..) | Float(_), Int(..) | Float(_)) => { + if from_backend_ty == to_backend_ty { + imm + } else { + bx.bitcast(imm, to_backend_ty) + } + } (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), (Pointer(..), Int(..)) => { diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index c080259a9172..c57ade58c30e 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -55,3 +55,48 @@ pub fn ptr_to_int(p: *mut u16) -> usize { pub fn int_to_ptr(i: usize) -> *mut u16 { unsafe { std::mem::transmute(i) } } + +// This is the one case where signedness matters to transmuting: +// the LLVM type is `i8` here because of `repr(i8)`, +// whereas below with the `repr(u8)` it's `i1` in LLVM instead. +#[repr(i8)] +pub enum FakeBoolSigned { + False = 0, + True = 1, +} + +// CHECK-LABEL: define{{.*}}i8 @bool_to_fake_bool_signed(i1 zeroext %b) +// CHECK: %_0 = zext i1 %b to i8 +// CHECK-NEXT: ret i8 %_0 +#[no_mangle] +pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned { + unsafe { std::mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b) +// CHECK: %_0 = trunc nuw i8 %b to i1 +// CHECK-NEXT: ret i1 %_0 +#[no_mangle] +pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool { + unsafe { std::mem::transmute(b) } +} + +#[repr(u8)] +pub enum FakeBoolUnsigned { + False = 0, + True = 1, +} + +// CHECK-LABEL: define{{.*}}i1 @bool_to_fake_bool_unsigned(i1 zeroext %b) +// CHECK: ret i1 %b +#[no_mangle] +pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned { + unsafe { std::mem::transmute(b) } +} + +// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b) +// CHECK: ret i1 %b +#[no_mangle] +pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool { + unsafe { std::mem::transmute(b) } +} From 75bcc9ca6e6d9096bad314fce2351b394ce8d2d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 19 Jun 2025 11:48:11 +0200 Subject: [PATCH 174/356] remove equivalent new method on context --- compiler/rustc_attr_parsing/src/context.rs | 14 ++++---------- compiler/rustc_resolve/src/def_collector.rs | 4 ++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d7570634c1f7..feee15743632 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -420,19 +420,13 @@ impl<'sess> AttributeParser<'sess, Early> { parsed.pop() } - - pub fn new_early(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { - Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } - } -} - -impl<'sess> AttributeParser<'sess, Late> { - pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { - Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } - } } impl<'sess, S: Stage> AttributeParser<'sess, S> { + pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { + Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } + } + pub(crate) fn sess(&self) -> &'sess Session { &self.sess } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index f8e0a6936a00..16852d1661eb 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -3,7 +3,7 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeParser, OmitDoc}; +use rustc_attr_parsing::{AttributeParser, Early, OmitDoc}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -128,7 +128,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // FIXME(jdonszelmann) make one of these in the resolver? // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can. // Does that prevents errors from happening? maybe - let mut parser = AttributeParser::new_early( + let mut parser = AttributeParser::<'_, Early>::new( &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), From d475e10dcb1bbd3193edb9968dc9e8f60b7247df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 20 Jun 2025 08:17:39 +0200 Subject: [PATCH 175/356] Add temporary directory for executing snapshot tests --- src/bootstrap/src/core/builder/tests.rs | 5 ++- src/bootstrap/src/utils/tests/mod.rs | 56 ++++++++++++++++++------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 1d1c315c1cfd..f1af2b285a28 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1242,12 +1242,13 @@ mod staging { use crate::core::builder::tests::{ TEST_TRIPLE_1, configure, configure_with_args, render_steps, run_build, }; - use crate::utils::tests::ConfigBuilder; + use crate::utils::tests::{ConfigBuilder, TestCtx}; #[test] fn build_compiler_stage_1() { + let ctx = TestCtx::new(); insta::assert_snapshot!( - ConfigBuilder::build() + ctx.config("build") .path("compiler") .stage(1) .get_steps(), @r" diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index ec6293f3c2c1..91877fd0da4d 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -1,25 +1,49 @@ //! This module contains shared utilities for bootstrap tests. +use std::path::{Path, PathBuf}; +use std::thread; + +use tempfile::TempDir; + use crate::core::builder::Builder; use crate::core::config::DryRun; -use crate::{Build, Config, Flags}; +use crate::{Build, Config, Flags, t}; pub mod git; +/// Holds temporary state of a bootstrap test. +/// Right now it is only used to redirect the build directory of the bootstrap +/// invocation, in the future it would be great if we could actually execute +/// the whole test with this directory set as the workdir. +pub struct TestCtx { + directory: TempDir, +} + +impl TestCtx { + pub fn new() -> Self { + let directory = TempDir::new().expect("cannot create temporary directory"); + eprintln!("Running test in {}", directory.path().display()); + Self { directory } + } + + /// Starts a new invocation of bootstrap that executes `kind` as its top level command + /// (i.e. `x `). Returns a builder that configures the created config through CLI flags. + pub fn config(&self, kind: &str) -> ConfigBuilder { + ConfigBuilder::from_args(&[kind], self.directory.path().to_owned()) + } +} + /// Used to configure an invocation of bootstrap. /// Currently runs in the rustc checkout, long-term it should be switched /// to run in a (cache-primed) temporary directory instead. pub struct ConfigBuilder { args: Vec, + directory: PathBuf, } impl ConfigBuilder { - pub fn from_args(args: &[&str]) -> Self { - Self::new(args) - } - - pub fn build() -> Self { - Self::new(&["build"]) + fn from_args(args: &[&str], directory: PathBuf) -> Self { + Self { args: args.iter().copied().map(String::from).collect(), directory } } pub fn path(mut self, path: &str) -> Self { @@ -33,14 +57,18 @@ impl ConfigBuilder { self } - fn new(args: &[&str]) -> Self { - Self { args: args.iter().copied().map(String::from).collect() } - } - pub fn create_config(mut self) -> Config { - let mut config = Config::parse(Flags::parse(&self.args)); // Run in dry-check, otherwise the test would be too slow - config.set_dry_run(DryRun::SelfCheck); - config + self.args.push("--dry-run".to_string()); + + // Ignore submodules + self.args.push("--set".to_string()); + self.args.push("build.submodules=false".to_string()); + + // Do not mess with the local rustc checkout build directory + self.args.push("--build-dir".to_string()); + self.args.push(self.directory.join("build").display().to_string()); + + Config::parse(Flags::parse(&self.args)) } } From e159cf0c9e943c7f9b95f7c931abc825ee33f958 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 Jun 2025 10:35:59 +0000 Subject: [PATCH 176/356] Add regression test --- tests/ui/statics/read_before_init.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/ui/statics/read_before_init.rs diff --git a/tests/ui/statics/read_before_init.rs b/tests/ui/statics/read_before_init.rs new file mode 100644 index 000000000000..02af783063ae --- /dev/null +++ b/tests/ui/statics/read_before_init.rs @@ -0,0 +1,15 @@ +//@ check-pass + +use std::mem::MaybeUninit; + +pub static X: (i32, MaybeUninit) = (1, foo(&X.0)); + +const fn foo(x: &i32) -> MaybeUninit { + let mut temp = MaybeUninit::::uninit(); + unsafe { + std::ptr::copy(x, temp.as_mut_ptr(), 1); + } + temp +} + +fn main() {} From cfc22cfffb7a75229752de6a76e2fc94791b5203 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 Jun 2025 10:52:29 +0000 Subject: [PATCH 177/356] Ensure copy* intrinsics also perform the static self-init checks --- .../rustc_const_eval/src/interpret/memory.rs | 7 ++++++- tests/ui/statics/read_before_init.rs | 9 ++++++++- tests/ui/statics/read_before_init.stderr | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/ui/statics/read_before_init.stderr diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 99a4bc1b7d6e..36d1a413598d 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1412,8 +1412,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation"); - // For the overlapping case, it is crucial that we trigger the read hook + + // Trigger read hooks. + // For the overlapping case, it is crucial that we trigger the read hooks // before the write hook -- the aliasing model cares about the order. + if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes() as i64) { + M::before_alloc_read(self, alloc_id)?; + } M::before_memory_read( tcx, &self.machine, diff --git a/tests/ui/statics/read_before_init.rs b/tests/ui/statics/read_before_init.rs index 02af783063ae..d779ef6dffab 100644 --- a/tests/ui/statics/read_before_init.rs +++ b/tests/ui/statics/read_before_init.rs @@ -1,8 +1,15 @@ -//@ check-pass +//! This test checks the one code path that does not go through +//! the regular CTFE memory access (as an optimization). We forgot +//! to duplicate the static item self-initialization check, allowing +//! reading from the uninitialized static memory before it was +//! initialized at the end of the static initializer. +//! +//! https://github.com/rust-lang/rust/issues/142532 use std::mem::MaybeUninit; pub static X: (i32, MaybeUninit) = (1, foo(&X.0)); +//~^ ERROR: encountered static that tried to initialize itself with itself const fn foo(x: &i32) -> MaybeUninit { let mut temp = MaybeUninit::::uninit(); diff --git a/tests/ui/statics/read_before_init.stderr b/tests/ui/statics/read_before_init.stderr new file mode 100644 index 000000000000..aeebcf7d9ce5 --- /dev/null +++ b/tests/ui/statics/read_before_init.stderr @@ -0,0 +1,17 @@ +error[E0080]: encountered static that tried to initialize itself with itself + --> $DIR/read_before_init.rs:11:45 + | +LL | pub static X: (i32, MaybeUninit) = (1, foo(&X.0)); + | ^^^^^^^^^ evaluation of `X` failed inside this call + | +note: inside `foo` + --> $DIR/read_before_init.rs:17:9 + | +LL | std::ptr::copy(x, temp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `std::ptr::copy::` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From 88f1ed4871887db8b4d96688480bf96666d82005 Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Fri, 20 Jun 2025 03:37:07 -0400 Subject: [PATCH 178/356] Convert `ilog(10)` to `ilog10()` --- library/alloc/src/string.rs | 4 ++-- library/core/src/fmt/num.rs | 8 ++++---- src/librustdoc/html/sources.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 5197e40764b3..c200a92e1bd0 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2841,7 +2841,7 @@ macro_rules! impl_to_string { impl SpecToString for $signed { #[inline] fn spec_to_string(&self) -> String { - const SIZE: usize = $signed::MAX.ilog(10) as usize + 1; + const SIZE: usize = $signed::MAX.ilog10() as usize + 1; let mut buf = [core::mem::MaybeUninit::::uninit(); SIZE]; // Only difference between signed and unsigned are these 8 lines. let mut out; @@ -2861,7 +2861,7 @@ macro_rules! impl_to_string { impl SpecToString for $unsigned { #[inline] fn spec_to_string(&self) -> String { - const SIZE: usize = $unsigned::MAX.ilog(10) as usize + 1; + const SIZE: usize = $unsigned::MAX.ilog10() as usize + 1; let mut buf = [core::mem::MaybeUninit::::uninit(); SIZE]; self._fmt(&mut buf).to_string() diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 13cd7f710943..42af595ae417 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -208,7 +208,7 @@ macro_rules! impl_Display { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[cfg(not(feature = "optimize_for_size"))] { - const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1; + const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1; // Buffer decimals for $unsigned with right alignment. let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; @@ -226,7 +226,7 @@ macro_rules! impl_Display { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[cfg(not(feature = "optimize_for_size"))] { - const MAX_DEC_N: usize = $unsigned::MAX.ilog(10) as usize + 1; + const MAX_DEC_N: usize = $unsigned::MAX.ilog10() as usize + 1; // Buffer decimals for $unsigned with right alignment. let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; @@ -323,7 +323,7 @@ macro_rules! impl_Display { #[cfg(feature = "optimize_for_size")] fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1; + const MAX_DEC_N: usize = $u::MAX.ilog10() as usize + 1; let mut buf = [MaybeUninit::::uninit(); MAX_DEC_N]; let mut curr = MAX_DEC_N; let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); @@ -565,7 +565,7 @@ mod imp { } impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128); -const U128_MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; +const U128_MAX_DEC_N: usize = u128::MAX.ilog10() as usize + 1; #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for u128 { diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 1fa6b5a60f3a..c34b31542697 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -353,7 +353,7 @@ pub(crate) fn print_src( ); Ok(()) }); - let max_nb_digits = if lines > 0 { lines.ilog(10) + 1 } else { 1 }; + let max_nb_digits = if lines > 0 { lines.ilog10() + 1 } else { 1 }; match source_context { SourceContext::Standalone { file_path } => Source { code_html: code, From af3f9d1f555c16bfa8971e475f006f5aeb80a2d8 Mon Sep 17 00:00:00 2001 From: Lucas Holten Date: Fri, 20 Jun 2025 13:20:59 +0200 Subject: [PATCH 179/356] Add better documentation for excluding imports from symbol search --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 6 +++++- .../rust-analyzer/docs/book/src/configuration_generated.md | 6 +++++- src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 76a4a26af645..05e1b832cd16 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -762,7 +762,11 @@ config_data! { /// though Cargo might be the eventual consumer. vfs_extraIncludes: Vec = vec![], - /// Exclude imports from symbol search. + /// Exclude all imports from workspace symbol search. + /// + /// In addition to regular imports (which are always excluded), + /// this option removes public imports (better known as re-exports) + /// and removes imports that rename the imported symbol. workspace_symbol_search_excludeImports: bool = false, /// Workspace symbol search kind. workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes, diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 54a624d25abe..9404b1454a08 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -1542,7 +1542,11 @@ https://github.com/facebook/buck2/tree/main/integrations/rust-project. Default: `false` -Exclude imports from symbol search. +Exclude all imports from workspace symbol search. + +In addition to regular imports (which are always excluded), +this option removes public imports (better known as re-exports) +and removes imports that rename the imported symbol. ## rust-analyzer.workspace.symbol.search.kind {#workspace.symbol.search.kind} diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index fb41225ca0dc..26a21c1468d8 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2905,7 +2905,7 @@ "title": "workspace", "properties": { "rust-analyzer.workspace.symbol.search.excludeImports": { - "markdownDescription": "Exclude imports from symbol search.", + "markdownDescription": "Exclude all imports from workspace symbol search.\n\nIn addition to regular imports (which are always excluded),\nthis option removes public imports (better known as re-exports)\nand removes imports that rename the imported symbol.", "default": false, "type": "boolean" } From 0be168e93eafa7c8d2baf7e9163e2126859100eb Mon Sep 17 00:00:00 2001 From: Valdemar Erk Date: Fri, 20 Jun 2025 11:59:05 +0200 Subject: [PATCH 180/356] Add note about `str::split` handling of no matches. --- library/core/src/str/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 41834793d22a..5c8d84f5c12d 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1495,6 +1495,9 @@ impl str { /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. /// + /// If there are no matches the full string slice is returned as the only + /// item in the iterator. + /// /// [`char`]: prim@char /// [pattern]: self::pattern /// @@ -1526,6 +1529,9 @@ impl str { /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect(); /// assert_eq!(v, ["lion", "tiger", "leopard"]); /// + /// let v: Vec<&str> = "AABBCC".split("DD").collect(); + /// assert_eq!(v, ["AABBCC"]); + /// /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect(); /// assert_eq!(v, ["abc", "def", "ghi"]); /// From a0badba6eeb4b24dd9748f5e99cec285b473c43b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 24 Apr 2025 14:47:27 +0000 Subject: [PATCH 181/356] Pass -Cpanic=abort for the panic_abort crate The panic_abort crate must be compiled with panic=abort, but cargo doesn't allow setting the panic strategy for a single crate the usual way using panic="abort", but luckily per-package rustflags do allow this. Bootstrap previously handled this in its rustc wrapper, but for example the build systems of cg_clif and cg_gcc don't use the rustc wrapper, so they would either need to add one, patch the standard library or be unable to build a sysroot suitable for both panic=abort and panic=unwind (as is currently the case). --- library/Cargo.toml | 10 ++++++++++ src/bootstrap/src/bin/rustc.rs | 12 ------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/library/Cargo.toml b/library/Cargo.toml index 35480b9319d7..c66f621ffde0 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["profile-rustflags"] + [workspace] resolver = "1" members = [ @@ -44,6 +46,14 @@ object.debug = 0 rustc-demangle.debug = 0 rustc-demangle.opt-level = "s" +# panic_abort must always be compiled with panic=abort, even when the rest of the +# sysroot is panic=unwind. +[profile.dev.package.panic_abort] +rustflags = ["-Cpanic=abort"] + +[profile.release.package.panic_abort] +rustflags = ["-Cpanic=abort"] + [patch.crates-io] # See comments in `library/rustc-std-workspace-core/README.md` for what's going on # here diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 0671a8467e81..0364c664ba51 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -151,18 +151,6 @@ fn main() { cmd.arg("--sysroot").arg(&sysroot); } - // If we're compiling specifically the `panic_abort` crate then we pass - // the `-C panic=abort` option. Note that we do not do this for any - // other crate intentionally as this is the only crate for now that we - // ship with panic=abort. - // - // This... is a bit of a hack how we detect this. Ideally this - // information should be encoded in the crate I guess? Would likely - // require an RFC amendment to RFC 1513, however. - if crate_name == Some("panic_abort") { - cmd.arg("-C").arg("panic=abort"); - } - let crate_type = parse_value_from_args(&orig_args, "--crate-type"); // `-Ztls-model=initial-exec` must not be applied to proc-macros, see // issue https://github.com/rust-lang/rust/issues/100530 From 21805038412de0224f7cefe3b4c98cc7fda17c39 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 18 Jun 2025 17:27:01 +0200 Subject: [PATCH 182/356] Add CI check to ensure that rustdoc JSON `FORMAT_VERSION` is correctly updated --- src/tools/tidy/src/lib.rs | 1 + src/tools/tidy/src/main.rs | 1 + src/tools/tidy/src/rustdoc_json.rs | 66 ++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 src/tools/tidy/src/rustdoc_json.rs diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index e8a12d563358..28aa80225b17 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -83,6 +83,7 @@ pub mod pal; pub mod rustdoc_css_themes; pub mod rustdoc_gui_tests; pub mod rustdoc_js; +pub mod rustdoc_json; pub mod rustdoc_templates; pub mod style; pub mod target_policy; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 776f1bde2eb7..420260a97a04 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -110,6 +110,7 @@ fn main() { check!(rustdoc_css_themes, &librustdoc_path); check!(rustdoc_templates, &librustdoc_path); check!(rustdoc_js, &librustdoc_path, &tools_path, &src_path); + check!(rustdoc_json); check!(known_bug, &crashes_path); check!(unknown_revision, &tests_path); diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs new file mode 100644 index 000000000000..a98c4f4cc3e6 --- /dev/null +++ b/src/tools/tidy/src/rustdoc_json.rs @@ -0,0 +1,66 @@ +//! Tidy check to ensure that `FORMAT_VERSION` was correctly updated if `rustdoc-json-types` was +//! updated as well. + +use std::process::Command; + +fn git_diff(base_commit: &str, extra_arg: &str) -> Option { + let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?; + Some(String::from_utf8_lossy(&output.stdout).into()) +} + +pub fn check(bad: &mut bool) { + let Ok(base_commit) = std::env::var("BASE_COMMIT") else { + // Not in CI so nothing we can check here. + println!("not checking rustdoc JSON `FORMAT_VERSION` update"); + return; + }; + + // First we check that `src/rustdoc-json-types` was modified. + match git_diff(&base_commit, "--name-status") { + Some(output) => { + if !output + .lines() + .any(|line| line.starts_with("M") && line.contains("src/rustdoc-json-types")) + { + // `rustdoc-json-types` was not modified so nothing more to check here. + return; + } + } + None => { + *bad = true; + eprintln!("Failed to run `git diff`"); + return; + } + } + // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated. + match git_diff(&base_commit, "src/rustdoc-json-types") { + Some(output) => { + let mut format_version_updated = false; + let mut latest_feature_comment_updated = false; + for line in output.lines() { + if line.starts_with("+pub const FORMAT_VERSION: u32 =") { + format_version_updated = true; + } else if line.starts_with("+// Latest feature:") { + latest_feature_comment_updated = true; + } + } + if format_version_updated != latest_feature_comment_updated { + *bad = true; + if latest_feature_comment_updated { + eprintln!( + "`Latest feature` comment was updated whereas `FORMAT_VERSION` wasn't" + ); + } else { + eprintln!( + "`Latest feature` comment was not updated whereas `FORMAT_VERSION` was" + ); + } + } + } + None => { + *bad = true; + eprintln!("Failed to run `git diff`"); + return; + } + } +} From de0fd27f347c783b45fc9764baa944455369cd33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 12 Jun 2025 13:52:23 +0200 Subject: [PATCH 183/356] cold --- .../src/attributes.rs | 3 +++ .../src/attributes/codegen_attrs.rs | 18 ++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 13 +++++++++- .../src/session_diagnostics.rs | 5 ++++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 19 +++++++++++---- compiler/rustc_passes/src/check_attr.rs | 16 ++++++------- ...issue-43106-gating-of-builtin-attrs.stderr | 16 ++++++------- .../lint/unused/unused-attr-duplicate.stderr | 24 +++++++++---------- 8 files changed, 81 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 65061059a02e..9ebf4c1793dd 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -202,6 +202,9 @@ pub enum AttributeKind { span: Span, }, + /// Represents `#[cold]`. + Cold(Span), + /// Represents `#[rustc_confusables]`. Confusables { symbols: ThinVec, diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index ddcf82cbf7cd..1509531ca987 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -38,3 +38,21 @@ impl SingleAttributeParser for OptimizeParser { Some(AttributeKind::Optimize(res, cx.attr_span)) } } + +pub(crate) struct ColdParser; + +impl SingleAttributeParser for ColdParser { + const PATH: &[rustc_span::Symbol] = &[sym::cold]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if !args.no_args() { + cx.expected_no_args(cx.attr_span); + return None; + }; + + Some(AttributeKind::Cold(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1708fd72e588..e8bcf57e1090 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,7 +15,7 @@ use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; -use crate::attributes::codegen_attrs::OptimizeParser; +use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -106,6 +106,7 @@ attribute_parsers!( // tidy-alphabetical-start Single, + Single, Single, Single, Single, @@ -234,6 +235,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + pub(crate) fn expected_no_args(&self, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedNoArgs, + }) + } + /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for /// a nicer error message talking about the specific name that was found lacking a value. pub(crate) fn expected_name_value(&self, span: Span, name: Option) -> ErrorGuaranteed { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 337921a318c3..29f2e44a98a0 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -474,6 +474,7 @@ pub(crate) struct UnrecognizedReprHint { } pub(crate) enum AttributeParseErrorReason { + ExpectedNoArgs, ExpectedStringLiteral { byte_string: Option }, ExpectedSingleArgument, ExpectedList, @@ -529,6 +530,10 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.span_label(self.span, format!("didn't expect a literal here")); diag.code(E0565); } + AttributeParseErrorReason::ExpectedNoArgs => { + diag.span_label(self.span, format!("didn't expect any arguments here")); + diag.code(E0565); + } AttributeParseErrorReason::ExpectedNameValue(None) => { diag.span_label( self.span, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e855f1d35589..39818be5bde5 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -4,7 +4,7 @@ use rustc_abi::ExternAbi; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; use rustc_attr_data_structures::{ - AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr, + AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, ReprAttr, find_attr, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; @@ -110,8 +110,20 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } }; - if let hir::Attribute::Parsed(AttributeKind::Align { align, .. }) = attr { - codegen_fn_attrs.alignment = Some(*align); + if let hir::Attribute::Parsed(p) = attr { + match p { + AttributeKind::Repr(reprs) => { + codegen_fn_attrs.alignment = reprs + .iter() + .filter_map( + |(r, _)| if let ReprAttr::ReprAlign(x) = r { Some(*x) } else { None }, + ) + .max(); + } + AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, + AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), + _ => {} + } } let Some(Ident { name, .. }) = attr.ident() else { @@ -119,7 +131,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { }; match name { - sym::cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR, sym::ffi_pure => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE, sym::ffi_const => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a5d2ad4dc205..f25c9f353c27 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -149,10 +149,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ } + Attribute::Parsed(AttributeKind::Cold(attr_span)) => { + self.check_cold(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => { self.check_align(span, target, *align, *repr_span) } - Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -245,7 +247,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target), [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), - [sym::cold, ..] => self.check_cold(hir_id, attr, span, target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), @@ -651,8 +652,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::repr, sym::align, sym::rustc_std_internal_symbol, - // code generation - sym::cold, // documentation sym::doc, ]; @@ -688,7 +687,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed( AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. } - | AttributeKind::Align { .. }, + | AttributeKind::Align { .. } + | AttributeKind::Cold(..), ) => { continue; } @@ -1637,7 +1637,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[cold]` is applied to a non-function. - fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_cold(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { match target { Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1645,7 +1645,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "cold"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "cold"); } _ => { // FIXME: #[cold] was previously allowed on non-functions and some crates used @@ -1653,7 +1653,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID }, ); } diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 1c6868dc95d9..9280dfdf92e5 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -379,14 +379,6 @@ warning: `#[proc_macro_derive]` only has an effect on functions LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 - | -LL | #![cold] - | ^^^^^^^^ cannot be applied to crates - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | @@ -417,6 +409,14 @@ warning: `#[must_use]` has no effect when applied to a module LL | #![must_use] | ^^^^^^^^^^^^ +warning: attribute should be applied to a function definition + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 + | +LL | #![cold] + | ^^^^^^^^ cannot be applied to crates + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[macro_use]` only has an effect on `extern crate` and modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5 | diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index e1c45e832af3..03ce97570144 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -102,18 +102,6 @@ note: attribute also specified here LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:77:1 - | -LL | #[cold] - | ^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:76:1 - | -LL | #[cold] - | ^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:79:1 | @@ -289,5 +277,17 @@ LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:77:1 + | +LL | #[cold] + | ^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:76:1 + | +LL | #[cold] + | ^^^^^^^ + error: aborting due to 23 previous errors From b9107a83a1ace3f292641977df70e9610e0e4482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 12 Jun 2025 14:24:40 +0200 Subject: [PATCH 184/356] expected word diagnostic test --- .../src/attributes/codegen_attrs.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 4 ++-- compiler/rustc_parse/src/validate_attr.rs | 1 + src/rustdoc-json-types/lib.rs | 4 ++-- tests/ui/attributes/expected-word.rs | 3 +++ tests/ui/attributes/expected-word.stderr | 12 ++++++++++++ 6 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 tests/ui/attributes/expected-word.rs create mode 100644 tests/ui/attributes/expected-word.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 1509531ca987..1b03525a5ce8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -49,7 +49,7 @@ impl SingleAttributeParser for ColdParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { if !args.no_args() { - cx.expected_no_args(cx.attr_span); + cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); return None; }; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index e8bcf57e1090..648bd4318989 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -235,9 +235,9 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } - pub(crate) fn expected_no_args(&self, span: Span) -> ErrorGuaranteed { + pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed { self.emit_err(AttributeParseError { - span, + span: args_span, attr_span: self.attr_span, template: self.template.clone(), attribute: self.attr_path.clone(), diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 646e996ff303..ed1737bee330 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -292,6 +292,7 @@ fn emit_malformed_attribute( | sym::align | sym::deprecated | sym::optimize + | sym::cold ) { return; } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index d5de43feb588..4d25124f9f2b 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Pretty printing of optimize attributes changed -pub const FORMAT_VERSION: u32 = 49; +// Latest feature: Pretty printing of cold attributes changed +pub const FORMAT_VERSION: u32 = 50; /// The root of the emitted JSON blob. /// diff --git a/tests/ui/attributes/expected-word.rs b/tests/ui/attributes/expected-word.rs new file mode 100644 index 000000000000..246aa78db828 --- /dev/null +++ b/tests/ui/attributes/expected-word.rs @@ -0,0 +1,3 @@ +#[cold = true] +//~^ ERROR malformed `cold` attribute input [E0565] +fn main() {} diff --git a/tests/ui/attributes/expected-word.stderr b/tests/ui/attributes/expected-word.stderr new file mode 100644 index 000000000000..dcb10e7aee89 --- /dev/null +++ b/tests/ui/attributes/expected-word.stderr @@ -0,0 +1,12 @@ +error[E0565]: malformed `cold` attribute input + --> $DIR/expected-word.rs:1:1 + | +LL | #[cold = true] + | ^^^^^^^------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[cold]` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0565`. From bbe8a2ad19c0486986a535c103e57fabfbb81441 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Jun 2025 16:50:01 +0200 Subject: [PATCH 185/356] Generate base commit in rustdoc_json tidy checks --- src/build_helper/src/git.rs | 2 +- src/tools/tidy/src/rustdoc_json.rs | 31 ++++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 438cd14389c1..9d1195aadf84 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -198,7 +198,7 @@ fn get_latest_upstream_commit_that_modified_files( /// author. /// /// If we are in CI, we simply return our first parent. -fn get_closest_upstream_commit( +pub fn get_closest_upstream_commit( git_dir: Option<&Path>, config: &GitConfig<'_>, env: CiEnv, diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs index a98c4f4cc3e6..3f78d565deb2 100644 --- a/src/tools/tidy/src/rustdoc_json.rs +++ b/src/tools/tidy/src/rustdoc_json.rs @@ -3,16 +3,39 @@ use std::process::Command; +use build_helper::ci::CiEnv; +use build_helper::git::{GitConfig, get_closest_upstream_commit}; +use build_helper::stage0_parser::parse_stage0_file; + fn git_diff(base_commit: &str, extra_arg: &str) -> Option { let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?; Some(String::from_utf8_lossy(&output.stdout).into()) } pub fn check(bad: &mut bool) { - let Ok(base_commit) = std::env::var("BASE_COMMIT") else { - // Not in CI so nothing we can check here. - println!("not checking rustdoc JSON `FORMAT_VERSION` update"); - return; + println!("Checking tidy rustdoc_json..."); + let stage0 = parse_stage0_file(); + let base_commit = match get_closest_upstream_commit( + None, + &GitConfig { + nightly_branch: &stage0.config.nightly_branch, + git_merge_commit_email: &stage0.config.git_merge_commit_email, + }, + CiEnv::current(), + ) { + Ok(Some(commit)) => commit, + Ok(None) => { + *bad = true; + eprintln!("No base commit found, skipping rustdoc_json check"); + return; + } + Err(error) => { + *bad = true; + eprintln!( + "Failed to retrieve base commit for rustdoc_json check because of `{error}`, skipping it" + ); + return; + } }; // First we check that `src/rustdoc-json-types` was modified. From 636769490445a477746a1242e40fa11b633388a5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 20 Jun 2025 15:02:15 +0200 Subject: [PATCH 186/356] Pass `src_path` to rustdoc_json tidy check --- src/tools/tidy/src/main.rs | 2 +- src/tools/tidy/src/rustdoc_json.rs | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 420260a97a04..0b66017b8652 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -110,7 +110,7 @@ fn main() { check!(rustdoc_css_themes, &librustdoc_path); check!(rustdoc_templates, &librustdoc_path); check!(rustdoc_js, &librustdoc_path, &tools_path, &src_path); - check!(rustdoc_json); + check!(rustdoc_json, &src_path); check!(known_bug, &crashes_path); check!(unknown_revision, &tests_path); diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs index 3f78d565deb2..808341fbd061 100644 --- a/src/tools/tidy/src/rustdoc_json.rs +++ b/src/tools/tidy/src/rustdoc_json.rs @@ -1,18 +1,20 @@ //! Tidy check to ensure that `FORMAT_VERSION` was correctly updated if `rustdoc-json-types` was //! updated as well. +use std::ffi::OsStr; +use std::path::Path; use std::process::Command; use build_helper::ci::CiEnv; use build_helper::git::{GitConfig, get_closest_upstream_commit}; use build_helper::stage0_parser::parse_stage0_file; -fn git_diff(base_commit: &str, extra_arg: &str) -> Option { +fn git_diff>(base_commit: &str, extra_arg: S) -> Option { let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?; Some(String::from_utf8_lossy(&output.stdout).into()) } -pub fn check(bad: &mut bool) { +pub fn check(src_path: &Path, bad: &mut bool) { println!("Checking tidy rustdoc_json..."); let stage0 = parse_stage0_file(); let base_commit = match get_closest_upstream_commit( @@ -26,13 +28,13 @@ pub fn check(bad: &mut bool) { Ok(Some(commit)) => commit, Ok(None) => { *bad = true; - eprintln!("No base commit found, skipping rustdoc_json check"); + eprintln!("error: no base commit found for rustdoc_json check"); return; } Err(error) => { *bad = true; eprintln!( - "Failed to retrieve base commit for rustdoc_json check because of `{error}`, skipping it" + "error: failed to retrieve base commit for rustdoc_json check because of `{error}`" ); return; } @@ -46,17 +48,18 @@ pub fn check(bad: &mut bool) { .any(|line| line.starts_with("M") && line.contains("src/rustdoc-json-types")) { // `rustdoc-json-types` was not modified so nothing more to check here. + println!("`rustdoc-json-types` was not modified."); return; } } None => { *bad = true; - eprintln!("Failed to run `git diff`"); + eprintln!("error: failed to run `git diff` in rustdoc_json check"); return; } } // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated. - match git_diff(&base_commit, "src/rustdoc-json-types") { + match git_diff(&base_commit, src_path.join("rustdoc-json-types")) { Some(output) => { let mut format_version_updated = false; let mut latest_feature_comment_updated = false; @@ -71,19 +74,18 @@ pub fn check(bad: &mut bool) { *bad = true; if latest_feature_comment_updated { eprintln!( - "`Latest feature` comment was updated whereas `FORMAT_VERSION` wasn't" + "error: `Latest feature` comment was updated whereas `FORMAT_VERSION` wasn't" ); } else { eprintln!( - "`Latest feature` comment was not updated whereas `FORMAT_VERSION` was" + "error: `Latest feature` comment was not updated whereas `FORMAT_VERSION` was" ); } } } None => { *bad = true; - eprintln!("Failed to run `git diff`"); - return; + eprintln!("error: failed to run `git diff` in rustdoc_json check"); } } } From 367c8feb482d87ba184a6a2ffaf5a2ab6a5fd1cf Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 20 Jun 2025 09:09:53 -0500 Subject: [PATCH 187/356] fix(linkcheck): Build using the lockfile This is to unblock cargo from servo/html5ever#623 --- src/tools/linkchecker/linkcheck.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh index 6c1e668a7f0d..d230610a6e79 100755 --- a/src/tools/linkchecker/linkcheck.sh +++ b/src/tools/linkchecker/linkcheck.sh @@ -98,6 +98,7 @@ then nightly_hash=$(rustc +nightly -Vv | grep commit-hash | cut -f2 -d" ") url="https://raw.githubusercontent.com/rust-lang/rust" mkdir linkchecker + curl -o linkchecker/Cargo.lock ${url}/${nightly_hash}/Cargo.lock curl -o linkchecker/Cargo.toml ${url}/${nightly_hash}/src/tools/linkchecker/Cargo.toml curl -o linkchecker/main.rs ${url}/${nightly_hash}/src/tools/linkchecker/main.rs fi From 0fc950735ac35784b2ba49679f164f3ae2dfc8f7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 20 Jun 2025 16:12:41 +0200 Subject: [PATCH 188/356] Improve error message for rustdoc_json_types tidy check Only emit git errors if we are in CI environment --- src/build_helper/src/ci.rs | 6 +++++- src/tools/tidy/src/rustdoc_json.rs | 30 ++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/build_helper/src/ci.rs b/src/build_helper/src/ci.rs index 60f319129a0b..9d114c70a671 100644 --- a/src/build_helper/src/ci.rs +++ b/src/build_helper/src/ci.rs @@ -17,7 +17,11 @@ impl CiEnv { } pub fn is_ci() -> bool { - Self::current() != CiEnv::None + Self::current().is_running_in_ci() + } + + pub fn is_running_in_ci(self) -> bool { + self != CiEnv::None } /// Checks if running in rust-lang/rust managed CI job. diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs index 808341fbd061..f179acf4a510 100644 --- a/src/tools/tidy/src/rustdoc_json.rs +++ b/src/tools/tidy/src/rustdoc_json.rs @@ -9,33 +9,41 @@ use build_helper::ci::CiEnv; use build_helper::git::{GitConfig, get_closest_upstream_commit}; use build_helper::stage0_parser::parse_stage0_file; +const RUSTDOC_JSON_TYPES: &str = "src/rustdoc-json-types"; + fn git_diff>(base_commit: &str, extra_arg: S) -> Option { let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?; Some(String::from_utf8_lossy(&output.stdout).into()) } +fn error_if_in_ci(ci_env: CiEnv, msg: &str, bad: &mut bool) { + if ci_env.is_running_in_ci() { + *bad = true; + eprintln!("error in `rustdoc_json` tidy check: {msg}"); + } else { + eprintln!("{msg}. Skipping `rustdoc_json` tidy check"); + } +} + pub fn check(src_path: &Path, bad: &mut bool) { println!("Checking tidy rustdoc_json..."); let stage0 = parse_stage0_file(); + let ci_env = CiEnv::current(); let base_commit = match get_closest_upstream_commit( None, &GitConfig { nightly_branch: &stage0.config.nightly_branch, git_merge_commit_email: &stage0.config.git_merge_commit_email, }, - CiEnv::current(), + ci_env, ) { Ok(Some(commit)) => commit, Ok(None) => { - *bad = true; - eprintln!("error: no base commit found for rustdoc_json check"); + error_if_in_ci(ci_env, "no base commit found", bad); return; } Err(error) => { - *bad = true; - eprintln!( - "error: failed to retrieve base commit for rustdoc_json check because of `{error}`" - ); + error_if_in_ci(ci_env, &format!("failed to retrieve base commit: {error}"), bad); return; } }; @@ -45,7 +53,7 @@ pub fn check(src_path: &Path, bad: &mut bool) { Some(output) => { if !output .lines() - .any(|line| line.starts_with("M") && line.contains("src/rustdoc-json-types")) + .any(|line| line.starts_with("M") && line.contains(RUSTDOC_JSON_TYPES)) { // `rustdoc-json-types` was not modified so nothing more to check here. println!("`rustdoc-json-types` was not modified."); @@ -74,11 +82,13 @@ pub fn check(src_path: &Path, bad: &mut bool) { *bad = true; if latest_feature_comment_updated { eprintln!( - "error: `Latest feature` comment was updated whereas `FORMAT_VERSION` wasn't" + "error in `rustdoc_json` tidy check: `Latest feature` comment was updated \ + whereas `FORMAT_VERSION` wasn't in `{RUSTDOC_JSON_TYPES}/lib.rs`" ); } else { eprintln!( - "error: `Latest feature` comment was not updated whereas `FORMAT_VERSION` was" + "error in `rustdoc_json` tidy check: `Latest feature` comment was not \ + updated whereas `FORMAT_VERSION` was in `{RUSTDOC_JSON_TYPES}/lib.rs`" ); } } From 6a9f223f0030729560fd60fbd112e3e6e81ae2a9 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Fri, 20 Jun 2025 12:25:09 +0200 Subject: [PATCH 189/356] Add diagnostic items for Clippy --- compiler/rustc_span/src/symbol.rs | 7 +++++++ library/core/src/char/methods.rs | 1 + library/core/src/iter/range.rs | 1 + library/core/src/macros/mod.rs | 1 + library/core/src/mem/mod.rs | 1 + library/core/src/slice/raw.rs | 1 + library/std/src/io/error.rs | 2 ++ 7 files changed, 14 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 812a254990ca..6425cae02a47 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -642,6 +642,7 @@ symbols! { cfi_encoding, char, char_is_ascii, + char_to_digit, child_id, child_kill, client, @@ -1217,6 +1218,8 @@ symbols! { intrinsics, intrinsics_unaligned_volatile_load, intrinsics_unaligned_volatile_store, + io_error_new, + io_errorkind, io_stderr, io_stdout, irrefutable_let_patterns, @@ -1306,6 +1309,7 @@ symbols! { m68k_target_feature, macro_at_most_once_rep, macro_attributes_in_derive_output, + macro_concat, macro_escape, macro_export, macro_lifetime_matcher, @@ -1340,6 +1344,7 @@ symbols! { maybe_uninit, maybe_uninit_uninit, maybe_uninit_zeroed, + mem_align_of, mem_discriminant, mem_drop, mem_forget, @@ -1707,6 +1712,7 @@ symbols! { question_mark, quote, range_inclusive_new, + range_step, raw_dylib, raw_dylib_elf, raw_eq, @@ -2023,6 +2029,7 @@ symbols! { slice, slice_from_raw_parts, slice_from_raw_parts_mut, + slice_from_ref, slice_get_unchecked, slice_into_vec, slice_iter, diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index af2edf141b22..b0752a85faf1 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -395,6 +395,7 @@ impl char { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")] + #[rustc_diagnostic_item = "char_to_digit"] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 4fa719de5ebf..9e43d5688cec 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -20,6 +20,7 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6 /// /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. +#[rustc_diagnostic_item = "range_step"] #[unstable(feature = "step_trait", issue = "42168")] pub trait Step: Clone + PartialOrd + Sized { /// Returns the bounds on the number of *successor* steps required to get from `start` to `end` diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index b21845a1c169..d7b2ec815551 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1192,6 +1192,7 @@ pub(crate) mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] + #[rustc_diagnostic_item = "macro_concat"] #[macro_export] macro_rules! concat { ($($e:expr),* $(,)?) => {{ /* compiler built-in */ }}; diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 73d9a8ee26d5..b93f854b9dc4 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -481,6 +481,7 @@ pub fn min_align_of_val(val: &T) -> usize { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_align_of", since = "1.24.0")] +#[rustc_diagnostic_item = "mem_align_of"] pub const fn align_of() -> usize { intrinsics::align_of::() } diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index eba2f89a169a..80b2176933da 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -198,6 +198,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m /// Converts a reference to T into a slice of length 1 (without copying). #[stable(feature = "from_ref", since = "1.28.0")] #[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")] +#[rustc_diagnostic_item = "slice_from_ref"] #[must_use] pub const fn from_ref(s: &T) -> &[T] { array::from_ref(s) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index ba765a6203f2..d43976ecc9e5 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -219,6 +219,7 @@ struct Custom { /// the recognized error kinds and fail in those cases. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "io_errorkind")] #[allow(deprecated)] #[non_exhaustive] pub enum ErrorKind { @@ -562,6 +563,7 @@ impl Error { /// let eof_error = Error::from(ErrorKind::UnexpectedEof); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")] #[inline(never)] pub fn new(kind: ErrorKind, error: E) -> Error where From 07338a40de90d64155ca25bb58fc24cf9d6b0caa Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Fri, 20 Jun 2025 17:51:23 +0200 Subject: [PATCH 190/356] clippy: replace path uses by diagnostic items --- .../clippy/clippy_lints/src/casts/manual_dangling_ptr.rs | 5 ++--- .../clippy/clippy_lints/src/manual_option_as_slice.rs | 4 ++-- .../clippy/clippy_lints/src/methods/io_other_error.rs | 9 ++++++--- .../clippy/clippy_lints/src/single_range_in_vec_init.rs | 4 ++-- src/tools/clippy/clippy_lints/src/to_digit_is_some.rs | 4 ++-- src/tools/clippy/clippy_lints/src/useless_concat.rs | 5 ++--- src/tools/clippy/clippy_utils/src/paths.rs | 9 --------- 7 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs index 61dfc0fc0425..d9e88d6a401c 100644 --- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{expr_or_init, path_def_id, paths, std_or_core}; +use clippy_utils::{expr_or_init, is_path_diagnostic_item, std_or_core, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind}; @@ -53,8 +53,7 @@ fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) -> fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool { if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind - && let Some(fun_id) = path_def_id(cx, fun) - && paths::ALIGN_OF.matches(cx, fun_id) + && is_path_diagnostic_item(cx, fun, sym::mem_align_of) && let Some(args) = path.segments.last().and_then(|seg| seg.args) && let [GenericArg::Type(generic_ty)] = args.args { diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs index b55c11f2d5b6..922db174e3d4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs +++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::msrvs::Msrv; -use clippy_utils::{is_none_arm, msrvs, paths, peel_hir_expr_refs, sym}; +use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal}; @@ -220,5 +220,5 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - paths::SLICE_FROM_REF.matches_path(cx, expr) + clippy_utils::is_path_diagnostic_item(cx, expr, sym::slice_from_ref) } diff --git a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs index ec4b9c7ae2ee..9276261606e1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs +++ b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::{expr_or_init, paths}; +use clippy_utils::{expr_or_init, is_path_diagnostic_item, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; @@ -10,8 +10,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, path: &Expr<'_>, args && !expr.span.from_expansion() && !error_kind.span.from_expansion() && let ExprKind::Path(QPath::TypeRelative(_, new_segment)) = path.kind - && paths::IO_ERROR_NEW.matches_path(cx, path) - && paths::IO_ERRORKIND_OTHER_CTOR.matches_path(cx, expr_or_init(cx, error_kind)) + && is_path_diagnostic_item(cx, path, sym::io_error_new) + && let ExprKind::Path(QPath::Resolved(_, init_path)) = &expr_or_init(cx, error_kind).kind + && let [.., error_kind_ty, error_kind_variant] = init_path.segments + && cx.tcx.is_diagnostic_item(sym::io_errorkind, error_kind_ty.res.def_id()) + && error_kind_variant.ident.name == sym::Other && msrv.meets(cx, msrvs::IO_ERROR_OTHER) { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs index 54d09ff9ee40..dda2f8cc1d00 100644 --- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs @@ -3,7 +3,7 @@ use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_no_std_crate, paths}; +use clippy_utils::{is_no_std_crate, sym}; use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr}; @@ -100,7 +100,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { && let Some(start_snippet) = start.span.get_source_text(cx) && let Some(end_snippet) = end.span.get_source_text(cx) { - let should_emit_every_value = if let Some(step_def_id) = paths::ITER_STEP.only(cx) + let should_emit_every_value = if let Some(step_def_id) = cx.tcx.get_diagnostic_item(sym::range_step) && implements_trait(cx, ty, step_def_id, &[]) { true diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index 7d7d74f27b3c..3e847543e1c1 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_in_const_context, paths, sym}; +use clippy_utils::{is_in_const_context, is_path_diagnostic_item, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { } }, hir::ExprKind::Call(to_digits_call, [char_arg, radix_arg]) => { - if paths::CHAR_TO_DIGIT.matches_path(cx, to_digits_call) { + if is_path_diagnostic_item(cx, to_digits_call, sym::char_to_digit) { Some((false, char_arg, radix_arg)) } else { None diff --git a/src/tools/clippy/clippy_lints/src/useless_concat.rs b/src/tools/clippy/clippy_lints/src/useless_concat.rs index 1ed1fbb3b9c6..96845adb04a2 100644 --- a/src/tools/clippy/clippy_lints/src/useless_concat.rs +++ b/src/tools/clippy/clippy_lints/src/useless_concat.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; -use clippy_utils::paths::CONCAT; use clippy_utils::source::snippet_opt; -use clippy_utils::tokenize_with_text; +use clippy_utils::{sym, tokenize_with_text}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; @@ -43,7 +42,7 @@ impl LateLintPass<'_> for UselessConcat { // Get the direct parent of the expression. && let Some(macro_call) = macro_backtrace(expr.span).next() // Check if the `concat` macro from the `core` library. - && CONCAT.matches(cx, macro_call.def_id) + && cx.tcx.is_diagnostic_item(sym::macro_concat, macro_call.def_id) // We get the original code to parse it. && let Some(original_code) = snippet_opt(cx, macro_call.span) // This check allows us to ensure that the code snippet: diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index f37a609497eb..8bbcb220210a 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -126,15 +126,6 @@ path_macros! { macro_path: PathNS::Macro, } -// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. -pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of); -pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit); -pub static CONCAT: PathLookup = macro_path!(core::concat); -pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new); -pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other); -pub static ITER_STEP: PathLookup = type_path!(core::iter::Step); -pub static SLICE_FROM_REF: PathLookup = value_path!(core::slice::from_ref); - // Paths in external crates pub static FUTURES_IO_ASYNCREADEXT: PathLookup = type_path!(futures_util::AsyncReadExt); pub static FUTURES_IO_ASYNCWRITEEXT: PathLookup = type_path!(futures_util::AsyncWriteExt); From 8d18f3d609e9e31da8a3c2bb1613499d5ba0fe9a Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 20 Jun 2025 11:09:45 -0500 Subject: [PATCH 191/356] add doc(alias("AsciiChar")) to core::ascii::Char Added it to the reexported, which is intended rustdoc behavior, but is apparently untested, so I also added a test for it. --- library/core/src/ascii.rs | 1 + tests/rustdoc-js-std/doc-alias-use.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/rustdoc-js-std/doc-alias-use.js diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index d3c6c046e717..f5e628030431 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -15,6 +15,7 @@ use crate::iter::FusedIterator; use crate::num::NonZero; mod ascii_char; +#[doc(alias("AsciiChar"))] #[unstable(feature = "ascii_char", issue = "110998")] pub use ascii_char::AsciiChar as Char; diff --git a/tests/rustdoc-js-std/doc-alias-use.js b/tests/rustdoc-js-std/doc-alias-use.js new file mode 100644 index 000000000000..e08d94533a93 --- /dev/null +++ b/tests/rustdoc-js-std/doc-alias-use.js @@ -0,0 +1,12 @@ +// AsciiChar has a doc alias on its reexport and we +// want to make sure that actually works correctly, +// since apperently there are no other tests for this. + +const EXPECTED = [ + { + 'query': 'AsciiChar', + 'others': [ + { 'path': 'core::ascii', 'name': 'Char' }, + ], + }, +]; From 01fbeb806570a94e1520b6b74e6db70e88574627 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 17 Jun 2025 15:19:51 -0500 Subject: [PATCH 192/356] update configure.py to handle new bootstrap.example.toml --- bootstrap.example.toml | 2 +- src/bootstrap/configure.py | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 38c3195deb9d..fade30c0c33e 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -385,7 +385,7 @@ # # The default value for the `features` array is `[]`. However, please note that other flags in # `bootstrap.toml` might influence the features enabled for some tools. -#tool.TOOL_NAME.features = [FEATURE1, FEATURE2] +#build.tool.TOOL_NAME.features = [FEATURE1, FEATURE2] # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation #build.verbose = 0 diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 0d4d6e0ff54c..ce9290620cb5 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -6,6 +6,7 @@ from __future__ import absolute_import, division, print_function import shlex import sys import os +import re rust_dir = os.path.dirname(os.path.abspath(__file__)) rust_dir = os.path.dirname(rust_dir) @@ -585,16 +586,31 @@ def parse_example_config(known_args, config): section_order = [None] targets = {} top_level_keys = [] + comment_lines = [] with open(rust_dir + "/bootstrap.example.toml") as example_config: example_lines = example_config.read().split("\n") for line in example_lines: - if cur_section is None: - if line.count("=") == 1: - top_level_key = line.split("=")[0] - top_level_key = top_level_key.strip(" #") - top_level_keys.append(top_level_key) - if line.startswith("["): + if line.count("=") == 1 and not line.startswith("# "): + key = line.split("=")[0] + key = key.strip(" #") + parts = key.split(".") + if len(parts) > 1: + cur_section = parts[0] + if cur_section not in sections: + sections[cur_section] = ["[" + cur_section + "]"] + section_order.append(cur_section) + elif cur_section is None: + top_level_keys.append(key) + # put the comment lines within the start of + # a new section, not outside it. + sections[cur_section] += comment_lines + comment_lines = [] + # remove just the `section.` part from the line, if present. + sections[cur_section].append( + re.sub("(#?)([a-zA-Z_-]+\\.)?(.*)", "\\1\\3", line) + ) + elif line.startswith("["): cur_section = line[1:-1] if cur_section.startswith("target"): cur_section = "target" @@ -605,8 +621,9 @@ def parse_example_config(known_args, config): sections[cur_section] = [line] section_order.append(cur_section) else: - sections[cur_section].append(line) + comment_lines.append(line) + sections[cur_section] += comment_lines # Fill out the `targets` array by giving all configured targets a copy of the # `target` section we just loaded from the example config configured_targets = [build(known_args)] From bedc0eaa9d63f4fae716e7f737b50dde2ff2b59d Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 20 Jun 2025 11:35:53 -0500 Subject: [PATCH 193/356] bootstrap.example.toml: add note explaining toml --- bootstrap.example.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index fade30c0c33e..cc1ea796a028 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -8,6 +8,14 @@ # `bootstrap.toml` in the current directory of a build for build configuration, but # a custom configuration file can also be specified with `--config` to the build # system. +# +# Note that the following are equivelent, for more details see . +# +# build.verbose = 1 +# +# [build] +# verbose = 1 + # ============================================================================= # Global Settings From 09d0a739f7dc4d84ae7baeac03a7e0d94671f3cb Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 20 Jun 2025 18:59:34 +0200 Subject: [PATCH 194/356] Switch `non_upper_case_globals` suggestions to being machine-applicable --- compiler/rustc_lint/src/lints.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index a20050a10b48..0ef7b3c14acd 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1359,7 +1359,7 @@ pub(crate) enum NonUpperCaseGlobalSub { #[primary_span] span: Span, }, - #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] + #[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")] Suggestion { #[primary_span] span: Span, @@ -1371,7 +1371,7 @@ pub(crate) enum NonUpperCaseGlobalSub { #[suggestion( lint_suggestion, code = "{replace}", - applicability = "maybe-incorrect", + applicability = "machine-applicable", style = "tool-only" )] pub(crate) struct NonUpperCaseGlobalSubTool { From 8c9cafbf5d15fae6bd59e9b83bd76a1471161b6b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 20 Jun 2025 10:08:52 -0700 Subject: [PATCH 195/356] Bump the version number to 1.90.0 --- src/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version b/src/version index 636ea711ad96..82e24bf241e5 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.89.0 +1.90.0 From a32d0856804e75953144ac5173f06894e55ed846 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 16 Jun 2025 21:26:29 +0200 Subject: [PATCH 196/356] error on calls to ABIs that cannot be called --- compiler/rustc_hir_typeck/messages.ftl | 6 +- compiler/rustc_hir_typeck/src/callee.rs | 54 ++++++-- compiler/rustc_hir_typeck/src/errors.rs | 7 +- compiler/rustc_hir_typeck/src/expr.rs | 10 +- tests/codegen/naked-asan.rs | 22 ++-- tests/ui/abi/bad-custom.rs | 14 +- tests/ui/abi/bad-custom.stderr | 56 +++++++- tests/ui/abi/cannot-be-called.avr.stderr | 132 +++++++++++++++++++ tests/ui/abi/cannot-be-called.i686.stderr | 132 +++++++++++++++++++ tests/ui/abi/cannot-be-called.msp430.stderr | 132 +++++++++++++++++++ tests/ui/abi/cannot-be-called.riscv32.stderr | 130 ++++++++++++++++++ tests/ui/abi/cannot-be-called.riscv64.stderr | 130 ++++++++++++++++++ tests/ui/abi/cannot-be-called.rs | 93 +++++++++++++ tests/ui/abi/cannot-be-called.x64.stderr | 132 +++++++++++++++++++ tests/ui/abi/cannot-be-called.x64_win.stderr | 132 +++++++++++++++++++ tests/ui/abi/unsupported.aarch64.stderr | 56 ++++---- tests/ui/abi/unsupported.arm.stderr | 56 ++++---- tests/ui/abi/unsupported.i686.stderr | 28 ++-- tests/ui/abi/unsupported.riscv32.stderr | 68 ++++++---- tests/ui/abi/unsupported.riscv64.stderr | 68 ++++++---- tests/ui/abi/unsupported.rs | 2 + tests/ui/abi/unsupported.x64.stderr | 54 +++++--- tests/ui/abi/unsupported.x64_win.stderr | 54 +++++--- 23 files changed, 1359 insertions(+), 209 deletions(-) create mode 100644 tests/ui/abi/cannot-be-called.avr.stderr create mode 100644 tests/ui/abi/cannot-be-called.i686.stderr create mode 100644 tests/ui/abi/cannot-be-called.msp430.stderr create mode 100644 tests/ui/abi/cannot-be-called.riscv32.stderr create mode 100644 tests/ui/abi/cannot-be-called.riscv64.stderr create mode 100644 tests/ui/abi/cannot-be-called.rs create mode 100644 tests/ui/abi/cannot-be-called.x64.stderr create mode 100644 tests/ui/abi/cannot-be-called.x64_win.stderr diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index ac7ff65528d9..258535f3742d 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -1,6 +1,6 @@ -hir_typeck_abi_custom_call = - functions with the `"custom"` ABI cannot be called - .note = an `extern "custom"` function can only be called from within inline assembly +hir_typeck_abi_cannot_be_called = + functions with the {$abi} ABI cannot be called + .note = an `extern {$abi}` function can only be called using inline assembly hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 80bff09d0a43..7a3647df0c40 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -1,6 +1,6 @@ use std::iter; -use rustc_abi::ExternAbi; +use rustc_abi::{CanonAbi, ExternAbi}; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; use rustc_hir::def::{self, CtorKind, Namespace, Res}; @@ -16,6 +16,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; +use rustc_target::spec::{AbiMap, AbiMapping}; use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -84,7 +85,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef); } - self.check_call_custom_abi(autoderef.final_ty(false), call_expr.span); + + match autoderef.final_ty(false).kind() { + ty::FnDef(def_id, _) => { + let abi = self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi; + self.check_call_abi(abi, call_expr.span); + } + ty::FnPtr(_, header) => { + self.check_call_abi(header.abi, call_expr.span); + } + _ => { /* cannot have a non-rust abi */ } + } + self.register_predicates(autoderef.into_obligations()); let output = match result { @@ -137,19 +149,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { output } - /// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`. + /// Can a function with this ABI be called with a rust call expression? /// - /// These functions have a calling convention that is unknown to rust, hence it cannot generate - /// code for the call. The only way to execute such a function is via inline assembly. - fn check_call_custom_abi(&self, callee_ty: Ty<'tcx>, span: Span) { - let abi = match callee_ty.kind() { - ty::FnDef(def_id, _) => self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi, - ty::FnPtr(_, header) => header.abi, - _ => return, + /// Some ABIs cannot be called from rust, either because rust does not know how to generate + /// code for the call, or because a call does not semantically make sense. + pub(crate) fn check_call_abi(&self, abi: ExternAbi, span: Span) { + let canon_abi = match AbiMap::from_target(&self.sess().target).canonize_abi(abi, false) { + AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => canon_abi, + AbiMapping::Invalid => return, }; - if let ExternAbi::Custom = abi { - self.tcx.dcx().emit_err(errors::AbiCustomCall { span }); + let valid = match canon_abi { + // Rust doesn't know how to call functions with this ABI. + CanonAbi::Custom => false, + + // These is an entry point for the host, and cannot be called on the GPU. + CanonAbi::GpuKernel => false, + + // The interrupt ABIs should only be called by the CPU. They have complex + // pre- and postconditions, and can use non-standard instructions like `iret` on x86. + CanonAbi::Interrupt(_) => false, + + CanonAbi::C + | CanonAbi::Rust + | CanonAbi::RustCold + | CanonAbi::Arm(_) + | CanonAbi::X86(_) => true, + }; + + if !valid { + let err = crate::errors::AbiCannotBeCalled { span, abi }; + self.tcx.dcx().emit_err(err); } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index abb8cdc1cdf3..681135fdede5 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; +use rustc_abi::ExternAbi; use rustc_ast::Label; use rustc_errors::codes::*; use rustc_errors::{ @@ -1165,8 +1166,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm { } #[derive(Diagnostic)] -#[diag(hir_typeck_abi_custom_call)] -pub(crate) struct AbiCustomCall { +#[diag(hir_typeck_abi_cannot_be_called)] +pub(crate) struct AbiCannotBeCalled { #[primary_span] + #[note] pub span: Span, + pub abi: ExternAbi, } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 55c39d960e7c..7d2f4743bd76 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -5,7 +5,7 @@ //! //! See [`rustc_hir_analysis::check`] for more context on type checking in general. -use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx}; +use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -1651,13 +1651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(method.def_id), ); - // Functions of type `extern "custom" fn(/* ... */)` cannot be called using - // `ExprKind::MethodCall`. These functions have a calling convention that is - // unknown to rust, hence it cannot generate code for the call. The only way - // to execute such a function is via inline assembly. - if let ExternAbi::Custom = method.sig.abi { - self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span }); - } + self.check_call_abi(method.sig.abi, expr.span); method.sig.output() } diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs index 223c41b15bb3..46218cf79d6d 100644 --- a/tests/codegen/naked-asan.rs +++ b/tests/codegen/naked-asan.rs @@ -1,22 +1,28 @@ +//@ add-core-stubs +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu -Zsanitizer=address -Ctarget-feature=-crt-static + // Make sure we do not request sanitizers for naked functions. -//@ only-x86_64 -//@ needs-sanitizer-address -//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static - #![crate_type = "lib"] +#![feature(no_core)] #![no_std] +#![no_core] #![feature(abi_x86_interrupt)] +extern crate minicore; +use minicore::*; + +#[no_mangle] pub fn caller() { - page_fault_handler(1, 2); + unsafe { asm!("call {}", sym page_fault_handler) } } -// CHECK: declare x86_intrcc void @page_fault_handler(ptr {{.*}}, i64{{.*}}){{.*}}#[[ATTRS:[0-9]+]] +// CHECK: declare x86_intrcc void @page_fault_handler(){{.*}}#[[ATTRS:[0-9]+]] #[unsafe(naked)] #[no_mangle] -pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { - core::arch::naked_asm!("ud2") +pub extern "x86-interrupt" fn page_fault_handler() { + naked_asm!("ud2") } // CHECK: #[[ATTRS]] = diff --git a/tests/ui/abi/bad-custom.rs b/tests/ui/abi/bad-custom.rs index e792f0955b91..a3b15f244b72 100644 --- a/tests/ui/abi/bad-custom.rs +++ b/tests/ui/abi/bad-custom.rs @@ -73,19 +73,19 @@ unsafe extern "custom" { fn caller(f: unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 { unsafe { f(x) } - //~^ ERROR functions with the `"custom"` ABI cannot be called + //~^ ERROR functions with the "custom" ABI cannot be called } fn caller_by_ref(f: &unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 { unsafe { f(x) } - //~^ ERROR functions with the `"custom"` ABI cannot be called + //~^ ERROR functions with the "custom" ABI cannot be called } type Custom = unsafe extern "custom" fn(i64) -> i64; fn caller_alias(f: Custom, mut x: i64) -> i64 { unsafe { f(x) } - //~^ ERROR functions with the `"custom"` ABI cannot be called + //~^ ERROR functions with the "custom" ABI cannot be called } #[unsafe(naked)] @@ -107,15 +107,15 @@ fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() { pub fn main() { unsafe { assert_eq!(double(21), 42); - //~^ ERROR functions with the `"custom"` ABI cannot be called + //~^ ERROR functions with the "custom" ABI cannot be called assert_eq!(unsafe { increment(41) }, 42); - //~^ ERROR functions with the `"custom"` ABI cannot be called + //~^ ERROR functions with the "custom" ABI cannot be called assert!(Thing(41).is_even()); - //~^ ERROR functions with the `"custom"` ABI cannot be called + //~^ ERROR functions with the "custom" ABI cannot be called assert_eq!(Thing::bitwise_not(42), !42); - //~^ ERROR functions with the `"custom"` ABI cannot be called + //~^ ERROR functions with the "custom" ABI cannot be called } } diff --git a/tests/ui/abi/bad-custom.stderr b/tests/ui/abi/bad-custom.stderr index ec0f11af8980..77cad1b872b2 100644 --- a/tests/ui/abi/bad-custom.stderr +++ b/tests/ui/abi/bad-custom.stderr @@ -245,43 +245,85 @@ LL + #[unsafe(naked)] LL | extern "custom" fn negate(a: i64) -> i64 { | -error: functions with the `"custom"` ABI cannot be called +error: functions with the "custom" ABI cannot be called + --> $DIR/bad-custom.rs:75:14 + | +LL | unsafe { f(x) } + | ^^^^ + | +note: an `extern "custom"` function can only be called using inline assembly --> $DIR/bad-custom.rs:75:14 | LL | unsafe { f(x) } | ^^^^ -error: functions with the `"custom"` ABI cannot be called +error: functions with the "custom" ABI cannot be called + --> $DIR/bad-custom.rs:80:14 + | +LL | unsafe { f(x) } + | ^^^^ + | +note: an `extern "custom"` function can only be called using inline assembly --> $DIR/bad-custom.rs:80:14 | LL | unsafe { f(x) } | ^^^^ -error: functions with the `"custom"` ABI cannot be called +error: functions with the "custom" ABI cannot be called + --> $DIR/bad-custom.rs:87:14 + | +LL | unsafe { f(x) } + | ^^^^ + | +note: an `extern "custom"` function can only be called using inline assembly --> $DIR/bad-custom.rs:87:14 | LL | unsafe { f(x) } | ^^^^ -error: functions with the `"custom"` ABI cannot be called +error: functions with the "custom" ABI cannot be called + --> $DIR/bad-custom.rs:109:20 + | +LL | assert_eq!(double(21), 42); + | ^^^^^^^^^^ + | +note: an `extern "custom"` function can only be called using inline assembly --> $DIR/bad-custom.rs:109:20 | LL | assert_eq!(double(21), 42); | ^^^^^^^^^^ -error: functions with the `"custom"` ABI cannot be called +error: functions with the "custom" ABI cannot be called + --> $DIR/bad-custom.rs:112:29 + | +LL | assert_eq!(unsafe { increment(41) }, 42); + | ^^^^^^^^^^^^^ + | +note: an `extern "custom"` function can only be called using inline assembly --> $DIR/bad-custom.rs:112:29 | LL | assert_eq!(unsafe { increment(41) }, 42); | ^^^^^^^^^^^^^ -error: functions with the `"custom"` ABI cannot be called +error: functions with the "custom" ABI cannot be called + --> $DIR/bad-custom.rs:115:17 + | +LL | assert!(Thing(41).is_even()); + | ^^^^^^^^^^^^^^^^^^^ + | +note: an `extern "custom"` function can only be called using inline assembly --> $DIR/bad-custom.rs:115:17 | LL | assert!(Thing(41).is_even()); | ^^^^^^^^^^^^^^^^^^^ -error: functions with the `"custom"` ABI cannot be called +error: functions with the "custom" ABI cannot be called + --> $DIR/bad-custom.rs:118:20 + | +LL | assert_eq!(Thing::bitwise_not(42), !42); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: an `extern "custom"` function can only be called using inline assembly --> $DIR/bad-custom.rs:118:20 | LL | assert_eq!(Thing::bitwise_not(42), !42); diff --git a/tests/ui/abi/cannot-be-called.avr.stderr b/tests/ui/abi/cannot-be-called.avr.stderr new file mode 100644 index 000000000000..64ce3efe52b2 --- /dev/null +++ b/tests/ui/abi/cannot-be-called.avr.stderr @@ -0,0 +1,132 @@ +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "x86-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:88:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:36:1 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:1 + | +LL | extern "riscv-interrupt-m" fn riscv_m() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:1 + | +LL | extern "riscv-interrupt-s" fn riscv_s() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:1 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions with the "avr-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:50:5 + | +LL | avr(); + | ^^^^^ + | +note: an `extern "avr-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:50:5 + | +LL | avr(); + | ^^^^^ + +error: functions with the "avr-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:70:5 + | +LL | f() + | ^^^ + | +note: an `extern "avr-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:70:5 + | +LL | f() + | ^^^ + +error: aborting due to 6 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0570`. +Future incompatibility report: Future breakage diagnostic: +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "x86-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:88:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + diff --git a/tests/ui/abi/cannot-be-called.i686.stderr b/tests/ui/abi/cannot-be-called.i686.stderr new file mode 100644 index 000000000000..113b40eb67b8 --- /dev/null +++ b/tests/ui/abi/cannot-be-called.i686.stderr @@ -0,0 +1,132 @@ +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:36:1 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:1 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:1 + | +LL | extern "riscv-interrupt-m" fn riscv_m() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:1 + | +LL | extern "riscv-interrupt-s" fn riscv_s() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:56:5 + | +LL | x86(); + | ^^^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:56:5 + | +LL | x86(); + | ^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + +error: aborting due to 6 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0570`. +Future incompatibility report: Future breakage diagnostic: +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + diff --git a/tests/ui/abi/cannot-be-called.msp430.stderr b/tests/ui/abi/cannot-be-called.msp430.stderr new file mode 100644 index 000000000000..d7630d96f8ce --- /dev/null +++ b/tests/ui/abi/cannot-be-called.msp430.stderr @@ -0,0 +1,132 @@ +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "x86-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:88:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:1 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:1 + | +LL | extern "riscv-interrupt-m" fn riscv_m() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:1 + | +LL | extern "riscv-interrupt-s" fn riscv_s() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:1 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions with the "msp430-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:48:5 + | +LL | msp430(); + | ^^^^^^^^ + | +note: an `extern "msp430-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:48:5 + | +LL | msp430(); + | ^^^^^^^^ + +error: functions with the "msp430-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:63:5 + | +LL | f() + | ^^^ + | +note: an `extern "msp430-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:63:5 + | +LL | f() + | ^^^ + +error: aborting due to 6 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0570`. +Future incompatibility report: Future breakage diagnostic: +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "x86-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:88:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + diff --git a/tests/ui/abi/cannot-be-called.riscv32.stderr b/tests/ui/abi/cannot-be-called.riscv32.stderr new file mode 100644 index 000000000000..9fadbd639b8b --- /dev/null +++ b/tests/ui/abi/cannot-be-called.riscv32.stderr @@ -0,0 +1,130 @@ +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "x86-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:88:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:36:1 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:1 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:1 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/cannot-be-called.rs:52:5 + | +LL | riscv_m(); + | ^^^^^^^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:52:5 + | +LL | riscv_m(); + | ^^^^^^^^^ + +error: functions with the "riscv-interrupt-s" ABI cannot be called + --> $DIR/cannot-be-called.rs:54:5 + | +LL | riscv_s(); + | ^^^^^^^^^ + | +note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:54:5 + | +LL | riscv_s(); + | ^^^^^^^^^ + +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/cannot-be-called.rs:77:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:77:5 + | +LL | f() + | ^^^ + +error: functions with the "riscv-interrupt-s" ABI cannot be called + --> $DIR/cannot-be-called.rs:84:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:84:5 + | +LL | f() + | ^^^ + +error: aborting due to 7 previous errors; 3 warnings emitted + +For more information about this error, try `rustc --explain E0570`. +Future incompatibility report: Future breakage diagnostic: +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "x86-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:88:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + diff --git a/tests/ui/abi/cannot-be-called.riscv64.stderr b/tests/ui/abi/cannot-be-called.riscv64.stderr new file mode 100644 index 000000000000..9fadbd639b8b --- /dev/null +++ b/tests/ui/abi/cannot-be-called.riscv64.stderr @@ -0,0 +1,130 @@ +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "x86-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:88:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:36:1 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:1 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:1 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/cannot-be-called.rs:52:5 + | +LL | riscv_m(); + | ^^^^^^^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:52:5 + | +LL | riscv_m(); + | ^^^^^^^^^ + +error: functions with the "riscv-interrupt-s" ABI cannot be called + --> $DIR/cannot-be-called.rs:54:5 + | +LL | riscv_s(); + | ^^^^^^^^^ + | +note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:54:5 + | +LL | riscv_s(); + | ^^^^^^^^^ + +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/cannot-be-called.rs:77:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:77:5 + | +LL | f() + | ^^^ + +error: functions with the "riscv-interrupt-s" ABI cannot be called + --> $DIR/cannot-be-called.rs:84:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:84:5 + | +LL | f() + | ^^^ + +error: aborting due to 7 previous errors; 3 warnings emitted + +For more information about this error, try `rustc --explain E0570`. +Future incompatibility report: Future breakage diagnostic: +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "x86-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:88:15 + | +LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + diff --git a/tests/ui/abi/cannot-be-called.rs b/tests/ui/abi/cannot-be-called.rs new file mode 100644 index 000000000000..89173655a4ac --- /dev/null +++ b/tests/ui/abi/cannot-be-called.rs @@ -0,0 +1,93 @@ +//@ add-core-stubs +//@ revisions: x64 x64_win i686 riscv32 riscv64 avr msp430 +// +//@ [x64] needs-llvm-components: x86 +//@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib +//@ [x64_win] needs-llvm-components: x86 +//@ [x64_win] compile-flags: --target=x86_64-pc-windows-msvc --crate-type=rlib +//@ [i686] needs-llvm-components: x86 +//@ [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib +//@ [riscv32] needs-llvm-components: riscv +//@ [riscv32] compile-flags: --target=riscv32i-unknown-none-elf --crate-type=rlib +//@ [riscv64] needs-llvm-components: riscv +//@ [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf --crate-type=rlib +//@ [avr] needs-llvm-components: avr +//@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib +//@ [msp430] needs-llvm-components: msp430 +//@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib +#![no_core] +#![feature( + no_core, + lang_items, + abi_ptx, + abi_msp430_interrupt, + abi_avr_interrupt, + abi_gpu_kernel, + abi_x86_interrupt, + abi_riscv_interrupt, + abi_c_cmse_nonsecure_call, + abi_vectorcall, + cmse_nonsecure_entry +)] + +extern crate minicore; +use minicore::*; + +extern "msp430-interrupt" fn msp430() {} +//[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI +extern "avr-interrupt" fn avr() {} +//[x64,x64_win,i686,riscv32,riscv64,msp430]~^ ERROR is not a supported ABI +extern "riscv-interrupt-m" fn riscv_m() {} +//[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI +extern "riscv-interrupt-s" fn riscv_s() {} +//[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI +extern "x86-interrupt" fn x86() {} +//[riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI + +fn call_the_interrupts() { + msp430(); + //[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called + avr(); + //[avr]~^ ERROR functions with the "avr-interrupt" ABI cannot be called + riscv_m(); + //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called + riscv_s(); + //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-s" ABI cannot be called + x86(); + //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called +} + +fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + //[x64,x64_win,i686,riscv32,riscv64,avr]~^ WARN unsupported_fn_ptr_calling_conventions + //[x64,x64_win,i686,riscv32,riscv64,avr]~^^ WARN this was previously accepted + f() + //[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called +} + +fn avr_ptr(f: extern "avr-interrupt" fn()) { + //[x64,x64_win,i686,riscv32,riscv64,msp430]~^ WARN unsupported_fn_ptr_calling_conventions + //[x64,x64_win,i686,riscv32,riscv64,msp430]~^^ WARN this was previously accepted + f() + //[avr]~^ ERROR functions with the "avr-interrupt" ABI cannot be called +} + +fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + //[x64,x64_win,i686,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions + //[x64,x64_win,i686,avr,msp430]~^^ WARN this was previously accepted + f() + //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called +} + +fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + //[x64,x64_win,i686,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions + //[x64,x64_win,i686,avr,msp430]~^^ WARN this was previously accepted + f() + //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-s" ABI cannot be called +} + +fn x86_ptr(f: extern "x86-interrupt" fn()) { + //[riscv32,riscv64,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions + //[riscv32,riscv64,avr,msp430]~^^ WARN this was previously accepted + f() + //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called +} diff --git a/tests/ui/abi/cannot-be-called.x64.stderr b/tests/ui/abi/cannot-be-called.x64.stderr new file mode 100644 index 000000000000..113b40eb67b8 --- /dev/null +++ b/tests/ui/abi/cannot-be-called.x64.stderr @@ -0,0 +1,132 @@ +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:36:1 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:1 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:1 + | +LL | extern "riscv-interrupt-m" fn riscv_m() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:1 + | +LL | extern "riscv-interrupt-s" fn riscv_s() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:56:5 + | +LL | x86(); + | ^^^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:56:5 + | +LL | x86(); + | ^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + +error: aborting due to 6 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0570`. +Future incompatibility report: Future breakage diagnostic: +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + diff --git a/tests/ui/abi/cannot-be-called.x64_win.stderr b/tests/ui/abi/cannot-be-called.x64_win.stderr new file mode 100644 index 000000000000..113b40eb67b8 --- /dev/null +++ b/tests/ui/abi/cannot-be-called.x64_win.stderr @@ -0,0 +1,132 @@ +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + +error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:36:1 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:1 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:1 + | +LL | extern "riscv-interrupt-m" fn riscv_m() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:1 + | +LL | extern "riscv-interrupt-s" fn riscv_s() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:56:5 + | +LL | x86(); + | ^^^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:56:5 + | +LL | x86(); + | ^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + +error: aborting due to 6 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0570`. +Future incompatibility report: Future breakage diagnostic: +warning: the calling convention "msp430-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:60:18 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "avr-interrupt" is not supported on this target + --> $DIR/cannot-be-called.rs:67:15 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-m" is not supported on this target + --> $DIR/cannot-be-called.rs:74:19 + | +LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + +Future breakage diagnostic: +warning: the calling convention "riscv-interrupt-s" is not supported on this target + --> $DIR/cannot-be-called.rs:81:19 + | +LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #130260 + = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 4721c26026d1..7b9b9d5c978c 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -69,13 +69,13 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { = note: for more information, see issue #130260 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:85:1 + --> $DIR/unsupported.rs:86:1 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:90:15 + --> $DIR/unsupported.rs:91:15 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,13 +84,13 @@ LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { = note: for more information, see issue #130260 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:95:1 + --> $DIR/unsupported.rs:97:1 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -99,13 +99,13 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +114,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:119:1 + --> $DIR/unsupported.rs:121:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:123:1 + --> $DIR/unsupported.rs:125:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,7 +130,7 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 + --> $DIR/unsupported.rs:133:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -141,7 +141,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 + --> $DIR/unsupported.rs:138:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 + --> $DIR/unsupported.rs:141:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -161,7 +161,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:145:22 + --> $DIR/unsupported.rs:147:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,13 +170,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:150:1 + --> $DIR/unsupported.rs:152:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -194,7 +194,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:166:1 + --> $DIR/unsupported.rs:168:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,19 +236,19 @@ LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:88:1 + --> $DIR/unsupported.rs:89:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:98:1 + --> $DIR/unsupported.rs:100:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -256,7 +256,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -266,13 +266,13 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:143:1 + --> $DIR/unsupported.rs:145:1 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:159:1 + --> $DIR/unsupported.rs:161:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { Future breakage diagnostic: warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:90:15 + --> $DIR/unsupported.rs:91:15 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -348,7 +348,7 @@ LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { Future breakage diagnostic: warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -359,7 +359,7 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { Future breakage diagnostic: warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -370,7 +370,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:145:22 + --> $DIR/unsupported.rs:147:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -381,7 +381,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -392,7 +392,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index ed9cd2ab2c5d..5b057bdcbaeb 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -54,13 +54,13 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { = note: for more information, see issue #130260 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:85:1 + --> $DIR/unsupported.rs:86:1 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:90:15 + --> $DIR/unsupported.rs:91:15 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,13 +69,13 @@ LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { = note: for more information, see issue #130260 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:95:1 + --> $DIR/unsupported.rs:97:1 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -84,13 +84,13 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:119:1 + --> $DIR/unsupported.rs:121:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:123:1 + --> $DIR/unsupported.rs:125:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 + --> $DIR/unsupported.rs:133:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 + --> $DIR/unsupported.rs:138:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 + --> $DIR/unsupported.rs:141:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,7 +146,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:145:22 + --> $DIR/unsupported.rs:147:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -155,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:150:1 + --> $DIR/unsupported.rs:152:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:166:1 + --> $DIR/unsupported.rs:168:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -215,19 +215,19 @@ LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:88:1 + --> $DIR/unsupported.rs:89:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:98:1 + --> $DIR/unsupported.rs:100:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -235,7 +235,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,13 +245,13 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:143:1 + --> $DIR/unsupported.rs:145:1 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:159:1 + --> $DIR/unsupported.rs:161:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -305,7 +305,7 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { Future breakage diagnostic: warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:90:15 + --> $DIR/unsupported.rs:91:15 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -316,7 +316,7 @@ LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { Future breakage diagnostic: warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -327,7 +327,7 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { Future breakage diagnostic: warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -338,7 +338,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:145:22 + --> $DIR/unsupported.rs:147:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -360,7 +360,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 4d903b435d87..568841660199 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -69,13 +69,13 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { = note: for more information, see issue #130260 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:85:1 + --> $DIR/unsupported.rs:86:1 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:166:1 + --> $DIR/unsupported.rs:168:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -134,13 +134,25 @@ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current targe LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/unsupported.rs:94:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/unsupported.rs:94:5 + | +LL | f() + | ^^^ + error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:159:1 + --> $DIR/unsupported.rs:161:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors; 7 warnings emitted +error: aborting due to 14 previous errors; 7 warnings emitted For more information about this error, try `rustc --explain E0570`. Future incompatibility report: Future breakage diagnostic: @@ -200,7 +212,7 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -211,7 +223,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index 9e75dfafca0f..124ba13cc236 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -60,7 +60,7 @@ LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:90:15 + --> $DIR/unsupported.rs:91:15 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,13 +69,13 @@ LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { = note: for more information, see issue #130260 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:95:1 + --> $DIR/unsupported.rs:97:1 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -84,13 +84,13 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:119:1 + --> $DIR/unsupported.rs:121:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:123:1 + --> $DIR/unsupported.rs:125:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 + --> $DIR/unsupported.rs:133:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 + --> $DIR/unsupported.rs:138:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 + --> $DIR/unsupported.rs:141:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,7 +146,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:145:22 + --> $DIR/unsupported.rs:147:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -155,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:150:1 + --> $DIR/unsupported.rs:152:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:166:1 + --> $DIR/unsupported.rs:168:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -214,20 +214,32 @@ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/unsupported.rs:83:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/unsupported.rs:83:5 + | +LL | f() + | ^^^ + error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:88:1 + --> $DIR/unsupported.rs:89:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:98:1 + --> $DIR/unsupported.rs:100:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -235,7 +247,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,18 +257,18 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:143:1 + --> $DIR/unsupported.rs:145:1 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:159:1 + --> $DIR/unsupported.rs:161:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 20 previous errors; 14 warnings emitted +error: aborting due to 21 previous errors; 14 warnings emitted For more information about this error, try `rustc --explain E0570`. Future incompatibility report: Future breakage diagnostic: @@ -305,7 +317,7 @@ LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { Future breakage diagnostic: warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:90:15 + --> $DIR/unsupported.rs:91:15 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -316,7 +328,7 @@ LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { Future breakage diagnostic: warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -327,7 +339,7 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { Future breakage diagnostic: warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -338,7 +350,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:145:22 + --> $DIR/unsupported.rs:147:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -349,7 +361,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -360,7 +372,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index 9e75dfafca0f..124ba13cc236 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -60,7 +60,7 @@ LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:90:15 + --> $DIR/unsupported.rs:91:15 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,13 +69,13 @@ LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { = note: for more information, see issue #130260 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:95:1 + --> $DIR/unsupported.rs:97:1 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -84,13 +84,13 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:119:1 + --> $DIR/unsupported.rs:121:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:123:1 + --> $DIR/unsupported.rs:125:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 + --> $DIR/unsupported.rs:133:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 + --> $DIR/unsupported.rs:138:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 + --> $DIR/unsupported.rs:141:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,7 +146,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:145:22 + --> $DIR/unsupported.rs:147:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -155,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:150:1 + --> $DIR/unsupported.rs:152:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:166:1 + --> $DIR/unsupported.rs:168:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -214,20 +214,32 @@ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/unsupported.rs:83:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/unsupported.rs:83:5 + | +LL | f() + | ^^^ + error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:88:1 + --> $DIR/unsupported.rs:89:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:98:1 + --> $DIR/unsupported.rs:100:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -235,7 +247,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,18 +257,18 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:143:1 + --> $DIR/unsupported.rs:145:1 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:159:1 + --> $DIR/unsupported.rs:161:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 20 previous errors; 14 warnings emitted +error: aborting due to 21 previous errors; 14 warnings emitted For more information about this error, try `rustc --explain E0570`. Future incompatibility report: Future breakage diagnostic: @@ -305,7 +317,7 @@ LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { Future breakage diagnostic: warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:90:15 + --> $DIR/unsupported.rs:91:15 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -316,7 +328,7 @@ LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { Future breakage diagnostic: warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -327,7 +339,7 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { Future breakage diagnostic: warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -338,7 +350,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:145:22 + --> $DIR/unsupported.rs:147:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -349,7 +361,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -360,7 +372,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 43bdfe3ea240..4ddcbae409bc 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -81,6 +81,7 @@ fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { //[x64,x64_win,i686,arm,aarch64]~^ WARN unsupported_fn_ptr_calling_conventions //[x64,x64_win,i686,arm,aarch64]~^^ WARN this was previously accepted f() + //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called } extern "riscv-interrupt-m" {} //[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI @@ -91,6 +92,7 @@ fn x86_ptr(f: extern "x86-interrupt" fn()) { //[aarch64,arm,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions //[aarch64,arm,riscv32,riscv64]~^^ WARN this was previously accepted f() + //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called } extern "x86-interrupt" {} //[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 5b55e5707fad..737c4c670b83 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -69,13 +69,13 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { = note: for more information, see issue #130260 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:85:1 + --> $DIR/unsupported.rs:86:1 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -84,13 +84,13 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:119:1 + --> $DIR/unsupported.rs:121:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:123:1 + --> $DIR/unsupported.rs:125:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 + --> $DIR/unsupported.rs:133:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 + --> $DIR/unsupported.rs:138:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 + --> $DIR/unsupported.rs:141:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,7 +146,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +164,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:166:1 + --> $DIR/unsupported.rs:168:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,14 +205,26 @@ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current targe LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/unsupported.rs:94:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/unsupported.rs:94:5 + | +LL | f() + | ^^^ + error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:98:1 + --> $DIR/unsupported.rs:100:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +232,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -230,12 +242,12 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:159:1 + --> $DIR/unsupported.rs:161:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 18 previous errors; 13 warnings emitted +error: aborting due to 19 previous errors; 13 warnings emitted For more information about this error, try `rustc --explain E0570`. Future incompatibility report: Future breakage diagnostic: @@ -295,7 +307,7 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { Future breakage diagnostic: warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -306,7 +318,7 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { Future breakage diagnostic: warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -317,7 +329,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +340,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 93b5a272e926..f201a089d3f9 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -69,13 +69,13 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { = note: for more information, see issue #130260 error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:85:1 + --> $DIR/unsupported.rs:86:1 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -84,13 +84,13 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { = note: for more information, see issue #130260 error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:112:19 + --> $DIR/unsupported.rs:114:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -101,7 +101,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:119:1 + --> $DIR/unsupported.rs:121:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:123:1 + --> $DIR/unsupported.rs:125:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:131:17 + --> $DIR/unsupported.rs:133:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:136:1 + --> $DIR/unsupported.rs:138:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -141,7 +141,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:139:1 + --> $DIR/unsupported.rs:141:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,13 +169,13 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:166:1 + --> $DIR/unsupported.rs:168:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:171:1 + --> $DIR/unsupported.rs:173:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -220,14 +220,26 @@ error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current targe LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/unsupported.rs:94:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/unsupported.rs:94:5 + | +LL | f() + | ^^^ + error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:98:1 + --> $DIR/unsupported.rs:100:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -237,7 +249,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:128:1 + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -247,12 +259,12 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:159:1 + --> $DIR/unsupported.rs:161:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors; 17 warnings emitted +error: aborting due to 16 previous errors; 17 warnings emitted For more information about this error, try `rustc --explain E0570`. Future incompatibility report: Future breakage diagnostic: @@ -312,7 +324,7 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { Future breakage diagnostic: warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:100:20 + --> $DIR/unsupported.rs:102:20 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -323,7 +335,7 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:153:21 + --> $DIR/unsupported.rs:155:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -334,7 +346,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:161:22 + --> $DIR/unsupported.rs:163:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 890ade5ae85300cc96b1f948d4ac2d756cc67ccd Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Fri, 20 Jun 2025 19:31:30 +0200 Subject: [PATCH 197/356] Bless UI tests: do not print alternate implementors of `Step` Alternative candidates for a trait implementation are not printed when the trait has a diagnostic name, to avoid printing alternatives for common stdlib traits such as `Copy` or `Debug`. However, this affects all traits for which a diagnostic item is added. Here, the list of alternatives candidates for `Step` does not seem useful, and `Step` is unstable, so this will not be missed. --- tests/ui/range/range-1.stderr | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 37669dd3f47c..8878ba143097 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -10,16 +10,6 @@ error[E0277]: the trait bound `bool: Step` is not satisfied LL | for i in false..true {} | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool` | - = help: the following other types implement trait `Step`: - Char - Ipv4Addr - Ipv6Addr - char - i128 - i16 - i32 - i64 - and 8 others = note: required for `std::ops::Range` to implement `Iterator` = note: required for `std::ops::Range` to implement `IntoIterator` From 6809ec16482ec72ba46566fe815b2bc89210612f Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 20 Jun 2025 12:45:26 -0500 Subject: [PATCH 198/356] Factor out seen_comma variable --- compiler/rustc_parse/src/parser/item.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 658ed4bd41c4..28da287fcc2d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1916,11 +1916,7 @@ impl<'a> Parser<'a> { safety: Safety, attrs: AttrVec, ) -> PResult<'a, FieldDef> { - let mut seen_comma: bool = false; let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?; - if self.token == token::Comma { - seen_comma = true; - } if self.eat(exp!(Semi)) { let sp = self.prev_token.span; let mut err = @@ -1945,19 +1941,11 @@ impl<'a> Parser<'a> { missing_comma: None, }; self.bump(); // consume the doc comment - let comma_after_doc_seen = self.eat(exp!(Comma)); - // `seen_comma` is always false, because we are inside doc block - // condition is here to make code more readable - if !seen_comma && comma_after_doc_seen { - seen_comma = true; - } - if comma_after_doc_seen || self.token == token::CloseBrace { + if self.eat(exp!(Comma)) || self.token == token::CloseBrace { self.dcx().emit_err(err); } else { - if !seen_comma { - let sp = previous_span.shrink_to_hi(); - err.missing_comma = Some(sp); - } + let sp = previous_span.shrink_to_hi(); + err.missing_comma = Some(sp); return Err(self.dcx().create_err(err)); } } From 78c2ef2d488fbd8e4688139224f76ec0a33dc31e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 20 Jun 2025 12:50:12 -0500 Subject: [PATCH 199/356] compiler: Rename LayoutS to LayoutData in comments --- compiler/rustc_abi/src/layout.rs | 12 ++++++------ compiler/rustc_abi/src/layout/ty.rs | 2 +- compiler/rustc_abi/src/lib.rs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 58a7fcae9f64..80b44e432eeb 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -432,7 +432,7 @@ impl LayoutCalculator { align = align.min(AbiAlign::new(pack)); } // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). - // See documentation on `LayoutS::unadjusted_abi_align`. + // See documentation on `LayoutData::unadjusted_abi_align`. let unadjusted_abi_align = align.abi; if let Some(repr_align) = repr.align { align = align.max(AbiAlign::new(repr_align)); @@ -602,10 +602,10 @@ impl LayoutCalculator { dont_niche_optimize_enum: bool, ) -> LayoutCalculatorResult { // Until we've decided whether to use the tagged or - // niche filling LayoutS, we don't want to intern the + // niche filling LayoutData, we don't want to intern the // variant layouts, so we can't store them in the - // overall LayoutS. Store the overall LayoutS - // and the variant LayoutSs here until then. + // overall LayoutData. Store the overall LayoutData + // and the variant LayoutDatas here until then. struct TmpLayout { layout: LayoutData, variants: IndexVec>, @@ -1214,7 +1214,7 @@ impl LayoutCalculator { match kind { StructKind::AlwaysSized | StructKind::MaybeUnsized => { - // Currently `LayoutS` only exposes a single niche so sorting is usually + // Currently `LayoutData` only exposes a single niche so sorting is usually // sufficient to get one niche into the preferred position. If it ever // supported multiple niches then a more advanced pick-and-pack approach could // provide better results. But even for the single-niche cache it's not @@ -1333,7 +1333,7 @@ impl LayoutCalculator { } // The unadjusted ABI alignment does not include repr(align), but does include repr(pack). - // See documentation on `LayoutS::unadjusted_abi_align`. + // See documentation on `LayoutData::unadjusted_abi_align`. let unadjusted_abi_align = align.abi; if let Some(repr_align) = repr.align { align = align.max(AbiAlign::new(repr_align)); diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index bb880a58e527..18f0750aaa1f 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -71,7 +71,7 @@ pub struct Layout<'a>(pub Interned<'a, LayoutData>); impl<'a> fmt::Debug for Layout<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // See comment on `::fmt` above. + // See comment on `::fmt` above. self.0.0.fmt(f) } } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 4268e68b2e42..6d729b6919a7 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1785,7 +1785,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // This is how `Layout` used to print before it become - // `Interned`. We print it like this to avoid having to update + // `Interned`. We print it like this to avoid having to update // expected output in a lot of tests. let LayoutData { size, From a7ff98e143864c2edf060835d874d70862ba8915 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 20 Jun 2025 12:50:55 -0500 Subject: [PATCH 200/356] rust-analyzer: Rename LayoutS to LayoutData in comments --- src/tools/rust-analyzer/crates/hir-ty/src/layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index c253fe25672f..c58bd1b773e2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -268,7 +268,7 @@ pub fn layout_of_ty_query( // let pointee = tcx.normalize_erasing_regions(param_env, pointee); // if pointee.is_sized(tcx.at(DUMMY_SP), param_env) { - // return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); + // return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); // } let mut unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone()); From 5babf246574d5d4a789f7a34a2d1c1bc1b9595c3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 20 Jun 2025 20:38:29 +0200 Subject: [PATCH 201/356] integer docs: remove extraneous text "Basic usage" implies there is an example that shows advanced usage, but these APIs are extra simple. --- library/core/src/num/int_macros.rs | 208 ---------------------------- library/core/src/num/mod.rs | 4 - library/core/src/num/saturating.rs | 46 ------ library/core/src/num/uint_macros.rs | 197 -------------------------- 4 files changed, 455 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 3a7bc902f93c..5683d5ec92dc 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -29,8 +29,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");")] /// ``` @@ -42,8 +40,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");")] /// ``` @@ -64,8 +60,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0b100_0000", stringify!($SelfT), ";")] /// @@ -85,8 +79,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);")] /// ``` @@ -106,8 +98,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = -1", stringify!($SelfT), ";")] /// @@ -127,8 +117,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = -4", stringify!($SelfT), ";")] /// @@ -147,8 +135,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = -1", stringify!($SelfT), ";")] /// @@ -167,8 +153,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 3", stringify!($SelfT), ";")] /// @@ -188,8 +172,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(isolate_most_least_significant_one)] /// @@ -211,8 +193,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(isolate_most_least_significant_one)] /// @@ -236,8 +216,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = -1", stringify!($SelfT), ";")] /// @@ -259,8 +237,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", $rot_op, stringify!($SelfT), ";")] #[doc = concat!("let m = ", $rot_result, ";")] @@ -284,8 +260,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", $rot_result, stringify!($SelfT), ";")] #[doc = concat!("let m = ", $rot_op, ";")] @@ -305,8 +279,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")] /// @@ -328,8 +300,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")] /// let m = n.reverse_bits(); @@ -352,8 +322,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")] /// @@ -384,8 +352,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")] /// @@ -416,8 +382,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")] /// @@ -449,8 +413,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")] /// @@ -481,8 +443,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);")] @@ -508,8 +468,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] @@ -576,8 +534,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")] @@ -603,8 +559,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")] @@ -631,8 +585,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);")] @@ -658,8 +610,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")] @@ -726,8 +676,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")] @@ -753,8 +701,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")] @@ -781,8 +727,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);")] @@ -808,8 +752,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")] @@ -876,8 +818,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_div(-1), Some(", stringify!($Max), "));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None);")] @@ -914,8 +854,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")] @@ -949,8 +887,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), "));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None);")] @@ -987,8 +923,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")] @@ -1023,8 +957,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(exact_div)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_exact_div(-1), Some(", stringify!($Max), "));")] @@ -1063,8 +995,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(exact_div)] #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")] @@ -1126,8 +1056,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);")] @@ -1163,8 +1091,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")] @@ -1198,8 +1124,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);")] @@ -1235,8 +1159,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")] @@ -1269,8 +1191,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);")] @@ -1328,8 +1248,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")] @@ -1356,8 +1274,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);")] @@ -1389,8 +1305,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] @@ -1453,7 +1367,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] @@ -1478,8 +1391,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);")] @@ -1510,8 +1421,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] @@ -1575,7 +1484,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: /// ``` #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] @@ -1605,8 +1513,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);")] @@ -1635,8 +1541,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")] @@ -1666,8 +1570,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);")] @@ -1709,8 +1611,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")] @@ -1753,7 +1653,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_isqrt(), Some(3));")] /// ``` @@ -1801,8 +1700,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), "::MAX);")] @@ -1823,8 +1720,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")] @@ -1848,8 +1743,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), "::MIN);")] @@ -1869,8 +1762,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")] @@ -1894,8 +1785,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100);")] #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100);")] @@ -1917,8 +1806,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100);")] #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100);")] @@ -1944,8 +1831,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX);")] @@ -1976,8 +1861,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_div(-1), ", stringify!($SelfT), "::MIN + 1);")] @@ -2001,8 +1884,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX);")] @@ -2026,8 +1907,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), "::MIN + 1);")] @@ -2046,8 +1925,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")] @@ -2066,8 +1943,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127);")] #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", stringify!($SelfT), "::MAX);")] @@ -2086,8 +1961,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")] #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")] @@ -2106,8 +1979,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120);")] /// assert_eq!(11i8.wrapping_mul(12), -124); @@ -2134,8 +2005,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);")] /// assert_eq!((-128i8).wrapping_div(-1), -128); @@ -2162,8 +2031,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);")] /// assert_eq!((-128i8).wrapping_div_euclid(-1), -128); @@ -2190,8 +2057,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);")] /// assert_eq!((-128i8).wrapping_rem(-1), 0); @@ -2217,8 +2082,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);")] /// assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); @@ -2241,8 +2104,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100);")] #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").wrapping_neg(), 100);")] @@ -2267,8 +2128,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128);")] #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);")] @@ -2296,8 +2155,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1);")] /// assert_eq!((-128i16).wrapping_shr(64), -128); @@ -2324,8 +2181,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100);")] #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100);")] @@ -2352,8 +2207,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");")] #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");")] @@ -2373,8 +2226,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);")] /// assert_eq!(3i8.wrapping_pow(5), -13); @@ -2432,8 +2283,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), "::MIN, true));")] @@ -2513,8 +2362,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")] @@ -2538,8 +2385,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));")] @@ -2620,8 +2465,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")] @@ -2645,8 +2488,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false));")] /// assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true)); @@ -2671,8 +2512,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// Please note that this example is shared between integer types. /// Which explains why `i32` is used here. /// @@ -2704,8 +2543,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// Please note that this example is shared between integer types. /// Which explains why `i32` is used here. /// @@ -2744,8 +2581,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// Please note that this example is shared between integer types. /// Which explains why `i32` is used here. /// @@ -2780,8 +2615,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), "::MIN, true));")] @@ -2811,8 +2644,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), "::MIN, true));")] @@ -2842,8 +2673,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));")] @@ -2873,8 +2702,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true));")] @@ -2902,8 +2729,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), "::MIN, true));")] @@ -2930,8 +2755,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false));")] /// assert_eq!(0x1i32.overflowing_shl(36), (0x10, true)); @@ -2954,8 +2777,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));")] /// assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); @@ -2979,8 +2800,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false));")] #[doc = concat!("assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false));")] @@ -3002,8 +2821,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));")] /// assert_eq!(3i8.overflowing_pow(5), (-13, true)); @@ -3045,8 +2862,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let x: ", stringify!($SelfT), " = 2; // or any other integer type")] /// @@ -3106,7 +2921,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] /// ``` @@ -3142,8 +2956,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let a: ", stringify!($SelfT), " = 7; // or any other integer type")] /// let b = 4; @@ -3181,8 +2993,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let a: ", stringify!($SelfT), " = 7; // or any other integer type")] /// let b = 4; @@ -3230,8 +3040,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(int_roundings)] #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] @@ -3274,8 +3082,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(int_roundings)] #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] @@ -3321,8 +3127,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(int_roundings)] #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] @@ -3367,8 +3171,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(int_roundings)] #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")] @@ -3582,8 +3384,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".abs(), 10);")] #[doc = concat!("assert_eq!((-10", stringify!($SelfT), ").abs(), 10);")] @@ -3613,8 +3413,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($UnsignedT), ");")] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($UnsignedT), ");")] @@ -3656,8 +3454,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".signum(), 1);")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".signum(), 0);")] @@ -3682,8 +3478,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert!(10", stringify!($SelfT), ".is_positive());")] #[doc = concat!("assert!(!(-10", stringify!($SelfT), ").is_positive());")] @@ -3699,8 +3493,6 @@ macro_rules! int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert!((-10", stringify!($SelfT), ").is_negative());")] #[doc = concat!("assert!(!10", stringify!($SelfT), ".is_negative());")] diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index ab2fcff61cd1..faa41ddf13ca 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1399,7 +1399,6 @@ macro_rules! from_str_int_impl { /// /// # Examples /// - /// Basic usage: /// ``` /// use std::str::FromStr; /// @@ -1445,7 +1444,6 @@ macro_rules! from_str_int_impl { /// /// # Examples /// - /// Basic usage: /// ``` #[doc = concat!("assert_eq!(", stringify!($int_ty), "::from_str_radix(\"A\", 16), Ok(10));")] /// ``` @@ -1478,7 +1476,6 @@ macro_rules! from_str_int_impl { /// /// # Examples /// - /// Basic usage: /// ``` /// #![feature(int_from_ascii)] /// @@ -1523,7 +1520,6 @@ macro_rules! from_str_int_impl { /// /// # Examples /// - /// Basic usage: /// ``` /// #![feature(int_from_ascii)] /// diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs index 3f4791e163e6..4460e430aecf 100644 --- a/library/core/src/num/saturating.rs +++ b/library/core/src/num/saturating.rs @@ -300,8 +300,6 @@ macro_rules! saturating_impl { /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -490,8 +488,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -504,8 +500,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -518,8 +512,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -532,8 +524,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -556,8 +546,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -576,8 +564,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -603,8 +589,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -631,8 +615,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -654,8 +636,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -683,8 +663,6 @@ macro_rules! saturating_int_impl { /// Please note that this example is shared between integer types. /// Which explains why `i16` is used here. /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -712,8 +690,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -740,8 +716,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -768,8 +742,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -797,8 +769,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -823,8 +793,6 @@ macro_rules! saturating_int_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -860,8 +828,6 @@ macro_rules! saturating_int_impl_signed { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -883,8 +849,6 @@ macro_rules! saturating_int_impl_signed { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -911,8 +875,6 @@ macro_rules! saturating_int_impl_signed { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -934,8 +896,6 @@ macro_rules! saturating_int_impl_signed { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -955,8 +915,6 @@ macro_rules! saturating_int_impl_signed { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -994,8 +952,6 @@ macro_rules! saturating_int_impl_unsigned { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// @@ -1016,8 +972,6 @@ macro_rules! saturating_int_impl_unsigned { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::num::Saturating; /// diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 4ee0e7326b3a..079032f2f96d 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -27,8 +27,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN, 0);")] /// ``` @@ -40,8 +38,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");")] /// ``` @@ -62,8 +58,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0b01001100", stringify!($SelfT), ";")] /// assert_eq!(n.count_ones(), 3); @@ -89,8 +83,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let zero = 0", stringify!($SelfT), ";")] #[doc = concat!("assert_eq!(zero.count_zeros(), ", stringify!($BITS), ");")] @@ -114,8 +106,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", stringify!($SelfT), "::MAX >> 2;")] /// assert_eq!(n.leading_zeros(), 2); @@ -141,8 +131,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0b0101000", stringify!($SelfT), ";")] /// assert_eq!(n.trailing_zeros(), 3); @@ -166,8 +154,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = !(", stringify!($SelfT), "::MAX >> 2);")] /// assert_eq!(n.leading_ones(), 2); @@ -192,8 +178,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0b1010111", stringify!($SelfT), ";")] /// assert_eq!(n.trailing_ones(), 3); @@ -219,8 +203,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(uint_bit_width)] /// @@ -242,8 +224,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(isolate_most_least_significant_one)] /// @@ -265,8 +245,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(isolate_most_least_significant_one)] /// @@ -290,8 +268,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", stringify!($SelfT), "::MAX;")] /// @@ -313,8 +289,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", $rot_op, stringify!($SelfT), ";")] #[doc = concat!("let m = ", $rot_result, ";")] @@ -338,8 +312,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", $rot_result, stringify!($SelfT), ";")] #[doc = concat!("let m = ", $rot_op, ";")] @@ -359,8 +331,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")] /// let m = n.swap_bytes(); @@ -381,8 +351,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = ", $swap_op, stringify!($SelfT), ";")] /// let m = n.reverse_bits(); @@ -406,8 +374,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")] /// @@ -439,8 +405,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")] /// @@ -472,8 +436,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")] /// @@ -506,8 +468,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("let n = 0x1A", stringify!($SelfT), ";")] /// @@ -538,8 +498,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!( "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ", @@ -579,8 +537,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")] @@ -647,8 +603,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")] @@ -675,8 +629,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_signed(2), 3);")] @@ -708,8 +660,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0));")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);")] @@ -744,8 +694,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub(1), 0);")] @@ -837,8 +785,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(mixed_integer_ops_unsigned_sub)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_signed(2), None);")] @@ -866,8 +812,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(unsigned_signed_diff)] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_signed_diff(2), Some(8));")] @@ -925,8 +869,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);")] @@ -952,8 +894,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_mul(1), 5);")] @@ -1020,8 +960,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);")] @@ -1053,8 +991,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div(10), 10);")] @@ -1080,8 +1016,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None);")] @@ -1113,8 +1047,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div_euclid(10), 10);")] @@ -1142,8 +1074,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(exact_div)] #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")] @@ -1184,8 +1114,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(exact_div)] #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")] @@ -1241,8 +1169,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1));")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);")] @@ -1275,8 +1201,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem(10), 0);")] @@ -1302,8 +1226,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1));")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None);")] @@ -1336,8 +1258,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem_euclid(10), 0);")] @@ -1583,8 +1503,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);")] @@ -1612,8 +1530,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".strict_neg(), 0);")] @@ -1640,8 +1556,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10));")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);")] @@ -1673,8 +1587,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")] @@ -1737,7 +1649,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] @@ -1762,8 +1673,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1));")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);")] @@ -1794,8 +1703,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")] @@ -1858,7 +1765,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: /// ``` #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] @@ -1883,8 +1789,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);")] @@ -1925,8 +1829,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(strict_overflow_ops)] #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".strict_pow(5), 32);")] @@ -1968,8 +1870,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);")] @@ -1988,8 +1888,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")] @@ -2016,8 +1914,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73);")] #[doc = concat!("assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);")] @@ -2036,8 +1932,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(mixed_integer_ops_unsigned_sub)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_sub_signed(2), 0);")] @@ -2065,8 +1959,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20);")] #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT),"::MAX);")] @@ -2092,8 +1984,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")] /// @@ -2114,8 +2004,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);")] @@ -2137,8 +2025,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255);")] #[doc = concat!("assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);")] @@ -2157,8 +2043,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")] @@ -2178,8 +2062,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0);")] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);")] @@ -2198,8 +2080,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(mixed_integer_ops_unsigned_sub)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_sub_signed(2), ", stringify!($SelfT), "::MAX);")] @@ -2219,8 +2099,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// Please note that this example is shared between integer types. /// Which explains why `u8` is used here. /// @@ -2249,8 +2127,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);")] /// ``` @@ -2278,8 +2154,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10);")] /// ``` @@ -2306,8 +2180,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);")] /// ``` @@ -2336,8 +2208,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);")] /// ``` @@ -2363,8 +2233,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".wrapping_neg(), 0);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_neg(), 1);")] @@ -2393,8 +2261,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128);")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);")] @@ -2425,8 +2291,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1);")] #[doc = concat!("assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);")] @@ -2449,8 +2313,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);")] /// assert_eq!(3u8.wrapping_pow(6), 217); @@ -2507,8 +2369,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));")] @@ -2587,8 +2447,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")] @@ -2612,8 +2470,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")] #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));")] @@ -2683,8 +2539,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(mixed_integer_ops_unsigned_sub)] #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_signed(2), (", stringify!($SelfT), "::MAX, true));")] @@ -2705,8 +2559,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($SelfT), ");")] #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($SelfT), ");")] @@ -2738,8 +2590,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// Please note that this example is shared between integer types. /// Which explains why `u32` is used here. /// @@ -2767,8 +2617,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// Please note that this example is shared between integer types. /// Which explains why `u32` is used here. /// @@ -2800,8 +2648,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// Please note that this example is shared between integer types. /// Which explains why `u32` is used here. /// @@ -2888,8 +2734,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// Please note that this example is shared between integer types, /// which explains why `u32` is used here. /// @@ -2955,8 +2799,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")] /// ``` @@ -2986,8 +2828,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")] /// ``` @@ -3014,8 +2854,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")] /// ``` @@ -3045,8 +2883,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")] /// ``` @@ -3069,8 +2905,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));")] #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), ", true));")] @@ -3094,8 +2928,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));")] @@ -3120,8 +2952,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));")] @@ -3142,8 +2972,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));")] /// assert_eq!(3u8.overflowing_pow(6), (217, true)); @@ -3185,8 +3013,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".pow(5), 32);")] /// ``` @@ -3240,7 +3066,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: /// ``` #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")] /// ``` @@ -3282,8 +3107,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type")] /// ``` @@ -3310,8 +3133,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type")] /// ``` @@ -3336,8 +3157,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(int_roundings)] #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")] @@ -3359,8 +3178,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")] /// ``` @@ -3394,8 +3211,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] @@ -3419,8 +3234,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(16));")] #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".checked_next_multiple_of(8), Some(24));")] @@ -3448,8 +3261,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert!(6_", stringify!($SelfT), ".is_multiple_of(2));")] #[doc = concat!("assert!(!5_", stringify!($SelfT), ".is_multiple_of(2));")] @@ -3473,8 +3284,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert!(16", stringify!($SelfT), ".is_power_of_two());")] #[doc = concat!("assert!(!10", stringify!($SelfT), ".is_power_of_two());")] @@ -3517,8 +3326,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);")] #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);")] @@ -3540,8 +3347,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_next_power_of_two(), Some(2));")] #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4));")] @@ -3562,8 +3367,6 @@ macro_rules! uint_impl { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(wrapping_next_power_of_two)] /// From 48060c97c8f707170149e93ffb71032186439aa1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 20 Jun 2025 18:57:47 +0000 Subject: [PATCH 202/356] Use gen blocks in the compiler instead of from_coroutine --- .../src/collect/resolve_bound_vars.rs | 136 +++++++++--------- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_metadata/src/lib.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 44 +++--- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_middle/src/ty/closure.rs | 80 +++++------ compiler/rustc_middle/src/ty/context.rs | 27 ++-- 7 files changed, 139 insertions(+), 154 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index d45f0475e991..95743f9a63eb 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -2177,84 +2177,80 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { /// Walk the generics of the item for a trait bound whose self type /// corresponds to the expected res, and return the trait def id. fn for_each_trait_bound_on_res(&self, expected_res: Res) -> impl Iterator { - std::iter::from_coroutine( - #[coroutine] - move || { - let mut scope = self.scope; - loop { - let hir_id = match *scope { - Scope::Binder { hir_id, .. } => Some(hir_id), - Scope::Root { opt_parent_item: Some(parent_def_id) } => { - Some(self.tcx.local_def_id_to_hir_id(parent_def_id)) - } - Scope::Body { .. } - | Scope::ObjectLifetimeDefault { .. } - | Scope::Supertrait { .. } - | Scope::TraitRefBoundary { .. } - | Scope::LateBoundary { .. } - | Scope::Opaque { .. } - | Scope::Root { opt_parent_item: None } => None, - }; + gen move { + let mut scope = self.scope; + loop { + let hir_id = match *scope { + Scope::Binder { hir_id, .. } => Some(hir_id), + Scope::Root { opt_parent_item: Some(parent_def_id) } => { + Some(self.tcx.local_def_id_to_hir_id(parent_def_id)) + } + Scope::Body { .. } + | Scope::ObjectLifetimeDefault { .. } + | Scope::Supertrait { .. } + | Scope::TraitRefBoundary { .. } + | Scope::LateBoundary { .. } + | Scope::Opaque { .. } + | Scope::Root { opt_parent_item: None } => None, + }; - if let Some(hir_id) = hir_id { - let node = self.tcx.hir_node(hir_id); - // If this is a `Self` bound in a trait, yield the trait itself. - // Specifically, we don't need to look at any supertraits since - // we already do that in `BoundVarContext::supertrait_hrtb_vars`. - if let Res::SelfTyParam { trait_: _ } = expected_res - && let hir::Node::Item(item) = node - && let hir::ItemKind::Trait(..) = item.kind - { - // Yield the trait's def id. Supertraits will be - // elaborated from that. - yield item.owner_id.def_id.to_def_id(); - } else if let Some(generics) = node.generics() { - for pred in generics.predicates { - let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind - else { - continue; - }; - let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = - pred.bounded_ty.kind - else { - continue; - }; - // Match the expected res. - if bounded_path.res != expected_res { - continue; - } - for pred in pred.bounds { - match pred { - hir::GenericBound::Trait(poly_trait_ref) => { - if let Some(def_id) = - poly_trait_ref.trait_ref.trait_def_id() - { - yield def_id; - } + if let Some(hir_id) = hir_id { + let node = self.tcx.hir_node(hir_id); + // If this is a `Self` bound in a trait, yield the trait itself. + // Specifically, we don't need to look at any supertraits since + // we already do that in `BoundVarContext::supertrait_hrtb_vars`. + if let Res::SelfTyParam { trait_: _ } = expected_res + && let hir::Node::Item(item) = node + && let hir::ItemKind::Trait(..) = item.kind + { + // Yield the trait's def id. Supertraits will be + // elaborated from that. + yield item.owner_id.def_id.to_def_id(); + } else if let Some(generics) = node.generics() { + for pred in generics.predicates { + let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind else { + continue; + }; + let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = + pred.bounded_ty.kind + else { + continue; + }; + // Match the expected res. + if bounded_path.res != expected_res { + continue; + } + for pred in pred.bounds { + match pred { + hir::GenericBound::Trait(poly_trait_ref) => { + if let Some(def_id) = + poly_trait_ref.trait_ref.trait_def_id() + { + yield def_id; } - hir::GenericBound::Outlives(_) - | hir::GenericBound::Use(_, _) => {} } + hir::GenericBound::Outlives(_) + | hir::GenericBound::Use(_, _) => {} } } } } - - match *scope { - Scope::Binder { s, .. } - | Scope::Body { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s } - | Scope::LateBoundary { s, .. } - | Scope::Opaque { s, .. } => { - scope = s; - } - Scope::Root { .. } => break, - } } - }, - ) + + match *scope { + Scope::Binder { s, .. } + | Scope::Body { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s } + | Scope::LateBoundary { s, .. } + | Scope::Opaque { s, .. } => { + scope = s; + } + Scope::Root { .. } => break, + } + } + } } } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 7c8c9425a03d..76ab2e57a1b5 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -62,8 +62,8 @@ This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(coroutines)] #![feature(debug_closure_helpers)] +#![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(iter_from_coroutine)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 389a4ab74662..23ffb1e487fd 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -2,10 +2,10 @@ #![allow(internal_features)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(coroutines)] #![feature(decl_macro)] #![feature(error_iter)] #![feature(file_buffered)] +#![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(iter_from_coroutine)] #![feature(macro_metavar_expr)] diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 0bc980b4d9f8..d886f25247f2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -3,7 +3,7 @@ use std::iter::TrustedLen; use std::path::{Path, PathBuf}; use std::sync::{Arc, OnceLock}; -use std::{io, iter, mem}; +use std::{io, mem}; pub(super) use cstore_impl::provide; use rustc_ast as ast; @@ -1272,34 +1272,30 @@ impl<'a> CrateMetadataRef<'a> { id: DefIndex, sess: &'a Session, ) -> impl Iterator { - iter::from_coroutine( - #[coroutine] - move || { - if let Some(data) = &self.root.proc_macro_data { - // If we are loading as a proc macro, we want to return - // the view of this crate as a proc macro crate. - if id == CRATE_DEF_INDEX { - for child_index in data.macros.decode(self) { - yield self.get_mod_child(child_index, sess); - } - } - } else { - // Iterate over all children. - let non_reexports = - self.root.tables.module_children_non_reexports.get(self, id); - for child_index in non_reexports.unwrap().decode(self) { + gen move { + if let Some(data) = &self.root.proc_macro_data { + // If we are loading as a proc macro, we want to return + // the view of this crate as a proc macro crate. + if id == CRATE_DEF_INDEX { + for child_index in data.macros.decode(self) { yield self.get_mod_child(child_index, sess); } + } + } else { + // Iterate over all children. + let non_reexports = self.root.tables.module_children_non_reexports.get(self, id); + for child_index in non_reexports.unwrap().decode(self) { + yield self.get_mod_child(child_index, sess); + } - let reexports = self.root.tables.module_children_reexports.get(self, id); - if !reexports.is_default() { - for reexport in reexports.decode((self, sess)) { - yield reexport; - } + let reexports = self.root.tables.module_children_reexports.get(self, id); + if !reexports.is_default() { + for reexport in reexports.decode((self, sess)) { + yield reexport; } } - }, - ) + } + } } fn is_ctfe_mir_available(self, id: DefIndex) -> bool { diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index c488ef9b575b..ce2cb33c1736 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -40,12 +40,12 @@ #![feature(box_patterns)] #![feature(closure_track_caller)] #![feature(core_intrinsics)] -#![feature(coroutines)] #![feature(debug_closure_helpers)] #![feature(decl_macro)] #![feature(discriminant_kind)] #![feature(extern_types)] #![feature(file_buffered)] +#![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(iter_from_coroutine)] diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index df67bb505a68..b8c7d6cf3b13 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -422,53 +422,49 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>( child_captures: impl IntoIterator>, mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T, ) -> impl Iterator { - std::iter::from_coroutine( - #[coroutine] - move || { - let mut child_captures = child_captures.into_iter().enumerate().peekable(); + gen move { + let mut child_captures = child_captures.into_iter().enumerate().peekable(); - // One parent capture may correspond to several child captures if we end up - // refining the set of captures via edition-2021 precise captures. We want to - // match up any number of child captures with one parent capture, so we keep - // peeking off this `Peekable` until the child doesn't match anymore. - for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() { - // Make sure we use every field at least once, b/c why are we capturing something - // if it's not used in the inner coroutine. - let mut field_used_at_least_once = false; + // One parent capture may correspond to several child captures if we end up + // refining the set of captures via edition-2021 precise captures. We want to + // match up any number of child captures with one parent capture, so we keep + // peeking off this `Peekable` until the child doesn't match anymore. + for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() { + // Make sure we use every field at least once, b/c why are we capturing something + // if it's not used in the inner coroutine. + let mut field_used_at_least_once = false; - // A parent matches a child if they share the same prefix of projections. - // The child may have more, if it is capturing sub-fields out of - // something that is captured by-move in the parent closure. - while child_captures.peek().is_some_and(|(_, child_capture)| { - child_prefix_matches_parent_projections(parent_capture, child_capture) - }) { - let (child_field_idx, child_capture) = child_captures.next().unwrap(); - // This analysis only makes sense if the parent capture is a - // prefix of the child capture. - assert!( - child_capture.place.projections.len() - >= parent_capture.place.projections.len(), - "parent capture ({parent_capture:#?}) expected to be prefix of \ - child capture ({child_capture:#?})" - ); - - yield for_each( - (parent_field_idx, parent_capture), - (child_field_idx, child_capture), - ); - - field_used_at_least_once = true; - } - - // Make sure the field was used at least once. + // A parent matches a child if they share the same prefix of projections. + // The child may have more, if it is capturing sub-fields out of + // something that is captured by-move in the parent closure. + while child_captures.peek().is_some_and(|(_, child_capture)| { + child_prefix_matches_parent_projections(parent_capture, child_capture) + }) { + let (child_field_idx, child_capture) = child_captures.next().unwrap(); + // This analysis only makes sense if the parent capture is a + // prefix of the child capture. assert!( - field_used_at_least_once, - "we captured {parent_capture:#?} but it was not used in the child coroutine?" + child_capture.place.projections.len() >= parent_capture.place.projections.len(), + "parent capture ({parent_capture:#?}) expected to be prefix of \ + child capture ({child_capture:#?})" ); + + yield for_each( + (parent_field_idx, parent_capture), + (child_field_idx, child_capture), + ); + + field_used_at_least_once = true; } - assert_eq!(child_captures.next(), None, "leftover child captures?"); - }, - ) + + // Make sure the field was used at least once. + assert!( + field_used_at_least_once, + "we captured {parent_capture:#?} but it was not used in the child coroutine?" + ); + } + assert_eq!(child_captures.next(), None, "leftover child captures?"); + } } fn child_prefix_matches_parent_projections( diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4f8cfd865979..c5f4b95cbbe6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2087,23 +2087,20 @@ impl<'tcx> TyCtxt<'tcx> { self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); let definitions = &self.untracked.definitions; - std::iter::from_coroutine( - #[coroutine] - || { - let mut i = 0; + gen { + let mut i = 0; - // Recompute the number of definitions each time, because our caller may be creating - // new ones. - while i < { definitions.read().num_definitions() } { - let local_def_index = rustc_span::def_id::DefIndex::from_usize(i); - yield LocalDefId { local_def_index }; - i += 1; - } + // Recompute the number of definitions each time, because our caller may be creating + // new ones. + while i < { definitions.read().num_definitions() } { + let local_def_index = rustc_span::def_id::DefIndex::from_usize(i); + yield LocalDefId { local_def_index }; + i += 1; + } - // Freeze definitions once we finish iterating on them, to prevent adding new ones. - definitions.freeze(); - }, - ) + // Freeze definitions once we finish iterating on them, to prevent adding new ones. + definitions.freeze(); + } } pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable { From a56bf51d823f1e231797a55043157ab5f7e75296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Jun 2025 17:34:25 +0000 Subject: [PATCH 203/356] Make some `use _` tests multi-edition --- ...tern-by-macro-for-underscore.ed2015.stderr | 15 ++++ ...ern-by-macro-for-underscore.ed2021.stderr} | 2 +- ...multiple-extern-by-macro-for-underscore.rs | 6 +- ...0164.stderr => issue-110164.ed2015.stderr} | 20 +++--- .../issue-110164.ed2021.stderr | 71 +++++++++++++++++++ tests/ui/underscore-imports/issue-110164.rs | 3 + 6 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2015.stderr rename tests/ui/imports/{multiple-extern-by-macro-for-underscore.stderr => multiple-extern-by-macro-for-underscore.ed2021.stderr} (75%) rename tests/ui/underscore-imports/{issue-110164.stderr => issue-110164.ed2015.stderr} (88%) create mode 100644 tests/ui/underscore-imports/issue-110164.ed2021.stderr diff --git a/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2015.stderr b/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2015.stderr new file mode 100644 index 000000000000..719d90d8c492 --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2015.stderr @@ -0,0 +1,15 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/multiple-extern-by-macro-for-underscore.rs:18:11 + | +LL | use ::_; + | ^ expected identifier, found reserved identifier + +error[E0432]: unresolved import `_` + --> $DIR/multiple-extern-by-macro-for-underscore.rs:18:9 + | +LL | use ::_; + | ^^^ no `_` in the root + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr b/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2021.stderr similarity index 75% rename from tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr rename to tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2021.stderr index 1da5aa870704..985cd654c394 100644 --- a/tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr +++ b/tests/ui/imports/multiple-extern-by-macro-for-underscore.ed2021.stderr @@ -1,5 +1,5 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/multiple-extern-by-macro-for-underscore.rs:16:11 + --> $DIR/multiple-extern-by-macro-for-underscore.rs:18:11 | LL | use ::_; | ^ expected identifier, found reserved identifier diff --git a/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs b/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs index ddf735d89475..2f9fc266ffd2 100644 --- a/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs +++ b/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs @@ -1,4 +1,6 @@ -//@ edition: 2021 +//@ revisions: ed2015 ed2021 +//@[ed2015] edition: 2015 +//@[ed2021] edition: 2021 // issue#128813 @@ -13,6 +15,6 @@ macro_rules! m { m!(); fn main() { - use ::_; + use ::_; //[ed2015]~ ERROR: unresolved import `_` //~^ ERROR: expected identifier, found reserved identifier `_` } diff --git a/tests/ui/underscore-imports/issue-110164.stderr b/tests/ui/underscore-imports/issue-110164.ed2015.stderr similarity index 88% rename from tests/ui/underscore-imports/issue-110164.stderr rename to tests/ui/underscore-imports/issue-110164.ed2015.stderr index d8a4b6bbb754..fab6b19156a2 100644 --- a/tests/ui/underscore-imports/issue-110164.stderr +++ b/tests/ui/underscore-imports/issue-110164.ed2015.stderr @@ -1,59 +1,59 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/issue-110164.rs:5:5 + --> $DIR/issue-110164.rs:8:5 | LL | use _::a; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/issue-110164.rs:8:5 + --> $DIR/issue-110164.rs:11:5 | LL | use _::*; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/issue-110164.rs:13:9 + --> $DIR/issue-110164.rs:16:9 | LL | use _::a; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/issue-110164.rs:16:9 + --> $DIR/issue-110164.rs:19:9 | LL | use _::*; | ^ expected identifier, found reserved identifier error[E0432]: unresolved import `self::*` - --> $DIR/issue-110164.rs:1:5 + --> $DIR/issue-110164.rs:4:5 | LL | use self::*; | ^^^^^^^ cannot glob-import a module into itself error[E0432]: unresolved import `crate::*` - --> $DIR/issue-110164.rs:3:5 + --> $DIR/issue-110164.rs:6:5 | LL | use crate::*; | ^^^^^^^^ cannot glob-import a module into itself error[E0432]: unresolved import `_` - --> $DIR/issue-110164.rs:8:5 + --> $DIR/issue-110164.rs:11:5 | LL | use _::*; | ^ `_` is not a valid crate or module name error[E0432]: unresolved import `_` - --> $DIR/issue-110164.rs:5:5 + --> $DIR/issue-110164.rs:8:5 | LL | use _::a; | ^ `_` is not a valid crate or module name error[E0432]: unresolved import `_` - --> $DIR/issue-110164.rs:13:9 + --> $DIR/issue-110164.rs:16:9 | LL | use _::a; | ^ `_` is not a valid crate or module name error[E0432]: unresolved import `_` - --> $DIR/issue-110164.rs:16:9 + --> $DIR/issue-110164.rs:19:9 | LL | use _::*; | ^ `_` is not a valid crate or module name diff --git a/tests/ui/underscore-imports/issue-110164.ed2021.stderr b/tests/ui/underscore-imports/issue-110164.ed2021.stderr new file mode 100644 index 000000000000..fab502760ad7 --- /dev/null +++ b/tests/ui/underscore-imports/issue-110164.ed2021.stderr @@ -0,0 +1,71 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:8:5 + | +LL | use _::a; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:11:5 + | +LL | use _::*; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:16:9 + | +LL | use _::a; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:19:9 + | +LL | use _::*; + | ^ expected identifier, found reserved identifier + +error[E0432]: unresolved import `self::*` + --> $DIR/issue-110164.rs:4:5 + | +LL | use self::*; + | ^^^^^^^ cannot glob-import a module into itself + +error[E0432]: unresolved import `crate::*` + --> $DIR/issue-110164.rs:6:5 + | +LL | use crate::*; + | ^^^^^^^^ cannot glob-import a module into itself + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:11:5 + | +LL | use _::*; + | ^ use of unresolved module or unlinked crate `_` + | + = help: you might be missing a crate named `_` + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:8:5 + | +LL | use _::a; + | ^ use of unresolved module or unlinked crate `_` + | + = help: you might be missing a crate named `_` + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:16:9 + | +LL | use _::a; + | ^ use of unresolved module or unlinked crate `_` + | + = help: you might be missing a crate named `_` + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:19:9 + | +LL | use _::*; + | ^ use of unresolved module or unlinked crate `_` + | + = help: you might be missing a crate named `_` + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/underscore-imports/issue-110164.rs b/tests/ui/underscore-imports/issue-110164.rs index 6fd13414500d..59ab0e1d588f 100644 --- a/tests/ui/underscore-imports/issue-110164.rs +++ b/tests/ui/underscore-imports/issue-110164.rs @@ -1,3 +1,6 @@ +//@ revisions: ed2015 ed2021 +//@[ed2015] edition: 2015 +//@[ed2021] edition: 2021 use self::*; //~^ ERROR unresolved import `self::*` use crate::*; From 045faa8c5c27e0506b1dfdd3cc06840f0a059513 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sun, 15 Jun 2025 16:50:37 +0300 Subject: [PATCH 204/356] Port `#[may_dangle]` to the new attribute system --- .../src/attributes.rs | 5 +++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/semantics.rs | 19 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 ++ compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 8 +++++--- 6 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/semantics.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 65061059a02e..b2c4b53f94fe 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -230,8 +230,13 @@ pub enum AttributeKind { /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), + + /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html). + MayDangle(Span), + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), + /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 3bb4c163d326..ff816faa033f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -34,6 +34,7 @@ pub(crate) mod deprecation; pub(crate) mod inline; pub(crate) mod lint_helpers; pub(crate) mod repr; +pub(crate) mod semantics; pub(crate) mod stability; pub(crate) mod transparency; pub(crate) mod util; diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs new file mode 100644 index 000000000000..071574a5612a --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -0,0 +1,19 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct MayDangleParser; +impl SingleAttributeParser for MayDangleParser { + const PATH: &[Symbol] = &[sym::may_dangle]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { + Some(AttributeKind::MayDangle(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1708fd72e588..60b70ff9aba8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -21,6 +21,7 @@ use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::lint_helpers::AsPtrParser; use crate::attributes::repr::{AlignParser, ReprParser}; +use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; @@ -109,6 +110,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 556f50a85af7..1a526d5bce0b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1302,6 +1302,7 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, + Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a5d2ad4dc205..ca6f62294a2e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -161,6 +161,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) } + &Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { + self.check_may_dangle(hir_id, attr_span) + } Attribute::Unparsed(_) => { match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend, ..] => { @@ -234,7 +237,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), - [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr), [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), [sym::rustc_allow_incoherent_impl, ..] => { self.check_allow_incoherent_impl(attr, span, target) @@ -1616,7 +1618,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. - fn check_may_dangle(&self, hir_id: HirId, attr: &Attribute) { + fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) { if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id) && matches!( param.kind, @@ -1633,7 +1635,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } - self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span() }); + self.dcx().emit_err(errors::InvalidMayDangle { attr_span }); } /// Checks if `#[cold]` is applied to a non-function. From 26a6b557172a7186c140c7aa42bf3873802a39fd Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 20 Jun 2025 12:18:37 -0500 Subject: [PATCH 205/356] Recover from semicolon field separator --- compiler/rustc_parse/src/parser/item.rs | 33 ++++++++++--------- tests/ui/parser/recover/recover-field-semi.rs | 6 ++-- .../parser/recover/recover-field-semi.stderr | 12 +++---- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 28da287fcc2d..5088caa80f88 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1781,7 +1781,7 @@ impl<'a> Parser<'a> { let mut recovered = Recovered::No; if self.eat(exp!(OpenBrace)) { while self.token != token::CloseBrace { - match self.parse_field_def(adt_ty) { + match self.parse_field_def(adt_ty, ident_span) { Ok(field) => { fields.push(field); } @@ -1894,7 +1894,7 @@ impl<'a> Parser<'a> { } /// Parses an element of a struct declaration. - fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> { + fn parse_field_def(&mut self, adt_ty: &str, ident_span: Span) -> PResult<'a, FieldDef> { self.recover_vcs_conflict_marker(); let attrs = self.parse_outer_attributes()?; self.recover_vcs_conflict_marker(); @@ -1902,7 +1902,7 @@ impl<'a> Parser<'a> { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; let safety = this.parse_unsafe_field(); - this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs) + this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs, ident_span) .map(|field| (field, Trailing::No, UsePreAttrPos::No)) }) } @@ -1915,24 +1915,27 @@ impl<'a> Parser<'a> { vis: Visibility, safety: Safety, attrs: AttrVec, + ident_span: Span, ) -> PResult<'a, FieldDef> { let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?; - if self.eat(exp!(Semi)) { - let sp = self.prev_token.span; - let mut err = - self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`")); - err.span_suggestion_short( - sp, - "replace `;` with `,`", - ",", - Applicability::MachineApplicable, - ); - return Err(err); - } match self.token.kind { token::Comma => { self.bump(); } + token::Semi => { + self.bump(); + let sp = self.prev_token.span; + let mut err = + self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`")); + err.span_suggestion_short( + sp, + "replace `;` with `,`", + ",", + Applicability::MachineApplicable, + ); + err.span_label(ident_span, format!("while parsing this {adt_ty}")); + err.emit(); + } token::CloseBrace => {} token::DocComment(..) => { let previous_span = self.prev_token.span; diff --git a/tests/ui/parser/recover/recover-field-semi.rs b/tests/ui/parser/recover/recover-field-semi.rs index b703578860ec..b6f235f8ad1c 100644 --- a/tests/ui/parser/recover/recover-field-semi.rs +++ b/tests/ui/parser/recover/recover-field-semi.rs @@ -3,7 +3,7 @@ struct Foo { //~^ ERROR struct fields are separated by `,` } -union Bar { //~ ERROR +union Bar { foo: i32; //~^ ERROR union fields are separated by `,` } @@ -13,4 +13,6 @@ enum Baz { //~^ ERROR struct fields are separated by `,` } -fn main() {} +fn main() { + let _ = Foo { foo: "" }; //~ ERROR mismatched types +} diff --git a/tests/ui/parser/recover/recover-field-semi.stderr b/tests/ui/parser/recover/recover-field-semi.stderr index 3cf4847488c0..9b1a34e134b6 100644 --- a/tests/ui/parser/recover/recover-field-semi.stderr +++ b/tests/ui/parser/recover/recover-field-semi.stderr @@ -22,14 +22,12 @@ LL | Qux { foo: i32; } | | | while parsing this struct -error: unions cannot have zero fields - --> $DIR/recover-field-semi.rs:6:1 +error[E0308]: mismatched types + --> $DIR/recover-field-semi.rs:17:24 | -LL | / union Bar { -LL | | foo: i32; -LL | | -LL | | } - | |_^ +LL | let _ = Foo { foo: "" }; + | ^^ expected `i32`, found `&str` error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0308`. From cbef8f6e0745e7ee5bcd91a482a3152a2b1dd23b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 13 Jun 2025 12:51:07 -0700 Subject: [PATCH 206/356] Add AST pretty-printer tests involving attr on binary operation This test currently fails (as expected). --- stderr ------------------------------- Pretty-printer lost necessary parentheses BEFORE: #[attr] (1 + 1) AFTER: #[attr] 1 + 1 Pretty-printer lost necessary parentheses BEFORE: #[attr] (1 as T) AFTER: #[attr] 1 as T Pretty-printer lost necessary parentheses BEFORE: #[attr] (x = 1) AFTER: #[attr] x = 1 Pretty-printer lost necessary parentheses BEFORE: #[attr] (x += 1) AFTER: #[attr] x += 1 ------------------------------------------ --- tests/ui-fulldeps/pprust-parenthesis-insertion.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index 6ac079ae4342..346b8ed5fda7 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -92,6 +92,15 @@ static EXPRS: &[&str] = &[ "#[attr] loop {}.field", "(#[attr] loop {}).field", "loop { #![attr] }.field", + // Attributes on a Binary, Cast, Assign, AssignOp, and Range expression + // require parentheses. Without parentheses `#[attr] lo..hi` means + // `(#[attr] lo)..hi`, and `#[attr] ..hi` is invalid syntax. + "#[attr] (1 + 1)", + "#[attr] (1 as T)", + "#[attr] (x = 1)", + "#[attr] (x += 1)", + "#[attr] (lo..hi)", + "#[attr] (..hi)", // Grammar restriction: break value starting with a labeled loop is not // allowed, except if the break is also labeled. "break 'outer 'inner: loop {} + 2", From 12a855d2c8420032700c5e3df32d07e0e12d3647 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 13 Jun 2025 13:00:46 -0700 Subject: [PATCH 207/356] Insert parentheses around binary operation with attribute --- .../rustc_ast_pretty/src/pprust/state/expr.rs | 50 ++++++++++++++----- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ee49246a4bbf..f6b5ff404db6 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -386,18 +386,44 @@ impl<'a> State<'a> { let ib = self.ibox(INDENT_UNIT); - // The Match subexpression in `match x {} - 1` must be parenthesized if - // it is the leftmost subexpression in a statement: - // - // (match x {}) - 1; - // - // But not otherwise: - // - // let _ = match x {} - 1; - // - // Same applies to a small set of other expression kinds which eagerly - // terminate a statement which opens with them. - let needs_par = fixup.would_cause_statement_boundary(expr); + let needs_par = { + // The Match subexpression in `match x {} - 1` must be parenthesized + // if it is the leftmost subexpression in a statement: + // + // (match x {}) - 1; + // + // But not otherwise: + // + // let _ = match x {} - 1; + // + // Same applies to a small set of other expression kinds which + // eagerly terminate a statement which opens with them. + fixup.would_cause_statement_boundary(expr) + } || { + // If a binary operation ends up with an attribute, such as + // resulting from the following macro expansion, then parentheses + // are required so that the attribute encompasses the right + // subexpression and not just the left one. + // + // #![feature(stmt_expr_attributes)] + // + // macro_rules! add_attr { + // ($e:expr) => { #[attr] $e }; + // } + // + // let _ = add_attr!(1 + 1); + // + // We must pretty-print `#[attr] (1 + 1)` not `#[attr] 1 + 1`. + !attrs.is_empty() + && matches!( + expr.kind, + ast::ExprKind::Binary(..) + | ast::ExprKind::Cast(..) + | ast::ExprKind::Assign(..) + | ast::ExprKind::AssignOp(..) + | ast::ExprKind::Range(..) + ) + }; if needs_par { self.popen(); fixup = FixupContext::default(); From 535e11f72e0c2460fac74aa0625b47fb0ff43ec6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 13 Jun 2025 13:26:24 -0700 Subject: [PATCH 208/356] Add an attribute-related parenthesization edge case --- tests/ui-fulldeps/pprust-parenthesis-insertion.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index 346b8ed5fda7..72b5cfb90630 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -101,6 +101,12 @@ static EXPRS: &[&str] = &[ "#[attr] (x += 1)", "#[attr] (lo..hi)", "#[attr] (..hi)", + // If the attribute were not present on the binary operation, it would be + // legal to render this without not just the inner parentheses, but also the + // outer ones. `return x + .. .field` (Yes, really.) Currently the + // pretty-printer does not take advantage of this edge case. + "(return #[attr] (x + ..)).field", + "(return x + ..).field", // Grammar restriction: break value starting with a labeled loop is not // allowed, except if the break is also labeled. "break 'outer 'inner: loop {} + 2", From a759f05a71fa9faf79087f8621865462aa166a48 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 20 Jun 2025 16:17:31 -0500 Subject: [PATCH 209/356] configure.py: fix edge case --- src/bootstrap/configure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index ce9290620cb5..c077555b9069 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -591,7 +591,7 @@ def parse_example_config(known_args, config): with open(rust_dir + "/bootstrap.example.toml") as example_config: example_lines = example_config.read().split("\n") for line in example_lines: - if line.count("=") == 1 and not line.startswith("# "): + if line.count("=") >= 1 and not line.startswith("# "): key = line.split("=")[0] key = key.strip(" #") parts = key.split(".") From 2b5fd9a3074d0ac5f9e07d135e2cb9d83f270da7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 14 Jun 2025 22:01:12 +1000 Subject: [PATCH 210/356] rustdoc_json: Add static asserts for the size of important types. A lot of these are large! Lots of room for improvement in the future. --- src/librustdoc/json/mod.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 61493c1ed702..f5064ae55b81 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -377,3 +377,33 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { } } } + +// Some nodes are used a lot. Make sure they don't unintentionally get bigger. +// +// These assertions are here, not in `src/rustdoc-json-types/lib.rs` where the types are defined, +// because we have access to `static_assert_size` here. +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use rustc_data_structures::static_assert_size; + + use super::types::*; + // tidy-alphabetical-start + static_assert_size!(AssocItemConstraint, 208); + static_assert_size!(Crate, 184); + static_assert_size!(ExternalCrate, 48); + static_assert_size!(FunctionPointer, 168); + static_assert_size!(GenericArg, 80); + static_assert_size!(GenericArgs, 104); + static_assert_size!(GenericBound, 72); + static_assert_size!(GenericParamDef, 136); + static_assert_size!(Impl, 304); + // `Item` contains a `PathBuf`, which is different sizes on different OSes. + static_assert_size!(Item, 528 + size_of::()); + static_assert_size!(ItemSummary, 32); + static_assert_size!(PolyTrait, 64); + static_assert_size!(PreciseCapturingArg, 32); + static_assert_size!(TargetFeature, 80); + static_assert_size!(Type, 80); + static_assert_size!(WherePredicate, 160); + // tidy-alphabetical-end +} From 18d742bda07d6f5d047c249cdd533c0e462b3298 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 16 Jun 2025 09:52:23 +1000 Subject: [PATCH 211/356] rustdoc_json: Add a test for some `GenericArgs` cases. --- tests/rustdoc-json/generic-args.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/rustdoc-json/generic-args.rs diff --git a/tests/rustdoc-json/generic-args.rs b/tests/rustdoc-json/generic-args.rs new file mode 100644 index 000000000000..e48c3329f56b --- /dev/null +++ b/tests/rustdoc-json/generic-args.rs @@ -0,0 +1,20 @@ +pub struct MyStruct(u32); + +pub trait MyTrait { + type MyType; + fn my_fn(&self); +} + +impl MyTrait for MyStruct { + type MyType = u32; + fn my_fn(&self) {} +} + +//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}} +//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}} +pub fn my_fn1(_: ::MyType) {} + +//@ is "$.index[?(@.name=='my_fn2')].inner.function.sig.inputs[0][1].dyn_trait.traits[0].trait.args.angle_bracketed.constraints[0].args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}} +pub fn my_fn2(_: IntoIterator) {} + +fn main() {} From 40ba7913fc229ff2d17824fadc3b7c66a931f040 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 14 Jun 2025 20:14:51 +1000 Subject: [PATCH 212/356] rustdoc_json: Fix handling of paths with no generic args. A path without generic args, like `Reader`, currently has JSON produced like this: ``` {"path":"Reader","id":286,"args":{"angle_bracketed":{"args":[],"constraints":[]}}} ``` Even though `types::Path::args` is `Option` and allows for "no args", instead it gets represented as "empty args". (More like `Reader<>` than `Reader`.) This is due to a problem in `clean::Path::from_clean`. It only produces `None` if the path is an empty string. This commit changes it to also produce `None` if there are no generic args. The example above becomes: ``` {"path":"Reader","id":286,"args":null} ``` I looked at a few examples and saw this reduce the size of the JSON output by 3-9%. The commit also adds an assertion that non-final segments don't have any generics; something the old code was implicitly relying on. Note: the original sin here is that `clean::PathSegment::args` is not an `Option`, unlike `{ast,hir}::PathSegment::args`. I want to fix that, but it can be done separately. --- src/librustdoc/json/conversions.rs | 19 ++++++++++++++++++- tests/rustdoc-json/generic-args.rs | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 8b4be107ace6..4719bd5d1182 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -579,7 +579,24 @@ impl FromClean for Path { Path { path: path.whole_name(), id: renderer.id_from_item_default(path.def_id().into()), - args: path.segments.last().map(|args| Box::new(args.args.into_json(renderer))), + args: { + if let Some((final_seg, rest_segs)) = path.segments.split_last() { + // In general, `clean::Path` can hold things like + // `std::vec::Vec::::new`, where generic args appear + // in a middle segment. But for the places where `Path` is + // used by rustdoc-json-types, generic args can only be + // used in the final segment, e.g. `std::vec::Vec`. So + // check that the non-final segments have no generic args. + assert!(rest_segs.iter().all(|seg| seg.args.is_empty())); + if final_seg.args.is_empty() { + None + } else { + Some(Box::new(final_seg.args.into_json(renderer))) + } + } else { + None // no generics on any segments because there are no segments + } + }, } } } diff --git a/tests/rustdoc-json/generic-args.rs b/tests/rustdoc-json/generic-args.rs index e48c3329f56b..e87c1e623043 100644 --- a/tests/rustdoc-json/generic-args.rs +++ b/tests/rustdoc-json/generic-args.rs @@ -11,7 +11,7 @@ impl MyTrait for MyStruct { } //@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}} -//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}} +//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args" null pub fn my_fn1(_: ::MyType) {} //@ is "$.index[?(@.name=='my_fn2')].inner.function.sig.inputs[0][1].dyn_trait.traits[0].trait.args.angle_bracketed.constraints[0].args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}} From 59a3399148d02d412485999dee78c0e72a54c0a5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 14 Jun 2025 20:22:30 +1000 Subject: [PATCH 213/356] Fix some comments. As per the previous commit, generic args here can only appear on the final segment. So make the comments obey that constraint. --- src/rustdoc-json-types/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 4d25124f9f2b..0404f3ff0341 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -277,8 +277,8 @@ pub struct PolyTrait { /// A set of generic arguments provided to a path segment, e.g. /// /// ```text -/// std::option::Option::::None -/// ^^^^^ +/// std::option::Option +/// ^^^^^ /// ``` #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] @@ -331,7 +331,7 @@ pub enum GenericArg { Const(Constant), /// A generic argument that's explicitly set to be inferred. /// ```text - /// std::vec::Vec::<_>::new() + /// std::vec::Vec::<_> /// ^ /// ``` Infer, From 7fa8901cd090093a57723d3f196c27db3b98ad94 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 14 Jun 2025 21:39:09 +1000 Subject: [PATCH 214/356] rustdoc_json: represent generic args consistently. They show up in three places: once as `Option>`, once as `Box`, and once as `GenericArgs`. The first option is best. It is more compact because generic args are often missing. This commit changes the latter two to the former. Example output, before and after, for the `AssocItemConstraint` change: ``` {"name":"Offset","args":{"angle_bracketed":{"args":[],"constraints":[]}},"binding":{...}} {"name":"Offset","args":null,"binding":{...}} ``` Example output, before and after, for the `Type::QualifiedPath` change: ``` {"qualified_path":{"name":"Offset","args":{"angle_bracketed":{"args":[],"constraints":[]}}, ...}} {"qualified_path":{"name":"Offset","args":null, ...}} ``` This reduces JSON output size, but not by much (e.g. 0.5%), because `AssocItemConstraint` and `Type::QualifiedPath` are uncommon. --- src/librustdoc/json/conversions.rs | 17 ++++++++--------- src/librustdoc/json/mod.rs | 2 +- src/rustdoc-json-types/lib.rs | 8 ++++---- src/tools/jsondoclint/src/validator.rs | 13 ++++++------- tests/rustdoc-json/generic-args.rs | 4 ++-- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 4719bd5d1182..cb4c1f7fbc06 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -169,10 +169,13 @@ pub(crate) fn from_deprecation(deprecation: attrs::Deprecation) -> Deprecation { Deprecation { since, note: note.map(|s| s.to_string()) } } -impl FromClean for GenericArgs { +impl FromClean for Option> { fn from_clean(args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericArgs::*; - match args { + if args.is_empty() { + return None; + } + Some(Box::new(match args { AngleBracketed { args, constraints } => GenericArgs::AngleBracketed { args: args.into_json(renderer), constraints: constraints.into_json(renderer), @@ -182,7 +185,7 @@ impl FromClean for GenericArgs { output: output.as_ref().map(|a| a.as_ref().into_json(renderer)), }, ReturnTypeNotation => GenericArgs::ReturnTypeNotation, - } + })) } } @@ -588,11 +591,7 @@ impl FromClean for Path { // used in the final segment, e.g. `std::vec::Vec`. So // check that the non-final segments have no generic args. assert!(rest_segs.iter().all(|seg| seg.args.is_empty())); - if final_seg.args.is_empty() { - None - } else { - Some(Box::new(final_seg.args.into_json(renderer))) - } + final_seg.args.into_json(renderer) } else { None // no generics on any segments because there are no segments } @@ -607,7 +606,7 @@ impl FromClean for Type { Self::QualifiedPath { name: assoc.name.to_string(), - args: Box::new(assoc.args.into_json(renderer)), + args: assoc.args.into_json(renderer), self_type: Box::new(self_type.into_json(renderer)), trait_: trait_.as_ref().map(|trait_| trait_.into_json(renderer)), } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index f5064ae55b81..600a4b429f3c 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -388,7 +388,7 @@ mod size_asserts { use super::types::*; // tidy-alphabetical-start - static_assert_size!(AssocItemConstraint, 208); + static_assert_size!(AssocItemConstraint, 112); static_assert_size!(Crate, 184); static_assert_size!(ExternalCrate, 48); static_assert_size!(FunctionPointer, 168); diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 0404f3ff0341..c9b4da183a3a 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Pretty printing of cold attributes changed -pub const FORMAT_VERSION: u32 = 50; +// Latest feature: improve handling of generic args +pub const FORMAT_VERSION: u32 = 51; /// The root of the emitted JSON blob. /// @@ -362,7 +362,7 @@ pub struct AssocItemConstraint { /// The name of the associated type/constant. pub name: String, /// Arguments provided to the associated type/constant. - pub args: GenericArgs, + pub args: Option>, /// The kind of bound applied to the associated type/constant. pub binding: AssocItemConstraintKind, } @@ -1118,7 +1118,7 @@ pub enum Type { /// as BetterIterator>::Item<'static> /// // ^^^^^^^^^ /// ``` - args: Box, + args: Option>, /// The type with which this type is associated. /// /// ```ignore (incomplete expression) diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 8c9e4c8bb3a6..0a4051fcbe8c 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -271,7 +271,7 @@ impl<'a> Validator<'a> { Type::RawPointer { is_mutable: _, type_ } => self.check_type(&**type_), Type::BorrowedRef { lifetime: _, is_mutable: _, type_ } => self.check_type(&**type_), Type::QualifiedPath { name: _, args, self_type, trait_ } => { - self.check_generic_args(&**args); + self.check_opt_generic_args(&args); self.check_type(&**self_type); if let Some(trait_) = trait_ { self.check_path(trait_, PathKind::Trait); @@ -309,13 +309,12 @@ impl<'a> Validator<'a> { self.fail(&x.id, ErrorKind::Custom(format!("No entry in '$.paths' for {x:?}"))); } - if let Some(args) = &x.args { - self.check_generic_args(&**args); - } + self.check_opt_generic_args(&x.args); } - fn check_generic_args(&mut self, x: &'a GenericArgs) { - match x { + fn check_opt_generic_args(&mut self, x: &'a Option>) { + let Some(x) = x else { return }; + match &**x { GenericArgs::AngleBracketed { args, constraints } => { args.iter().for_each(|arg| self.check_generic_arg(arg)); constraints.iter().for_each(|bind| self.check_assoc_item_constraint(bind)); @@ -355,7 +354,7 @@ impl<'a> Validator<'a> { } fn check_assoc_item_constraint(&mut self, bind: &'a AssocItemConstraint) { - self.check_generic_args(&bind.args); + self.check_opt_generic_args(&bind.args); match &bind.binding { AssocItemConstraintKind::Equality(term) => self.check_term(term), AssocItemConstraintKind::Constraint(bounds) => { diff --git a/tests/rustdoc-json/generic-args.rs b/tests/rustdoc-json/generic-args.rs index e87c1e623043..0f588820da75 100644 --- a/tests/rustdoc-json/generic-args.rs +++ b/tests/rustdoc-json/generic-args.rs @@ -10,11 +10,11 @@ impl MyTrait for MyStruct { fn my_fn(&self) {} } -//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}} +//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.args" null //@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args" null pub fn my_fn1(_: ::MyType) {} -//@ is "$.index[?(@.name=='my_fn2')].inner.function.sig.inputs[0][1].dyn_trait.traits[0].trait.args.angle_bracketed.constraints[0].args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}} +//@ is "$.index[?(@.name=='my_fn2')].inner.function.sig.inputs[0][1].dyn_trait.traits[0].trait.args.angle_bracketed.constraints[0].args" null pub fn my_fn2(_: IntoIterator) {} fn main() {} From 8329c93bd42fe49f446a82da1f872d288f08d079 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Thu, 19 Jun 2025 22:56:50 +0900 Subject: [PATCH 215/356] internal: Utilize `cargo check --compile-time-deps` --- .../project-model/src/build_dependencies.rs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs index e0c38ccf3331..4435376eab62 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs @@ -20,7 +20,9 @@ use toolchain::Tool; use crate::{ CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot, - TargetKind, utf8_stdout, + TargetKind, + toolchain_info::{QueryConfig, version}, + utf8_stdout, }; /// Output of the build script and proc-macro building steps for a workspace. @@ -446,10 +448,30 @@ impl WorkspaceBuildScripts { } }; - if config.wrap_rustc_in_build_scripts { + // If [`--compile-time-deps` flag](https://github.com/rust-lang/cargo/issues/14434) is + // available in current toolchain's cargo, use it to build compile time deps only. + const COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION: semver::Version = semver::Version { + major: 1, + minor: 90, + patch: 0, + pre: semver::Prerelease::EMPTY, + build: semver::BuildMetadata::EMPTY, + }; + + let query_config = QueryConfig::Cargo(sysroot, manifest_path); + let toolchain = version::get(query_config, &config.extra_env).ok().flatten(); + let cargo_comp_time_deps_available = + toolchain.is_some_and(|v| v >= COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION); + + if cargo_comp_time_deps_available { + cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly"); + cmd.arg("-Zunstable-options"); + cmd.arg("--compile-time-deps"); + } else if config.wrap_rustc_in_build_scripts { // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use // that to compile only proc macros and build scripts during the initial // `cargo check`. + // We don't need this if we are using `--compile-time-deps` flag. let myself = std::env::current_exe()?; cmd.env("RUSTC_WRAPPER", myself); cmd.env("RA_RUSTC_WRAPPER", "1"); From 29a8b831b1a2151d67ab7dbfd018349f37303128 Mon Sep 17 00:00:00 2001 From: Zakaria Elkatani Date: Sat, 21 Jun 2025 01:48:55 -0400 Subject: [PATCH 216/356] fix: Correct grammar in remove all unused imports assist --- .../crates/ide-assists/src/handlers/remove_unused_imports.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index 16debc4d7285..c38bdfdccf5b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -117,7 +117,7 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) if unused.peek().is_some() { acc.add( AssistId::quick_fix("remove_unused_imports"), - "Remove all the unused imports", + "Remove all unused imports", selected_el.text_range(), |builder| { let unused: Vec = unused.map(|x| builder.make_mut(x)).collect(); From 8b882651330b08bb5c99be5d10d92d21422dad7c Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 21 Jun 2025 11:39:28 +0200 Subject: [PATCH 217/356] Lazily collect `NonUpperCaseGlobalSubTool` diagnostics --- compiler/rustc_lint/src/nonstandard_style.rs | 38 ++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index e92e8e063829..0cb3dac24823 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,6 +1,7 @@ use rustc_abi::ExternAbi; use rustc_attr_data_structures::{AttributeKind, ReprAttr}; use rustc_attr_parsing::AttributeParser; +use rustc_errors::LintDiagnostic; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; @@ -529,25 +530,26 @@ impl NonUpperCaseGlobals { } } - let usages = if let Some(did) = did - && *name != uc - { - let mut usage_collector = UsageCollector { cx, did, collected: Vec::new() }; - cx.tcx.hir_walk_toplevel_module(&mut usage_collector); - usage_collector - .collected - .into_iter() - .map(|span| NonUpperCaseGlobalSubTool { span, replace: uc.clone() }) - .collect() - } else { - vec![] - }; + #[allow(rustc::diagnostic_outside_of_impl)] + cx.opt_span_lint(NON_UPPER_CASE_GLOBALS, ident.span.into(), |diag| { + // Compute usages lazily as it can expansive and useless when the lint is allowed. + // cf. https://github.com/rust-lang/rust/pull/142645#issuecomment-2993024625 + let usages = if let Some(did) = did + && *name != uc + { + let mut usage_collector = UsageCollector { cx, did, collected: Vec::new() }; + cx.tcx.hir_walk_toplevel_module(&mut usage_collector); + usage_collector + .collected + .into_iter() + .map(|span| NonUpperCaseGlobalSubTool { span, replace: uc.clone() }) + .collect() + } else { + vec![] + }; - cx.emit_span_lint( - NON_UPPER_CASE_GLOBALS, - ident.span, - NonUpperCaseGlobal { sort, name, sub, usages }, - ); + NonUpperCaseGlobal { sort, name, sub, usages }.decorate_lint(diag) + }); } } } From 1b5ec3fa1d81c1e469e5bc1c29fa2bc0452697c3 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 21 Jun 2025 13:40:05 +0200 Subject: [PATCH 218/356] Add `emit_span_lint_lazy` to lazily create `LintDiagnostic` structs --- compiler/rustc_lint/src/context.rs | 14 ++++++++++++++ compiler/rustc_lint/src/nonstandard_style.rs | 6 ++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b6bf45dfbcfb..8a0f50e0219b 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -524,6 +524,20 @@ pub trait LintContext { }); } + /// Emit a lint at `span` from a lazily-constructed lint struct (some type that implements + /// `LintDiagnostic`, typically generated by `#[derive(LintDiagnostic)]`). + fn emit_span_lint_lazy, L: for<'a> LintDiagnostic<'a, ()>>( + &self, + lint: &'static Lint, + span: S, + decorator: impl FnOnce() -> L, + ) { + self.opt_span_lint(lint, Some(span), |lint| { + let decorator = decorator(); + decorator.decorate_lint(lint); + }); + } + /// Emit a lint at the appropriate level, with an associated span. /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 0cb3dac24823..c325b7a95c9b 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,7 +1,6 @@ use rustc_abi::ExternAbi; use rustc_attr_data_structures::{AttributeKind, ReprAttr}; use rustc_attr_parsing::AttributeParser; -use rustc_errors::LintDiagnostic; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; @@ -530,8 +529,7 @@ impl NonUpperCaseGlobals { } } - #[allow(rustc::diagnostic_outside_of_impl)] - cx.opt_span_lint(NON_UPPER_CASE_GLOBALS, ident.span.into(), |diag| { + cx.emit_span_lint_lazy(NON_UPPER_CASE_GLOBALS, ident.span, || { // Compute usages lazily as it can expansive and useless when the lint is allowed. // cf. https://github.com/rust-lang/rust/pull/142645#issuecomment-2993024625 let usages = if let Some(did) = did @@ -548,7 +546,7 @@ impl NonUpperCaseGlobals { vec![] }; - NonUpperCaseGlobal { sort, name, sub, usages }.decorate_lint(diag) + NonUpperCaseGlobal { sort, name, sub, usages } }); } } From cddf2589d9bde633a600aa5111c7f7317a2b0813 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 21 Jun 2025 11:15:00 -0400 Subject: [PATCH 219/356] 1.88.0 release notes --- RELEASES.md | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 3c72cb1de0a3..fd47317c7546 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,103 @@ +Version 1.88.0 (2025-06-26) +========================== + + + +Language +-------- +- [Stabilize `#![feature(let_chains)]` in the 2024 edition.](https://github.com/rust-lang/rust/pull/132833) + This feature allows `&&`-chaining `let` statements inside `if` and `while`, allowing intermixture with boolean expressions. The patterns inside the `let` sub-expressions can be irrefutable or refutable. +- [Stabilize `#![feature(naked_functions)]`.](https://github.com/rust-lang/rust/pull/134213) + Naked functions allow writing functions with no compiler-generated epilogue and prologue, allowing full control over the generated assembly for a particular function. +- [Stabilize `#![feature(cfg_boolean_literals)]`.](https://github.com/rust-lang/rust/pull/138632) + This allows using boolean literals as `cfg` predicates, e.g. `#[cfg(true)]` and `#[cfg(false)]`. +- [Fully de-stabilize the `#[bench]` attribute](https://github.com/rust-lang/rust/pull/134273). Usage of `#[bench]` without `#![feature(custom_test_frameworks)]` already triggered a deny-by-default future-incompatibility lint since Rust 1.77, but will now become a hard error. +- [Add warn-by-default `dangerous_implicit_autorefs` lint against implicit autoref of raw pointer dereference.](https://github.com/rust-lang/rust/pull/123239) + The lint [may be bumped to deny-by-default](https://github.com/rust-lang/rust/pull/141661) in a future version of Rust. +- [Add `invalid_null_arguments` lint to prevent invalid usage of null pointers.](https://github.com/rust-lang/rust/pull/119220) + This lint is uplifted from `clippy::invalid_null_ptr_usage`. +- [Change trait impl candidate preference for builtin impls and trivial where-clauses.](https://github.com/rust-lang/rust/pull/138176) +- [Check types of generic const parameter defaults](https://github.com/rust-lang/rust/pull/139646) + + + +Compiler +-------- +- [Stabilize `-Cdwarf-version` for selecting the version of DWARF debug information to generate.](https://github.com/rust-lang/rust/pull/136926) + + + + +Platform Support +---------------- +- [Demote `i686-pc-windows-gnu` to Tier 2.](https://blog.rust-lang.org/2025/05/26/demoting-i686-pc-windows-gnu/) + + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html + + + +Libraries +--------- +- [Remove backticks from `#[should_panic]` test failure message.](https://github.com/rust-lang/rust/pull/136160) +- [Guarantee that `[T; N]::from_fn` is generated in order of increasing indices.](https://github.com/rust-lang/rust/pull/139099), for those passing it a stateful closure. +- [The libtest flag `--nocapture` is deprecated in favor of the more consistent `--no-capture` flag.](https://github.com/rust-lang/rust/pull/139224) +- [Guarantee that `{float}::NAN` is a quiet NaN.](https://github.com/rust-lang/rust/pull/139483) + + + + +Stabilized APIs +--------------- + +- [`Cell::update`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.update) +- [`impl Default for *const T`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#impl-Default-for-*const+T) +- [`impl Default for *mut T`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#impl-Default-for-*mut+T) +- [`HashMap::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html#method.extract_if) +- [`HashSet::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html#method.extract_if) +- [`proc_macro::Span::line`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.line) +- [`proc_macro::Span::column`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.column) +- [`proc_macro::Span::start`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.start) +- [`proc_macro::Span::end`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.end) +- [`proc_macro::Span::file`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.file) +- [`proc_macro::Span::local_file`](https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.local_file) + +These previously stable APIs are now stable in const contexts: + +- [`NonNull::replace`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.replace) +- [`<*mut T>::replace`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.replace) +- [`std::ptr::swap_nonoverlapping`](https://github.com/rust-lang/rust/pull/137280) +- [`Cell::{replace, get, get_mut, from_mut, as_slice_of_cells}`](https://github.com/rust-lang/rust/pull/137928) + + + + +Cargo +----- +- [Stabilize automatic garbage collection.](https://github.com/rust-lang/cargo/pull/14287/) +- [use `zlib-rs` for gzip compression in rust code](https://github.com/rust-lang/cargo/pull/15417/) + + + +Rustdoc +----- +- [Doctests can be ignored based on target names using `ignore-*` attributes.](https://github.com/rust-lang/rust/pull/137096) +- [Stabilize the `--test-runtool` and `--test-runtool-arg` CLI options to specify a program (like qemu) and its arguments to run a doctest.](https://github.com/rust-lang/rust/pull/137096) + + + +Compatibility Notes +------------------- +- [Finish changing the internal representation of pasted tokens](https://github.com/rust-lang/rust/pull/124141). Certain invalid declarative macros that were previously accepted in obscure circumstances are now correctly rejected by the compiler. Use of a `tt` fragment specifier can often fix these macros. +- [Fully de-stabilize the `#[bench]` attribute](https://github.com/rust-lang/rust/pull/134273). Usage of `#[bench]` without `#![feature(custom_test_frameworks)]` already triggered a deny-by-default future-incompatibility lint since Rust 1.77, but will now become a hard error. +- [Fix borrow checking some always-true patterns.](https://github.com/rust-lang/rust/pull/139042) + The borrow checker was overly permissive in some cases, allowing programs that shouldn't have compiled. +- [Update the minimum external LLVM to 19.](https://github.com/rust-lang/rust/pull/139275) +- [Make it a hard error to use a vector type with a non-Rust ABI without enabling the required target feature.](https://github.com/rust-lang/rust/pull/139309) + Version 1.87.0 (2025-05-15) ========================== From 3719abbb33c7925e29a7d5c92a5c33e1ef0cb3ca Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 7 Jun 2025 18:07:43 +0000 Subject: [PATCH 220/356] Update to Cranelift 0.121 --- Cargo.lock | 84 ++++++++++++++++++++++++++++++++---------------------- Cargo.toml | 24 ++++++++-------- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a906bec8b7e2..b893a2be9a2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,42 +43,42 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-assembler-x64" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff8e35182c7372df00447cb90a04e584e032c42b9b9b6e8c50ddaaf0d7900d5" +checksum = "f6f53499803b1607b6ee0ba0de4ba036e6da700c2e489fe8f9d0f683d0b84d31" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14220f9c2698015c3b94dc6b84ae045c1c45509ddc406e43c6139252757fdb7a" +checksum = "1aadaa5bc8430d0e7bb999459369bedd0e5816ad4a82a0e20748341c4e333eda" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d372ef2777ceefd75829e1390211ac240e9196bc60699218f7ea2419038288ee" +checksum = "2005fda2fc52a2dbce58229b4fb4483b70cbc806ba8ecc11b3f050c1a2d26cac" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56323783e423818fa89ce8078e90a3913d2a6e0810399bfce8ebd7ee87baa81f" +checksum = "56935e02452ca1249d39ad5c45a96304d0b4300a158a391fd113451e0cd4483d" [[package]] name = "cranelift-codegen" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ffb780aab6186c6e9ba26519654b1ac55a09c0a866f6088a4efbbd84da68ed" +checksum = "62612786bf00e10999f50217d6f455d02b31591155881a45a903d1a95d1a4043" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -97,13 +97,14 @@ dependencies = [ "serde", "smallvec", "target-lexicon", + "wasmtime-math", ] [[package]] name = "cranelift-codegen-meta" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c23ef13814d3b39c869650d5961128cbbecad83fbdff4e6836a03ecf6862d7ed" +checksum = "07bae789df91ef236079733af9df11d852256c64af196f0bc6471ea0f5f301be" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -112,33 +113,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f623300657679f847803ce80811454bfff89cea4f6bf684be5c468d4a73631" +checksum = "1be319616d36527782558a8312508757815f64deb19b094c7b8f4337229a9bc6" [[package]] name = "cranelift-control" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4168af69989aa6b91fab46799ed4df6096f3209f4a6c8fb4358f49c60188f" +checksum = "8810ee1ab5e9bd5cff4c0c8d240e2009cb5c2b79888fde1d5256d605712314b7" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6fa9bae1c8de26d71ac2162f069447610fd91e7780cb480ee0d76ac81eabb8" +checksum = "086452c97cfbe116bf17dbe622dc5fdf2ea97299c7d4ce42460f284387c9928a" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8219205608aa0b0e6769b580284a7e055c7e0c323c1041cde7ca078add3e412" +checksum = "4c27947010ab759330f252610c17a8cd64d123358be4f33164233d04fcd77b80" dependencies = [ "cranelift-codegen", "log", @@ -148,15 +149,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "588d0c5964f10860b04043e55aab26d7f7a206b0fd4f10c5260e8aa5773832bd" +checksum = "ec67bfb8bd55b1e9760eb9f5186dca8d81bd4d86110f8d5af01154a044c91802" [[package]] name = "cranelift-jit" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56bd917ddc524f84f4066f954062875bdfc0dffea068ee94e906d98de5ac7c33" +checksum = "d67cdfc447f2abdb46bb30a6582cce189539c3c051c1d5330692376e1400edff" dependencies = [ "anyhow", "cranelift-codegen", @@ -174,9 +175,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a03c057d8a992e06596c871341e446af43ff9224f941e5b8adea39137a5391" +checksum = "e4597eaa52bca1ed111986c7a7f70cdbe192f83d271d627201365078e37b7e84" dependencies = [ "anyhow", "cranelift-codegen", @@ -185,9 +186,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed3c94cb97b14f92b6a94a1d45ef8c851f6a2ad9114e5d91d233f7da638fed" +checksum = "75a9b63edea46e013fce459c46e500462cb03a0490fdd9c18fe42b1dd7b93aa1" dependencies = [ "cranelift-codegen", "libc", @@ -196,9 +197,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64dacef362a69375a604f6636e5e9a174fb96dba3b273646fcd9fa85c1d0997" +checksum = "ce706f0166d5b7f31693dff521e87cb9858e12adf22ffcde93c4a2826f8f04a9" dependencies = [ "anyhow", "cranelift-codegen", @@ -211,9 +212,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.120.0" +version = "0.121.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85256fac1519a7d25a040c1d850fba67478f3f021ad5fdf738ba4425ee862dbf" +checksum = "7d5870e266df8237b56cc98b04f5739c228565c92dd629ec6c66efa87271a158" [[package]] name = "crc32fast" @@ -288,6 +289,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "log" version = "0.4.22" @@ -446,9 +453,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "wasmtime-jit-icache-coherence" -version = "33.0.0" +version = "34.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175e924dbc944c185808466d1e90b5a7feb610f3b9abdfe26f8ee25fd1086d1c" +checksum = "2eedc0324e37cf39b049f4dca0c30997eaab49f09006d5f4c1994e64e7b7dba8" dependencies = [ "anyhow", "cfg-if", @@ -456,6 +463,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "wasmtime-math" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd35fae4cf51d2b4a9bd2ef04b0eb309fa1849cab6a6ab5ac27cbd054ea284d" +dependencies = [ + "libm", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 94fcbd0a5023..9066e4dbbb52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.120.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.120.0" } -cranelift-module = { version = "0.120.0" } -cranelift-native = { version = "0.120.0" } -cranelift-jit = { version = "0.120.0", optional = true } -cranelift-object = { version = "0.120.0" } +cranelift-codegen = { version = "0.121.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.121.0" } +cranelift-module = { version = "0.121.0" } +cranelift-native = { version = "0.121.0" } +cranelift-jit = { version = "0.121.0", optional = true } +cranelift-object = { version = "0.121.0" } target-lexicon = "0.13" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-33.0.0", version = "0.120.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-34.0.0", version = "0.121.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } From e51c37c34c3f576a2e1b7b3d5f0bd5d993c87d24 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 20 Jun 2025 11:49:32 -0700 Subject: [PATCH 221/356] Add AttributeExt::doc_resolution_scope --- compiler/rustc_ast/src/attr/mod.rs | 21 +++++++++++++++++++++ compiler/rustc_hir/src/hir.rs | 10 ++++++++++ compiler/rustc_resolve/src/rustdoc.rs | 7 ++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 621e3042b62e..755bd3577ea4 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -206,6 +206,18 @@ impl AttributeExt for Attribute { } } + fn doc_resolution_scope(&self) -> Option { + match &self.kind { + AttrKind::DocComment(..) => Some(self.style), + AttrKind::Normal(normal) + if normal.item.path == sym::doc && normal.item.value_str().is_some() => + { + Some(self.style) + } + _ => None, + } + } + fn style(&self) -> AttrStyle { self.style } @@ -806,6 +818,15 @@ pub trait AttributeExt: Debug { /// * `#[doc(...)]` returns `None`. fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>; + /// Returns outer or inner if this is a doc attribute or a sugared doc + /// comment, otherwise None. + /// + /// This is used in the case of doc comments on modules, to decide whether + /// to resolve intra-doc links against the symbols in scope within the + /// commented module (for inner doc) vs within its parent module (for outer + /// doc). + fn doc_resolution_scope(&self) -> Option; + fn style(&self) -> AttrStyle; } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1a526d5bce0b..883161318d3e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1346,6 +1346,16 @@ impl AttributeExt for Attribute { } } + fn doc_resolution_scope(&self) -> Option { + match self { + Attribute::Parsed(AttributeKind::DocComment { style, .. }) => Some(*style), + Attribute::Unparsed(attr) if self.has_name(sym::doc) && self.value_str().is_some() => { + Some(attr.style) + } + _ => None, + } + } + #[inline] fn style(&self) -> AttrStyle { match &self { diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index fa839d2748d8..931c6241bf21 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -356,7 +356,12 @@ pub fn strip_generics_from_path(path_str: &str) -> Result, MalformedGen /// If there are no doc-comments, return true. /// FIXME(#78591): Support both inner and outer attributes on the same item. pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool { - attrs.iter().find(|a| a.doc_str().is_some()).is_none_or(|a| a.style() == ast::AttrStyle::Inner) + for attr in attrs { + if let Some(attr_style) = attr.doc_resolution_scope() { + return attr_style == ast::AttrStyle::Inner; + } + } + true } /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`. From 86f40acce3ba62845642fb972e5a28191eb27c8a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 20 Jun 2025 11:52:24 -0700 Subject: [PATCH 222/356] Remove style() from AttributeExt trait --- compiler/rustc_ast/src/attr/mod.rs | 14 ++++---------- compiler/rustc_hir/src/hir.rs | 22 ++++++++-------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 755bd3577ea4..44865c493b3b 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -217,13 +217,13 @@ impl AttributeExt for Attribute { _ => None, } } - - fn style(&self) -> AttrStyle { - self.style - } } impl Attribute { + pub fn style(&self) -> AttrStyle { + self.style + } + pub fn may_have_doc_links(&self) -> bool { self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str())) } @@ -826,8 +826,6 @@ pub trait AttributeExt: Debug { /// commented module (for inner doc) vs within its parent module (for outer /// doc). fn doc_resolution_scope(&self) -> Option; - - fn style(&self) -> AttrStyle; } // FIXME(fn_delegation): use function delegation instead of manually forwarding @@ -902,8 +900,4 @@ impl Attribute { pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { AttributeExt::doc_str_and_comment_kind(self) } - - pub fn style(&self) -> AttrStyle { - AttributeExt::style(self) - } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 883161318d3e..73ece05377c4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1207,6 +1207,14 @@ pub enum Attribute { } impl Attribute { + pub fn style(&self) -> AttrStyle { + match &self { + Attribute::Unparsed(u) => u.style, + Attribute::Parsed(AttributeKind::DocComment { style, .. }) => *style, + _ => panic!(), + } + } + pub fn get_normal_item(&self) -> &AttrItem { match &self { Attribute::Unparsed(normal) => &normal, @@ -1355,15 +1363,6 @@ impl AttributeExt for Attribute { _ => None, } } - - #[inline] - fn style(&self) -> AttrStyle { - match &self { - Attribute::Unparsed(u) => u.style, - Attribute::Parsed(AttributeKind::DocComment { style, .. }) => *style, - _ => panic!(), - } - } } // FIXME(fn_delegation): use function delegation instead of manually forwarding @@ -1452,11 +1451,6 @@ impl Attribute { pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { AttributeExt::doc_str_and_comment_kind(self) } - - #[inline] - pub fn style(&self) -> AttrStyle { - AttributeExt::style(self) - } } /// Attributes owned by a HIR owner. From 715e02ff3ce28e330a278db1eb834547b7ab86f2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Jun 2025 16:20:15 -0700 Subject: [PATCH 223/356] Add regression test for issue 142649 --- tests/ui/deprecation/deprecated-expr-precedence.rs | 8 ++++++++ tests/ui/unpretty/deprecated-attr.rs | 5 +++++ tests/ui/unpretty/deprecated-attr.stdout | 9 +++++++++ 3 files changed, 22 insertions(+) create mode 100644 tests/ui/deprecation/deprecated-expr-precedence.rs diff --git a/tests/ui/deprecation/deprecated-expr-precedence.rs b/tests/ui/deprecation/deprecated-expr-precedence.rs new file mode 100644 index 000000000000..9636b46df201 --- /dev/null +++ b/tests/ui/deprecation/deprecated-expr-precedence.rs @@ -0,0 +1,8 @@ +//@ check-fail +//@ compile-flags: --crate-type=lib + +// Regression test for issue 142649 +pub fn public() { + #[deprecated] 0 + //~^ ERROR mismatched types +} diff --git a/tests/ui/unpretty/deprecated-attr.rs b/tests/ui/unpretty/deprecated-attr.rs index 0c80203e9652..e2ab5efb5d87 100644 --- a/tests/ui/unpretty/deprecated-attr.rs +++ b/tests/ui/unpretty/deprecated-attr.rs @@ -16,3 +16,8 @@ pub struct SinceAndNote; #[deprecated(note = "here's why this is deprecated", since = "1.2.3")] pub struct FlippedOrder; + +pub fn f() { + // Attribute is ignored here (with a warning), but still preserved in HIR + #[deprecated] 0 +} diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index 97d863b2e943..a2b645d00d06 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -24,3 +24,12 @@ struct SinceAndNote; #[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), note: "here's why this is deprecated"}}] struct FlippedOrder; + +fn f() { + + // Attribute is ignored here (with a warning), but still preserved in HIR + #[attr = Deprecation {deprecation: + Deprecation {since: + Unspecified}}] + 0 +} From 6729b667ce4b013a5ec6f50b096bde3edabc28e3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 19 Jun 2025 23:56:23 -0700 Subject: [PATCH 224/356] All HIR attributes are outer --- compiler/rustc_hir/src/hir.rs | 21 +---- compiler/rustc_hir_pretty/src/lib.rs | 94 ++++++++----------- compiler/rustc_hir_typeck/src/expr.rs | 9 +- compiler/rustc_lint/src/context.rs | 7 +- compiler/rustc_passes/src/check_attr.rs | 66 +++++++------ .../src/doc/doc_suspicious_footnotes.rs | 13 ++- .../deprecated-expr-precedence.stderr | 11 +++ tests/ui/unpretty/diagnostic-attr.stdout | 4 +- tests/ui/unpretty/exhaustive-asm.hir.stdout | 2 +- tests/ui/unpretty/exhaustive.hir.stdout | 69 ++++++-------- 10 files changed, 140 insertions(+), 156 deletions(-) create mode 100644 tests/ui/deprecation/deprecated-expr-precedence.stderr diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 73ece05377c4..679904c7cfe4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1207,14 +1207,6 @@ pub enum Attribute { } impl Attribute { - pub fn style(&self) -> AttrStyle { - match &self { - Attribute::Unparsed(u) => u.style, - Attribute::Parsed(AttributeKind::DocComment { style, .. }) => *style, - _ => panic!(), - } - } - pub fn get_normal_item(&self) -> &AttrItem { match &self { Attribute::Unparsed(normal) => &normal, @@ -2290,16 +2282,9 @@ pub struct Expr<'hir> { } impl Expr<'_> { - pub fn precedence( - &self, - for_each_attr: &dyn Fn(HirId, &mut dyn FnMut(&Attribute)), - ) -> ExprPrecedence { + pub fn precedence(&self, has_attr: &dyn Fn(HirId) -> bool) -> ExprPrecedence { let prefix_attrs_precedence = || -> ExprPrecedence { - let mut has_outer_attr = false; - for_each_attr(self.hir_id, &mut |attr: &Attribute| { - has_outer_attr |= matches!(attr.style(), AttrStyle::Outer) - }); - if has_outer_attr { ExprPrecedence::Prefix } else { ExprPrecedence::Unambiguous } + if has_attr(self.hir_id) { ExprPrecedence::Prefix } else { ExprPrecedence::Unambiguous } }; match &self.kind { @@ -2355,7 +2340,7 @@ impl Expr<'_> { | ExprKind::Use(..) | ExprKind::Err(_) => prefix_attrs_precedence(), - ExprKind::DropTemps(expr, ..) => expr.precedence(for_each_attr), + ExprKind::DropTemps(expr, ..) => expr.precedence(has_attr), } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 233bb5cd5b85..d3289e4cc6d0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -10,7 +10,7 @@ use std::vec; use rustc_abi::ExternAbi; use rustc_ast::util::parser::{self, ExprPrecedence, Fixity}; -use rustc_ast::{AttrStyle, DUMMY_NODE_ID, DelimArgs}; +use rustc_ast::{DUMMY_NODE_ID, DelimArgs}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, BoxMarker, Breaks}; use rustc_ast_pretty::pprust::state::MacHeader; @@ -81,32 +81,24 @@ impl<'a> State<'a> { } fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence { - let for_each_attr = |id: HirId, callback: &mut dyn FnMut(&hir::Attribute)| { - self.attrs(id).iter().for_each(callback); - }; - expr.precedence(&for_each_attr) + let has_attr = |id: HirId| !self.attrs(id).is_empty(); + expr.precedence(&has_attr) } - fn print_attrs_as_inner(&mut self, attrs: &[hir::Attribute]) { - self.print_either_attributes(attrs, ast::AttrStyle::Inner) - } - - fn print_attrs_as_outer(&mut self, attrs: &[hir::Attribute]) { - self.print_either_attributes(attrs, ast::AttrStyle::Outer) - } - - fn print_either_attributes(&mut self, attrs: &[hir::Attribute], style: ast::AttrStyle) { + fn print_attrs(&mut self, attrs: &[hir::Attribute]) { if attrs.is_empty() { return; } for attr in attrs { - self.print_attribute_inline(attr, style); + self.print_attribute_as_style(attr, ast::AttrStyle::Outer); } self.hardbreak_if_not_bol(); } - fn print_attribute_inline(&mut self, attr: &hir::Attribute, style: AttrStyle) { + /// Print a single attribute as if it has style `style`, disregarding the + /// actual style of the attribute. + fn print_attribute_as_style(&mut self, attr: &hir::Attribute, style: ast::AttrStyle) { match &attr { hir::Attribute::Unparsed(unparsed) => { self.maybe_print_comment(unparsed.span.lo()); @@ -118,14 +110,17 @@ impl<'a> State<'a> { self.word("]"); self.hardbreak() } - hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => { + hir::Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => { self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string( - *kind, *style, *comment, + *kind, style, *comment, )); self.hardbreak() } hir::Attribute::Parsed(pa) => { - self.word("#[attr = "); + match style { + ast::AttrStyle::Inner => self.word("#![attr = "), + ast::AttrStyle::Outer => self.word("#[attr = "), + } pa.print_attribute(self); self.word("]"); self.hardbreak() @@ -281,10 +276,17 @@ pub fn print_crate<'a>( ann, }; + // Print all attributes, regardless of actual style, as inner attributes + // since this is the crate root with nothing above it to print outer + // attributes. + for attr in s.attrs(hir::CRATE_HIR_ID) { + s.print_attribute_as_style(attr, ast::AttrStyle::Inner); + } + // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. - s.print_mod(krate, (*attrs)(hir::CRATE_HIR_ID)); + s.print_mod(krate); s.print_remaining_comments(); s.s.eof() } @@ -299,7 +301,7 @@ where } pub fn attribute_to_string(ann: &dyn PpAnn, attr: &hir::Attribute) -> String { - to_string(ann, |s| s.print_attribute_inline(attr, AttrStyle::Outer)) + to_string(ann, |s| s.print_attribute_as_style(attr, ast::AttrStyle::Outer)) } pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String { @@ -361,8 +363,7 @@ impl<'a> State<'a> { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span); } - fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[hir::Attribute]) { - self.print_attrs_as_inner(attrs); + fn print_mod(&mut self, _mod: &hir::Mod<'_>) { for &item_id in _mod.item_ids { self.ann.nested(self, Nested::Item(item_id)); } @@ -479,7 +480,7 @@ impl<'a> State<'a> { fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); - self.print_attrs_as_outer(self.attrs(item.hir_id())); + self.print_attrs(self.attrs(item.hir_id())); match item.kind { hir::ForeignItemKind::Fn(sig, arg_idents, generics) => { let (cb, ib) = self.head(""); @@ -565,7 +566,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); let attrs = self.attrs(item.hir_id()); - self.print_attrs_as_outer(attrs); + self.print_attrs(attrs); self.ann.pre(self, AnnNode::Item(item)); match item.kind { hir::ItemKind::ExternCrate(orig_name, ident) => { @@ -647,14 +648,13 @@ impl<'a> State<'a> { self.print_ident(ident); self.nbsp(); self.bopen(ib); - self.print_mod(mod_, attrs); + self.print_mod(mod_); self.bclose(item.span, cb); } hir::ItemKind::ForeignMod { abi, items } => { let (cb, ib) = self.head("extern"); self.word_nbsp(abi.to_string()); self.bopen(ib); - self.print_attrs_as_inner(self.attrs(item.hir_id())); for item in items { self.ann.nested(self, Nested::ForeignItem(item.id)); } @@ -731,7 +731,6 @@ impl<'a> State<'a> { self.space(); self.bopen(ib); - self.print_attrs_as_inner(attrs); for impl_item in items { self.ann.nested(self, Nested::ImplItem(impl_item.id)); } @@ -822,7 +821,7 @@ impl<'a> State<'a> { for v in variants { self.space_if_not_bol(); self.maybe_print_comment(v.span.lo()); - self.print_attrs_as_outer(self.attrs(v.hir_id)); + self.print_attrs(self.attrs(v.hir_id)); let ib = self.ibox(INDENT_UNIT); self.print_variant(v); self.word(","); @@ -857,7 +856,7 @@ impl<'a> State<'a> { self.popen(); self.commasep(Inconsistent, struct_def.fields(), |s, field| { s.maybe_print_comment(field.span.lo()); - s.print_attrs_as_outer(s.attrs(field.hir_id)); + s.print_attrs(s.attrs(field.hir_id)); s.print_type(field.ty); }); self.pclose(); @@ -878,7 +877,7 @@ impl<'a> State<'a> { for field in struct_def.fields() { self.hardbreak_if_not_bol(); self.maybe_print_comment(field.span.lo()); - self.print_attrs_as_outer(self.attrs(field.hir_id)); + self.print_attrs(self.attrs(field.hir_id)); self.print_ident(field.ident); self.word_nbsp(":"); self.print_type(field.ty); @@ -916,7 +915,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::SubItem(ti.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ti.span.lo()); - self.print_attrs_as_outer(self.attrs(ti.hir_id())); + self.print_attrs(self.attrs(ti.hir_id())); match ti.kind { hir::TraitItemKind::Const(ty, default) => { self.print_associated_const(ti.ident, ti.generics, ty, default); @@ -944,7 +943,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::SubItem(ii.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ii.span.lo()); - self.print_attrs_as_outer(self.attrs(ii.hir_id())); + self.print_attrs(self.attrs(ii.hir_id())); match ii.kind { hir::ImplItemKind::Const(ty, expr) => { @@ -1028,27 +1027,16 @@ impl<'a> State<'a> { } fn print_block(&mut self, blk: &hir::Block<'_>, cb: BoxMarker, ib: BoxMarker) { - self.print_block_with_attrs(blk, &[], cb, ib) + self.print_block_maybe_unclosed(blk, Some(cb), ib) } fn print_block_unclosed(&mut self, blk: &hir::Block<'_>, ib: BoxMarker) { - self.print_block_maybe_unclosed(blk, &[], None, ib) - } - - fn print_block_with_attrs( - &mut self, - blk: &hir::Block<'_>, - attrs: &[hir::Attribute], - cb: BoxMarker, - ib: BoxMarker, - ) { - self.print_block_maybe_unclosed(blk, attrs, Some(cb), ib) + self.print_block_maybe_unclosed(blk, None, ib) } fn print_block_maybe_unclosed( &mut self, blk: &hir::Block<'_>, - attrs: &[hir::Attribute], cb: Option, ib: BoxMarker, ) { @@ -1060,8 +1048,6 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Block(blk)); self.bopen(ib); - self.print_attrs_as_inner(attrs); - for st in blk.stmts { self.print_stmt(st); } @@ -1251,7 +1237,7 @@ impl<'a> State<'a> { fn print_expr_field(&mut self, field: &hir::ExprField<'_>) { let cb = self.cbox(INDENT_UNIT); - self.print_attrs_as_outer(self.attrs(field.hir_id)); + self.print_attrs(self.attrs(field.hir_id)); if !field.is_shorthand { self.print_ident(field.ident); self.word_space(":"); @@ -1451,7 +1437,7 @@ impl<'a> State<'a> { fn print_expr(&mut self, expr: &hir::Expr<'_>) { self.maybe_print_comment(expr.span.lo()); - self.print_attrs_as_outer(self.attrs(expr.hir_id)); + self.print_attrs(self.attrs(expr.hir_id)); let ib = self.ibox(INDENT_UNIT); self.ann.pre(self, AnnNode::Expr(expr)); match expr.kind { @@ -2076,7 +2062,7 @@ impl<'a> State<'a> { self.space(); } let cb = self.cbox(INDENT_UNIT); - self.print_attrs_as_outer(self.attrs(field.hir_id)); + self.print_attrs(self.attrs(field.hir_id)); if !field.is_shorthand { self.print_ident(field.ident); self.word_nbsp(":"); @@ -2086,7 +2072,7 @@ impl<'a> State<'a> { } fn print_param(&mut self, arg: &hir::Param<'_>) { - self.print_attrs_as_outer(self.attrs(arg.hir_id)); + self.print_attrs(self.attrs(arg.hir_id)); self.print_pat(arg.pat); } @@ -2121,7 +2107,7 @@ impl<'a> State<'a> { let cb = self.cbox(INDENT_UNIT); self.ann.pre(self, AnnNode::Arm(arm)); let ib = self.ibox(0); - self.print_attrs_as_outer(self.attrs(arm.hir_id)); + self.print_attrs(self.attrs(arm.hir_id)); self.print_pat(arm.pat); self.space(); if let Some(ref g) = arm.guard { @@ -2409,7 +2395,7 @@ impl<'a> State<'a> { } fn print_where_predicate(&mut self, predicate: &hir::WherePredicate<'_>) { - self.print_attrs_as_outer(self.attrs(predicate.hir_id)); + self.print_attrs(self.attrs(predicate.hir_id)); match *predicate.kind { hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 223cadc056f0..bd3ca8317eb4 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -18,7 +18,7 @@ use rustc_errors::{ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_hir::{Attribute, ExprKind, HirId, QPath}; +use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::NoVariantNamed; use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _}; use rustc_infer::infer; @@ -55,7 +55,7 @@ use crate::{ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence { - let for_each_attr = |id: HirId, callback: &mut dyn FnMut(&Attribute)| { + let has_attr = |id: HirId| -> bool { for attr in self.tcx.hir_attrs(id) { // For the purpose of rendering suggestions, disregard attributes // that originate from desugaring of any kind. For example, `x?` @@ -71,11 +71,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // let y: u32 = (x?).try_into().unwrap(); // + +++++++++++++++++++++ if attr.span().desugaring_kind().is_none() { - callback(attr); + return true; } } + false }; - expr.precedence(&for_each_attr) + expr.precedence(&has_attr) } /// Check an expr with an expectation type, and also demand that the expr's diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b6bf45dfbcfb..414f2a1846b3 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -855,14 +855,15 @@ impl<'tcx> LateContext<'tcx> { /// rendering diagnostic. This is not the same as the precedence that would /// be used for pretty-printing HIR by rustc_hir_pretty. pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence { - let for_each_attr = |id: hir::HirId, callback: &mut dyn FnMut(&hir::Attribute)| { + let has_attr = |id: hir::HirId| -> bool { for attr in self.tcx.hir_attrs(id) { if attr.span().desugaring_kind().is_none() { - callback(attr); + return true; } } + false }; - expr.precedence(&for_each_attr) + expr.precedence(&has_attr) } /// If the given expression is a local binding, find the initializer expression. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d0630383477b..30ac1bbe94b9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -116,6 +116,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir_attrs(hir_id); for attr in attrs { + let mut style = None; match attr { Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { self.check_confusables(*first_span, target); @@ -163,10 +164,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) } - &Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { - self.check_may_dangle(hir_id, attr_span) + Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { + self.check_may_dangle(hir_id, *attr_span) } - Attribute::Unparsed(_) => { + Attribute::Unparsed(attr_item) => { + style = Some(attr_item.style); match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend, ..] => { self.check_do_not_recommend(attr.span(), hir_id, target, attr, item) @@ -189,6 +191,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } [sym::doc, ..] => self.check_doc_attrs( attr, + attr_item.style, hir_id, target, &mut specified_inline, @@ -350,14 +353,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { - match attr.style() { - ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( + match style { + Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), errors::OuterCrateLevelAttr, ), - ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( + Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), @@ -371,7 +374,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen); } - self.check_unused_attribute(hir_id, attr) + self.check_unused_attribute(hir_id, attr, style) } self.check_repr(attrs, span, target, item, hir_id); @@ -1194,7 +1197,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// the first `inline`/`no_inline` attribute. fn check_doc_inline( &self, - attr: &Attribute, + style: AttrStyle, meta: &MetaItemInner, hir_id: HirId, target: Target, @@ -1224,8 +1227,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocInlineOnlyUse { attr_span: meta.span(), - item_span: (attr.style() == AttrStyle::Outer) - .then(|| self.tcx.hir_span(hir_id)), + item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)), }, ); } @@ -1234,7 +1236,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_masked( &self, - attr: &Attribute, + style: AttrStyle, meta: &MetaItemInner, hir_id: HirId, target: Target, @@ -1246,8 +1248,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocMaskedOnlyExternCrate { attr_span: meta.span(), - item_span: (attr.style() == AttrStyle::Outer) - .then(|| self.tcx.hir_span(hir_id)), + item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)), }, ); return; @@ -1260,8 +1261,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocMaskedNotExternCrateSelf { attr_span: meta.span(), - item_span: (attr.style() == AttrStyle::Outer) - .then(|| self.tcx.hir_span(hir_id)), + item_span: (style == AttrStyle::Outer).then(|| self.tcx.hir_span(hir_id)), }, ); } @@ -1285,13 +1285,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_attr_crate_level( &self, attr: &Attribute, + style: AttrStyle, meta: &MetaItemInner, hir_id: HirId, ) -> bool { if hir_id != CRATE_HIR_ID { // insert a bang between `#` and `[...` let bang_span = attr.span().lo() + BytePos(1); - let sugg = (attr.style() == AttrStyle::Outer + let sugg = (style == AttrStyle::Outer && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) .then_some(errors::AttrCrateLevelOnlySugg { attr: attr.span().with_lo(bang_span).with_hi(bang_span), @@ -1308,7 +1309,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. - fn check_test_attr(&self, attr: &Attribute, meta: &MetaItemInner, hir_id: HirId) { + fn check_test_attr( + &self, + attr: &Attribute, + style: AttrStyle, + meta: &MetaItemInner, + hir_id: HirId, + ) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name(), i_meta.meta_item()) { @@ -1316,7 +1323,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // Allowed everywhere like `#[doc]` } (Some(sym::no_crate_inject), _) => { - self.check_attr_crate_level(attr, meta, hir_id); + self.check_attr_crate_level(attr, style, meta, hir_id); } (_, Some(m)) => { self.tcx.emit_node_span_lint( @@ -1370,6 +1377,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_attrs( &self, attr: &Attribute, + style: AttrStyle, hir_id: HirId, target: Target, specified_inline: &mut Option<(bool, Span)>, @@ -1404,7 +1412,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Some(sym::test) => { - self.check_test_attr(attr, meta, hir_id); + self.check_test_attr(attr, style, meta, hir_id); } Some( @@ -1415,25 +1423,25 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::html_root_url | sym::html_no_source, ) => { - self.check_attr_crate_level(attr, meta, hir_id); + self.check_attr_crate_level(attr, style, meta, hir_id); } Some(sym::cfg_hide) => { - if self.check_attr_crate_level(attr, meta, hir_id) { + if self.check_attr_crate_level(attr, style, meta, hir_id) { self.check_doc_cfg_hide(meta, hir_id); } } Some(sym::inline | sym::no_inline) => { - self.check_doc_inline(attr, meta, hir_id, target, specified_inline) + self.check_doc_inline(style, meta, hir_id, target, specified_inline) } - Some(sym::masked) => self.check_doc_masked(attr, meta, hir_id, target), + Some(sym::masked) => self.check_doc_masked(style, meta, hir_id, target), Some(sym::cfg | sym::hidden | sym::notable_trait) => {} Some(sym::rust_logo) => { - if self.check_attr_crate_level(attr, meta, hir_id) + if self.check_attr_crate_level(attr, style, meta, hir_id) && !self.tcx.features().rustdoc_internals() { feature_err( @@ -1472,7 +1480,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { errors::DocTestUnknownInclude { path, value: value.to_string(), - inner: match attr.style() { + inner: match style { AttrStyle::Inner => "!", AttrStyle::Outer => "", }, @@ -2426,7 +2434,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) { + fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option) { // FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very // ugly now but can 100% be removed later. if let Attribute::Parsed(p) = attr { @@ -2479,14 +2487,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }) { if hir_id != CRATE_HIR_ID { - match attr.style() { - ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( + match style { + Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), errors::OuterCrateLevelAttr, ), - ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( + Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs index 289b6b915d46..d3c396869766 100644 --- a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs +++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::attr::AttributeExt as _; use rustc_ast::token::CommentKind; use rustc_errors::Applicability; use rustc_hir::{AttrStyle, Attribute}; @@ -43,13 +44,19 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range, fragments: &F "looks like a footnote ref, but has no matching footnote", |diag| { if this_fragment.kind == DocFragmentKind::SugaredDoc { - let (doc_attr, (_, doc_attr_comment_kind)) = attrs + let (doc_attr, (_, doc_attr_comment_kind), attr_style) = attrs .iter() .filter(|attr| attr.span().overlaps(this_fragment.span)) .rev() - .find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?))) + .find_map(|attr| { + Some(( + attr, + attr.doc_str_and_comment_kind()?, + attr.doc_resolution_scope()?, + )) + }) .unwrap(); - let (to_add, terminator) = match (doc_attr_comment_kind, doc_attr.style()) { + let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) { (CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""), (CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""), (CommentKind::Block, AttrStyle::Outer) => ("\n/** ", " */"), diff --git a/tests/ui/deprecation/deprecated-expr-precedence.stderr b/tests/ui/deprecation/deprecated-expr-precedence.stderr new file mode 100644 index 000000000000..3275f2e790ae --- /dev/null +++ b/tests/ui/deprecation/deprecated-expr-precedence.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/deprecated-expr-precedence.rs:6:19 + | +LL | pub fn public() { + | - help: try adding a return type: `-> i32` +LL | #[deprecated] 0 + | ^ expected `()`, found integer + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/unpretty/diagnostic-attr.stdout b/tests/ui/unpretty/diagnostic-attr.stdout index 81d71b91d815..3b15a845d68f 100644 --- a/tests/ui/unpretty/diagnostic-attr.stdout +++ b/tests/ui/unpretty/diagnostic-attr.stdout @@ -12,6 +12,4 @@ extern crate std; trait ImportantTrait { } #[diagnostic::do_not_recommend] -impl ImportantTrait for T where T: Clone - {#![diagnostic::do_not_recommend] -} +impl ImportantTrait for T where T: Clone { } diff --git a/tests/ui/unpretty/exhaustive-asm.hir.stdout b/tests/ui/unpretty/exhaustive-asm.hir.stdout index 810db69bff16..ec9bda573312 100644 --- a/tests/ui/unpretty/exhaustive-asm.hir.stdout +++ b/tests/ui/unpretty/exhaustive-asm.hir.stdout @@ -26,7 +26,7 @@ mod expressions { mod items { /// ItemKind::GlobalAsm - mod item_global_asm {/// ItemKind::GlobalAsm + mod item_global_asm { global_asm! (".globl my_asm_func"); } } diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 5d6e3907d757..b15c02003a67 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -50,20 +50,14 @@ mod prelude { } } -//! inner single-line doc comment -/*! +/// inner single-line doc comment +/** * inner multi-line doc comment */ #[doc = "inner doc attribute"] #[allow(dead_code, unused_variables)] #[no_std] -mod attributes {//! inner single-line doc comment - /*! - * inner multi-line doc comment - */ - #![doc = "inner doc attribute"] - #![allow(dead_code, unused_variables)] - #![no_std] +mod attributes { /// outer single-line doc comment /** @@ -413,25 +407,25 @@ mod expressions { } mod items { /// ItemKind::ExternCrate - mod item_extern_crate {/// ItemKind::ExternCrate + mod item_extern_crate { extern crate core; extern crate self as unpretty; extern crate core as _; } /// ItemKind::Use - mod item_use {/// ItemKind::Use + mod item_use { use ::{}; use crate::expressions; use crate::items::item_use; use core::*; } /// ItemKind::Static - mod item_static {/// ItemKind::Static + mod item_static { static A: () = { }; static mut B: () = { }; } /// ItemKind::Const - mod item_const {/// ItemKind::Const + mod item_const { const A: () = { }; trait TraitItems { const @@ -445,7 +439,7 @@ mod items { } } /// ItemKind::Fn - mod item_fn {/// ItemKind::Fn + mod item_fn { const unsafe extern "C" fn f() { } async unsafe extern "C" fn g() -> @@ -460,21 +454,19 @@ mod items { } } /// ItemKind::Mod - mod item_mod {/// ItemKind::Mod - } + mod item_mod { } /// ItemKind::ForeignMod - mod item_foreign_mod {/// ItemKind::ForeignMod + mod item_foreign_mod { extern "Rust" { } extern "C" { } } /// ItemKind::GlobalAsm: see exhaustive-asm.rs /// ItemKind::TyAlias - mod item_ty_alias {/// ItemKind::GlobalAsm: see exhaustive-asm.rs - /// ItemKind::TyAlias + mod item_ty_alias { type Type<'a> where T: 'a = T; } /// ItemKind::Enum - mod item_enum {/// ItemKind::Enum + mod item_enum { enum Void { } enum Empty { Unit, @@ -490,7 +482,7 @@ mod items { } } /// ItemKind::Struct - mod item_struct {/// ItemKind::Struct + mod item_struct { struct Unit; struct Tuple(); struct Newtype(Unit); @@ -501,45 +493,40 @@ mod items { } } /// ItemKind::Union - mod item_union {/// ItemKind::Union + mod item_union { union Generic<'a, T> where T: 'a { t: T, } } /// ItemKind::Trait - mod item_trait {/// ItemKind::Trait + mod item_trait { auto unsafe trait Send { } trait Trait<'a>: Sized where Self: 'a { } } /// ItemKind::TraitAlias - mod item_trait_alias {/// ItemKind::TraitAlias + mod item_trait_alias { trait Trait = Sized where for<'a> T: 'a; } /// ItemKind::Impl - mod item_impl {/// ItemKind::Impl + mod item_impl { impl () { } impl () { } impl Default for () { } impl const Default for () { } } /// ItemKind::MacCall - mod item_mac_call {/// ItemKind::MacCall - } + mod item_mac_call { } /// ItemKind::MacroDef - mod item_macro_def {/// ItemKind::MacroDef + mod item_macro_def { macro_rules! mac { () => {...}; } macro stringify { () => {} } } /// ItemKind::Delegation - /*! FIXME: todo */ - mod item_delegation {/// ItemKind::Delegation - /*! FIXME: todo */ - } + /** FIXME: todo */ + mod item_delegation { } /// ItemKind::DelegationMac - /*! FIXME: todo */ - mod item_delegation_mac {/// ItemKind::DelegationMac - /*! FIXME: todo */ - } + /** FIXME: todo */ + mod item_delegation_mac { } } mod patterns { /// PatKind::Missing @@ -690,29 +677,29 @@ mod types { /// TyKind::Paren fn ty_paren() { let _: T; } /// TyKind::Typeof - /*! unused for now */ + /** unused for now */ fn ty_typeof() { } /// TyKind::Infer fn ty_infer() { let _: _; } /// TyKind::ImplicitSelf - /*! there is no syntax for this */ + /** there is no syntax for this */ fn ty_implicit_self() { } /// TyKind::MacCall #[expect(deprecated)] fn ty_mac_call() { let _: T; let _: T; let _: T; } /// TyKind::CVarArgs - /*! FIXME: todo */ + /** FIXME: todo */ fn ty_c_var_args() { } /// TyKind::Pat fn ty_pat() { let _: u32 is 1..=RangeMax; } } mod visibilities { /// VisibilityKind::Public - mod visibility_public {/// VisibilityKind::Public + mod visibility_public { struct Pub; } /// VisibilityKind::Restricted - mod visibility_restricted {/// VisibilityKind::Restricted + mod visibility_restricted { struct PubCrate; struct PubSelf; struct PubSuper; From 33b3ea23c9b5a1192e78e3ee7306cf2aafeff3d1 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Sat, 21 Jun 2025 11:50:44 -0700 Subject: [PATCH 225/356] Enable fmt-write-bloat for Windows --- tests/run-make/fmt-write-bloat/rmake.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs index 6875ef9ddc05..3348651d501f 100644 --- a/tests/run-make/fmt-write-bloat/rmake.rs +++ b/tests/run-make/fmt-write-bloat/rmake.rs @@ -15,14 +15,9 @@ //! `NO_DEBUG_ASSERTIONS=1`). If debug assertions are disabled, then we can check for the absence of //! additional `usize` formatting and padding related symbols. -//@ ignore-windows -// Reason: -// - MSVC targets really need to parse the .pdb file (aka the debug information). -// On Windows there's an API for that (dbghelp) which maybe we can use -// - MinGW targets have a lot of symbols included in their runtime which we can't avoid. -// We would need to make the symbols we're looking for more specific for this test to work. //@ ignore-cross-compile +use run_make_support::artifact_names::bin_name; use run_make_support::env::no_debug_assertions; use run_make_support::rustc; use run_make_support::symbols::any_symbol_contains; @@ -36,5 +31,5 @@ fn main() { // otherwise, add them to the list of symbols to deny. panic_syms.extend_from_slice(&["panicking", "panic_fmt", "pad_integral", "Display"]); } - assert!(!any_symbol_contains("main", &panic_syms)); + assert!(!any_symbol_contains(bin_name("main"), &panic_syms)); } From d86d3f3742caad06488a1bf1d7eb045606f95cdd Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sat, 14 Jun 2025 20:54:30 +0300 Subject: [PATCH 226/356] Port `#[rustc_pub_transparent]` to the new attribute system --- .../rustc_attr_data_structures/src/attributes.rs | 3 +++ .../src/attributes/lint_helpers.rs | 13 +++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_hir_analysis/src/check/check.rs | 7 ++++++- compiler/rustc_passes/src/check_attr.rs | 5 ++++- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 066e3e9eceb2..f0f5cc4db07d 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -240,6 +240,9 @@ pub enum AttributeKind { /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), + /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint). + PubTransparent(Span), + /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index d4c846de56eb..4cfd9a82ce8d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -19,3 +19,16 @@ impl SingleAttributeParser for AsPtrParser { Some(AttributeKind::AsPtr(cx.attr_span)) } } + +pub(crate) struct PubTransparentParser; +impl SingleAttributeParser for PubTransparentParser { + const PATH: &[Symbol] = &[sym::rustc_pub_transparent]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { + // FIXME: check that there's no args (this is currently checked elsewhere) + Some(AttributeKind::PubTransparent(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1bcf500459d9..b95ea598e72e 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -19,7 +19,7 @@ use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; -use crate::attributes::lint_helpers::AsPtrParser; +use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; use crate::attributes::repr::{AlignParser, ReprParser}; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -113,6 +113,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, // tidy-alphabetical-end diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5b1f1684d54c..280b33f07234 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -710,7 +710,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_pub_transparent, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, + ErrorFollowing, EncodeCrossCrate::Yes, "used internally to mark types with a `transparent` representation when it is guaranteed by the documentation", ), diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 32fec0604c0f..752cc2eff973 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2,6 +2,7 @@ use std::cell::LazyCell; use std::ops::ControlFlow; use rustc_abi::FieldIdx; +use rustc_attr_data_structures::AttributeKind; use rustc_attr_data_structures::ReprAttr::ReprPacked; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; @@ -1384,7 +1385,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)), ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), ty::Adt(def, args) => { - if !def.did().is_local() && !tcx.has_attr(def.did(), sym::rustc_pub_transparent) + if !def.did().is_local() + && !attrs::find_attr!( + tcx.get_all_attrs(def.did()), + AttributeKind::PubTransparent(_) + ) { let non_exhaustive = def.is_variant_list_non_exhaustive() || def diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d0630383477b..57af9d629992 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -149,6 +149,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ } + + &Attribute::Parsed(AttributeKind::PubTransparent(attr_span)) => { + self.check_rustc_pub_transparent(attr_span, span, attrs) + } Attribute::Parsed(AttributeKind::Cold(attr_span)) => { self.check_cold(hir_id, *attr_span, span, target) } @@ -288,7 +292,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_type_const(hir_id,attr, target); } [sym::linkage, ..] => self.check_linkage(attr, span, target), - [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span(), span, attrs), [ // ok sym::allow From 0d50f9109bd0309122ea23094d9471684f18dc62 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Sat, 21 Jun 2025 13:16:57 -0700 Subject: [PATCH 227/356] Enable textrel-on-minimal-lib for Windows --- tests/run-make/textrel-on-minimal-lib/rmake.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/run-make/textrel-on-minimal-lib/rmake.rs b/tests/run-make/textrel-on-minimal-lib/rmake.rs index 625ded70ad62..08e2b45a75f4 100644 --- a/tests/run-make/textrel-on-minimal-lib/rmake.rs +++ b/tests/run-make/textrel-on-minimal-lib/rmake.rs @@ -6,25 +6,23 @@ // See https://github.com/rust-lang/rust/issues/68794 //@ ignore-cross-compile -//@ ignore-windows -// Reason: There is no `bar.dll` produced by CC to run readobj on use run_make_support::{ - cc, dynamic_lib_name, extra_c_flags, extra_cxx_flags, llvm_readobj, rustc, static_lib_name, + bin_name, cc, extra_c_flags, extra_cxx_flags, llvm_readobj, rustc, static_lib_name, }; fn main() { rustc().input("foo.rs").run(); cc().input("bar.c") .input(static_lib_name("foo")) - .out_exe(&dynamic_lib_name("bar")) + .out_exe(&bin_name("bar")) .arg("-fPIC") .arg("-shared") .args(extra_c_flags()) .args(extra_cxx_flags()) .run(); llvm_readobj() - .input(dynamic_lib_name("bar")) + .input(bin_name("bar")) .arg("--dynamic") .run() .assert_stdout_not_contains("TEXTREL"); From eb86d0951ea632c68931b525775084282ceb063e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 21 Jun 2025 23:26:56 +0200 Subject: [PATCH 228/356] remove asm_goto feature annotation, for it is now stabilized --- tests/codegen/asm/critical.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/codegen/asm/critical.rs b/tests/codegen/asm/critical.rs index 8c039900cab3..0f29d7c69b46 100644 --- a/tests/codegen/asm/critical.rs +++ b/tests/codegen/asm/critical.rs @@ -1,6 +1,5 @@ //@ only-x86_64 //@ compile-flags: -C no-prepopulate-passes -#![feature(asm_goto)] #![feature(asm_goto_with_outputs)] #![crate_type = "lib"] use std::arch::asm; From 6854f7d89ae60c96ae487e98f6cae03418435614 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 17 Jun 2025 14:35:26 +1000 Subject: [PATCH 229/356] Use `sym::asterisk` to avoid a `Symbol::intern` call. --- src/librustdoc/json/conversions.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index cb4c1f7fbc06..076d373887af 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -11,7 +11,7 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_metadata::rendered_const; use rustc_middle::{bug, ty}; -use rustc_span::{Pos, Symbol, kw}; +use rustc_span::{Pos, kw, sym}; use rustdoc_json_types::*; use thin_vec::ThinVec; @@ -783,10 +783,7 @@ impl FromClean for Use { use clean::ImportKind::*; let (name, is_glob) = match import.kind { Simple(s) => (s.to_string(), false), - Glob => ( - import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(), - true, - ), + Glob => (import.source.path.last_opt().unwrap_or(sym::asterisk).to_string(), true), }; Use { source: import.source.path.whole_name(), From 4736142c48590dfa4de48bef702348501d7fcc28 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 17 Jun 2025 15:09:04 +1000 Subject: [PATCH 230/356] Remove some dead code. We currently have both `FromClean for Constant` and `FromClean for Constant` which are basically identical, but the former is unused. --- src/librustdoc/clean/types.rs | 14 -------------- src/librustdoc/json/conversions.rs | 11 ----------- 2 files changed, 25 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 408ef611ee52..c0a9d8c84f6c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2432,20 +2432,6 @@ pub(crate) enum ConstantKind { Infer, } -impl Constant { - pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String { - self.kind.expr(tcx) - } - - pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option { - self.kind.value(tcx) - } - - pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool { - self.kind.is_literal(tcx) - } -} - impl ConstantKind { pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String { match *self { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 076d373887af..3d028fe681b1 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -201,17 +201,6 @@ impl FromClean for GenericArg { } } -impl FromClean for Constant { - // FIXME(generic_const_items): Add support for generic const items. - fn from_clean(constant: &clean::Constant, renderer: &JsonRenderer<'_>) -> Self { - let tcx = renderer.tcx; - let expr = constant.expr(tcx); - let value = constant.value(tcx); - let is_literal = constant.is_literal(tcx); - Constant { expr, value, is_literal } - } -} - impl FromClean for Constant { // FIXME(generic_const_items): Add support for generic const items. fn from_clean(constant: &clean::ConstantKind, renderer: &JsonRenderer<'_>) -> Self { From 9a597743efefc0f912990931cde402047e7861dd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 17 Jun 2025 16:08:48 +1000 Subject: [PATCH 231/356] Remove some code. It's just replicating exactly what is done by ` as FromClean>::into_json` --- src/librustdoc/json/conversions.rs | 33 +----------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 3d028fe681b1..02f50d1b8bf0 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -423,38 +423,7 @@ impl FromClean for WherePredicate { BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate { type_: ty.into_json(renderer), bounds: bounds.into_json(renderer), - generic_params: bound_params - .iter() - .map(|x| { - let name = x.name.to_string(); - let kind = match &x.kind { - clean::GenericParamDefKind::Lifetime { outlives } => { - GenericParamDefKind::Lifetime { - outlives: outlives.iter().map(|lt| lt.0.to_string()).collect(), - } - } - clean::GenericParamDefKind::Type { bounds, default, synthetic } => { - GenericParamDefKind::Type { - bounds: bounds - .into_iter() - .map(|bound| bound.into_json(renderer)) - .collect(), - default: default - .as_ref() - .map(|ty| ty.as_ref().into_json(renderer)), - is_synthetic: *synthetic, - } - } - clean::GenericParamDefKind::Const { ty, default, synthetic: _ } => { - GenericParamDefKind::Const { - type_: ty.as_ref().into_json(renderer), - default: default.as_ref().map(|d| d.as_ref().clone()), - } - } - }; - GenericParamDef { name, kind } - }) - .collect(), + generic_params: bound_params.into_json(renderer), }, RegionPredicate { lifetime, bounds } => WherePredicate::LifetimePredicate { lifetime: convert_lifetime(lifetime), From 88388f45d625efb58faddde5766c224d3b9bcf4f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 17 Jun 2025 14:26:27 +1000 Subject: [PATCH 232/356] Use `FromClean` more. The `FromClean` trait is used a lot for converting to rustdoc-json format. But it's not used universally; there are still some ad hoc functions and methods for converting. This commit fixes this inconsistency by using `FromClean` more. The commit also introduces `FromClean` for `Box` and `Option`. This lets a lot of `as_ref` and `map` calls be removed in favour of simple `into_json` calls. --- src/librustdoc/json/conversions.rs | 277 ++++++++++++++++------------- 1 file changed, 156 insertions(+), 121 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 02f50d1b8bf0..3694769ff70b 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -66,47 +66,16 @@ impl JsonRenderer<'_> { id, crate_id: item_id.krate().as_u32(), name: name.map(|sym| sym.to_string()), - span: span.and_then(|span| self.convert_span(span)), - visibility: self.convert_visibility(visibility), + span: span.and_then(|span| span.into_json(self)), + visibility: visibility.into_json(self), docs, attrs, - deprecation: deprecation.map(from_deprecation), + deprecation: deprecation.into_json(self), inner, links, }) } - fn convert_span(&self, span: clean::Span) -> Option { - match span.filename(self.sess()) { - rustc_span::FileName::Real(name) => { - if let Some(local_path) = name.into_local_path() { - let hi = span.hi(self.sess()); - let lo = span.lo(self.sess()); - Some(Span { - filename: local_path, - begin: (lo.line, lo.col.to_usize() + 1), - end: (hi.line, hi.col.to_usize() + 1), - }) - } else { - None - } - } - _ => None, - } - } - - fn convert_visibility(&self, v: Option>) -> Visibility { - match v { - None => Visibility::Default, - Some(ty::Visibility::Public) => Visibility::Public, - Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate, - Some(ty::Visibility::Restricted(did)) => Visibility::Restricted { - parent: self.id_from_item_default(did.into()), - path: self.tcx.def_path(did).to_string_no_crate_verbose(), - }, - } - } - fn ids(&self, items: &[clean::Item]) -> Vec { items .iter() @@ -140,11 +109,29 @@ where } } +impl FromClean> for U +where + U: FromClean, +{ + fn from_clean(opt: &Box, renderer: &JsonRenderer<'_>) -> Self { + opt.as_ref().into_json(renderer) + } +} + +impl FromClean> for Option +where + U: FromClean, +{ + fn from_clean(opt: &Option, renderer: &JsonRenderer<'_>) -> Self { + opt.as_ref().map(|x| x.into_json(renderer)) + } +} + impl FromClean> for Vec where U: FromClean, { - fn from_clean(items: &Vec, renderer: &JsonRenderer<'_>) -> Vec { + fn from_clean(items: &Vec, renderer: &JsonRenderer<'_>) -> Self { items.iter().map(|i| i.into_json(renderer)).collect() } } @@ -153,20 +140,57 @@ impl FromClean> for Vec where U: FromClean, { - fn from_clean(items: &ThinVec, renderer: &JsonRenderer<'_>) -> Vec { + fn from_clean(items: &ThinVec, renderer: &JsonRenderer<'_>) -> Self { items.iter().map(|i| i.into_json(renderer)).collect() } } -pub(crate) fn from_deprecation(deprecation: attrs::Deprecation) -> Deprecation { - let attrs::Deprecation { since, note, suggestion: _ } = deprecation; - let since = match since { - DeprecatedSince::RustcVersion(version) => Some(version.to_string()), - DeprecatedSince::Future => Some("TBD".to_owned()), - DeprecatedSince::NonStandard(since) => Some(since.to_string()), - DeprecatedSince::Unspecified | DeprecatedSince::Err => None, - }; - Deprecation { since, note: note.map(|s| s.to_string()) } +impl FromClean for Option { + fn from_clean(span: &clean::Span, renderer: &JsonRenderer<'_>) -> Self { + match span.filename(renderer.sess()) { + rustc_span::FileName::Real(name) => { + if let Some(local_path) = name.into_local_path() { + let hi = span.hi(renderer.sess()); + let lo = span.lo(renderer.sess()); + Some(Span { + filename: local_path, + begin: (lo.line, lo.col.to_usize() + 1), + end: (hi.line, hi.col.to_usize() + 1), + }) + } else { + None + } + } + _ => None, + } + } +} + +impl FromClean>> for Visibility { + fn from_clean(v: &Option>, renderer: &JsonRenderer<'_>) -> Self { + match v { + None => Visibility::Default, + Some(ty::Visibility::Public) => Visibility::Public, + Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate, + Some(ty::Visibility::Restricted(did)) => Visibility::Restricted { + parent: renderer.id_from_item_default((*did).into()), + path: renderer.tcx.def_path(*did).to_string_no_crate_verbose(), + }, + } + } +} + +impl FromClean for Deprecation { + fn from_clean(deprecation: &attrs::Deprecation, _renderer: &JsonRenderer<'_>) -> Self { + let attrs::Deprecation { since, note, suggestion: _ } = deprecation; + let since = match since { + DeprecatedSince::RustcVersion(version) => Some(version.to_string()), + DeprecatedSince::Future => Some("TBD".to_string()), + DeprecatedSince::NonStandard(since) => Some(since.to_string()), + DeprecatedSince::Unspecified | DeprecatedSince::Err => None, + }; + Deprecation { since, note: note.map(|sym| sym.to_string()) } + } } impl FromClean for Option> { @@ -182,7 +206,7 @@ impl FromClean for Option> { }, Parenthesized { inputs, output } => GenericArgs::Parenthesized { inputs: inputs.into_json(renderer), - output: output.as_ref().map(|a| a.as_ref().into_json(renderer)), + output: output.into_json(renderer), }, ReturnTypeNotation => GenericArgs::ReturnTypeNotation, })) @@ -193,7 +217,7 @@ impl FromClean for GenericArg { fn from_clean(arg: &clean::GenericArg, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericArg::*; match arg { - Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)), + Lifetime(l) => GenericArg::Lifetime(l.into_json(renderer)), Type(t) => GenericArg::Type(t.into_json(renderer)), Const(box c) => GenericArg::Const(c.into_json(renderer)), Infer => GenericArg::Infer, @@ -252,17 +276,17 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum ForeignFunctionItem(f, _) => { ItemEnum::Function(from_function(f, false, header.unwrap(), renderer)) } - TraitItem(t) => ItemEnum::Trait(t.as_ref().into_json(renderer)), + TraitItem(t) => ItemEnum::Trait(t.into_json(renderer)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)), MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)), RequiredMethodItem(m) => { ItemEnum::Function(from_function(m, false, header.unwrap(), renderer)) } - ImplItem(i) => ItemEnum::Impl(i.as_ref().into_json(renderer)), - StaticItem(s) => ItemEnum::Static(convert_static(s, &rustc_hir::Safety::Safe, renderer)), - ForeignStaticItem(s, safety) => ItemEnum::Static(convert_static(s, safety, renderer)), + ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)), + StaticItem(s) => ItemEnum::Static(convert_static(s, rustc_hir::Safety::Safe, renderer)), + ForeignStaticItem(s, safety) => ItemEnum::Static(convert_static(s, *safety, renderer)), ForeignTypeItem => ItemEnum::ExternType, - TypeAliasItem(t) => ItemEnum::TypeAlias(t.as_ref().into_json(renderer)), + TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_json(renderer)), // FIXME(generic_const_items): Add support for generic free consts ConstantItem(ci) => ItemEnum::Constant { type_: ci.type_.into_json(renderer), @@ -278,7 +302,7 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum } // FIXME(generic_const_items): Add support for generic associated consts. RequiredAssocConstItem(_generics, ty) => { - ItemEnum::AssocConst { type_: ty.as_ref().into_json(renderer), value: None } + ItemEnum::AssocConst { type_: ty.into_json(renderer), value: None } } // FIXME(generic_const_items): Add support for generic associated consts. ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst { @@ -350,32 +374,38 @@ impl FromClean for Union { } } -pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> FunctionHeader { - FunctionHeader { - is_async: header.is_async(), - is_const: header.is_const(), - is_unsafe: header.is_unsafe(), - abi: convert_abi(header.abi), +impl FromClean for FunctionHeader { + fn from_clean(header: &rustc_hir::FnHeader, renderer: &JsonRenderer<'_>) -> Self { + FunctionHeader { + is_async: header.is_async(), + is_const: header.is_const(), + is_unsafe: header.is_unsafe(), + abi: header.abi.into_json(renderer), + } } } -fn convert_abi(a: ExternAbi) -> Abi { - match a { - ExternAbi::Rust => Abi::Rust, - ExternAbi::C { unwind } => Abi::C { unwind }, - ExternAbi::Cdecl { unwind } => Abi::Cdecl { unwind }, - ExternAbi::Stdcall { unwind } => Abi::Stdcall { unwind }, - ExternAbi::Fastcall { unwind } => Abi::Fastcall { unwind }, - ExternAbi::Aapcs { unwind } => Abi::Aapcs { unwind }, - ExternAbi::Win64 { unwind } => Abi::Win64 { unwind }, - ExternAbi::SysV64 { unwind } => Abi::SysV64 { unwind }, - ExternAbi::System { unwind } => Abi::System { unwind }, - _ => Abi::Other(a.to_string()), +impl FromClean for Abi { + fn from_clean(a: &ExternAbi, _renderer: &JsonRenderer<'_>) -> Self { + match *a { + ExternAbi::Rust => Abi::Rust, + ExternAbi::C { unwind } => Abi::C { unwind }, + ExternAbi::Cdecl { unwind } => Abi::Cdecl { unwind }, + ExternAbi::Stdcall { unwind } => Abi::Stdcall { unwind }, + ExternAbi::Fastcall { unwind } => Abi::Fastcall { unwind }, + ExternAbi::Aapcs { unwind } => Abi::Aapcs { unwind }, + ExternAbi::Win64 { unwind } => Abi::Win64 { unwind }, + ExternAbi::SysV64 { unwind } => Abi::SysV64 { unwind }, + ExternAbi::System { unwind } => Abi::System { unwind }, + _ => Abi::Other(a.to_string()), + } } } -fn convert_lifetime(l: &clean::Lifetime) -> String { - l.0.to_string() +impl FromClean for String { + fn from_clean(l: &clean::Lifetime, _renderer: &JsonRenderer<'_>) -> String { + l.0.to_string() + } } impl FromClean for Generics { @@ -400,16 +430,16 @@ impl FromClean for GenericParamDefKind { fn from_clean(kind: &clean::GenericParamDefKind, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericParamDefKind::*; match kind { - Lifetime { outlives } => GenericParamDefKind::Lifetime { - outlives: outlives.into_iter().map(convert_lifetime).collect(), - }, + Lifetime { outlives } => { + GenericParamDefKind::Lifetime { outlives: outlives.into_json(renderer) } + } Type { bounds, default, synthetic } => GenericParamDefKind::Type { bounds: bounds.into_json(renderer), - default: default.as_ref().map(|x| x.as_ref().into_json(renderer)), + default: default.into_json(renderer), is_synthetic: *synthetic, }, Const { ty, default, synthetic: _ } => GenericParamDefKind::Const { - type_: ty.as_ref().into_json(renderer), + type_: ty.into_json(renderer), default: default.as_ref().map(|x| x.as_ref().clone()), }, } @@ -426,11 +456,11 @@ impl FromClean for WherePredicate { generic_params: bound_params.into_json(renderer), }, RegionPredicate { lifetime, bounds } => WherePredicate::LifetimePredicate { - lifetime: convert_lifetime(lifetime), + lifetime: lifetime.into_json(renderer), outlives: bounds .iter() .map(|bound| match bound { - clean::GenericBound::Outlives(lt) => convert_lifetime(lt), + clean::GenericBound::Outlives(lt) => lt.into_json(renderer), _ => bug!("found non-outlives-bound on lifetime predicate"), }) .collect(), @@ -454,15 +484,15 @@ impl FromClean for GenericBound { GenericBound::TraitBound { trait_: trait_.into_json(renderer), generic_params: generic_params.into_json(renderer), - modifier: from_trait_bound_modifier(modifier), + modifier: modifier.into_json(renderer), } } - Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), + Outlives(lifetime) => GenericBound::Outlives(lifetime.into_json(renderer)), Use(args) => GenericBound::Use( args.iter() .map(|arg| match arg { clean::PreciseCapturingArg::Lifetime(lt) => { - PreciseCapturingArg::Lifetime(convert_lifetime(lt)) + PreciseCapturingArg::Lifetime(lt.into_json(renderer)) } clean::PreciseCapturingArg::Param(param) => { PreciseCapturingArg::Param(param.to_string()) @@ -474,19 +504,22 @@ impl FromClean for GenericBound { } } -pub(crate) fn from_trait_bound_modifier( - modifiers: &rustc_hir::TraitBoundModifiers, -) -> TraitBoundModifier { - use rustc_hir as hir; - let hir::TraitBoundModifiers { constness, polarity } = modifiers; - match (constness, polarity) { - (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None, - (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe, - (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => { - TraitBoundModifier::MaybeConst +impl FromClean for TraitBoundModifier { + fn from_clean( + modifiers: &rustc_hir::TraitBoundModifiers, + _renderer: &JsonRenderer<'_>, + ) -> Self { + use rustc_hir as hir; + let hir::TraitBoundModifiers { constness, polarity } = modifiers; + match (constness, polarity) { + (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None, + (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe, + (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => { + TraitBoundModifier::MaybeConst + } + // FIXME: Fill out the rest of this matrix. + _ => TraitBoundModifier::None, } - // FIXME: Fill out the rest of this matrix. - _ => TraitBoundModifier::None, } } @@ -500,35 +533,35 @@ impl FromClean for Type { match ty { clean::Type::Path { path } => Type::ResolvedPath(path.into_json(renderer)), clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { - lifetime: lt.as_ref().map(convert_lifetime), + lifetime: lt.into_json(renderer), traits: bounds.into_json(renderer), }), Generic(s) => Type::Generic(s.to_string()), // FIXME: add dedicated variant to json Type? SelfTy => Type::Generic("Self".to_owned()), Primitive(p) => Type::Primitive(p.as_sym().to_string()), - BareFunction(f) => Type::FunctionPointer(Box::new(f.as_ref().into_json(renderer))), + BareFunction(f) => Type::FunctionPointer(Box::new(f.into_json(renderer))), Tuple(t) => Type::Tuple(t.into_json(renderer)), - Slice(t) => Type::Slice(Box::new(t.as_ref().into_json(renderer))), + Slice(t) => Type::Slice(Box::new(t.into_json(renderer))), Array(t, s) => { - Type::Array { type_: Box::new(t.as_ref().into_json(renderer)), len: s.to_string() } + Type::Array { type_: Box::new(t.into_json(renderer)), len: s.to_string() } } clean::Type::Pat(t, p) => Type::Pat { - type_: Box::new(t.as_ref().into_json(renderer)), + type_: Box::new(t.into_json(renderer)), __pat_unstable_do_not_use: p.to_string(), }, ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)), Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { is_mutable: *mutability == ast::Mutability::Mut, - type_: Box::new(type_.as_ref().into_json(renderer)), + type_: Box::new(type_.into_json(renderer)), }, BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { - lifetime: lifetime.as_ref().map(convert_lifetime), + lifetime: lifetime.into_json(renderer), is_mutable: *mutability == ast::Mutability::Mut, - type_: Box::new(type_.as_ref().into_json(renderer)), + type_: Box::new(type_.into_json(renderer)), }, - QPath(qpath) => qpath.as_ref().into_json(renderer), + QPath(qpath) => qpath.into_json(renderer), // FIXME(unsafe_binder): Implement rustdoc-json. UnsafeBinder(_) => todo!(), } @@ -536,7 +569,7 @@ impl FromClean for Type { } impl FromClean for Path { - fn from_clean(path: &clean::Path, renderer: &JsonRenderer<'_>) -> Path { + fn from_clean(path: &clean::Path, renderer: &JsonRenderer<'_>) -> Self { Path { path: path.whole_name(), id: renderer.id_from_item_default(path.def_id().into()), @@ -566,13 +599,13 @@ impl FromClean for Type { name: assoc.name.to_string(), args: assoc.args.into_json(renderer), self_type: Box::new(self_type.into_json(renderer)), - trait_: trait_.as_ref().map(|trait_| trait_.into_json(renderer)), + trait_: trait_.into_json(renderer), } } } impl FromClean for Term { - fn from_clean(term: &clean::Term, renderer: &JsonRenderer<'_>) -> Term { + fn from_clean(term: &clean::Term, renderer: &JsonRenderer<'_>) -> Self { match term { clean::Term::Type(ty) => Term::Type(ty.into_json(renderer)), clean::Term::Constant(c) => Term::Constant(c.into_json(renderer)), @@ -588,7 +621,7 @@ impl FromClean for FunctionPointer { is_unsafe: safety.is_unsafe(), is_const: false, is_async: false, - abi: convert_abi(*abi), + abi: abi.into_json(renderer), }, generic_params: generic_params.into_json(renderer), sig: decl.into_json(renderer), @@ -667,12 +700,12 @@ impl FromClean for Impl { .into_iter() .map(|x| x.to_string()) .collect(), - trait_: trait_.as_ref().map(|path| path.into_json(renderer)), + trait_: trait_.into_json(renderer), for_: for_.into_json(renderer), items: renderer.ids(&items), is_negative, is_synthetic, - blanket_impl: blanket_impl.map(|x| x.as_ref().into_json(renderer)), + blanket_impl: blanket_impl.map(|x| x.into_json(renderer)), } } } @@ -686,7 +719,7 @@ pub(crate) fn from_function( Function { sig: decl.into_json(renderer), generics: generics.into_json(renderer), - header: from_fn_header(&header), + header: header.into_json(renderer), has_body, } } @@ -708,7 +741,7 @@ impl FromClean for Variant { fn from_clean(variant: &clean::Variant, renderer: &JsonRenderer<'_>) -> Self { use clean::VariantKind::*; - let discriminant = variant.discriminant.as_ref().map(|d| d.into_json(renderer)); + let discriminant = variant.discriminant.into_json(renderer); let kind = match &variant.kind { CLike => VariantKind::Plain, @@ -753,20 +786,22 @@ impl FromClean for Use { } impl FromClean for ProcMacro { - fn from_clean(mac: &clean::ProcMacro, _renderer: &JsonRenderer<'_>) -> Self { + fn from_clean(mac: &clean::ProcMacro, renderer: &JsonRenderer<'_>) -> Self { ProcMacro { - kind: from_macro_kind(mac.kind), + kind: mac.kind.into_json(renderer), helpers: mac.helpers.iter().map(|x| x.to_string()).collect(), } } } -pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind { - use rustc_span::hygiene::MacroKind::*; - match kind { - Bang => MacroKind::Bang, - Attr => MacroKind::Attr, - Derive => MacroKind::Derive, +impl FromClean for MacroKind { + fn from_clean(kind: &rustc_span::hygiene::MacroKind, _renderer: &JsonRenderer<'_>) -> Self { + use rustc_span::hygiene::MacroKind::*; + match kind { + Bang => MacroKind::Bang, + Attr => MacroKind::Attr, + Derive => MacroKind::Derive, + } } } @@ -779,7 +814,7 @@ impl FromClean for TypeAlias { fn convert_static( stat: &clean::Static, - safety: &rustc_hir::Safety, + safety: rustc_hir::Safety, renderer: &JsonRenderer<'_>, ) -> Static { let tcx = renderer.tcx; From 2878e1cba320314e2abf74acbe60da49e6628827 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 20 Jun 2025 09:16:49 +1000 Subject: [PATCH 233/356] Rename some methods. - `convert_static` -> `from_clean_static` - `from_function` -> `from_clean_function` To match the pre-existing `from_clean_item` and `FromClean::from_clean`. I left `JsonRenderer::convert_item` unchanged because it's a bit different. --- src/librustdoc/json/conversions.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 3694769ff70b..abad6e480291 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -272,19 +272,23 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum StructFieldItem(f) => ItemEnum::StructField(f.into_json(renderer)), EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)), VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)), - FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), renderer)), + FunctionItem(f) => { + ItemEnum::Function(from_clean_function(f, true, header.unwrap(), renderer)) + } ForeignFunctionItem(f, _) => { - ItemEnum::Function(from_function(f, false, header.unwrap(), renderer)) + ItemEnum::Function(from_clean_function(f, false, header.unwrap(), renderer)) } TraitItem(t) => ItemEnum::Trait(t.into_json(renderer)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)), - MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)), + MethodItem(m, _) => { + ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer)) + } RequiredMethodItem(m) => { - ItemEnum::Function(from_function(m, false, header.unwrap(), renderer)) + ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer)) } ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)), - StaticItem(s) => ItemEnum::Static(convert_static(s, rustc_hir::Safety::Safe, renderer)), - ForeignStaticItem(s, safety) => ItemEnum::Static(convert_static(s, *safety, renderer)), + StaticItem(s) => ItemEnum::Static(from_clean_static(s, rustc_hir::Safety::Safe, renderer)), + ForeignStaticItem(s, safety) => ItemEnum::Static(from_clean_static(s, *safety, renderer)), ForeignTypeItem => ItemEnum::ExternType, TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_json(renderer)), // FIXME(generic_const_items): Add support for generic free consts @@ -710,7 +714,7 @@ impl FromClean for Impl { } } -pub(crate) fn from_function( +pub(crate) fn from_clean_function( clean::Function { decl, generics }: &clean::Function, has_body: bool, header: rustc_hir::FnHeader, @@ -812,7 +816,7 @@ impl FromClean for TypeAlias { } } -fn convert_static( +fn from_clean_static( stat: &clean::Static, safety: rustc_hir::Safety, renderer: &JsonRenderer<'_>, From a123a36a1f52fa8ac85bfa1ba4cef7062058db7b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 22 Jun 2025 00:47:10 +0200 Subject: [PATCH 234/356] centralize `-Zmin-function-alignment` logic --- compiler/rustc_codegen_llvm/src/attributes.rs | 6 +----- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 6 ++++++ compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 8 ++------ compiler/rustc_const_eval/src/interpret/memory.rs | 7 +------ 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 27fd09745ff0..adb53e0b66c2 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -491,11 +491,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); } - // function alignment can be set globally with the `-Zmin-function-alignment=` flag; - // the alignment from a `#[repr(align())]` is used if it specifies a higher alignment. - if let Some(align) = - Ord::max(cx.tcx.sess.opts.unstable_opts.min_function_alignment, codegen_fn_attrs.alignment) - { + if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } if let Some(backchain) = backchain_attr(cx) { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 39818be5bde5..ce83bd62dddb 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -126,6 +126,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } + // Apply the minimum function alignment here, so that individual backends don't have to. + codegen_fn_attrs.alignment = Ord::max( + codegen_fn_attrs.alignment, + tcx.sess.opts.unstable_opts.min_function_alignment, + ); + let Some(Ident { name, .. }) = attr.ident() else { continue; }; diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 9f66457a7400..9da4b8cc8fd4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -131,12 +131,8 @@ fn prefix_and_suffix<'tcx>( let attrs = tcx.codegen_fn_attrs(instance.def_id()); let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); - // function alignment can be set globally with the `-Zmin-function-alignment=` flag; - // the alignment from a `#[repr(align())]` is used if it specifies a higher alignment. - // if no alignment is specified, an alignment of 4 bytes is used. - let min_function_alignment = tcx.sess.opts.unstable_opts.min_function_alignment; - let align_bytes = - Ord::max(min_function_alignment, attrs.alignment).map(|a| a.bytes()).unwrap_or(4); + // If no alignment is specified, an alignment of 4 bytes is used. + let align_bytes = attrs.alignment.map(|a| a.bytes()).unwrap_or(4); // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`. let (arch_prefix, arch_suffix) = if is_arm { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 36d1a413598d..57bf867e389b 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -877,12 +877,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(fn_val) = self.get_fn_alloc(id) { let align = match fn_val { FnVal::Instance(instance) => { - // Function alignment can be set globally with the `-Zmin-function-alignment=` flag; - // the alignment from a `#[repr(align())]` is used if it specifies a higher alignment. - let fn_align = self.tcx.codegen_fn_attrs(instance.def_id()).alignment; - let global_align = self.tcx.sess.opts.unstable_opts.min_function_alignment; - - Ord::max(global_align, fn_align).unwrap_or(Align::ONE) + self.tcx.codegen_fn_attrs(instance.def_id()).alignment.unwrap_or(Align::ONE) } // Machine-specific extra functions currently do not support alignment restrictions. FnVal::Other(_) => Align::ONE, From 1f405735078ac34be300fd2bd7c532aaa0bb6fc5 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 14 Jun 2025 10:22:49 -0400 Subject: [PATCH 235/356] Skip collecting no-op DropGlue in vtables Since 122662 this no longer gets used in vtables, so we're safe to fully drop generating these empty functions. Those are eventually cleaned up by LLVM, but it's wasteful to produce them in the first place. This also adds a missing test for fn-ptr casts, which do still need to generate no-op drop glue. It's possible a future optimization could point all of those at the same drop glue (e.g., for *mut ()) rather than for each separate type, but that would require extra work for CFI and isn't particularly easy to do anyway. --- compiler/rustc_monomorphize/src/collector.rs | 12 ++++++++-- .../item-collection/drop-glue-noop.rs | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tests/codegen-units/item-collection/drop-glue-noop.rs diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 173030e0326e..e90e32ebebb9 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -949,6 +949,9 @@ fn visit_instance_use<'tcx>( } ty::InstanceKind::DropGlue(_, None) => { // Don't need to emit noop drop glue if we are calling directly. + // + // Note that we also optimize away the call to visit_instance_use in vtable construction + // (see create_mono_items_for_vtable_methods). if !is_direct_call { output.push(create_fn_mono_item(tcx, instance, source)); } @@ -1177,8 +1180,13 @@ fn create_mono_items_for_vtable_methods<'tcx>( output.extend(methods); } - // Also add the destructor. - visit_drop_use(tcx, impl_ty, false, source, output); + // Also add the destructor, if it's necessary. + // + // This matches the check in vtable_allocation_provider in middle/ty/vtable.rs, + // if we don't need drop we're not adding an actual pointer to the vtable. + if impl_ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) { + visit_drop_use(tcx, impl_ty, false, source, output); + } } /// Scans the CTFE alloc in order to find function pointers and statics that must be monomorphized. diff --git a/tests/codegen-units/item-collection/drop-glue-noop.rs b/tests/codegen-units/item-collection/drop-glue-noop.rs new file mode 100644 index 000000000000..604ba883bb28 --- /dev/null +++ b/tests/codegen-units/item-collection/drop-glue-noop.rs @@ -0,0 +1,23 @@ +//@ compile-flags:-Clink-dead-code -Zmir-opt-level=0 + +#![deny(dead_code)] +#![crate_type = "lib"] + +//~ MONO_ITEM fn start +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { + // No item produced for this, it's a no-op drop and so is removed. + unsafe { + std::ptr::drop_in_place::(&mut 0); + } + + // No choice but to codegen for indirect drop as a function pointer, since we have to produce a + // function with the right signature. In vtables we can avoid that (tested in + // instantiation-through-vtable.rs) because we special case null pointer for drop glue since + // #122662. + // + //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(None) @@ drop_glue_noop-cgu.0[External] + std::ptr::drop_in_place:: as unsafe fn(*mut u64); + + 0 +} From 0d4abfc7cc05c80f6d3ef6495156fe50c8900883 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 1 Jun 2025 15:27:28 +0200 Subject: [PATCH 236/356] forward the bootstrap `runner` to `run-make` The runner was already forwarded to `compiletest`, this just passes it on to `run-make` and uses it in the `run` functions. --- src/tools/compiletest/src/runtest/run_make.rs | 4 +++ src/tools/run-make-support/src/run.rs | 25 ++++++++++++++++++- .../c-link-to-rust-va-list-fn/rmake.rs | 3 ++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 029da1c18983..60e8e16e25ef 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -221,6 +221,10 @@ impl TestCx<'_> { cmd.env("REMOTE_TEST_CLIENT", remote_test_client); } + if let Some(runner) = &self.config.runner { + cmd.env("RUNNER", runner); + } + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 60e711d34027..b95f3a5cfe5a 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -1,4 +1,4 @@ -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::path::PathBuf; use std::{env, panic}; @@ -21,6 +21,20 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command { // will have to be changed (and the support files will have to be uploaded). cmd.arg("0"); cmd.arg(bin_path); + cmd + } else if let Ok(runner) = std::env::var("RUNNER") { + let mut args = split_maybe_args(&runner); + + let prog = args.remove(0); + let mut cmd = Command::new(prog); + + for arg in args { + cmd.arg(arg); + } + + cmd.arg("--"); + cmd.arg(bin_path); + cmd } else { Command::new(bin_path) @@ -92,3 +106,12 @@ pub fn cmd>(program: S) -> Command { command.env("LC_ALL", "C"); // force english locale command } + +fn split_maybe_args(s: &str) -> Vec { + // FIXME(132599): implement proper env var/shell argument splitting. + s.split(' ') + .filter_map(|s| { + if s.chars().all(|c| c.is_whitespace()) { None } else { Some(OsString::from(s)) } + }) + .collect() +} diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs index 63904bea6227..426d65b7af39 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs @@ -3,7 +3,8 @@ // prevent the creation of a functional binary. // See https://github.com/rust-lang/rust/pull/49878 -//@ ignore-cross-compile +//@ needs-target-std +//@ ignore-android: FIXME(#142855) use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; From 8e9552a6b5f05b181e9b550880d252d5282f96fe Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Jun 2025 23:54:16 +0000 Subject: [PATCH 237/356] Add a few inline directives in rustc_serialize. --- compiler/rustc_serialize/src/int_overflow.rs | 2 ++ compiler/rustc_serialize/src/opaque.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/compiler/rustc_serialize/src/int_overflow.rs b/compiler/rustc_serialize/src/int_overflow.rs index f2aac2ef711c..6782fbc33da1 100644 --- a/compiler/rustc_serialize/src/int_overflow.rs +++ b/compiler/rustc_serialize/src/int_overflow.rs @@ -20,6 +20,7 @@ macro_rules! impl_debug_strict_add { ($( $ty:ty )*) => { $( impl DebugStrictAdd for $ty { + #[inline] fn debug_strict_add(self, other: Self) -> Self { if cfg!(debug_assertions) { self + other @@ -42,6 +43,7 @@ macro_rules! impl_debug_strict_sub { ($( $ty:ty )*) => { $( impl DebugStrictSub for $ty { + #[inline] fn debug_strict_sub(self, other: Self) -> Self { if cfg!(debug_assertions) { self - other diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 00bad8e70cf2..4242642c6643 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -89,10 +89,12 @@ impl FileEncoder { self.buffered = 0; } + #[inline] pub fn file(&self) -> &File { &self.file } + #[inline] pub fn path(&self) -> &Path { &self.path } From 6ff229b5e1953f63b3beb03fec59305f12c26fab Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 22 Jun 2025 09:17:56 +0800 Subject: [PATCH 238/356] Notify `jieyouxu` on tidy changes --- triagebot.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 98eb99d9c607..4d13eaf1c84c 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1023,6 +1023,10 @@ Otherwise, you can ignore this comment. [mentions."src/tools/x"] message = "`src/tools/x` was changed. Bump version of Cargo.toml in `src/tools/x` so tidy will suggest installing the new version." +[mentions."src/tools/tidy"] +message = "There are changes to the `tidy` tool." +cc = ["@jieyouxu"] + [mentions."src/tools/tidy/src/deps.rs"] message = "The list of allowed third-party dependencies may have been modified! You must ensure that any new dependencies have compatible licenses before merging." cc = ["@davidtwco", "@wesleywiser"] From 17a8ba905b20c289f7bf6707652d001953752f70 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sun, 22 Jun 2025 02:22:45 +0900 Subject: [PATCH 239/356] Implement region negation to minicore and add a flag `fmt_before_1_89_0` --- .../crates/test-utils/src/fixture.rs | 42 +++++++++++++++---- .../crates/test-utils/src/minicore.rs | 15 +++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs index 7240069753e8..ddc722631163 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs @@ -412,44 +412,70 @@ impl MiniCore { } let mut active_regions = Vec::new(); + let mut inactive_regions = Vec::new(); let mut seen_regions = Vec::new(); for line in lines { let trimmed = line.trim(); if let Some(region) = trimmed.strip_prefix("// region:") { - active_regions.push(region); - continue; + if let Some(region) = region.strip_prefix('!') { + inactive_regions.push(region); + continue; + } else { + active_regions.push(region); + continue; + } } if let Some(region) = trimmed.strip_prefix("// endregion:") { - let prev = active_regions.pop().unwrap(); + let (prev, region) = if let Some(region) = region.strip_prefix('!') { + (inactive_regions.pop().unwrap(), region) + } else { + (active_regions.pop().unwrap(), region) + }; assert_eq!(prev, region, "unbalanced region pairs"); continue; } - let mut line_region = false; - if let Some(idx) = trimmed.find("// :") { - line_region = true; + let mut active_line_region = false; + let mut inactive_line_region = false; + if let Some(idx) = trimmed.find("// :!") { + inactive_line_region = true; + inactive_regions.push(&trimmed[idx + "// :!".len()..]); + } else if let Some(idx) = trimmed.find("// :") { + active_line_region = true; active_regions.push(&trimmed[idx + "// :".len()..]); } let mut keep = true; - for ®ion in &active_regions { + for ®ion in active_regions.iter() { assert!(!region.starts_with(' '), "region marker starts with a space: {region:?}"); self.assert_valid_flag(region); seen_regions.push(region); keep &= self.has_flag(region); } + for ®ion in inactive_regions.iter() { + assert!(!region.starts_with(' '), "region marker starts with a space: {region:?}"); + self.assert_valid_flag(region); + seen_regions.push(region); + keep &= !self.has_flag(region); + } if keep { buf.push_str(line); } - if line_region { + if active_line_region { active_regions.pop().unwrap(); } + if inactive_line_region { + inactive_regions.pop().unwrap(); + } } if !active_regions.is_empty() { panic!("unclosed regions: {active_regions:?} Add an `endregion` comment"); } + if !inactive_regions.is_empty() { + panic!("unclosed regions: {inactive_regions:?} Add an `endregion` comment"); + } for flag in &self.valid_flags { if !seen_regions.iter().any(|it| it == flag) { diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 4bdd791eb167..d13a81d287fa 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -31,6 +31,7 @@ //! eq: sized //! error: fmt //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive +//! fmt_before_1_89_0: fmt //! fn: tuple //! from: sized, result //! future: pin @@ -1175,6 +1176,7 @@ pub mod fmt { } } + // region:fmt_before_1_89_0 #[lang = "format_unsafe_arg"] pub struct UnsafeArg { _private: (), @@ -1185,6 +1187,7 @@ pub mod fmt { UnsafeArg { _private: () } } } + // endregion:fmt_before_1_89_0 } #[derive(Copy, Clone)] @@ -1204,6 +1207,7 @@ pub mod fmt { Arguments { pieces, fmt: None, args: &[] } } + // region:fmt_before_1_89_0 pub fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [rt::Argument<'a>], @@ -1212,6 +1216,17 @@ pub mod fmt { ) -> Arguments<'a> { Arguments { pieces, fmt: Some(fmt), args } } + // endregion:fmt_before_1_89_0 + + // region:!fmt_before_1_89_0 + pub unsafe fn new_v1_formatted( + pieces: &'a [&'static str], + args: &'a [rt::Argument<'a>], + fmt: &'a [rt::Placeholder], + ) -> Arguments<'a> { + Arguments { pieces, fmt: Some(fmt), args } + } + // endregion:!fmt_before_1_89_0 pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { From 03a82682863784a387bdf9ffbfe06f4eb5b66ecd Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sun, 22 Jun 2025 03:00:20 +0900 Subject: [PATCH 240/356] Minic rustc's new `format_args!` expansion --- .../crates/hir-def/src/expr_store/lower.rs | 223 +++++++++++++++++- .../hir-def/src/expr_store/tests/body.rs | 138 +++++++++-- .../ide-assists/src/handlers/term_search.rs | 12 +- .../ide-completion/src/tests/expression.rs | 4 +- .../src/handlers/missing_unsafe.rs | 25 ++ .../crates/intern/src/symbol/symbols.rs | 1 + .../crates/test-utils/src/fixture.rs | 4 +- 7 files changed, 366 insertions(+), 41 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 4ba31c1e20bf..efa1374a4465 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -2815,6 +2815,51 @@ impl ExprCollector<'_> { mutability: Mutability::Shared, }) }; + + // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists + // but `format_unsafe_arg` does not + let fmt_args = + || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatArguments); + let fmt_unsafe_arg = + || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatUnsafeArg); + let use_format_args_since_1_89_0 = fmt_args().is_some() && fmt_unsafe_arg().is_none(); + + let idx = if use_format_args_since_1_89_0 { + self.collect_format_args_impl( + syntax_ptr, + fmt, + hygiene, + argmap, + lit_pieces, + format_options, + ) + } else { + self.collect_format_args_before_1_89_0_impl( + syntax_ptr, + fmt, + argmap, + lit_pieces, + format_options, + ) + }; + + self.source_map + .template_map + .get_or_insert_with(Default::default) + .format_args_to_captures + .insert(idx, (hygiene, mappings)); + idx + } + + /// `format_args!` expansion implementation for rustc versions < `1.89.0` + fn collect_format_args_before_1_89_0_impl( + &mut self, + syntax_ptr: AstPtr, + fmt: FormatArgs, + argmap: FxIndexSet<(usize, ArgumentType)>, + lit_pieces: ExprId, + format_options: ExprId, + ) -> ExprId { let arguments = &*fmt.arguments.arguments; let args = if arguments.is_empty() { @@ -2902,19 +2947,181 @@ impl ExprCollector<'_> { }); } - let idx = self.alloc_expr( + self.alloc_expr( Expr::Call { callee: new_v1_formatted, args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]), }, syntax_ptr, - ); - self.source_map - .template_map - .get_or_insert_with(Default::default) - .format_args_to_captures - .insert(idx, (hygiene, mappings)); - idx + ) + } + + /// `format_args!` expansion implementation for rustc versions >= `1.89.0`, + /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748) + fn collect_format_args_impl( + &mut self, + syntax_ptr: AstPtr, + fmt: FormatArgs, + hygiene: HygieneId, + argmap: FxIndexSet<(usize, ArgumentType)>, + lit_pieces: ExprId, + format_options: ExprId, + ) -> ExprId { + let arguments = &*fmt.arguments.arguments; + + let (let_stmts, args) = if arguments.is_empty() { + ( + // Generate: + // [] + vec![], + self.alloc_expr_desugared(Expr::Array(Array::ElementList { + elements: Box::default(), + })), + ) + } else if argmap.len() == 1 && arguments.len() == 1 { + // Only one argument, so we don't need to make the `args` tuple. + // + // Generate: + // super let args = [::new_display(&arg)]; + let args = argmap + .iter() + .map(|&(arg_index, ty)| { + let ref_arg = self.alloc_expr_desugared(Expr::Ref { + expr: arguments[arg_index].expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + self.make_argument(ref_arg, ty) + }) + .collect(); + let args = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); + let args_name = Name::new_symbol_root(sym::args); + let args_binding = + self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + // TODO: We don't have `super let` yet. + let let_stmt = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(args), + else_branch: None, + }; + (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(Path::from(args_name)))) + } else { + // Generate: + // super let args = (&arg0, &arg1, &...); + let args_name = Name::new_symbol_root(sym::args); + let args_binding = + self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + let elements = arguments + .iter() + .map(|arg| { + self.alloc_expr_desugared(Expr::Ref { + expr: arg.expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }) + }) + .collect(); + let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements }); + // TODO: We don't have `super let` yet + let let_stmt1 = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(args_tuple), + else_branch: None, + }; + + // Generate: + // super let args = [ + // ::new_display(args.0), + // ::new_lower_hex(args.1), + // ::new_debug(args.0), + // … + // ]; + let args = argmap + .iter() + .map(|&(arg_index, ty)| { + let args_ident_expr = + self.alloc_expr_desugared(Expr::Path(args_name.clone().into())); + let arg = self.alloc_expr_desugared(Expr::Field { + expr: args_ident_expr, + name: Name::new_tuple_field(arg_index), + }); + self.make_argument(arg, ty) + }) + .collect(); + let array = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); + let args_binding = + self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + let let_stmt2 = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(array), + else_branch: None, + }; + (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into()))) + }; + + // Generate: + // &args + let args = self.alloc_expr_desugared(Expr::Ref { + expr: args, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + + let call_block = { + // Generate: + // unsafe { + // ::new_v1_formatted( + // lit_pieces, + // args, + // format_options, + // ) + // } + + let new_v1_formatted = LangItem::FormatArguments.ty_rel_path( + self.db, + self.module.krate(), + Name::new_symbol_root(sym::new_v1_formatted), + ); + let new_v1_formatted = + self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path)); + let args = [lit_pieces, args, format_options]; + let call = self + .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() }); + + Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) } + }; + + if !let_stmts.is_empty() { + // Generate: + // { + // super let … + // super let … + // ::new_…(…) + // } + let call = self.alloc_expr_desugared(call_block); + self.alloc_expr( + Expr::Block { + id: None, + statements: let_stmts.into(), + tail: Some(call), + label: None, + }, + syntax_ptr, + ) + } else { + self.alloc_expr(call_block, syntax_ptr) + } } /// Generate a hir expression for a format_args placeholder specification. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs index 29e249b07a72..927e280d7394 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs @@ -178,14 +178,14 @@ fn main() { } #[test] -fn desugar_builtin_format_args() { +fn desugar_builtin_format_args_before_1_89_0() { let (db, body, def) = lower( r#" -//- minicore: fmt +//- minicore: fmt_before_1_89_0 fn main() { let are = "are"; let count = 10; - builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!"); + builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); } "#, ); @@ -249,14 +249,100 @@ fn main() { builtin#lang(Count::Implied), ), ], - unsafe { - builtin#lang(UnsafeArg::new)() + { + (); + unsafe { + builtin#lang(UnsafeArg::new)() + } }, ); }"#]] .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } +#[test] +fn desugar_builtin_format_args() { + let (db, body, def) = lower( + r#" +//- minicore: fmt +fn main() { + let are = "are"; + let count = 10; + builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); +} +"#, + ); + + expect![[r#" + fn main() { + let are = "are"; + let count = 10; + { + let args = (&"fancy", &(), &"!", &count, &are, ); + let args = [ + builtin#lang(Argument::new_display)( + args.3, + ), builtin#lang(Argument::new_display)( + args.0, + ), builtin#lang(Argument::new_debug)( + args.4, + ), builtin#lang(Argument::new_display)( + args.2, + ), + ]; + unsafe { + builtin#lang(Arguments::new_v1_formatted)( + &[ + "\u{1b}hello ", " ", " friends, we ", " ", "", + ], + &args, + &[ + builtin#lang(Placeholder::new)( + 0usize, + ' ', + builtin#lang(Alignment::Unknown), + 8u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Is)( + 2, + ), + ), builtin#lang(Placeholder::new)( + 1usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), builtin#lang(Placeholder::new)( + 2usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), builtin#lang(Placeholder::new)( + 1usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), builtin#lang(Placeholder::new)( + 3usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), + ], + ) + } + }; + }"#]] + .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) +} + #[test] fn test_macro_hygiene() { let (db, body, def) = lower( @@ -295,29 +381,31 @@ impl SsrError { expect![[r#" fn main() { _ = ra_test_fixture::error::SsrError::new( - builtin#lang(Arguments::new_v1_formatted)( - &[ - "Failed to resolve path `", "`", - ], - &[ + { + let args = [ builtin#lang(Argument::new_display)( &node.text(), ), - ], - &[ - builtin#lang(Placeholder::new)( - 0usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), - ], + ]; unsafe { - builtin#lang(UnsafeArg::new)() - }, - ), + builtin#lang(Arguments::new_v1_formatted)( + &[ + "Failed to resolve path `", "`", + ], + &args, + &[ + builtin#lang(Placeholder::new)( + 0usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), + ], + ) + } + }, ); }"#]] .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) @@ -327,7 +415,7 @@ impl SsrError { fn regression_10300() { let (db, body, def) = lower( r#" -//- minicore: concat, panic +//- minicore: concat, panic, fmt_before_1_89_0 mod private { pub use core::concat; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs index f01b7c0bc24a..019ddaf1441d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs @@ -100,7 +100,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!() }"#, fn test_complete_todo_with_msg() { check_assist( term_search, - r#"//- minicore: todo, unimplemented + // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure. + // Should implement super let and remove `fmt_before_1_89_0` + r#"//- minicore: todo, unimplemented, fmt_before_1_89_0 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, r#"fn f() { let a: u128 = 1; let b: u128 = a }"#, ) @@ -110,7 +112,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, fn test_complete_unimplemented_with_msg() { check_assist( term_search, - r#"//- minicore: todo, unimplemented + // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure. + // Should implement super let and remove `fmt_before_1_89_0` + r#"//- minicore: todo, unimplemented, fmt_before_1_89_0 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, r#"fn f() { let a: u128 = 1; let b: u128 = a }"#, ) @@ -120,7 +124,9 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, fn test_complete_unimplemented() { check_assist( term_search, - r#"//- minicore: todo, unimplemented + // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure. + // Should implement super let and remove `fmt_before_1_89_0` + r#"//- minicore: todo, unimplemented, fmt_before_1_89_0 fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, r#"fn f() { let a: u128 = 1; let b: u128 = a }"#, ) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index b46e4c32061b..b2d18b796f19 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -1474,20 +1474,18 @@ fn main() { } "#, expect![[r#" + me foo() fn(&self) sn box Box::new(expr) sn call function(expr) sn const const {} sn dbg dbg!(expr) sn dbgr dbg!(&expr) sn deref *expr - sn if if expr {} sn match match expr {} - sn not !expr sn ref &expr sn refm &mut expr sn return return expr sn unsafe unsafe {} - sn while while expr {} "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 6bd5417b25d7..d8f6e813d800 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -628,6 +628,17 @@ fn main() { #[test] fn orphan_unsafe_format_args() { // Checks that we don't place orphan arguments for formatting under an unsafe block. + check_diagnostics( + r#" +//- minicore: fmt_before_1_89_0 +fn foo() { + let p = 0xDEADBEEF as *const i32; + format_args!("", *p); + // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block +} + "#, + ); + check_diagnostics( r#" //- minicore: fmt @@ -958,4 +969,18 @@ impl FooTrait for S2 { "#, ); } + + #[test] + fn no_false_positive_on_format_args_since_1_89_0() { + check_diagnostics( + r#" +//- minicore: fmt +fn test() { + let foo = 10; + let bar = true; + let _x = format_args!("{} {0} {} {last}", foo, bar, last = "!"); +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index d5cbb7328c14..adc581309d15 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -496,6 +496,7 @@ define_symbols! { vectorcall, wasm, win64, + args, array, boxed_slice, completions, diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs index ddc722631163..1d821e96e550 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs @@ -446,13 +446,13 @@ impl MiniCore { } let mut keep = true; - for ®ion in active_regions.iter() { + for ®ion in &active_regions { assert!(!region.starts_with(' '), "region marker starts with a space: {region:?}"); self.assert_valid_flag(region); seen_regions.push(region); keep &= self.has_flag(region); } - for ®ion in inactive_regions.iter() { + for ®ion in &inactive_regions { assert!(!region.starts_with(' '), "region marker starts with a space: {region:?}"); self.assert_valid_flag(region); seen_regions.push(region); From b1d18129d199c095372c39f75a5c3fb31ea166c2 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Mon, 16 Jun 2025 17:51:29 +0200 Subject: [PATCH 241/356] Implement DesugaringKind::FormatLiteral --- compiler/rustc_ast/src/format.rs | 8 +++ compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/format.rs | 9 +++- compiler/rustc_builtin_macros/src/format.rs | 1 + compiler/rustc_span/src/hygiene.rs | 16 ++++++ .../src/error_reporting/traits/suggestions.rs | 32 ++++++++--- library/core/src/fmt/mod.rs | 19 ++++--- .../argument-suggestions/issue-100154.stderr | 4 +- .../defaults-unsound-62211-1.current.stderr | 3 +- .../defaults-unsound-62211-1.next.stderr | 3 +- .../defaults-unsound-62211-2.current.stderr | 3 +- .../defaults-unsound-62211-2.next.stderr | 3 +- tests/ui/binop/issue-77910-1.stderr | 3 +- tests/ui/closures/issue-111932.stderr | 4 +- tests/ui/consts/const-eval/format.stderr | 2 +- ...ives-span-Debug-enum-struct-variant.stderr | 3 +- .../ui/derives/derives-span-Debug-enum.stderr | 3 +- .../derives/derives-span-Debug-struct.stderr | 3 +- .../derives-span-Debug-tuple-struct.stderr | 3 +- ...prefix-diagnostics.not-diag-in-deps.stderr | 4 +- ...-diagnostics.only-debuginfo-in-deps.stderr | 4 +- ...refix-diagnostics.only-diag-in-deps.stderr | 4 +- ...efix-diagnostics.only-macro-in-deps.stderr | 4 +- ...-diagnostics.with-debuginfo-in-deps.stderr | 4 +- ...refix-diagnostics.with-diag-in-deps.stderr | 4 +- ...efix-diagnostics.with-macro-in-deps.stderr | 4 +- tests/ui/fmt/format-args-argument-span.stderr | 10 ++-- tests/ui/fmt/ifmt-unimpl.stderr | 4 +- tests/ui/fmt/non-source-literals.rs | 13 +++++ tests/ui/fmt/non-source-literals.stderr | 53 +++++++++++++++++++ .../generic-associated-types-where.stderr | 3 +- .../impl-trait/in-trait/doesnt-satisfy.stderr | 4 +- tests/ui/impl-trait/in-trait/wf-bounds.stderr | 3 +- tests/ui/issues/issue-59488.stderr | 6 +-- ...70724-add_type_neq_err_label-unwrap.stderr | 3 +- .../methods/suggest-convert-ptr-to-ref.stderr | 6 +-- .../method-help-unsatisfied-bound.stderr | 3 +- tests/ui/modules/issue-107649.stderr | 3 +- tests/ui/on-unimplemented/no-debug.stderr | 16 ++++-- .../dbg-macro-requires-debug.stderr | 3 +- tests/ui/span/issue-71363.stderr | 7 +-- tests/ui/suggestions/bound-suggestions.stderr | 24 ++++++--- .../derive-macro-missing-bounds.stderr | 3 +- .../impl-trait-with-missing-bounds.stderr | 18 +++---- tests/ui/suggestions/issue-81098.stderr | 10 +--- tests/ui/suggestions/issue-97760.stderr | 5 +- ...missing-bound-in-derive-copy-impl-3.stderr | 6 +-- .../missing-bound-in-derive-copy-impl.stderr | 6 +-- tests/ui/suggestions/path-display.stderr | 9 +++- .../traits/on_unimplemented_long_types.stderr | 3 +- .../suggest-remove-deref-issue-140166.stderr | 4 +- .../bounds-are-checked3.stderr | 3 +- .../generic_duplicate_param_use2.stderr | 2 +- .../generic_duplicate_param_use4.stderr | 2 +- .../generic_underconstrained2.stderr | 8 +-- tests/ui/type-alias-impl-trait/nested.stderr | 4 +- ...igned-block-without-tail-expression.stderr | 16 ++++-- .../ui/type/pattern_types/derives_fail.stderr | 4 +- .../point-at-type-param-in-path-expr.stderr | 4 +- 59 files changed, 261 insertions(+), 159 deletions(-) create mode 100644 tests/ui/fmt/non-source-literals.rs create mode 100644 tests/ui/fmt/non-source-literals.stderr diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index b611ddea1d9f..28d260419c51 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -50,6 +50,14 @@ pub struct FormatArgs { /// /// Generally only useful for lints that care about the raw bytes the user wrote. pub uncooked_fmt_str: (LitKind, Symbol), + /// Was the format literal written in the source? + /// - `format!("boo")` => true, + /// - `format!(concat!("b", "o", "o"))` => false, + /// - `format!(include_str!("boo.txt"))` => false, + /// + /// If it wasn't written in the source then we have to be careful with spans pointing into it + /// and suggestions about rewriting it. + pub is_source_literal: bool, } /// A piece of a format template string. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index bd2ab34bfc19..245aa993affe 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1389,7 +1389,7 @@ macro_rules! common_visitor_and_walkers { // FIXME: visit the template exhaustively. pub fn walk_format_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, fmt: &$($lt)? $($mut)? FormatArgs) -> V::Result { - let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt; + let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _, is_source_literal: _ } = fmt; let args = $(${ignore($mut)} arguments.all_args_mut())? $(${ignore($lt)} arguments.all_args())? ; for FormatArgument { kind, expr } in args { match kind { diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 12f0af754868..943cde90dd20 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -4,7 +4,7 @@ use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_session::config::FmtDebug; -use rustc_span::{Ident, Span, Symbol, sym}; +use rustc_span::{DesugaringKind, Ident, Span, Symbol, sym}; use super::LoweringContext; @@ -14,6 +14,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // format_args!() had any arguments _before_ flattening/inlining. let allow_const = fmt.arguments.all_args().is_empty(); let mut fmt = Cow::Borrowed(fmt); + + let sp = self.mark_span_with_reason( + DesugaringKind::FormatLiteral { source: fmt.is_source_literal }, + sp, + sp.ctxt().outer_expn_data().allow_internal_unstable, + ); + if self.tcx.sess.opts.unstable_opts.flatten_format_args { fmt = flatten_format_args(fmt); fmt = self.inline_literals(fmt); diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 39f9d5f90051..6785cb6aef5a 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -606,6 +606,7 @@ fn make_format_args( template, arguments: args, uncooked_fmt_str, + is_source_literal, })) } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 315dedec1075..29be3b73ee99 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1213,6 +1213,17 @@ pub enum DesugaringKind { Contract, /// A pattern type range start/end PatTyRange, + /// A format literal. + FormatLiteral { + /// Was this format literal written in the source? + /// - `format!("boo")` => Yes, + /// - `format!(concat!("b", "o", "o"))` => No, + /// - `format!(include_str!("boo.txt"))` => No, + /// + /// If it wasn't written in the source then we have to be careful with suggestions about + /// rewriting it. + source: bool, + }, } impl DesugaringKind { @@ -1231,6 +1242,10 @@ impl DesugaringKind { DesugaringKind::BoundModifier => "trait bound modifier", DesugaringKind::Contract => "contract check", DesugaringKind::PatTyRange => "pattern type", + DesugaringKind::FormatLiteral { source: true } => "format string literal", + DesugaringKind::FormatLiteral { source: false } => { + "expression that expanded into a format string literal" + } } } @@ -1250,6 +1265,7 @@ impl DesugaringKind { DesugaringKind::BoundModifier => value == "BoundModifier", DesugaringKind::Contract => value == "Contract", DesugaringKind::PatTyRange => value == "PatTyRange", + DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral", } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 6d07ae021ae9..35fce041af4e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2872,13 +2872,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (), } } - let descr = format!("required by {a} bound in `{item_name}`"); - if span.is_visible(sm) { - let msg = format!("required by {this} in `{short_item_name}`"); - multispan.push_span_label(span, msg); - err.span_note(multispan, descr); + + // If this is from a format string literal desugaring, + // we've already said "required by this formatting parameter" + let is_in_fmt_lit = if let Some(s) = err.span.primary_span() { + matches!(s.desugaring_kind(), Some(DesugaringKind::FormatLiteral { .. })) } else { - err.span_note(tcx.def_span(item_def_id), descr); + false + }; + if !is_in_fmt_lit { + let descr = format!("required by {a} bound in `{item_name}`"); + if span.is_visible(sm) { + let msg = format!("required by {this} in `{short_item_name}`"); + multispan.push_span_label(span, msg); + err.span_note(multispan, descr); + } else { + err.span_note(tcx.def_span(item_def_id), descr); + } } if let Some(note) = note { err.note(note); @@ -3973,7 +3983,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) = expr.kind { if Some(*span) != err.span.primary_span() { - err.span_label(*span, "required by a bound introduced by this call"); + let msg = if span.is_desugaring(DesugaringKind::FormatLiteral { source: true }) + { + "required by this formatting parameter" + } else if span.is_desugaring(DesugaringKind::FormatLiteral { source: false }) { + "required by a formatting parameter in this expression" + } else { + "required by a bound introduced by this call" + }; + err.span_label(*span, msg); } } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c20b3d4817f9..2be8d37bbee6 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -855,11 +855,13 @@ impl Display for Arguments<'_> { #[rustc_on_unimplemented( on( crate_local, - label = "`{Self}` cannot be formatted using `{{:?}}`", note = "add `#[derive(Debug)]` to `{Self}` or manually `impl {This} for {Self}`" ), - message = "`{Self}` doesn't implement `{This}`", - label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`" + on( + from_desugaring = "FormatLiteral", + label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{This}`" + ), + message = "`{Self}` doesn't implement `{This}`" )] #[doc(alias = "{:?}")] #[rustc_diagnostic_item = "Debug"] @@ -986,11 +988,14 @@ pub use macros::Debug; any(Self = "std::path::Path", Self = "std::path::PathBuf"), label = "`{Self}` cannot be formatted with the default formatter; call `.display()` on it", note = "call `.display()` or `.to_string_lossy()` to safely print paths, \ - as they may contain non-Unicode data" + as they may contain non-Unicode data", ), - message = "`{Self}` doesn't implement `{This}`", - label = "`{Self}` cannot be formatted with the default formatter", - note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead" + on( + from_desugaring = "FormatLiteral", + note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead", + label = "`{Self}` cannot be formatted with the default formatter", + ), + message = "`{Self}` doesn't implement `{This}`" )] #[doc(alias = "{}")] #[rustc_diagnostic_item = "Display"] diff --git a/tests/ui/argument-suggestions/issue-100154.stderr b/tests/ui/argument-suggestions/issue-100154.stderr index 7eaebcafb595..9732beac4492 100644 --- a/tests/ui/argument-suggestions/issue-100154.stderr +++ b/tests/ui/argument-suggestions/issue-100154.stderr @@ -17,10 +17,8 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/issue-100154.rs:4:11 | LL | foo::<()>(()); - | ^^ `()` cannot be formatted with the default formatter + | ^^ the trait `std::fmt::Display` is not implemented for `()` | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `foo` --> $DIR/issue-100154.rs:1:16 | diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr index 8b6f0a47aed9..b17e26b608d9 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-1.current.stderr @@ -2,9 +2,8 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-1.rs:24:96 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ `Self` cannot be formatted with the default formatter + | ^^^^ the trait `std::fmt::Display` is not implemented for `Self` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `UncheckedCopy::Output` --> $DIR/defaults-unsound-62211-1.rs:24:86 | diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr index 010f51df15ad..a858c9c1ba04 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr @@ -2,9 +2,8 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-1.rs:24:96 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ `Self` cannot be formatted with the default formatter + | ^^^^ the trait `std::fmt::Display` is not implemented for `Self` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `UncheckedCopy::Output` --> $DIR/defaults-unsound-62211-1.rs:24:86 | diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr index 7552b0891333..facfec85afe3 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-2.current.stderr @@ -2,9 +2,8 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-2.rs:24:96 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ `Self` cannot be formatted with the default formatter + | ^^^^ the trait `std::fmt::Display` is not implemented for `Self` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `UncheckedCopy::Output` --> $DIR/defaults-unsound-62211-2.rs:24:86 | diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr index 934789465707..1360843172f9 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr @@ -2,9 +2,8 @@ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-2.rs:24:96 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ `Self` cannot be formatted with the default formatter + | ^^^^ the trait `std::fmt::Display` is not implemented for `Self` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `UncheckedCopy::Output` --> $DIR/defaults-unsound-62211-2.rs:24:86 | diff --git a/tests/ui/binop/issue-77910-1.stderr b/tests/ui/binop/issue-77910-1.stderr index 74deac900d42..80c384f39bd1 100644 --- a/tests/ui/binop/issue-77910-1.stderr +++ b/tests/ui/binop/issue-77910-1.stderr @@ -16,9 +16,8 @@ LL | fn foo(s: &i32) -> &i32 { | --- consider calling this function ... LL | assert_eq!(foo, y); - | ^^^^^^^^^^^^^^^^^^ `for<'a> fn(&'a i32) -> &'a i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `for<'a> fn(&'a i32) -> &'a i32 {foo}` | - = help: the trait `Debug` is not implemented for fn item `for<'a> fn(&'a i32) -> &'a i32 {foo}` = help: use parentheses to call this function: `foo(/* &i32 */)` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/closures/issue-111932.stderr b/tests/ui/closures/issue-111932.stderr index 93488ad2011e..fc3b7b0c6e66 100644 --- a/tests/ui/closures/issue-111932.stderr +++ b/tests/ui/closures/issue-111932.stderr @@ -14,11 +14,9 @@ error[E0277]: the size for values of type `dyn Foo` cannot be known at compilati LL | println!("{:?}", foo); | ---- ^^^ doesn't have a size known at compile-time | | - | required by a bound introduced by this call + | required by this formatting parameter | = help: the trait `Sized` is not implemented for `dyn Foo` -note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'_>::new_debug` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index 2f202705b7f9..bd50ac0bf411 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -13,7 +13,7 @@ LL | println!("{:?}", 0); | ^^^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0015]: cannot call non-const function `_print` in constant functions --> $DIR/format.rs:7:5 diff --git a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr index a7f6d094681a..147910b715f5 100644 --- a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr @@ -5,9 +5,8 @@ LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | x: Error - | ^^^^^^^^ `Error` cannot be formatted using `{:?}` + | ^^^^^^^^ the trait `Debug` is not implemented for `Error` | - = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | diff --git a/tests/ui/derives/derives-span-Debug-enum.stderr b/tests/ui/derives/derives-span-Debug-enum.stderr index b3a584781598..6f97ceb02d3a 100644 --- a/tests/ui/derives/derives-span-Debug-enum.stderr +++ b/tests/ui/derives/derives-span-Debug-enum.stderr @@ -5,9 +5,8 @@ LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | Error - | ^^^^^ `Error` cannot be formatted using `{:?}` + | ^^^^^ the trait `Debug` is not implemented for `Error` | - = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | diff --git a/tests/ui/derives/derives-span-Debug-struct.stderr b/tests/ui/derives/derives-span-Debug-struct.stderr index c8ad652716ca..46d69a892f25 100644 --- a/tests/ui/derives/derives-span-Debug-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-struct.stderr @@ -5,9 +5,8 @@ LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Struct { LL | x: Error - | ^^^^^^^^ `Error` cannot be formatted using `{:?}` + | ^^^^^^^^ the trait `Debug` is not implemented for `Error` | - = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | diff --git a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr index dbece4d2091b..a3feeff6df37 100644 --- a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr +++ b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr @@ -5,9 +5,8 @@ LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Struct( LL | Error - | ^^^^^ `Error` cannot be formatted using `{:?}` + | ^^^^^ the trait `Debug` is not implemented for `Error` | - = help: the trait `Debug` is not implemented for `Error` = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error` help: consider annotating `Error` with `#[derive(Debug)]` | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr index 3ddff11798de..229bfbe59e50 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> remapped/errors/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr index 85c781425b16..a59af3b6a826 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-debuginfo.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr index 792ea7925ad5..18fb9afcf390 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-diag.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr index d13333d2e482..9e770f07fba2 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-macro.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr index 85c781425b16..a59af3b6a826 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-debuginfo.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr index 08f7fb2c7364..ca6f2b1697a8 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> remapped/errors/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> remapped/errors/auxiliary/trait-diag.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr index d13333d2e482..9e770f07fba2 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr @@ -2,10 +2,8 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ `A` cannot be formatted with the default formatter + | ^ the trait `std::fmt::Display` is not implemented for `A` | - = help: the trait `std::fmt::Display` is not implemented for `A` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Trait` --> $DIR/auxiliary/trait-macro.rs:LL:COL | diff --git a/tests/ui/fmt/format-args-argument-span.stderr b/tests/ui/fmt/format-args-argument-span.stderr index 4e2702383d6c..d46cfb438cf6 100644 --- a/tests/ui/fmt/format-args-argument-span.stderr +++ b/tests/ui/fmt/format-args-argument-span.stderr @@ -12,7 +12,9 @@ error[E0277]: `Option<{integer}>` doesn't implement `std::fmt::Display` --> $DIR/format-args-argument-span.rs:15:37 | LL | println!("{x:?} {x} {x:?}", x = Some(1)); - | ^^^^^^^ `Option<{integer}>` cannot be formatted with the default formatter + | --- ^^^^^^^ `Option<{integer}>` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `Option<{integer}>` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -22,7 +24,7 @@ error[E0277]: `DisplayOnly` doesn't implement `Debug` --> $DIR/format-args-argument-span.rs:18:19 | LL | println!("{x} {x:?} {x}"); - | ^^^^^ `DisplayOnly` cannot be formatted using `{:?}` + | ^^^^^ `DisplayOnly` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `DisplayOnly` = note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly` @@ -37,7 +39,9 @@ error[E0277]: `DisplayOnly` doesn't implement `Debug` --> $DIR/format-args-argument-span.rs:20:35 | LL | println!("{x} {x:?} {x}", x = DisplayOnly); - | ^^^^^^^^^^^ `DisplayOnly` cannot be formatted using `{:?}` + | ----- ^^^^^^^^^^^ `DisplayOnly` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = help: the trait `Debug` is not implemented for `DisplayOnly` = note: add `#[derive(Debug)]` to `DisplayOnly` or manually `impl Debug for DisplayOnly` diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index b8d4425a4a71..5e80f892dcb5 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `str: UpperHex` is not satisfied LL | format!("{:X}", "3"); | ---- ^^^ the trait `UpperHex` is not implemented for `str` | | - | required by a bound introduced by this call + | required by this formatting parameter | = help: the following other types implement trait `UpperHex`: &T @@ -17,8 +17,6 @@ LL | format!("{:X}", "3"); i32 and 9 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `core::fmt::rt::Argument::<'_>::new_upper_hex` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/fmt/non-source-literals.rs b/tests/ui/fmt/non-source-literals.rs new file mode 100644 index 000000000000..e3ffdb40a6b7 --- /dev/null +++ b/tests/ui/fmt/non-source-literals.rs @@ -0,0 +1,13 @@ +/// Do not point at the format string if it wasn't written in the source. +//@ forbid-output: required by this formatting parameter + +#[derive(Debug)] +pub struct NonDisplay; +pub struct NonDebug; + +fn main() { + let _ = format!(concat!("{", "}"), NonDisplay); //~ ERROR + let _ = format!(concat!("{", "0", "}"), NonDisplay); //~ ERROR + let _ = format!(concat!("{:", "?}"), NonDebug); //~ ERROR + let _ = format!(concat!("{", "0", ":?}"), NonDebug); //~ ERROR +} diff --git a/tests/ui/fmt/non-source-literals.stderr b/tests/ui/fmt/non-source-literals.stderr new file mode 100644 index 000000000000..5f8a6200dab7 --- /dev/null +++ b/tests/ui/fmt/non-source-literals.stderr @@ -0,0 +1,53 @@ +error[E0277]: `NonDisplay` doesn't implement `std::fmt::Display` + --> $DIR/non-source-literals.rs:9:40 + | +LL | let _ = format!(concat!("{", "}"), NonDisplay); + | ^^^^^^^^^^ `NonDisplay` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `NonDisplay` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `NonDisplay` doesn't implement `std::fmt::Display` + --> $DIR/non-source-literals.rs:10:45 + | +LL | let _ = format!(concat!("{", "0", "}"), NonDisplay); + | ^^^^^^^^^^ `NonDisplay` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `NonDisplay` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `NonDebug` doesn't implement `Debug` + --> $DIR/non-source-literals.rs:11:42 + | +LL | let _ = format!(concat!("{:", "?}"), NonDebug); + | ^^^^^^^^ `NonDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = help: the trait `Debug` is not implemented for `NonDebug` + = note: add `#[derive(Debug)]` to `NonDebug` or manually `impl Debug for NonDebug` + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NonDebug` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | pub struct NonDebug; + | + +error[E0277]: `NonDebug` doesn't implement `Debug` + --> $DIR/non-source-literals.rs:12:47 + | +LL | let _ = format!(concat!("{", "0", ":?}"), NonDebug); + | ^^^^^^^^ `NonDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = help: the trait `Debug` is not implemented for `NonDebug` + = note: add `#[derive(Debug)]` to `NonDebug` or manually `impl Debug for NonDebug` + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NonDebug` with `#[derive(Debug)]` + | +LL + #[derive(Debug)] +LL | pub struct NonDebug; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/generic-associated-types/generic-associated-types-where.stderr b/tests/ui/generic-associated-types/generic-associated-types-where.stderr index 7dce34650d78..637f86f7bec2 100644 --- a/tests/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/tests/ui/generic-associated-types/generic-associated-types-where.stderr @@ -2,9 +2,8 @@ error[E0277]: `T` doesn't implement `std::fmt::Display` --> $DIR/generic-associated-types-where.rs:18:22 | LL | type Assoc2 = Vec; - | ^^^^^^ `T` cannot be formatted with the default formatter + | ^^^^^^ the trait `std::fmt::Display` is not implemented for `T` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider restricting type parameter `T` with trait `Display` | LL | type Assoc2 = Vec; diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr index 119195f17ffc..df89ed9f3b56 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr @@ -2,10 +2,8 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/doesnt-satisfy.rs:6:17 | LL | fn bar() -> () {} - | ^^ `()` cannot be formatted with the default formatter + | ^^ the trait `std::fmt::Display` is not implemented for `()` | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Foo::bar::{anon_assoc#0}` --> $DIR/doesnt-satisfy.rs:2:22 | diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.stderr index 634557094ced..40a029cdc920 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.stderr @@ -39,9 +39,8 @@ error[E0277]: `T` doesn't implement `std::fmt::Display` --> $DIR/wf-bounds.rs:21:26 | LL | fn nya4() -> impl Wf>; - | ^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter + | ^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `T` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `NeedsDisplay` --> $DIR/wf-bounds.rs:9:24 | diff --git a/tests/ui/issues/issue-59488.stderr b/tests/ui/issues/issue-59488.stderr index ac8862716c07..b6611ad63a81 100644 --- a/tests/ui/issues/issue-59488.stderr +++ b/tests/ui/issues/issue-59488.stderr @@ -87,18 +87,16 @@ error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` --> $DIR/issue-59488.rs:30:5 | LL | assert_eq!(Foo::Bar, i); - | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` | - = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` --> $DIR/issue-59488.rs:30:5 | LL | assert_eq!(Foo::Bar, i); - | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` | - = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors diff --git a/tests/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/tests/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr index b30bcfb776c8..736002c9335a 100644 --- a/tests/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr +++ b/tests/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -26,9 +26,8 @@ LL | fn a() -> i32 { | - consider calling this function ... LL | assert_eq!(a, 0); - | ^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `fn() -> i32 {a}` | - = help: the trait `Debug` is not implemented for fn item `fn() -> i32 {a}` = help: use parentheses to call this function: `a()` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr index 7d52b20121e9..8cb97ea458bc 100644 --- a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr +++ b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr @@ -2,7 +2,7 @@ error[E0599]: `*const u8` doesn't implement `std::fmt::Display` --> $DIR/suggest-convert-ptr-to-ref.rs:5:22 | LL | println!("{}", z.to_string()); - | ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter + | ^^^^^^^^^ method cannot be called on `*const u8` due to unsatisfied trait bounds | note: the method `to_string` exists on the type `&u8` --> $SRC_DIR/alloc/src/string.rs:LL:COL @@ -11,13 +11,12 @@ note: the method `to_string` exists on the type `&u8` = note: the following trait bounds were not satisfied: `*const u8: std::fmt::Display` which is required by `*const u8: ToString` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead error[E0599]: `*mut u8` doesn't implement `std::fmt::Display` --> $DIR/suggest-convert-ptr-to-ref.rs:8:22 | LL | println!("{}", t.to_string()); - | ^^^^^^^^^ `*mut u8` cannot be formatted with the default formatter + | ^^^^^^^^^ method cannot be called on `*mut u8` due to unsatisfied trait bounds | note: the method `to_string` exists on the type `&&mut u8` --> $SRC_DIR/alloc/src/string.rs:LL:COL @@ -26,7 +25,6 @@ note: the method `to_string` exists on the type `&&mut u8` = note: the following trait bounds were not satisfied: `*mut u8: std::fmt::Display` which is required by `*mut u8: ToString` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope --> $DIR/suggest-convert-ptr-to-ref.rs:9:7 diff --git a/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr index be3a3e2abf14..23bc9dc0f844 100644 --- a/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/tests/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -2,9 +2,8 @@ error[E0277]: `Foo` doesn't implement `Debug` --> $DIR/method-help-unsatisfied-bound.rs:5:7 | LL | a.unwrap(); - | ^^^^^^ `Foo` cannot be formatted using `{:?}` + | ^^^^^^ the trait `Debug` is not implemented for `Foo` | - = help: the trait `Debug` is not implemented for `Foo` = note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo` note: required by a bound in `Result::::unwrap` --> $SRC_DIR/core/src/result.rs:LL:COL diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index 0d203c1aacba..f0353282d285 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -2,10 +2,11 @@ error[E0277]: `Dummy` doesn't implement `Debug` --> $DIR/issue-107649.rs:105:5 | 105 | dbg!(lib::Dummy); - | ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}` + | ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `Dummy` = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` + = note: required for `&Dummy` to implement `Debug` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 diff --git a/tests/ui/on-unimplemented/no-debug.stderr b/tests/ui/on-unimplemented/no-debug.stderr index 97d67dbd82e7..5b0b060d40ef 100644 --- a/tests/ui/on-unimplemented/no-debug.stderr +++ b/tests/ui/on-unimplemented/no-debug.stderr @@ -2,7 +2,9 @@ error[E0277]: `Foo` doesn't implement `Debug` --> $DIR/no-debug.rs:10:27 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `Foo` cannot be formatted using `{:?}` + | ---- ^^^ `Foo` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = help: the trait `Debug` is not implemented for `Foo` = note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo` @@ -17,7 +19,9 @@ error[E0277]: `Bar` doesn't implement `Debug` --> $DIR/no-debug.rs:10:32 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = help: the trait `Debug` is not implemented for `Bar` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -26,7 +30,9 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:11:23 | LL | println!("{} {}", Foo, Bar); - | ^^^ `Foo` cannot be formatted with the default formatter + | -- ^^^ `Foo` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `Foo` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -36,7 +42,9 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:11:28 | LL | println!("{} {}", Foo, Bar); - | ^^^ `Bar` cannot be formatted with the default formatter + | -- ^^^ `Bar` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `Bar` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 7ec018a95cc7..190db0429943 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -2,10 +2,11 @@ error[E0277]: `NotDebug` doesn't implement `Debug` --> $DIR/dbg-macro-requires-debug.rs:6:23 | LL | let _: NotDebug = dbg!(NotDebug); - | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` + | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = help: the trait `Debug` is not implemented for `NotDebug` = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` + = note: required for `&NotDebug` to implement `Debug` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` | diff --git a/tests/ui/span/issue-71363.stderr b/tests/ui/span/issue-71363.stderr index 90b623e89cff..31069914daac 100644 --- a/tests/ui/span/issue-71363.stderr +++ b/tests/ui/span/issue-71363.stderr @@ -2,10 +2,8 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` --> $DIR/issue-71363.rs:4:28 | 4 | impl std::error::Error for MyError {} - | ^^^^^^^ `MyError` cannot be formatted with the default formatter + | ^^^^^^^ the trait `std::fmt::Display` is not implemented for `MyError` | - = help: the trait `std::fmt::Display` is not implemented for `MyError` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `std::error::Error` --> $SRC_DIR/core/src/error.rs:LL:COL @@ -13,9 +11,8 @@ error[E0277]: `MyError` doesn't implement `Debug` --> $DIR/issue-71363.rs:4:28 | 4 | impl std::error::Error for MyError {} - | ^^^^^^^ `MyError` cannot be formatted using `{:?}` + | ^^^^^^^ the trait `Debug` is not implemented for `MyError` | - = help: the trait `Debug` is not implemented for `MyError` = note: add `#[derive(Debug)]` to `MyError` or manually `impl Debug for MyError` note: required by a bound in `std::error::Error` --> $SRC_DIR/core/src/error.rs:LL:COL diff --git a/tests/ui/suggestions/bound-suggestions.stderr b/tests/ui/suggestions/bound-suggestions.stderr index f23e086afe4e..ec1d23fac458 100644 --- a/tests/ui/suggestions/bound-suggestions.stderr +++ b/tests/ui/suggestions/bound-suggestions.stderr @@ -2,7 +2,9 @@ error[E0277]: `impl Sized` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:9:22 | LL | println!("{:?}", t); - | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting opaque type `impl Sized` with trait `Debug` @@ -14,7 +16,9 @@ error[E0277]: `T` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:15:22 | LL | println!("{:?}", t); - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `Debug` @@ -26,7 +30,9 @@ error[E0277]: `T` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:21:22 | LL | println!("{:?}", t); - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `T` with trait `Debug` @@ -38,7 +44,9 @@ error[E0277]: `Y` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:27:30 | LL | println!("{:?} {:?}", x, y); - | ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `Y` with trait `Debug` @@ -50,7 +58,9 @@ error[E0277]: `X` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:33:22 | LL | println!("{:?}", x); - | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` with trait `Debug` @@ -62,7 +72,9 @@ error[E0277]: `X` doesn't implement `Debug` --> $DIR/bound-suggestions.rs:39:22 | LL | println!("{:?}", x); - | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` with trait `Debug` diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr index 68c8204d1e18..b28f39ced542 100644 --- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr @@ -4,9 +4,8 @@ error[E0277]: `a::Inner` doesn't implement `Debug` LL | #[derive(Debug)] | ----- in this derive macro expansion LL | struct Outer(Inner); - | ^^^^^^^^ `a::Inner` cannot be formatted using `{:?}` + | ^^^^^^^^ the trait `Debug` is not implemented for `a::Inner` | - = help: the trait `Debug` is not implemented for `a::Inner` = note: add `#[derive(Debug)]` to `a::Inner` or manually `impl Debug for a::Inner` help: consider annotating `a::Inner` with `#[derive(Debug)]` | diff --git a/tests/ui/suggestions/impl-trait-with-missing-bounds.stderr b/tests/ui/suggestions/impl-trait-with-missing-bounds.stderr index d0ce7c9ed4e8..b3f1865dd309 100644 --- a/tests/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/tests/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -2,11 +2,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:6:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -22,11 +21,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:14:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -42,11 +40,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:22:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -62,11 +59,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:30:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -82,11 +78,10 @@ error[E0277]: `::Item` doesn't impl --> $DIR/impl-trait-with-missing-bounds.rs:37:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | @@ -102,11 +97,10 @@ error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:45:13 | LL | qux(constraint); - | --- ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | --- ^^^^^^^^^^ the trait `Debug` is not implemented for `::Item` | | | required by a bound introduced by this call | - = help: the trait `Debug` is not implemented for `::Item` note: required by a bound in `qux` --> $DIR/impl-trait-with-missing-bounds.rs:50:16 | diff --git a/tests/ui/suggestions/issue-81098.stderr b/tests/ui/suggestions/issue-81098.stderr index 4dc47a202824..36948469a311 100644 --- a/tests/ui/suggestions/issue-81098.stderr +++ b/tests/ui/suggestions/issue-81098.stderr @@ -2,23 +2,17 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/issue-81098.rs:3:13 | LL | fn wat() -> impl core::fmt::Display { - | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter - | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `()` error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/issue-81098.rs:9:12 | LL | fn ok() -> impl core::fmt::Display { - | ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `()` LL | 1; | -- help: remove this semicolon | | | this expression has type `{integer}`, which implements `std::fmt::Display` - | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/issue-97760.stderr b/tests/ui/suggestions/issue-97760.stderr index ddd143b967c4..1084ea7c9e0e 100644 --- a/tests/ui/suggestions/issue-97760.stderr +++ b/tests/ui/suggestions/issue-97760.stderr @@ -2,7 +2,10 @@ error[E0277]: `::Item` doesn't implement `std --> $DIR/issue-97760.rs:4:20 | LL | println!("{x}"); - | ^ `::Item` cannot be formatted with the default formatter + | -^- + | || + | |`::Item` cannot be formatted with the default formatter + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `::Item` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr index 3f8b6f93e1f4..e3375b67c86d 100644 --- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr +++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.stderr @@ -21,7 +21,7 @@ error[E0277]: `K` doesn't implement `Debug` --> $DIR/missing-bound-in-derive-copy-impl-3.rs:12:14 | LL | pub loc: Vector2, - | ^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^ the trait `Debug` is not implemented for `K` | note: required by a bound in `Vector2` --> $DIR/missing-bound-in-derive-copy-impl-3.rs:5:23 @@ -40,7 +40,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion LL | pub struct AABB{ LL | pub loc: Vector2, - | ^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `K` | help: consider further restricting type parameter `K` with trait `Debug` | @@ -54,7 +54,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion ... LL | pub size: Vector2 - | ^^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `K` | help: consider further restricting type parameter `K` with trait `Debug` | diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr index 3766e3e2c7b5..645d6ebb3961 100644 --- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr +++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr @@ -21,7 +21,7 @@ error[E0277]: `K` doesn't implement `Debug` --> $DIR/missing-bound-in-derive-copy-impl.rs:11:14 | LL | pub loc: Vector2, - | ^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^ the trait `Debug` is not implemented for `K` | note: required by a bound in `Vector2` --> $DIR/missing-bound-in-derive-copy-impl.rs:4:23 @@ -78,7 +78,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion LL | pub struct AABB { LL | pub loc: Vector2, - | ^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `K` | help: consider restricting type parameter `K` with trait `Debug` | @@ -111,7 +111,7 @@ LL | #[derive(Debug, Copy, Clone)] | ----- in this derive macro expansion ... LL | pub size: Vector2, - | ^^^^^^^^^^^^^^^^^^^^ `K` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `K` | help: consider restricting type parameter `K` with trait `Debug` | diff --git a/tests/ui/suggestions/path-display.stderr b/tests/ui/suggestions/path-display.stderr index 46d0b35825bc..0c7271b3c1c3 100644 --- a/tests/ui/suggestions/path-display.stderr +++ b/tests/ui/suggestions/path-display.stderr @@ -2,18 +2,23 @@ error[E0277]: `Path` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:5:20 | LL | println!("{}", path); - | ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it + | -- ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `Path` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data + = note: required for `&Path` to implement `std::fmt::Display` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `PathBuf` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:9:20 | LL | println!("{}", path); - | ^^^^ `PathBuf` cannot be formatted with the default formatter; call `.display()` on it + | -- ^^^^ `PathBuf` cannot be formatted with the default formatter; call `.display()` on it + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `PathBuf` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/traits/on_unimplemented_long_types.stderr b/tests/ui/traits/on_unimplemented_long_types.stderr index 1628466e0818..f32d99a42b12 100644 --- a/tests/ui/traits/on_unimplemented_long_types.stderr +++ b/tests/ui/traits/on_unimplemented_long_types.stderr @@ -2,7 +2,7 @@ error[E0277]: `Option>>` doesn't implement `std::fmt::Display --> $DIR/on_unimplemented_long_types.rs:3:17 | LL | pub fn foo() -> impl std::fmt::Display { - | ^^^^^^^^^^^^^^^^^^^^^^ `Option>>` cannot be formatted with the default formatter + | ^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound LL | LL | / Some(Some(Some(Some(Some(Some(Some(Some(Some(S... LL | | Some(Some(Some(Some(Some(Some(Some(Some(So... @@ -14,7 +14,6 @@ LL | | ))))))))))) | |_______________- return type was inferred to be `Option>>` here | = help: the trait `std::fmt::Display` is not implemented for `Option>>` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: the full name for the type has been written to '$TEST_BUILD_DIR/on_unimplemented_long_types.long-type-$LONG_TYPE_HASH.txt' = note: consider using `--verbose` to print the full type name to the console diff --git a/tests/ui/traits/suggest-remove-deref-issue-140166.stderr b/tests/ui/traits/suggest-remove-deref-issue-140166.stderr index 90f24d86d53e..7c61f957fdcc 100644 --- a/tests/ui/traits/suggest-remove-deref-issue-140166.stderr +++ b/tests/ui/traits/suggest-remove-deref-issue-140166.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `&Chars: Trait` is not satisfied LL | format_args!("{:?}", FlatMap(&Chars)); | ---- ^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `&Chars` | | - | required by a bound introduced by this call + | required by this formatting parameter | = help: the trait `Trait` is implemented for `Chars` note: required for `FlatMap<&Chars>` to implement `Debug` @@ -14,8 +14,6 @@ LL | impl std::fmt::Debug for FlatMap { | ----- ^^^^^^^^^^^^^^^ ^^^^^^^^^^ | | | unsatisfied trait bound introduced here -note: required by a bound in `core::fmt::rt::Argument::<'_>::new_debug` - --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr b/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr index c0f6d6780976..01d24cabf48d 100644 --- a/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr +++ b/tests/ui/type-alias-impl-trait/bounds-are-checked3.stderr @@ -2,9 +2,8 @@ error[E0277]: `T` doesn't implement `std::fmt::Display` --> $DIR/bounds-are-checked3.rs:9:35 | LL | type Foo = (impl Debug, Struct); - | ^^^^^^^^^ `T` cannot be formatted with the default formatter + | ^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `T` | - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Struct` --> $DIR/bounds-are-checked3.rs:5:18 | diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr index ef0e73f1481f..193f0c92c9de 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr @@ -2,7 +2,7 @@ error[E0277]: `T` doesn't implement `Debug` --> $DIR/generic_duplicate_param_use2.rs:12:5 | LL | t - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^ the trait `Debug` is not implemented for `T` | note: required by a bound in an opaque type --> $DIR/generic_duplicate_param_use2.rs:8:23 diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr index 0932c72ff934..f0d1e93b0b76 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr @@ -2,7 +2,7 @@ error[E0277]: `U` doesn't implement `Debug` --> $DIR/generic_duplicate_param_use4.rs:12:5 | LL | u - | ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^ the trait `Debug` is not implemented for `U` | note: required by a bound in an opaque type --> $DIR/generic_duplicate_param_use4.rs:8:23 diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 429c3b9175a5..1e3c454a5bc2 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -2,7 +2,7 @@ error[E0277]: `U` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:9:33 | LL | fn underconstrained(_: U) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `U` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained2.rs:5:26 @@ -18,7 +18,7 @@ error[E0277]: `V` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:19:43 | LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `V` | note: required by a bound on the type alias `Underconstrained2` --> $DIR/generic_underconstrained2.rs:15:27 @@ -34,7 +34,7 @@ error[E0277]: `U` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:9:33 | LL | fn underconstrained(_: U) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `U` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained2.rs:5:26 @@ -51,7 +51,7 @@ error[E0277]: `V` doesn't implement `Debug` --> $DIR/generic_underconstrained2.rs:19:43 | LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `V` | note: required by a bound on the type alias `Underconstrained2` --> $DIR/generic_underconstrained2.rs:15:27 diff --git a/tests/ui/type-alias-impl-trait/nested.stderr b/tests/ui/type-alias-impl-trait/nested.stderr index 59911f65a234..f72830b864d1 100644 --- a/tests/ui/type-alias-impl-trait/nested.stderr +++ b/tests/ui/type-alias-impl-trait/nested.stderr @@ -15,7 +15,9 @@ error[E0277]: `Bar` doesn't implement `Debug` --> $DIR/nested.rs:17:22 | LL | println!("{:?}", bar()); - | ^^^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ---- ^^^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | | + | required by this formatting parameter | = help: the trait `Debug` is not implemented for `Bar` = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/type/binding-assigned-block-without-tail-expression.stderr b/tests/ui/type/binding-assigned-block-without-tail-expression.stderr index 3e96d7f317b4..ff34facf3892 100644 --- a/tests/ui/type/binding-assigned-block-without-tail-expression.stderr +++ b/tests/ui/type/binding-assigned-block-without-tail-expression.stderr @@ -5,7 +5,9 @@ LL | 42; | - help: remove this semicolon ... LL | println!("{}", x); - | ^ `()` cannot be formatted with the default formatter + | -- ^ `()` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -18,7 +20,9 @@ LL | let y = {}; | -- this empty block is missing a tail expression ... LL | println!("{}", y); - | ^ `()` cannot be formatted with the default formatter + | -- ^ `()` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -31,7 +35,9 @@ LL | "hi"; | - help: remove this semicolon ... LL | println!("{}", z); - | ^ `()` cannot be formatted with the default formatter + | -- ^ `()` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead @@ -47,7 +53,9 @@ LL | | }; | |_____- this block is missing a tail expression ... LL | println!("{}", s); - | ^ `()` cannot be formatted with the default formatter + | -- ^ `()` cannot be formatted with the default formatter + | | + | required by this formatting parameter | = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead diff --git a/tests/ui/type/pattern_types/derives_fail.stderr b/tests/ui/type/pattern_types/derives_fail.stderr index 78bef726341d..6b2e27494f0e 100644 --- a/tests/ui/type/pattern_types/derives_fail.stderr +++ b/tests/ui/type/pattern_types/derives_fail.stderr @@ -26,9 +26,7 @@ LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default) | ----- in this derive macro expansion LL | #[repr(transparent)] LL | struct Nanoseconds(NanoI32); - | ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | - = help: the trait `Debug` is not implemented for `(i32) is 0..=999999999` + | ^^^^^^^ the trait `Debug` is not implemented for `(i32) is 0..=999999999` error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied --> $DIR/derives_fail.rs:11:20 diff --git a/tests/ui/typeck/point-at-type-param-in-path-expr.stderr b/tests/ui/typeck/point-at-type-param-in-path-expr.stderr index 14642b25c994..3701b3e37988 100644 --- a/tests/ui/typeck/point-at-type-param-in-path-expr.stderr +++ b/tests/ui/typeck/point-at-type-param-in-path-expr.stderr @@ -2,10 +2,8 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` --> $DIR/point-at-type-param-in-path-expr.rs:4:19 | LL | let x = foo::<()>; - | ^^ `()` cannot be formatted with the default formatter + | ^^ the trait `std::fmt::Display` is not implemented for `()` | - = help: the trait `std::fmt::Display` is not implemented for `()` - = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `foo` --> $DIR/point-at-type-param-in-path-expr.rs:1:11 | From 29ce695cd4e148682b0d439cc47dd36edb494673 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 17 Jun 2025 19:37:29 +0200 Subject: [PATCH 242/356] Stop dbg! macro yapping about format modifiers --- library/std/src/macros.rs | 9 ++++++++- tests/ui/modules/issue-107649.stderr | 6 ++---- .../rfc-2361-dbg-macro/dbg-macro-ref-impl.rs | 17 +++++++++++++++++ .../dbg-macro-requires-debug.rs | 3 +++ .../dbg-macro-requires-debug.stderr | 8 +++----- 5 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-ref-impl.rs diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index f008d42804c0..25e2b7ea1370 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -363,7 +363,14 @@ macro_rules! dbg { match $val { tmp => { $crate::eprintln!("[{}:{}:{}] {} = {:#?}", - $crate::file!(), $crate::line!(), $crate::column!(), $crate::stringify!($val), &tmp); + $crate::file!(), + $crate::line!(), + $crate::column!(), + $crate::stringify!($val), + // The `&T: Debug` check happens here (not in the format literal desugaring) + // to avoid format literal related messages and suggestions. + &&tmp as &dyn $crate::fmt::Debug, + ); tmp } } diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr index f0353282d285..802ac669a10e 100644 --- a/tests/ui/modules/issue-107649.stderr +++ b/tests/ui/modules/issue-107649.stderr @@ -2,12 +2,10 @@ error[E0277]: `Dummy` doesn't implement `Debug` --> $DIR/issue-107649.rs:105:5 | 105 | dbg!(lib::Dummy); - | ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `Dummy` | - = help: the trait `Debug` is not implemented for `Dummy` = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy` - = note: required for `&Dummy` to implement `Debug` - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `Dummy` with `#[derive(Debug)]` --> $DIR/auxiliary/dummy_lib.rs:2:1 | diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-ref-impl.rs b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-ref-impl.rs new file mode 100644 index 000000000000..c6e38c0758d7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-ref-impl.rs @@ -0,0 +1,17 @@ +/// Check that only `&X: Debug` is required, not `X: Debug` +//@check-pass + +use std::fmt::Debug; +use std::fmt::Formatter; + +struct X; + +impl Debug for &X { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + f.write_str("X") + } +} + +fn main() { + dbg!(X); +} diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs index f2fb62d76f3d..fe71f106fdf9 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs @@ -1,4 +1,7 @@ // Test ensuring that `dbg!(expr)` requires the passed type to implement `Debug`. +// +// `dbg!` shouldn't tell the user about format literal syntax; the user didn't write one. +//@ forbid-output: cannot be formatted using struct NotDebug; diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 190db0429943..4e0ae9184150 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -1,13 +1,11 @@ error[E0277]: `NotDebug` doesn't implement `Debug` - --> $DIR/dbg-macro-requires-debug.rs:6:23 + --> $DIR/dbg-macro-requires-debug.rs:9:23 | LL | let _: NotDebug = dbg!(NotDebug); - | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | ^^^^^^^^^^^^^^ the trait `Debug` is not implemented for `NotDebug` | - = help: the trait `Debug` is not implemented for `NotDebug` = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug` - = note: required for `&NotDebug` to implement `Debug` - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NotDebug` with `#[derive(Debug)]` | LL + #[derive(Debug)] From 2ddbe39bfb2fd906ade40d622c0135c3d4bfbad0 Mon Sep 17 00:00:00 2001 From: klensy Date: Sun, 22 Jun 2025 13:05:09 +0300 Subject: [PATCH 243/356] remove allow(dead_code) leftovers from serial/parallel compiler --- compiler/rustc_data_structures/src/sync/lock.rs | 2 -- compiler/rustc_data_structures/src/sync/parallel.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs index 2ccf06ccd4f0..a8161c515115 100644 --- a/compiler/rustc_data_structures/src/sync/lock.rs +++ b/compiler/rustc_data_structures/src/sync/lock.rs @@ -1,8 +1,6 @@ //! This module implements a lock which only uses synchronization if `might_be_dyn_thread_safe` is true. //! It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync` traits. -#![allow(dead_code)] - use std::fmt; #[derive(Clone, Copy, PartialEq)] diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index ab65c7f3a6b5..e5778428d471 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -1,8 +1,6 @@ //! This module defines parallel operations that are implemented in //! one way for the serial compiler, and another way the parallel compiler. -#![allow(dead_code)] - use std::any::Any; use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; From d092dc9381bd6f09017c4b09777df4537999b952 Mon Sep 17 00:00:00 2001 From: klensy Date: Sun, 22 Jun 2025 13:24:05 +0300 Subject: [PATCH 244/356] remove few from bootstrap too --- src/bootstrap/src/core/build_steps/setup.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 86b7456d7b4e..9ce81ff9a229 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -531,7 +531,7 @@ enum EditorKind { impl EditorKind { // Used in `./tests.rs`. - #[allow(dead_code)] + #[cfg(test)] pub const ALL: &[EditorKind] = &[ EditorKind::Emacs, EditorKind::Helix, diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 53a5c6b282fb..dee4f107ca1a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -390,7 +390,6 @@ macro_rules! bootstrap_tool { ; )+) => { #[derive(PartialEq, Eq, Clone)] - #[allow(dead_code)] pub enum Tool { $( $name, From fdb76e2296a0dbc4293b85137b75bd62d23f4008 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 19 Jun 2025 21:24:06 +0200 Subject: [PATCH 245/356] Turn a comment that looks like a docstring into a docstring rewrite using let-chains --- compiler/rustc_hir_typeck/src/demand.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 5b55fbe91500..e5684f8cbe66 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1110,27 +1110,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // Returns whether the given expression is a destruct assignment desugaring. - // For example, `(a, b) = (1, &2);` - // Here we try to find the pattern binding of the expression, - // `default_binding_modes` is false only for destruct assignment desugaring. + /// Returns whether the given expression is a destruct assignment desugaring. + /// For example, `(a, b) = (1, &2);` + /// Here we try to find the pattern binding of the expression, + /// `default_binding_modes` is false only for destruct assignment desugaring. pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool { if let hir::ExprKind::Path(hir::QPath::Resolved( _, hir::Path { res: hir::def::Res::Local(bind_hir_id), .. }, )) = expr.kind - { - let bind = self.tcx.hir_node(*bind_hir_id); - let parent = self.tcx.parent_hir_node(*bind_hir_id); - if let hir::Node::Pat(hir::Pat { + && let bind = self.tcx.hir_node(*bind_hir_id) + && let parent = self.tcx.parent_hir_node(*bind_hir_id) + && let hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. }) = bind - && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent - { - return true; - } + && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent + { + true + } else { + false } - false } fn explain_self_literal( From 43084f8c05a2c1873974f28b631b603776f7f68f Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 22 Jun 2025 08:15:15 -0400 Subject: [PATCH 246/356] Indicate change is coming in the next release. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com> --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index fd47317c7546..8a6bb214d2d5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,7 +13,7 @@ Language This allows using boolean literals as `cfg` predicates, e.g. `#[cfg(true)]` and `#[cfg(false)]`. - [Fully de-stabilize the `#[bench]` attribute](https://github.com/rust-lang/rust/pull/134273). Usage of `#[bench]` without `#![feature(custom_test_frameworks)]` already triggered a deny-by-default future-incompatibility lint since Rust 1.77, but will now become a hard error. - [Add warn-by-default `dangerous_implicit_autorefs` lint against implicit autoref of raw pointer dereference.](https://github.com/rust-lang/rust/pull/123239) - The lint [may be bumped to deny-by-default](https://github.com/rust-lang/rust/pull/141661) in a future version of Rust. + The lint [will be bumped to deny-by-default](https://github.com/rust-lang/rust/pull/141661) in the next version of Rust. - [Add `invalid_null_arguments` lint to prevent invalid usage of null pointers.](https://github.com/rust-lang/rust/pull/119220) This lint is uplifted from `clippy::invalid_null_ptr_usage`. - [Change trait impl candidate preference for builtin impls and trivial where-clauses.](https://github.com/rust-lang/rust/pull/138176) From c35353910918eb40c814291996c585aababe0ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 21 Jun 2025 15:21:05 +0200 Subject: [PATCH 247/356] Leave from CopyProp early when there are no replacements --- compiler/rustc_mir_transform/src/copy_prop.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index fe78a104fa0b..cddeefca6817 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -33,24 +33,26 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp { debug!(borrowed_locals = ?ssa.borrowed_locals()); debug!(copy_classes = ?ssa.copy_classes()); - let fully_moved = fully_moved_locals(&ssa, body); - debug!(?fully_moved); - - let mut storage_to_remove = DenseBitSet::new_empty(fully_moved.domain_size()); + let mut any_replacement = false; + let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len()); for (local, &head) in ssa.copy_classes().iter_enumerated() { if local != head { + any_replacement = true; storage_to_remove.insert(head); } } - let any_replacement = ssa.copy_classes().iter_enumerated().any(|(l, &h)| l != h); + if !any_replacement { + return; + } + + let fully_moved = fully_moved_locals(&ssa, body); + debug!(?fully_moved); Replacer { tcx, copy_classes: ssa.copy_classes(), fully_moved, storage_to_remove } .visit_body_preserves_cfg(body); - if any_replacement { - crate::simplify::remove_unused_definitions(body); - } + crate::simplify::remove_unused_definitions(body); } fn is_required(&self) -> bool { From b24df424888d9db3a22d6d52f3f516e29d5be21a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 22 Jun 2025 12:09:14 +0200 Subject: [PATCH 248/356] Port `#[must_use]` to new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- .../src/attributes.rs | 7 ++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/must_use.rs | 40 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 + .../src/session_diagnostics.rs | 9 +++++ compiler/rustc_lint/src/unused.rs | 9 +++-- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 11 +++-- src/rustdoc-json-types/lib.rs | 4 +- .../clippy_lints/src/functions/must_use.rs | 30 ++++++++------ .../src/return_self_not_must_use.rs | 9 ++++- src/tools/clippy/clippy_utils/src/lib.rs | 5 ++- src/tools/clippy/clippy_utils/src/ty/mod.rs | 16 ++++++-- tests/rustdoc-json/attrs/must_use.rs | 4 +- tests/ui/attributes/malformed-must_use.rs | 4 ++ tests/ui/attributes/malformed-must_use.stderr | 8 ++++ ...issue-43106-gating-of-builtin-attrs.stderr | 12 +++--- .../lint/unused/unused-attr-duplicate.stderr | 26 ++++++------ tests/ui/parser/bad-lit-suffixes.rs | 1 - tests/ui/parser/bad-lit-suffixes.stderr | 21 ++-------- 20 files changed, 151 insertions(+), 69 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/must_use.rs create mode 100644 tests/ui/attributes/malformed-must_use.rs create mode 100644 tests/ui/attributes/malformed-must_use.stderr diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index f0f5cc4db07d..ce1d80802623 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -237,6 +237,13 @@ pub enum AttributeKind { /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html). MayDangle(Span), + /// Represents `#[must_use]`. + MustUse { + span: Span, + /// must_use can optionally have a reason: `#[must_use = "reason this must be used"]` + reason: Option, + }, + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 1bb5edba326c..3162c1fc7279 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -33,6 +33,7 @@ pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod inline; pub(crate) mod lint_helpers; +pub(crate) mod must_use; pub(crate) mod repr; pub(crate) mod semantics; pub(crate) mod stability; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs new file mode 100644 index 000000000000..a672d9561274 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -0,0 +1,40 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_errors::DiagArgValue; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; +use crate::session_diagnostics; + +pub(crate) struct MustUseParser; + +impl SingleAttributeParser for MustUseParser { + const PATH: &[Symbol] = &[sym::must_use]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + Some(AttributeKind::MustUse { + span: cx.attr_span, + reason: match args { + ArgParser::NoArgs => None, + ArgParser::NameValue(name_value) => name_value.value_as_str(), + ArgParser::List(_) => { + let suggestions = + >::TEMPLATE.suggestions(false, "must_use"); + cx.emit_err(session_diagnostics::MustUseIllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + span: cx.attr_span, + }); + return None; + } + }, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b95ea598e72e..fbe874d606cc 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,6 +20,7 @@ use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; +use crate::attributes::must_use::MustUseParser; use crate::attributes::repr::{AlignParser, ReprParser}; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -112,6 +113,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 29f2e44a98a0..2a020770e5d3 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -436,6 +436,15 @@ pub(crate) struct IllFormedAttributeInput { pub suggestions: DiagArgValue, } +#[derive(Diagnostic)] +#[diag(attr_parsing_ill_formed_attribute_input)] +pub(crate) struct MustUseIllFormedAttributeInput { + #[primary_span] + pub span: Span, + pub num_suggestions: usize, + pub suggestions: DiagArgValue, +} + #[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1620f425794f..a868c887493c 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -2,6 +2,7 @@ use std::iter; use rustc_ast::util::{classify, parser}; use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind}; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::{MultiSpan, pluralize}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -368,10 +369,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option { - if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { + if let Some(reason) = find_attr!( + cx.tcx.get_all_attrs(def_id), + AttributeKind::MustUse { reason, .. } => reason + ) { // check for #[must_use = "..."] - let reason = attr.value_str(); - Some(MustUsePath::Def(span, def_id, reason)) + Some(MustUsePath::Def(span, def_id, *reason)) } else { None } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index ed1737bee330..8e6442353c3e 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -293,6 +293,7 @@ fn emit_malformed_attribute( | sym::deprecated | sym::optimize | sym::cold + | sym::must_use ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d802bf4df19a..e11ec2ed47ab 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -171,6 +171,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { self.check_may_dangle(hir_id, *attr_span) } + Attribute::Parsed(AttributeKind::MustUse { span, .. }) => { + self.check_must_use(hir_id, *span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -245,7 +248,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), - [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), [sym::rustc_allow_incoherent_impl, ..] => { self.check_allow_incoherent_impl(attr, span, target) @@ -696,7 +698,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. } | AttributeKind::Align { .. } - | AttributeKind::Cold(..), + | AttributeKind::Cold(..) + | AttributeKind::MustUse { .. }, ) => { continue; } @@ -1576,7 +1579,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Warns against some misuses of `#[must_use]` - fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { + fn check_must_use(&self, hir_id: HirId, attr_span: Span, target: Target) { if matches!( target, Target::Fn @@ -1616,7 +1619,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::MustUseNoEffect { article, target }, ); } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index c9b4da183a3a..e5c246cb69c3 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: improve handling of generic args -pub const FORMAT_VERSION: u32 = 51; +// Latest feature: Pretty printing of must_use attributes changed +pub const FORMAT_VERSION: u32 = 52; /// The root of the emitted JSON blob. /// diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 70655838b6af..ea9ed4ddade7 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -15,6 +15,9 @@ use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; +use rustc_attr_data_structures::AttributeKind; +use rustc_span::Symbol; +use rustc_attr_data_structures::find_attr; use core::ops::ControlFlow; @@ -22,7 +25,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); + let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); if let hir::ItemKind::Fn { ref sig, body: ref body_id, @@ -31,8 +34,8 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); + if let Some((attr_span, reason)) = attr { + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, @@ -52,9 +55,9 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); - if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); + let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); + if let Some((attr_span, reason)) = attr { + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() { check_must_use_candidate( cx, @@ -75,9 +78,9 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir_attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); - if let Some(attr) = attr { - check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); + let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason)); + if let Some((attr_span, reason)) = attr { + check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir_body(eid); if attr.is_none() && is_public && !is_proc_macro(attrs) { @@ -103,7 +106,8 @@ fn check_needless_must_use( item_id: hir::OwnerId, item_span: Span, fn_header_span: Span, - attr: &Attribute, + attr_span: Span, + reason: Option, attrs: &[Attribute], sig: &FnSig<'_>, ) { @@ -119,7 +123,7 @@ fn check_needless_must_use( "this unit-returning function has a `#[must_use]` attribute", |diag| { diag.span_suggestion( - attr.span(), + attr_span, "remove the attribute", "", Applicability::MachineApplicable, @@ -137,11 +141,11 @@ fn check_needless_must_use( MUST_USE_UNIT, fn_header_span, "this unit-returning function has a `#[must_use]` attribute", - Some(attr.span()), + Some(attr_span), "remove `must_use`", ); } - } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { + } else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index 07ae92fa9843..1b304dc57680 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -6,7 +6,9 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::{Span}; +use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::find_attr; declare_clippy_lint! { /// ### What it does @@ -74,7 +76,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa // We only show this warning for public exported methods. && cx.effective_visibilities.is_exported(fn_def) // We don't want to emit this lint if the `#[must_use]` attribute is already there. - && !cx.tcx.hir_attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use)) + && !find_attr!( + cx.tcx.hir_attrs(owner_id.into()), + AttributeKind::MustUse { .. } + ) && cx.tcx.visibility(fn_def.to_def_id()).is_public() && let ret_ty = return_ty(cx, owner_id) && let self_arg = nth_arg(cx, owner_id, 0) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index c7a2375c8df7..913589319fcc 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1886,7 +1886,10 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => None, }; - did.is_some_and(|did| cx.tcx.has_attr(did, sym::must_use)) + did.is_some_and(|did| find_attr!( + cx.tcx.get_all_attrs(did), + AttributeKind::MustUse { ..} + )) } /// Checks if a function's body represents the identity function. Looks for bodies of the form: diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 32a992ccc2d7..782b079ce093 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -31,6 +31,8 @@ use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::assert_matches::debug_assert_matches; use std::collections::hash_map::Entry; use std::iter; +use rustc_attr_data_structures::find_attr; +use rustc_attr_data_structures::AttributeKind; use crate::path_res; use crate::paths::{PathNS, lookup_path_str}; @@ -326,8 +328,14 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // Returns whether the type has #[must_use] attribute pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { - ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use), - ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use), + ty::Adt(adt, _) => find_attr!( + cx.tcx.get_all_attrs(adt.did()), + AttributeKind::MustUse { ..} + ), + ty::Foreign(did) => find_attr!( + cx.tcx.get_all_attrs(*did), + AttributeKind::MustUse { ..} + ), ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays @@ -337,7 +345,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => { for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() { if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() - && cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) + && find_attr!(cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id), AttributeKind::MustUse { ..}) { return true; } @@ -347,7 +355,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Dynamic(binder, _, _) => { for predicate in *binder { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() - && cx.tcx.has_attr(trait_ref.def_id, sym::must_use) + && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { ..}) { return true; } diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs index 64df8e5f509f..3ca6f5a75a5a 100644 --- a/tests/rustdoc-json/attrs/must_use.rs +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -1,9 +1,9 @@ #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[must_use]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[attr = MustUse]"]' #[must_use] pub fn example() -> impl Iterator {} -//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]' +//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[attr = MustUse {reason: \"does nothing if you do not use it\"}]"]' #[must_use = "does nothing if you do not use it"] pub fn explicit_message() -> impl Iterator {} diff --git a/tests/ui/attributes/malformed-must_use.rs b/tests/ui/attributes/malformed-must_use.rs new file mode 100644 index 000000000000..4b98affa8abd --- /dev/null +++ b/tests/ui/attributes/malformed-must_use.rs @@ -0,0 +1,4 @@ +#[must_use()] //~ ERROR valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` +struct Test; + +fn main() {} diff --git a/tests/ui/attributes/malformed-must_use.stderr b/tests/ui/attributes/malformed-must_use.stderr new file mode 100644 index 000000000000..c948ba677444 --- /dev/null +++ b/tests/ui/attributes/malformed-must_use.stderr @@ -0,0 +1,8 @@ +error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` + --> $DIR/malformed-must_use.rs:1:1 + | +LL | #[must_use()] + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 9280dfdf92e5..d2b1d71ab87c 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -403,12 +403,6 @@ LL | #![link_section = "1800"] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 - | -LL | #![must_use] - | ^^^^^^^^^^^^ - warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | @@ -417,6 +411,12 @@ LL | #![cold] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: `#[must_use]` has no effect when applied to a module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 + | +LL | #![must_use] + | ^^^^^^^^^^^^ + warning: `#[macro_use]` only has an effect on `extern crate` and modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5 | diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 03ce97570144..6fdd0adf4cff 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -65,19 +65,6 @@ LL | #[should_panic] | ^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:60:1 - | -LL | #[must_use = "some message"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:59:1 - | -LL | #[must_use] - | ^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - error: unused attribute --> $DIR/unused-attr-duplicate.rs:66:1 | @@ -264,6 +251,19 @@ note: attribute also specified here LL | #[macro_export] | ^^^^^^^^^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:60:1 + | +LL | #[must_use = "some message"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:59:1 + | +LL | #[must_use] + | ^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + error: unused attribute --> $DIR/unused-attr-duplicate.rs:74:1 | diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs index f29dc53d322b..4e8edf4d46ea 100644 --- a/tests/ui/parser/bad-lit-suffixes.rs +++ b/tests/ui/parser/bad-lit-suffixes.rs @@ -33,7 +33,6 @@ fn f() {} #[must_use = "string"suffix] //~^ ERROR suffixes on string literals are invalid -//~| ERROR malformed `must_use` attribute input fn g() {} #[link(name = "string"suffix)] diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index 86ef35bf7833..416143e496af 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -22,29 +22,14 @@ error: suffixes on string literals are invalid LL | #[must_use = "string"suffix] | ^^^^^^^^^^^^^^ invalid suffix `suffix` -error: malformed `must_use` attribute input - --> $DIR/bad-lit-suffixes.rs:34:1 - | -LL | #[must_use = "string"suffix] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[must_use = "string"suffix] -LL + #[must_use = "reason"] - | -LL - #[must_use = "string"suffix] -LL + #[must_use] - | - error: suffixes on string literals are invalid - --> $DIR/bad-lit-suffixes.rs:39:15 + --> $DIR/bad-lit-suffixes.rs:38:15 | LL | #[link(name = "string"suffix)] | ^^^^^^^^^^^^^^ invalid suffix `suffix` error: invalid suffix `suffix` for number literal - --> $DIR/bad-lit-suffixes.rs:43:41 + --> $DIR/bad-lit-suffixes.rs:42:41 | LL | #[rustc_layout_scalar_valid_range_start(0suffix)] | ^^^^^^^ invalid suffix `suffix` @@ -165,5 +150,5 @@ LL | 1.0e10suffix; | = help: valid suffixes are `f32` and `f64` -error: aborting due to 21 previous errors; 2 warnings emitted +error: aborting due to 20 previous errors; 2 warnings emitted From 75674e2c2a21986ca07507fc98129e5be164e7ca Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Sun, 22 Jun 2025 16:32:54 +0200 Subject: [PATCH 249/356] cranelift: fix target feature name type: "fxsr" --- compiler/rustc_codegen_cranelift/src/lib.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 07ea29f3024e..8e34436fb5e0 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -184,7 +184,7 @@ impl CodegenBackend for CraneliftCodegenBackend { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" { // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled - vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")] + vec![sym::fxsr, sym::sse, sym::sse2, Symbol::intern("x87")] } else if sess.target.arch == "aarch64" { match &*sess.target.os { "none" => vec![], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index da69f6c44927..684b1781b44e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1080,7 +1080,6 @@ symbols! { fs_create_dir, fsub_algebraic, fsub_fast, - fsxr, full, fundamental, fused_iterator, @@ -1088,6 +1087,7 @@ symbols! { future_drop_poll, future_output, future_trait, + fxsr, gdb_script_file, ge, gen_blocks, From e3882618c887f6a6049a99edcf91094a64bd57f3 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Sun, 22 Jun 2025 16:32:54 +0200 Subject: [PATCH 250/356] cranelift: fix target feature name type: "fxsr" --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 07ea29f3024e..8e34436fb5e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -184,7 +184,7 @@ impl CodegenBackend for CraneliftCodegenBackend { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" { // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled - vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")] + vec![sym::fxsr, sym::sse, sym::sse2, Symbol::intern("x87")] } else if sess.target.arch == "aarch64" { match &*sess.target.os { "none" => vec![], From 6ffd0e6c235f9a28f724ce21bda7a9525a4dac03 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 21 Jun 2025 22:07:36 +0200 Subject: [PATCH 251/356] Address review comments --- compiler/rustc_lint/src/lints.rs | 4 ++- compiler/rustc_lint/src/nonstandard_style.rs | 36 ++++++++++++++----- tests/ui/lint/lint-non-uppercase-usages.fixed | 5 +++ tests/ui/lint/lint-non-uppercase-usages.rs | 5 +++ .../ui/lint/lint-non-uppercase-usages.stderr | 4 +-- 5 files changed, 43 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0ef7b3c14acd..eebb9339e246 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1359,10 +1359,12 @@ pub(crate) enum NonUpperCaseGlobalSub { #[primary_span] span: Span, }, - #[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")] + #[suggestion(lint_suggestion, code = "{replace}")] Suggestion { #[primary_span] span: Span, + #[applicability] + applicability: Applicability, replace: String, }, } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index c325b7a95c9b..a42a6076fc34 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,7 +1,9 @@ use rustc_abi::ExternAbi; use rustc_attr_data_structures::{AttributeKind, ReprAttr}; use rustc_attr_parsing::AttributeParser; +use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; use rustc_middle::hir::nested_filter::All; @@ -495,17 +497,33 @@ impl NonUpperCaseGlobals { if name.chars().any(|c| c.is_lowercase()) { let uc = NonSnakeCase::to_snake_case(name).to_uppercase(); + // If the item is exported, suggesting changing it's name would be breaking-change + // and could break users without a "nice" applicable fix, so let's avoid it. + let can_change_usages = if let Some(did) = did { + !cx.tcx.effective_visibilities(()).is_exported(did) + } else { + false + }; + // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". let sub = if *name != uc { - NonUpperCaseGlobalSub::Suggestion { span: ident.span, replace: uc.clone() } + NonUpperCaseGlobalSub::Suggestion { + span: ident.span, + replace: uc.clone(), + applicability: if can_change_usages { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }, + } } else { NonUpperCaseGlobalSub::Label { span: ident.span } }; struct UsageCollector<'a, 'tcx> { cx: &'tcx LateContext<'a>, - did: LocalDefId, + did: DefId, collected: Vec, } @@ -521,10 +539,10 @@ impl NonUpperCaseGlobals { path: &rustc_hir::Path<'v>, _id: rustc_hir::HirId, ) -> Self::Result { - for seg in path.segments { - if seg.res.opt_def_id() == Some(self.did.to_def_id()) { - self.collected.push(seg.ident.span); - } + if let Some(final_seg) = path.segments.last() + && final_seg.res.opt_def_id() == Some(self.did) + { + self.collected.push(final_seg.ident.span); } } } @@ -532,10 +550,12 @@ impl NonUpperCaseGlobals { cx.emit_span_lint_lazy(NON_UPPER_CASE_GLOBALS, ident.span, || { // Compute usages lazily as it can expansive and useless when the lint is allowed. // cf. https://github.com/rust-lang/rust/pull/142645#issuecomment-2993024625 - let usages = if let Some(did) = did + let usages = if can_change_usages && *name != uc + && let Some(did) = did { - let mut usage_collector = UsageCollector { cx, did, collected: Vec::new() }; + let mut usage_collector = + UsageCollector { cx, did: did.to_def_id(), collected: Vec::new() }; cx.tcx.hir_walk_toplevel_module(&mut usage_collector); usage_collector .collected diff --git a/tests/ui/lint/lint-non-uppercase-usages.fixed b/tests/ui/lint/lint-non-uppercase-usages.fixed index 048a936ff273..231991dcae08 100644 --- a/tests/ui/lint/lint-non-uppercase-usages.fixed +++ b/tests/ui/lint/lint-non-uppercase-usages.fixed @@ -15,6 +15,11 @@ const MY_STATIC: u32 = 0; const LOL: u32 = MY_STATIC + 0; //~^ SUGGESTION MY_STATIC +mod my_mod { + const INSIDE_MOD: u32 = super::MY_STATIC + 0; + //~^ SUGGESTION MY_STATIC +} + thread_local! { static FOO_FOO: Cell = unreachable!(); //~^ WARN constant `fooFOO` should have an upper case name diff --git a/tests/ui/lint/lint-non-uppercase-usages.rs b/tests/ui/lint/lint-non-uppercase-usages.rs index b5b9ffac6bce..9cdf5e47003d 100644 --- a/tests/ui/lint/lint-non-uppercase-usages.rs +++ b/tests/ui/lint/lint-non-uppercase-usages.rs @@ -15,6 +15,11 @@ const my_static: u32 = 0; const LOL: u32 = my_static + 0; //~^ SUGGESTION MY_STATIC +mod my_mod { + const INSIDE_MOD: u32 = super::my_static + 0; + //~^ SUGGESTION MY_STATIC +} + thread_local! { static fooFOO: Cell = unreachable!(); //~^ WARN constant `fooFOO` should have an upper case name diff --git a/tests/ui/lint/lint-non-uppercase-usages.stderr b/tests/ui/lint/lint-non-uppercase-usages.stderr index 34a0a5b0ca68..7c7e573a88ed 100644 --- a/tests/ui/lint/lint-non-uppercase-usages.stderr +++ b/tests/ui/lint/lint-non-uppercase-usages.stderr @@ -12,7 +12,7 @@ LL + const MY_STATIC: u32 = 0; | warning: constant `fooFOO` should have an upper case name - --> $DIR/lint-non-uppercase-usages.rs:19:12 + --> $DIR/lint-non-uppercase-usages.rs:24:12 | LL | static fooFOO: Cell = unreachable!(); | ^^^^^^ @@ -24,7 +24,7 @@ LL + static FOO_FOO: Cell = unreachable!(); | warning: const parameter `foo` should have an upper case name - --> $DIR/lint-non-uppercase-usages.rs:24:14 + --> $DIR/lint-non-uppercase-usages.rs:29:14 | LL | fn foo() { | ^^^ From 1a3cba83848344be97a2c139a5a439f942135e3b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 22 Jun 2025 16:37:13 +0200 Subject: [PATCH 252/356] Check rustdoc-json-types FORMAT_VERSION correct change --- src/tools/tidy/src/rustdoc_json.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs index f179acf4a510..2377356e14dc 100644 --- a/src/tools/tidy/src/rustdoc_json.rs +++ b/src/tools/tidy/src/rustdoc_json.rs @@ -4,6 +4,7 @@ use std::ffi::OsStr; use std::path::Path; use std::process::Command; +use std::str::FromStr; use build_helper::ci::CiEnv; use build_helper::git::{GitConfig, get_closest_upstream_commit}; @@ -71,9 +72,22 @@ pub fn check(src_path: &Path, bad: &mut bool) { Some(output) => { let mut format_version_updated = false; let mut latest_feature_comment_updated = false; + let mut new_version = None; + let mut old_version = None; for line in output.lines() { if line.starts_with("+pub const FORMAT_VERSION: u32 =") { format_version_updated = true; + new_version = line + .split('=') + .nth(1) + .and_then(|s| s.trim().split(';').next()) + .and_then(|s| u32::from_str(s.trim()).ok()); + } else if line.starts_with("-pub const FORMAT_VERSION: u32 =") { + old_version = line + .split('=') + .nth(1) + .and_then(|s| s.trim().split(';').next()) + .and_then(|s| u32::from_str(s.trim()).ok()); } else if line.starts_with("+// Latest feature:") { latest_feature_comment_updated = true; } @@ -92,6 +106,17 @@ pub fn check(src_path: &Path, bad: &mut bool) { ); } } + match (new_version, old_version) { + (Some(new_version), Some(old_version)) if new_version != old_version + 1 => { + *bad = true; + eprintln!( + "error in `rustdoc_json` tidy check: invalid `FORMAT_VERSION` increase in \ + `{RUSTDOC_JSON_TYPES}/lib.rs`, should be `{}`, found `{new_version}`", + old_version + 1, + ); + } + _ => {} + } } None => { *bad = true; From 188023a93cea7b2516a527aa100581687c15dd89 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 22 Jun 2025 16:15:58 +0200 Subject: [PATCH 253/356] Don't suggest changing a method inside a expansion --- .../rustc_hir_typeck/src/method/suggest.rs | 4 +++- tests/ui/hygiene/no_implicit_prelude.stderr | 2 -- .../ui/macros/missing-writer-issue-139830.rs | 9 ++++++++ .../macros/missing-writer-issue-139830.stderr | 23 +++++++++++++++++++ 4 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 tests/ui/macros/missing-writer-issue-139830.rs create mode 100644 tests/ui/macros/missing-writer-issue-139830.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 288d915e85c6..b35aef13c525 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1723,8 +1723,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't emit a suggestion if we found an actual method // that had unsatisfied trait bounds if unsatisfied_predicates.is_empty() - // ...or if we already suggested that name because of `rustc_confusable` annotation. + // ...or if we already suggested that name because of `rustc_confusable` annotation && Some(similar_candidate.name()) != confusable_suggested + // and if the we aren't in an expansion. + && !span.from_expansion() { self.find_likely_intended_associated_item( &mut err, diff --git a/tests/ui/hygiene/no_implicit_prelude.stderr b/tests/ui/hygiene/no_implicit_prelude.stderr index 5de6e3db327b..42049da23eb5 100644 --- a/tests/ui/hygiene/no_implicit_prelude.stderr +++ b/tests/ui/hygiene/no_implicit_prelude.stderr @@ -23,8 +23,6 @@ LL | ().clone() | ^^^^^ | = help: items from traits can only be used if the trait is in scope -help: there is a method `clone_from` with a similar name, but with different arguments - --> $SRC_DIR/core/src/clone.rs:LL:COL = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info) help: trait `Clone` which provides `clone` is implemented but not in scope; perhaps you want to import it | diff --git a/tests/ui/macros/missing-writer-issue-139830.rs b/tests/ui/macros/missing-writer-issue-139830.rs new file mode 100644 index 000000000000..da4608776c31 --- /dev/null +++ b/tests/ui/macros/missing-writer-issue-139830.rs @@ -0,0 +1,9 @@ +// Make sure we don't suggest a method change inside the `write!` macro. +// +// See + +fn main() { + let mut buf = String::new(); + let _ = write!(buf, "foo"); + //~^ ERROR cannot write into `String` +} diff --git a/tests/ui/macros/missing-writer-issue-139830.stderr b/tests/ui/macros/missing-writer-issue-139830.stderr new file mode 100644 index 000000000000..34dd61328e00 --- /dev/null +++ b/tests/ui/macros/missing-writer-issue-139830.stderr @@ -0,0 +1,23 @@ +error[E0599]: cannot write into `String` + --> $DIR/missing-writer-issue-139830.rs:7:20 + | +LL | let _ = write!(buf, "foo"); + | ^^^ + --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL + | + = note: the method is available for `String` here + | +note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method + --> $DIR/missing-writer-issue-139830.rs:7:20 + | +LL | let _ = write!(buf, "foo"); + | ^^^ + = help: items from traits can only be used if the trait is in scope +help: trait `Write` which provides `write_fmt` is implemented but not in scope; perhaps you want to import it + | +LL + use std::fmt::Write; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. From 90524da730f3682ec13da52ef8dc2b26a42e0fb0 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sun, 22 Jun 2025 15:18:58 +0000 Subject: [PATCH 254/356] Document why tidy checks if `eslint` is installed via `npm` --- src/tools/tidy/src/rustdoc_js.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs index 2517e2de12ce..720f0712ee03 100644 --- a/src/tools/tidy/src/rustdoc_js.rs +++ b/src/tools/tidy/src/rustdoc_js.rs @@ -62,6 +62,9 @@ pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &m return; } }; + // Having the correct `eslint` version installed via `npm` isn't strictly necessary, since we're invoking it via `npx`, + // but this check allows the vast majority that is not working on the rustdoc frontend to avoid the penalty of running + // `eslint` in tidy. See also: https://github.com/rust-lang/rust/pull/142851 match get_eslint_version() { Some(version) => { if version != eslint_version { From a46ef2d01ed9006097b0b71348d633bfb116acaa Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 22 Jun 2025 11:38:25 -0400 Subject: [PATCH 255/356] Remove dead instructions in terminate blocks --- compiler/rustc_codegen_gcc/src/builder.rs | 4 ++-- compiler/rustc_codegen_llvm/src/builder.rs | 3 +-- compiler/rustc_codegen_ssa/src/traits/builder.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index a2e34d1f8fbc..7852aebe0c23 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1591,9 +1591,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { (value1, value2) } - fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) { + fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) { // TODO(antoyo): generate the correct landing pad - self.cleanup_landing_pad(pers_fn) + self.cleanup_landing_pad(pers_fn); } #[cfg(feature = "master")] diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 5e9594dd06bb..d0aa7320b4b6 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1166,11 +1166,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1)) } - fn filter_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) { + fn filter_landing_pad(&mut self, pers_fn: &'ll Value) { let ty = self.type_struct(&[self.type_ptr(), self.type_i32()], false); let landing_pad = self.landing_pad(ty, pers_fn, 1); self.add_clause(landing_pad, self.const_array(self.type_ptr(), &[])); - (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1)) } fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index f35f551d5906..d19de6f5d267 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -516,7 +516,7 @@ pub trait BuilderMethods<'a, 'tcx>: // These are used by everyone except msvc fn cleanup_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); - fn filter_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); + fn filter_landing_pad(&mut self, pers_fn: Self::Function); fn resume(&mut self, exn0: Self::Value, exn1: Self::Value); // These are used only by msvc From a7baff819d7034246a63c01b07038555097e0b5d Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 22 Jun 2025 16:49:38 +0100 Subject: [PATCH 256/356] Avoid panic when debug info is missing --- compiler/rustc_borrowck/src/diagnostics/move_errors.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 0394a42ea9c7..52ed0f2a42c7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -465,11 +465,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let PlaceRef { local, projection: [] } = deref_base { let decl = &self.body.local_decls[local]; + let local_name = self.local_names[local].map(|sym| format!("`{sym}`")); if decl.is_ref_for_guard() { return self .cannot_move_out_of( span, - &format!("`{}` in pattern guard", self.local_names[local].unwrap()), + &format!( + "{} in pattern guard", + local_name.as_deref().unwrap_or("the place") + ), ) .with_note( "variables bound in patterns cannot be moved from \ @@ -825,7 +829,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } if binds_to.len() == 1 { - let place_desc = &format!("`{}`", self.local_names[*local].unwrap()); + let place_desc = self.local_names[*local].map(|sym| format!("`{sym}`")); if let Some(expr) = self.find_expr(binding_span) { self.suggest_cloning(err, bind_to.ty, expr, None); @@ -834,7 +838,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty: bind_to.ty, - place: place_desc, + place: place_desc.as_deref().unwrap_or("the place"), span: binding_span, }); } From b4568d9135e55cfc8739b465970aa636a0d45c1b Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 14 Jun 2025 10:36:53 -0400 Subject: [PATCH 257/356] Fix tests to drop now-skipped codegen --- .../instantiation-through-vtable.rs | 2 -- .../item-collection/non-generic-closures.rs | 29 ++++++++++++++++--- .../codegen-units/item-collection/unsizing.rs | 24 +++++++++++---- ...tadata-id-itanium-cxx-abi-drop-in-place.rs | 14 +++++---- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs index 8f13fd558083..7882a526b682 100644 --- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs @@ -24,7 +24,6 @@ impl Trait for Struct { pub fn start(_: isize, _: *const *const u8) -> isize { let s1 = Struct { _a: 0u32 }; - //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[External] //~ MONO_ITEM fn as Trait>::foo //~ MONO_ITEM fn as Trait>::bar let r1 = &s1 as &Trait; @@ -32,7 +31,6 @@ pub fn start(_: isize, _: *const *const u8) -> isize { r1.bar(); let s1 = Struct { _a: 0u64 }; - //~ MONO_ITEM fn std::ptr::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[External] //~ MONO_ITEM fn as Trait>::foo //~ MONO_ITEM fn as Trait>::bar let _ = &s1 as &Trait; diff --git a/tests/codegen-units/item-collection/non-generic-closures.rs b/tests/codegen-units/item-collection/non-generic-closures.rs index 124fe7e3b69a..2d9c461e6fd2 100644 --- a/tests/codegen-units/item-collection/non-generic-closures.rs +++ b/tests/codegen-units/item-collection/non-generic-closures.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Clink-dead-code -Zinline-mir=no +//@ compile-flags:-Clink-dead-code -Zinline-mir=no -O #![deny(dead_code)] #![crate_type = "lib"] @@ -22,9 +22,8 @@ fn assigned_to_variable_but_not_executed() { //~ MONO_ITEM fn assigned_to_variable_executed_indirectly @@ non_generic_closures-cgu.0[External] fn assigned_to_variable_executed_indirectly() { //~ MONO_ITEM fn assigned_to_variable_executed_indirectly::{closure#0} @@ non_generic_closures-cgu.0[External] - //~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim @@ non_generic_closures-cgu.0[External] - //~ MONO_ITEM fn <{closure@TEST_PATH:28:13: 28:21} as std::ops::FnOnce<(i32,)>>::call_once - shim(vtable) @@ non_generic_closures-cgu.0[External] - //~ MONO_ITEM fn std::ptr::drop_in_place::<{closure@TEST_PATH:28:13: 28:21}> - shim(None) @@ non_generic_closures-cgu.0[External] + //~ MONO_ITEM fn <{closure@TEST_PATH:27:13: 27:21} as std::ops::FnOnce<(i32,)>>::call_once - shim @@ non_generic_closures-cgu.0[External] + //~ MONO_ITEM fn <{closure@TEST_PATH:27:13: 27:21} as std::ops::FnOnce<(i32,)>>::call_once - shim(vtable) @@ non_generic_closures-cgu.0[External] let f = |a: i32| { let _ = a + 2; }; @@ -40,6 +39,20 @@ fn assigned_to_variable_executed_directly() { f(4); } +// Make sure we generate mono items for stateful closures that need dropping +//~ MONO_ITEM fn with_drop @@ non_generic_closures-cgu.0[External] +fn with_drop(v: PresentDrop) { + //~ MONO_ITEM fn with_drop::{closure#0} @@ non_generic_closures-cgu.0[External] + //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(PresentDrop)) @@ non_generic_closures-cgu.0[Internal] + //~ MONO_ITEM fn std::ptr::drop_in_place::<{closure@TEST_PATH:49:14: 49:24}> - shim(Some({closure@TEST_PATH:49:14: 49:24})) @@ non_generic_closures-cgu.0[Internal] + + let _f = |a: usize| { + let _ = a + 2; + //~ MONO_ITEM fn std::mem::drop:: @@ non_generic_closures-cgu.0[External] + drop(v); + }; +} + //~ MONO_ITEM fn start @@ non_generic_closures-cgu.0[External] #[no_mangle] pub fn start(_: isize, _: *const *const u8) -> isize { @@ -47,6 +60,7 @@ pub fn start(_: isize, _: *const *const u8) -> isize { assigned_to_variable_but_not_executed(); assigned_to_variable_executed_directly(); assigned_to_variable_executed_indirectly(); + with_drop(PresentDrop); 0 } @@ -55,3 +69,10 @@ pub fn start(_: isize, _: *const *const u8) -> isize { fn run_closure(f: &Fn(i32)) { f(3); } + +struct PresentDrop; + +impl Drop for PresentDrop { + //~ MONO_ITEM fn ::drop @@ non_generic_closures-cgu.0[External] + fn drop(&mut self) {} +} diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs index 15e42bce2495..b751d2153a94 100644 --- a/tests/codegen-units/item-collection/unsizing.rs +++ b/tests/codegen-units/item-collection/unsizing.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Zmir-opt-level=0 +//@ compile-flags:-Zmir-opt-level=0 -O #![deny(dead_code)] #![feature(coerce_unsized)] @@ -42,33 +42,47 @@ struct Wrapper(#[allow(dead_code)] *const T); impl, U: ?Sized> CoerceUnsized> for Wrapper {} +struct PresentDrop; + +impl Drop for PresentDrop { + fn drop(&mut self) {} +} + +// Custom Coercion Case +impl Trait for PresentDrop { + fn foo(&self) {} +} + //~ MONO_ITEM fn start #[no_mangle] pub fn start(_: isize, _: *const *const u8) -> isize { // simple case let bool_sized = &true; - //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] //~ MONO_ITEM fn ::foo let _bool_unsized = bool_sized as &Trait; let char_sized = &'a'; - //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] //~ MONO_ITEM fn ::foo let _char_unsized = char_sized as &Trait; // struct field let struct_sized = &Struct { _a: 1, _b: 2, _c: 3.0f64 }; - //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] //~ MONO_ITEM fn ::foo let _struct_unsized = struct_sized as &Struct; // custom coercion let wrapper_sized = Wrapper(&0u32); - //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] //~ MONO_ITEM fn ::foo let _wrapper_sized = wrapper_sized as Wrapper; + // with drop + let droppable = &PresentDrop; + //~ MONO_ITEM fn ::drop @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(PresentDrop)) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo + let droppable = droppable as &dyn Trait; + false.foo(); 0 diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs index 2a7eca6fc196..8fec275fd064 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs @@ -1,5 +1,9 @@ // Verifies that type metadata identifiers for drop functions are emitted correctly. // +// Non needs_drop drop glue isn't codegen'd at all, so we don't try to check the IDs there. But we +// do check it's not emitted which should help catch bugs if we do start generating it again in the +// future. +// //@ needs-sanitizer-cfi //@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static @@ -10,18 +14,18 @@ // CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE") struct EmptyDrop; -// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK-NOT: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -struct NonEmptyDrop; +struct PresentDrop; -impl Drop for NonEmptyDrop { +impl Drop for PresentDrop { fn drop(&mut self) {} - // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}NonEmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}PresentDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} } pub fn foo() { let _ = Box::new(EmptyDrop) as Box; - let _ = Box::new(NonEmptyDrop) as Box; + let _ = Box::new(PresentDrop) as Box; } // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"} From d18a43c3acd7174f28393100d09ce412036696b4 Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 22 Jun 2025 16:58:47 +0100 Subject: [PATCH 258/356] Init local_names lazily for borrowck diagnostics --- .../src/diagnostics/explain_borrow.rs | 11 +++-- .../rustc_borrowck/src/diagnostics/mod.rs | 43 +++++++++++++++++-- .../src/diagnostics/move_errors.rs | 4 +- .../src/diagnostics/mutability_errors.rs | 6 +-- .../src/diagnostics/region_errors.rs | 4 +- .../src/diagnostics/region_name.rs | 4 +- compiler/rustc_borrowck/src/lib.rs | 30 +++---------- 7 files changed, 58 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 095c0df98acc..f9e52239d6f6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -71,7 +71,6 @@ impl<'tcx> BorrowExplanation<'tcx> { ) { let tcx = cx.infcx.tcx; let body = cx.body; - let local_names = &cx.local_names; if let Some(span) = borrow_span { let def_id = body.source.def_id(); @@ -220,7 +219,7 @@ impl<'tcx> BorrowExplanation<'tcx> { _ => ("destructor", format!("type `{}`", local_decl.ty)), }; - match local_names[dropped_local] { + match cx.local_name(dropped_local) { Some(local_name) if !local_decl.from_compiler_desugaring() => { let message = format!( "{borrow_desc}borrow might be used here, when `{local_name}` is dropped \ @@ -670,10 +669,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { Some(Cause::DropVar(local, location)) => { let mut should_note_order = false; - if self.local_names[local].is_some() + if self.local_name(local).is_some() && let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place && let Some(borrowed_local) = place.as_local() - && self.local_names[borrowed_local].is_some() + && self.local_name(borrowed_local).is_some() && local != borrowed_local { should_note_order = true; @@ -748,7 +747,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { Operand::Copy(place) | Operand::Move(place) => { if let Some(l) = place.as_local() { let local_decl = &self.body.local_decls[l]; - if self.local_names[l].is_none() { + if self.local_name(l).is_none() { local_decl.source_info.span } else { span @@ -793,7 +792,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { Operand::Copy(place) | Operand::Move(place) => { if let Some(l) = place.as_local() { let local_decl = &self.body.local_decls[l]; - if self.local_names[l].is_none() { + if self.local_name(l).is_none() { local_decl.source_info.span } else { span diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 5e3f3ffa2ea8..7b4e38969eed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -7,17 +7,17 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{self as hir, CoroutineKind, LangItem}; -use rustc_index::IndexSlice; +use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin}; use rustc_infer::traits::SelectionError; -use rustc_middle::bug; use rustc_middle::mir::{ AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement, - StatementKind, Terminator, TerminatorKind, find_self_call, + StatementKind, Terminator, TerminatorKind, VarDebugInfoContents, find_self_call, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex}; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Spanned; @@ -190,6 +190,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> { self.diags_buffer.buffered_move_errors.get(move_out_indices) } + + /// Uses `body.var_debug_info` to find the symbol + fn local_name(&self, index: Local) -> Option { + *self.local_names().get(index)? + } + + fn local_names(&self) -> &IndexSlice> { + self.local_names.get_or_init(|| { + let mut local_names = IndexVec::from_elem(None, &self.body.local_decls); + for var_debug_info in &self.body.var_debug_info { + if let VarDebugInfoContents::Place(place) = var_debug_info.value { + if let Some(local) = place.as_local() { + if let Some(prev_name) = local_names[local] + && var_debug_info.name != prev_name + { + span_bug!( + var_debug_info.source_info.span, + "local {:?} has many names (`{}` vs `{}`)", + local, + prev_name, + var_debug_info.name + ); + } + local_names[local] = Some(var_debug_info.name); + } + } + } + local_names + }) + } } impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { @@ -430,7 +460,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// a name, or its name was generated by the compiler, then `Err` is returned fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> { let decl = &self.body.local_decls[local]; - match self.local_names[local] { + match self.local_name(local) { Some(name) if !decl.from_compiler_desugaring() => { buf.push_str(name.as_str()); Ok(()) @@ -1500,4 +1530,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } } + + /// Skip over locals that begin with an underscore or have no name + pub(crate) fn local_excluded_from_unused_mut_lint(&self, index: Local) -> bool { + self.local_name(index).is_none_or(|name| name.as_str().starts_with('_')) + } } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 52ed0f2a42c7..b21d348183fc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -465,7 +465,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let PlaceRef { local, projection: [] } = deref_base { let decl = &self.body.local_decls[local]; - let local_name = self.local_names[local].map(|sym| format!("`{sym}`")); + let local_name = self.local_name(local).map(|sym| format!("`{sym}`")); if decl.is_ref_for_guard() { return self .cannot_move_out_of( @@ -829,7 +829,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } if binds_to.len() == 1 { - let place_desc = self.local_names[*local].map(|sym| format!("`{sym}`")); + let place_desc = self.local_name(*local).map(|sym| format!("`{sym}`")); if let Some(expr) = self.find_expr(binding_span) { self.suggest_cloning(err, bind_to.ty, expr, None); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a5c9bad3ac2d..fd8a2a6bc354 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -60,7 +60,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if access_place.as_local().is_some() { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.local_names[local].expect("immutable unnamed local"); + let name = self.local_name(local).expect("immutable unnamed local"); reason = format!(", as `{name}` is not declared as mutable"); } } @@ -285,7 +285,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .body .local_decls .get(local) - .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) => + .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_name(local))) => { let decl = &self.body.local_decls[local]; err.span_label(span, format!("cannot {act}")); @@ -481,7 +481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let (pointer_sigil, pointer_desc) = if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") }; - match self.local_names[local] { + match self.local_name(local) { Some(name) if !local_decl.from_compiler_desugaring() => { err.span_label( span, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 3bec07afa0fe..d27e08573e03 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -664,14 +664,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( self.infcx.tcx, self.body, - &self.local_names, + &self.local_names(), &self.upvars, errci.fr, ); let outlived_fr_name_and_span = self.regioncx.get_var_name_and_span_for_region( self.infcx.tcx, self.body, - &self.local_names, + &self.local_names(), &self.upvars, errci.outlived_fr, ); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 487f78058a8c..1ad629ad167d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -399,7 +399,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { [implicit_inputs + argument_index]; let (_, span) = self.regioncx.get_argument_name_and_span_for_region( self.body, - &self.local_names, + self.local_names(), argument_index, ); @@ -973,7 +973,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { { let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region( self.body, - &self.local_names, + self.local_names(), arg_index, ); let region_name = self.synthesize_region_name(); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4d85f1090201..82b300dcb17d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -16,7 +16,7 @@ // tidy-alphabetical-end use std::borrow::Cow; -use std::cell::RefCell; +use std::cell::{OnceCell, RefCell}; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; @@ -391,7 +391,7 @@ fn do_mir_borrowck<'tcx>( used_mut_upvars: SmallVec::new(), borrow_set: &borrow_set, upvars: &[], - local_names: IndexVec::from_elem(None, &promoted_body.local_decls), + local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)), region_names: RefCell::default(), next_region_name: RefCell::new(1), polonius_output: None, @@ -414,26 +414,6 @@ fn do_mir_borrowck<'tcx>( promoted_mbcx.report_move_errors(); } - let mut local_names = IndexVec::from_elem(None, &body.local_decls); - for var_debug_info in &body.var_debug_info { - if let VarDebugInfoContents::Place(place) = var_debug_info.value { - if let Some(local) = place.as_local() { - if let Some(prev_name) = local_names[local] - && var_debug_info.name != prev_name - { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); - } - local_names[local] = Some(var_debug_info.name); - } - } - } - let mut mbcx = MirBorrowckCtxt { root_cx, infcx: &infcx, @@ -450,7 +430,7 @@ fn do_mir_borrowck<'tcx>( used_mut_upvars: SmallVec::new(), borrow_set: &borrow_set, upvars: tcx.closure_captures(def), - local_names, + local_names: OnceCell::new(), region_names: RefCell::default(), next_region_name: RefCell::new(1), move_errors: Vec::new(), @@ -682,7 +662,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>], /// Names of local (user) variables (extracted from `var_debug_info`). - local_names: IndexVec>, + local_names: OnceCell>>, /// Record the region names generated for each region in the given /// MIR def so that we can reuse them later in help/error messages. @@ -2610,7 +2590,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { }; // Skip over locals that begin with an underscore or have no name - if self.local_names[local].is_none_or(|name| name.as_str().starts_with('_')) { + if self.local_excluded_from_unused_mut_lint(local) { continue; } From b433aba3df460424dc3a94c875c34c13b23d6041 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 27 May 2025 14:24:03 -0400 Subject: [PATCH 259/356] Add a SUMMARY.md outlining immediate subdirectories of the ui test suite Co-authored-by: Jieyou Xu --- src/doc/rustc-dev-guide/src/tests/ui.md | 5 + tests/ui/SUMMARY.md | 1594 +++++++++++++++++++++++ 2 files changed, 1599 insertions(+) create mode 100644 tests/ui/SUMMARY.md diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 9e4a11044e81..8f4467a5551e 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -13,6 +13,11 @@ used for many other purposes. For example, tests can also be configured to [run the resulting program](#controlling-passfail-expectations) to verify its behavior. +For a survey of each subdirectory's purpose under `tests/ui`, consult the +[SUMMARY.md](https://github.com/rust-lang/rust/tree/master/tests/ui/SUMMARY.md). +This is useful if you write a new test, and are looking for a category to +place it in. + If you need to work with `#![no_std]` cross-compiling tests, consult the [`minicore` test auxiliary](./minicore.md) chapter. diff --git a/tests/ui/SUMMARY.md b/tests/ui/SUMMARY.md new file mode 100644 index 000000000000..d807e38dab28 --- /dev/null +++ b/tests/ui/SUMMARY.md @@ -0,0 +1,1594 @@ +# UI Test Suite Categories + +This is a high-level summary of the organization of the UI test suite (`tests/ui/`). It is not intended to be *prescriptive*, but instead provide a quick survey of existing groupings. + +For now, only immediate subdirectories under `tests/ui/` are described, but these subdirectories can themselves include a `SUMMARY.md` to further describe their own organization and intent, should that be helpful. + +## `tests/ui/abi` + +These tests deal with *Application Binary Interfaces* (ABI), mostly relating to function name mangling (and the `#[no_mangle]` attribute), calling conventions, or compiler flags which affect ABI. + +## `tests/ui/allocator` + +These tests exercise `#![feature(allocator_api)]` and the `#[global_allocator]` attribute. + +See [Allocator traits and `std::heap` #32838](https://github.com/rust-lang/rust/issues/32838). + +## `tests/ui/alloc-error` + +These tests exercise alloc error handling. + +See . + +## `tests/ui/annotate-snippet` + +These tests exercise the [`annotate-snippets`]-based emitter implementation. + +[`annotate-snippets`] is an initiative to share the diagnostics emitting infrastructure between rustc and cargo to reduce duplicate maintenance effort and divergence. See about the initiative. + +[`annotate-snippets`]: https://github.com/rust-lang/annotate-snippets-rs + +## `tests/ui/anon-params` + +These tests deal with anonymous parameters (no name, only type), a deprecated feature that becomes a hard error in Edition 2018. + +## `tests/ui/argfile`: External files providing command line arguments + +These tests exercise rustc reading command line arguments from an externally provided argfile (`@argsfile`). + +See [Implement `@argsfile` to read arguments from command line #63576](https://github.com/rust-lang/rust/issues/63576). + +## `tests/ui/array-slice-vec`: Arrays, slices and vectors + +Exercises various aspects surrounding basic collection types `[]`, `&[]` and `Vec`. E.g. type-checking, out-of-bounds indices, attempted instructions which are allowed in other programming languages, and more. + +## `tests/ui/argument-suggestions`: Argument suggestions + +Calling a function with the wrong number of arguments causes a compilation failure, but the compiler is able to, in some cases, provide suggestions on how to fix the error, such as which arguments to add or delete. These tests exercise the quality of such diagnostics. + +## `tests/ui/asm`: `asm!` macro + +These tests exercise the `asm!` macro, which is used for adding inline assembly. + +See: + +- [Inline assembly | Reference](https://doc.rust-lang.org/reference/inline-assembly.html) +- [`core::arch::asm`](https://doc.rust-lang.org/core/arch/macro.asm.html) +- [`core::arch::global_asm`](https://doc.rust-lang.org/core/arch/macro.global_asm.html) + +This directory contains subdirectories representing various architectures such as `riscv` or `aarch64`. If a test is specifically related to an architecture's particularities, it should be placed within the appropriate subdirectory.Architecture-agnostic tests should be placed below `tests/ui/asm/` directly. + +## `tests/ui/associated-consts`: Associated Constants + +These tests exercise associated constants in traits and impls, on aspects such as definitions, usage, and type checking in associated contexts. + +## `tests/ui/associated-inherent-types`: Inherent Associated Types + +These tests cover associated types defined directly within inherent impls (not in traits). + +See [RFC 0195 Associated items - Inherent associated items](https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#inherent-associated-items). + +## `tests/ui/associated-item`: Associated Items + +Tests for all kinds of associated items within traits and implementations. This directory serves as a catch-all for tests that don't fit the other more specific associated item directories. + +## `tests/ui/associated-type-bounds`: Associated Type Bounds + +These tests exercise associated type bounds, the feature that gives users a shorthand to express nested type bounds that would otherwise need to be expressed with nested `impl Trait` or broken into several `where` clauses. + +See: + +- [RFC 2289 Associated Type Bounds](https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html) +- [Stabilize associated type bounds (RFC 2289) #122055](https://github.com/rust-lang/rust/pull/122055) + +## `tests/ui/associated-types`: Trait Associated Types + +Tests focused on associated types. If the associated type is not in a trait definition, it belongs in the `tests/ui/associated-inherent-types/` directory. Aspects exercised include e.g. default associated types, overriding defaults, and type inference. + +See [Associated Types | Reference](https://doc.rust-lang.org/reference/items/associated-items.html#associated-types). + +## `tests/ui/async-await`: Async/Await + +Tests for the async/await related features. E.g. async functions, await expressions, and their interaction with other language features. + +## `tests/ui/attributes`: Compiler Attributes + +Tests for language attributes and compiler attributes. E.g. built-in attributes like `#[derive(..)]`, `#[cfg(..)]`, and `#[repr(..)]`, or proc-macro attributes. See [Attributes | Reference](https://doc.rust-lang.org/reference/attributes.html). + +## `tests/ui/auto-traits`: Auto Traits + +There are built-in auto traits (`Send`, `Sync`, etc.) but it is possible to define more with the unstable keyword `auto` through `#![feature(auto_traits)]`. + +See [Tracking Issue for auto traits (`auto_traits`) -- formerly called opt-in built-in traits (`optin_builtin_traits`) #13231](https://github.com/rust-lang/rust/issues/13231). + +## `tests/ui/autodiff`: Automatic Differentiation + +The `#[autodiff]` macro supports automatic differentiation. + +See [Tracking Issue for autodiff #124509](https://github.com/rust-lang/rust/issues/124509). + +## `tests/ui/autoref-autoderef`: Automatic Referencing/Dereferencing + +Tests for automatic referencing and dereferencing behavior, such as automatically adding reference operations (`&` or `&mut`) to make a value match a method's receiver type. Sometimes abbreviated as "auto-ref" or "auto-deref". + +## `tests/ui/auxiliary/`: Auxiliary files for tests directly under `tests/ui`. + +This top-level `auxiliary` subdirectory contains support files for tests immediately under `tests/ui/`. + +**FIXME(#133895)**: tests immediately under `tests/ui/` should be rehomed to more suitable subdirectories, after which this subdirectory can be removed. + +## `tests/ui/backtrace/`: Backtraces + +Runtime panics and error handling generate backtraces to assist in debugging and diagnostics. + +## `tests/ui/bench/`: Benchmarks and performance + +This directory was originally meant to contain tests related to time complexity and benchmarking. + +However, only a single test was ever added to this category: https://github.com/rust-lang/rust/pull/32062 + +**FIXME**: It is also unclear what would happen were this test to "fail" - would it cause the test suite to remain stuck on this test for a much greater duration than normal? + +## `tests/ui/binding/`: Pattern Binding + +Tests for pattern binding in match expressions, let statements, and other binding contexts. E.g. binding modes and refutability. See [Patterns | Reference](https://doc.rust-lang.org/reference/patterns.html). + +## `tests/ui/binop/`: Binary operators + +Tests for binary operators (such as `==`, `&&` or `^`). E.g. overloading, type checking, and diagnostics for invalid operations. + +## `tests/ui/blind/`: `struct` or `mod` inside a `mod` having a duplicate identifier + +Tests exercising name resolution. + +**FIXME**: Probably move to `tests/ui/resolve/`. + +## `tests/ui/block-result/`: Block results and returning + +Tests for block expression results. E.g. specifying the correct return types, semicolon handling, type inference, and expression/statement differences (for example, the difference between `1` and `1;`). + +## `tests/ui/bootstrap/`: RUSTC_BOOTSTRAP environment variable + +Meta tests for stability mechanisms surrounding [`RUSTC_BOOTSTRAP`](https://doc.rust-lang.org/nightly/unstable-book/compiler-environment-variables/RUSTC_BOOTSTRAP.html), which is coordinated between `rustc` and the build system, `bootstrap`. + +## `tests/ui/borrowck/`: Borrow Checking + +Tests for borrow checking. E.g. lifetime analysis, borrowing rules, and diagnostics. + +## `tests/ui/box/`: Box Behavior + +Tests for `Box` smart pointer and `#![feature(box_patterns)]`. E.g. allocation, deref coercion, and edge cases in box pattern matching and placement. + +See: + +- [`std::box::Boxed`](https://doc.rust-lang.org/std/boxed/struct.Box.html) +- [Tracking issue for `box_patterns` feature #29641](https://github.com/rust-lang/rust/issues/29641) + +## `tests/ui/btreemap/`: B-Tree Maps + +Tests focused on `BTreeMap` collections and their compiler interactions. E.g. collection patterns, iterator behavior, and trait implementations specific to `BTreeMap`. See [`std::collections::BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html). + +## `tests/ui/builtin-superkinds/`: Built-in Trait Hierarchy Tests + +Tests for built-in trait hierarchy (Send, Sync, Sized, etc.) and their supertrait relationships. E.g. auto traits and marker trait constraints. + +See [RFC 3729: Hierarchy of Sized traits](https://github.com/rust-lang/rfcs/pull/3729). + +Defining custom auto traits with the `auto` keyword belongs to `tests/ui/auto-traits/` instead. + +## `tests/ui/cast/`: Type Casting + +Tests for type casting using the `as` operator. Includes tests for valid/invalid casts between primitive types, trait objects, and custom types. For example, check that trying to cast `i32` into `bool` results in a helpful error message. + +See [Type cast expressions | Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html). + +## `tests/ui/cfg/`: Configuration Attribute + +Tests for `#[cfg]` conditional compilation attribute. E.g. feature flags, target architectures, and other configuration predicates and options. + +See [Conditional compilation | Reference](https://doc.rust-lang.org/reference/conditional-compilation.html). + +## `tests/ui/check-cfg/`: Configuration Checks + +Tests for the `--check-cfg` compiler mechanism for checking cfg configurations, for `#[cfg(..)]` and `cfg!(..)`. + +See [Checking conditional configurations | The rustc book](https://doc.rust-lang.org/rustc/check-cfg.html). + +## `tests/ui/closure_context/`: Closure type inference in context + +Tests for closure type inference with respect to surrounding scopes, mostly quality of diagnostics. + +## `tests/ui/closure-expected-type/`: Closure type inference + +Tests targeted at how we deduce the types of closure arguments. This process is a result of some heuristics which take into account the *expected type* we have alongside the *actual types* that we get from inputs. + +**FIXME**: Appears to have significant overlap with `tests/ui/closure_context` and `tests/ui/functions-closures/closure-expected-type`. Needs further investigation. + +## `tests/ui/closures/`: General Closure Tests + +Any closure-focused tests that does not fit in the other more specific closure subdirectories belong here. E.g. syntax, `move`, lifetimes. + +## `tests/ui/cmse-nonsecure/`: `C-cmse-nonsecure` ABIs + +Tests for `cmse_nonsecure_entry` and `abi_c_cmse_nonsecure_call` ABIs. Used specifically for the Armv8-M architecture, the former marks Secure functions with additional behaviours, such as adding a special symbol and constraining the number of parameters, while the latter alters function pointers to indicate they are non-secure and to handle them differently than usual. + +See: + +- [`cmse_nonsecure_entry` | The Unstable book](https://doc.rust-lang.org/unstable-book/language-features/cmse-nonsecure-entry.html) +- [`abi_c_cmse_nonsecure_call` | The Unstable book](https://doc.rust-lang.org/beta/unstable-book/language-features/abi-c-cmse-nonsecure-call.html) + +## `tests/ui/codegen/`: Code Generation + +Tests that exercise code generation. E.g. codegen flags (starting with `-C` on the command line), LLVM IR output, optimizations (and the various `opt-level`s), and target-specific code generation (such as tests specific to `x86_64`). + +## `tests/ui/codemap_tests/`: Source Mapping + +Tests that exercise source code mapping. + +## `tests/ui/coercion/`: Type Coercion + +Tests for implicit type coercion behavior, where the types of some values are changed automatically when compatible depending on the context. E.g. automatic dereferencing or downgrading a `&mut` into a `&`. + +See [Type coercions | Reference](https://doc.rust-lang.org/reference/type-coercions.html). + +## `tests/ui/coherence/`: Trait Implementation Coherence + +Tests for trait coherence rules, which govern where trait implementations can be defined. E.g. orphan rule, and overlap checks. + +See [Coherence | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/coherence.html#coherence). + +## `tests/ui/coinduction/`: Coinductive Trait Resolution + +Tests for coinduction in trait solving which may involve infinite proof trees. + +See: + +- [Coinduction | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/solve/coinduction.html). +- [Inductive cycles | Chalk](https://rust-lang.github.io/chalk/book/recursive/inductive_cycles.html#inductive-cycles)/ + +This directory only contains one highly specific test. Other coinduction tests can be found down the deeply located `tests/ui/traits/next-solver/cycles/coinduction/` subdirectory. + +## `tests/ui/command/`: `std::process::Command` + +This directory is actually for the standard library [`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html) type, where some tests are too difficult or inconvenient to write as unit tests or integration tests within the standard library itself. + +**FIXME**: the test `command-line-diagnostics` seems to have been misplaced in this category. + +## `tests/ui/compare-method/`: Trait implementation and definition comparisons + +Some traits' implementation must be compared with their definition, checking for problems such as the implementation having stricter requirements (such as needing to implement `Copy`). + +This subdirectory is *not* intended comparison traits (`PartialEq`, `Eq`, `PartialOrd`, `Ord`). + +## `tests/ui/compiletest-self-test/`: compiletest "meta" tests + +Meta test suite of the test harness `compiletest` itself. + +## `tests/ui/conditional-compilation/`: Conditional Compilation + +Tests for `#[cfg]` attribute or `--cfg` flags, used to compile certain files or code blocks only if certain conditions are met (such as developing on a specific architecture). + +**FIXME**: There is significant overlap with `tests/ui/cfg`, which even contains a `tests/ui/cfg/conditional-compile.rs` test. Also investigate `tests/ui/check-cfg`. + +## `tests/ui/confuse-field-and-method/`: Field/Method Ambiguity + +If a developer tries to create a `struct` where one of the fields is a closure function, it becomes unclear whether `struct.field()` is accessing the field itself or trying to call the closure function within as a method. + +**FIXME**: does this really need to be its own immediate subdirectory? + +## `tests/ui/const-generics/`: Constant Generics + +Tests for const generics, allowing types to be parameterized by constant values. It is generally observed in the form `` after the `fn` or `struct` keywords. Includes tests for const expressions in generic contexts and associated type bounds. + +See: + +- [Tracking Issue for complex generic constants: `feature(generic_const_exprs)` #76560](https://github.com/rust-lang/rust/issues/76560) +- [Const generics | Reference](https://doc.rust-lang.org/reference/items/generics.html#const-generics) + +## `tests/ui/const_prop/`: Constant Propagation + +Tests exercising `ConstProp` mir-opt pass (mostly regression tests). See . + +## `tests/ui/const-ptr/`: Constant Pointers + +Tests exercise const raw pointers. E.g. pointer arithmetic, casting and dereferencing, always with a `const`. + +See: + +- [`std::primitive::pointer`](https://doc.rust-lang.org/std/primitive.pointer.html) +- [`std::ptr`](https://doc.rust-lang.org/std/ptr/index.html) +- [Pointer types | Reference](https://doc.rust-lang.org/reference/types/pointer.html) + +## `tests/ui/consts/`: General Constant Evaluation + +Anything to do with constants, which does not fit in the previous two `const` categories, goes here. This does not always imply use of the `const` keyword - other values considered constant, such as defining an enum variant as `enum Foo { Variant = 5 }` also counts. + +## `tests/ui/contracts/`: Contracts feature + +Tests exercising `#![feature(contracts)]`. + +See [Tracking Issue for Contracts #128044](https://github.com/rust-lang/rust/issues/128044). + +## `tests/ui/coroutine/`: Coroutines feature and `gen` blocks + +Tests for `#![feature(coroutines)]` and `gen` blocks, it belongs here. + +See: + +- [Coroutines | The Unstable book](https://doc.rust-lang.org/beta/unstable-book/language-features/coroutines.html) +- [RFC 3513 Gen blocks](https://rust-lang.github.io/rfcs/3513-gen-blocks.html) + +## `tests/ui/coverage-attr/`: `#[coverage]` attribute + +Tests for `#![feature(coverage_attribute)]`. See [Tracking issue for function attribute `#[coverage]`](https://github.com/rust-lang/rust/issues/84605). + +## `tests/ui/crate-loading/`: Crate Loading + +Tests for crate resolution and loading behavior, including `extern crate` declarations, `--extern` flags, or the `use` keyword. + +## `tests/ui/cross/`: Various tests related to the concept of "cross" + +**FIXME**: The unifying topic of these tests appears to be that their filenames begin with the word "cross". The similarities end there - one test is about "cross-borrowing" a `Box` into `&T`, while another is about a global trait used "across" files. Some of these terminology are really outdated and does not match the current terminology. Additionally, "cross" is also way too generic, it's easy to confuse with cross-compile. + +## `tests/ui/cross-crate/`: Cross-Crate Interaction + +Tests for behavior spanning multiple crates, including visibility rules, trait implementations, and type resolution across crate boundaries. + +## `tests/ui/custom_test_frameworks/` + +Tests for `#[bench]`, `#[test_case]` attributes and the `custom_test_frameworks` lang item. + +See [Tracking issue for eRFC 2318, Custom test frameworks #50297](https://github.com/rust-lang/rust/issues/50297). + +## `tests/ui/c-variadic/`: C Variadic Function + +Tests for FFI with C varargs (`va_list`). + +## `tests/ui/cycle-trait/`: Trait Cycle Detection + +Tests for detection and handling of cyclic trait dependencies. + +## `tests/ui/dataflow_const_prop/` + +Contains a single regression test for const prop in `SwitchInt` pass crashing when `ptr2int` transmute is involved. + +**FIXME**: A category with a single test. Maybe it would fit inside the category `const-prop` or some kind of `mir-opt` directory. + +## `tests/ui/debuginfo/` + +Tests for generation of debug information (DWARF, etc.) including variable locations, type information, and source line mapping. Also exercises `-C split-debuginfo` and `-C debuginfo`. + +## `tests/ui/definition-reachable/`: Definition Reachability + +Tests to check whether definitions are reachable. + +## `tests/ui/delegation/`: `#![feature(fn_delegation)]` + +Tests for `#![feature(fn_delegation)]`. See [Implement function delegation in rustc #3530](https://github.com/rust-lang/rfcs/pull/3530) for the proposed prototype experimentation. + +## `tests/ui/dep-graph/`: `-Z query-dep-graph` + +These tests use the unstable command line option `query-dep-graph` to examine the dependency graph of a Rust program, which is useful for debugging. + +## `tests/ui/deprecation/`: Deprecation Attribute + +Tests for `#[deprecated]` attribute and `deprecated_in_future` internal lint. + +## `tests/ui/deref-patterns/`: `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]` + +Tests for `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]`. See [Deref patterns | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/deref-patterns.html). + +**FIXME**: May have some overlap with `tests/ui/pattern/deref-patterns`. + +## `tests/ui/derived-errors/`: Derived Error Messages + +Tests for quality of diagnostics involving suppression of cascading errors in some cases to avoid overwhelming the user. + +## `tests/ui/derives/`: Derive Macro + +Tests for built-in derive macros (`Debug`, `Clone`, etc.) when used in conjunction with built-in `#[derive(..)]` attributes. + +## `tests/ui/deriving/`: Derive Macro + +**FIXME**: Coalesce with `tests/ui/derives`. + +## `tests/ui/dest-prop/` Destination Propagation + +**FIXME**: Contains a single test for the `DestProp` mir-opt, should probably be rehomed. + +## `tests/ui/destructuring-assignment/` + +Exercises destructuring assignments. See [RFC 2909 Destructuring assignment](https://github.com/rust-lang/rfcs/blob/master/text/2909-destructuring-assignment.md). + +## `tests/ui/diagnostic-flags/` + +These tests revolve around command-line flags which change the way error/warning diagnostics are emitted. For example, `--error-format=human --color=always`. + +**FIXME**: Check redundancy with `annotate-snippet`, which is another emitter. + +## `tests/ui/diagnostic_namespace/` + +Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namepsace](https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md). + +## `tests/ui/diagnostic-width/`: `--diagnostic-width` + +Everything to do with `--diagnostic-width`. + +## `tests/ui/did_you_mean/` + +Tests for miscellaneous suggestions. + +## `tests/ui/directory_ownership/`: Declaring `mod` inside a block + +Exercises diagnostics for when a code block attempts to gain ownership of a non-inline module with a `mod` keyword placed inside of it. + +## `tests/ui/disallowed-deconstructing/`: Incorrect struct deconstruction + +Exercises diagnostics for disallowed struct destructuring. + +## `tests/ui/dollar-crate/`: `$crate` used with the `use` keyword + +There are a few rules - which are checked in this directory - to follow when using `$crate` - it must be used in the start of a `use` line and is a reserved identifier. + +**FIXME**: There are a few other tests in other directories with a filename starting with `dollar-crate`. They should perhaps be redirected here. + +## `tests/ui/drop/`: `Drop` and drop order + +Not necessarily about `Drop` and its implementation, but also about the drop order of fields inside a struct. + +## `tests/ui/drop-bounds/` + +Tests for linting on bounding a generic type on `Drop`. + +## `tests/ui/dropck/`: Drop Checking + +Mostly about checking the validity of `Drop` implementations. + +See: + +- [Dropck | The Nomicon](https://doc.rust-lang.org/nomicon/dropck.html) +- [Drop check | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/borrow_check/drop_check.html) + +## `tests/ui/dst/`: Dynamically Sized Types + +Tests for dynamically-sized types (DSTs). See [Dynamically Sized Types | Reference](https://doc.rust-lang.org/reference/dynamically-sized-types.html). + +## `tests/ui/duplicate/`: Duplicate Symbols + +Tests about duplicated symbol names and associated errors, such as using the `#[export_name]` attribute to rename a function with the same name as another function. + +## `tests/ui/dynamically-sized-types/`: Dynamically Sized Types + +**FIXME**: should be coalesced with `tests/ui/dst`. + +## `tests/ui/dyn-compatibility/`: Dyn-compatibility + +Tests for dyn-compatibility of traits. + +See: + +- [Trait object | Reference](https://doc.rust-lang.org/reference/types/trait-object.html) +- [Dyn compatibility | Reference](https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility) + +Previously known as "object safety". + +## `tests/ui/dyn-drop/`: `dyn Drop` + +**FIXME**: Contains a single test, used only to check the `dyn_drop` lint (which is normally `warn` level). + +## `tests/ui/dyn-keyword/`: `dyn` and Dynamic Dispatch + +The `dyn` keyword is used to highlight that calls to methods on the associated Trait are dynamically dispatched. To use the trait this way, it must be dyn-compatible - tests about dyn-compatibility belong in `tests/ui/dyn-compatibility/`, while more general tests on dynamic dispatch belong here. + +See [`dyn` keyword](https://doc.rust-lang.org/std/keyword.dyn.html). + +## `tests/ui/dyn-star/`: `dyn*`, Sized `dyn`, `#![feature(dyn_star)]` + +See [Tracking issue for dyn-star #102425](https://github.com/rust-lang/rust/issues/102425). + +## `tests/ui/editions/`: Rust edition-specific peculiarities + +These tests run in specific Rust editions, such as Rust 2015 or Rust 2018, and check errors and functionality related to specific now-deprecated idioms and features. + +**FIXME**: Maybe regroup `rust-2018`, `rust-2021` and `rust-2024` under this umbrella? + +## `tests/ui/empty/`: Various tests related to the concept of "empty" + +**FIXME**: These tests need better homes, this is not very informative. + +## `tests/ui/entry-point/`: `main` function + +Tests exercising the `main` entry-point. + +## `tests/ui/enum/` + +General-purpose tests on `enum`s. See [Enumerations | Reference](https://doc.rust-lang.org/reference/items/enumerations.html). + +## `tests/ui/enum-discriminant/` + +`enum` variants can be differentiated independently of their potential field contents with `discriminant`, which returns the type `Discriminant`. See [`std::mem::discriminant`](https://doc.rust-lang.org/std/mem/fn.discriminant.html). + +## `tests/ui/env-macro/`: `env!` + +Exercises `env!` and `option_env!` macros. + +## `tests/ui/ergonomic-clones/` + +See [RFC 3680 Ergonomic clones](https://github.com/rust-lang/rfcs/pull/3680). + +## `tests/ui/error-codes/`: Error codes + +Tests for errors with dedicated error codes. + +## `tests/ui/error-emitter/` + +Quite similar to `ui/diagnostic-flags` in some of its tests, this category checks some behaviours of Rust's error emitter into the user's terminal window, such as truncating error in the case of an excessive amount of them. + +## `tests/ui/errors/` + +These tests are about very different topics, only unified by the fact that they result in errors. + +**FIXME**: "Errors" is way too generic, the tests probably need to be rehomed into more descriptive subdirectories. + +## `tests/ui/explain/`: `rustc --explain EXXXX` + +Accompanies `tests/ui/error-codes/`, exercises the `--explain` cli flag. + +## `tests/ui/explicit/`: Errors involving the concept of "explicit" + +This category contains three tests: two which are about the specific error `explicit use of destructor method`, and one which is about explicit annotation of lifetimes: https://doc.rust-lang.org/stable/rust-by-example/scope/lifetime/explicit.html. + +**FIXME**: Rehome the two tests about the destructor method with `drop`-related categories, and rehome the last test with a category related to lifetimes. + +## `tests/ui/explicit-tail-calls/` + +Exercises `#![feature(explicit_tail_calls)]` and the `become` keyword. See [Explicit Tail Calls #3407](https://github.com/rust-lang/rfcs/pull/3407). + +## `tests/ui/expr/`: Expressions + +A broad directory for tests on expressions. + +## `tests/ui/extern/` + +Tests on the `extern` keyword and `extern` blocks and functions. + +## `tests/ui/extern-flag/`: `--extern` command line flag + +Tests for the `--extern` CLI flag. + +## `tests/ui/feature-gates/` + +Tests on feature-gating, and the `#![feature(..)]` mechanism itself. + +## `tests/ui/ffi-attrs/`: `#![feature(ffi_const, ffi_pure)]` + +The `#[ffi_const]` and `#[ffi_pure]` attributes applies clang's `const` and `pure` attributes to foreign functions declarations, respectively. These attributes are the core element of the tests in this category. + +See: + +- [`ffi_const` | The Unstable book](https://doc.rust-lang.org/unstable-book/language-features/ffi-const.html) +- [`ffi_pure` | The Unstable book](https://doc.rust-lang.org/beta/unstable-book/language-features/ffi-pure.html) + +## `tests/ui/fmt/` + +Exercises the `format!` macro. + +## `tests/ui/fn/` + +A broad category of tests on functions. + +## `tests/ui/fn-main/` + +**FIXME**: Serves a duplicate purpose with `ui/entry-point`, should be combined. + +## `tests/ui/for/`: `for` keyword + +Tests on the `for` keyword and some of its associated errors, such as attempting to write the faulty pattern `for _ in 0..1 {} else {}`. + +**FIXME**: Should be merged with `ui/for-loop-while`. + +## `tests/ui/force-inlining/`: `#[rustc_force_inline]` + +Tests for `#[rustc_force_inline]`, which will force a function to always be labelled as inline by the compiler (it will be inserted at the point of its call instead of being used as a normal function call.) If the compiler is unable to inline the function, an error will be reported. See . + +## `tests/ui/foreign/`: Foreign Function Interface (FFI) + +Tests for `extern "C"` and `extern "Rust`. + +**FIXME**: Check for potential overlap/merge with `ui/c-variadic` and/or `ui/extern`. + +## `tests/ui/for-loop-while/` + +Anything to do with loops and `for`, `loop` and `while` keywords to express them. + +**FIXME**: After `ui/for` is merged into this, also carry over its SUMMARY text. + +## `tests/ui/frontmatter/` + +Tests for `#![feature(frontmatter)]`. See [Tracking Issue for `frontmatter` #136889](https://github.com/rust-lang/rust/issues/136889). + +## `tests/ui/fully-qualified-type/` + +Tests for diagnostics when there may be identically named types that need further qualifications to disambiguate. + +## `tests/ui/functional-struct-update/` + +Functional Struct Update is the name for the idiom by which one can write `..` at the end of a struct literal expression to fill in all remaining fields of the struct literal by using `` as the source for them. + +See [RFC 0736 Privacy-respecting Functional Struct Update](https://github.com/rust-lang/rfcs/blob/master/text/0736-privacy-respecting-fru.md). + +## `tests/ui/function-pointer/` + +Tests on function pointers, such as testing their compatibility with higher-ranked trait bounds. + +See: + +- [Function pointer types | Reference](https://doc.rust-lang.org/reference/types/function-pointer.html) +- [Higher-ranked trait bounds | Nomicon](https://doc.rust-lang.org/nomicon/hrtb.html) + +## `tests/ui/functions-closures/` + +Tests on closures. See [Closure expressions | Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html). + +## `tests/ui/generic-associated-types/` + +Tests on Generic Associated Types (GATs). + +## `tests/ui/generic-const-items/` + +Tests for `#![feature(generic_const_items)]`. See [Tracking issue for generic const items #113521](https://github.com/rust-lang/rust/issues/113521). + +## `tests/ui/generics/` + +A broad category of tests on generics, usually used when no more specific subdirectories are fitting. + +## `tests/ui/half-open-range-patterns/`: `x..` or `..x` range patterns + +Tests on range patterns where one of the bounds is not a direct value. + +**FIXME**: Overlaps with `ui/range`. `impossible_range.rs` is particularly suspected to be a duplicate test. + +## `tests/ui/hashmap/` + +Tests for the standard library collection [`std::collections::HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html). + +## `tests/ui/hello_world/` + +Tests that the basic hello-world program is not somehow broken. + +## `tests/ui/higher-ranked/` + +Tests for higher-ranked trait bounds. + +See: + +- [Higher-ranked trait bounds | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/traits/hrtb.html) +- [Higher-ranked trait bounds | Nomicon](https://doc.rust-lang.org/nomicon/hrtb.html) + +## `tests/ui/hygiene/` + +This seems to have been originally intended for "hygienic macros" - macros which work in all contexts, independent of what surrounds them. However, this category has grown into a mish-mash of many tests that may belong in the other directories. + +**FIXME**: Reorganize this directory properly. + +## `tests/ui/illegal-sized-bound/` + +This test category revolves around trait objects with `Sized` having illegal operations performed on them. + +**FIXME**: There seems to be unrelated testing in this directory, such as `tests/ui/illegal-sized-bound/mutability-mismatch-arg.rs`. Investigate. + +## `tests/ui/impl-header-lifetime-elision/` + +Tests on lifetime elision in impl function signatures. See [Lifetime elision | Nomicon](https://doc.rust-lang.org/nomicon/lifetime-elision.html). + +## `tests/ui/implied-bounds/` + +See [Implied bounds | Reference](https://doc.rust-lang.org/reference/trait-bounds.html#implied-bounds). + +## `tests/ui/impl-trait/` + +Tests for trait impls. + +## `tests/ui/imports/` + +Tests for module system and imports. + +## `tests/ui/include-macros/` + +Exercise `include!`, `include_str!`, and `include_bytes!` macros. + +## `tests/ui/incoherent-inherent-impls/` + +Exercise forbidding inherent impls on a type defined in a different crate. + +## `tests/ui/indexing/` + +Tests on collection types (arrays, slices, vectors) and various errors encountered when indexing their contents, such as accessing out-of-bounds values. + +**FIXME**: (low-priority) could maybe be a subdirectory of `ui/array-slice-vec` + +## `tests/ui/inference/` + +Tests on type inference. + +## `tests/ui/infinite/` + +Tests for diagnostics on infinitely recursive types without indirection. + +## `tests/ui/inherent-impls-overlap-check/` + +Checks that repeating the same function names across separate `impl` blocks triggers an informative error, but not if the `impl` are for different types, such as `Bar` and `Bar`. + +NOTE: This should maybe be a subdirectory within another related to duplicate definitions, such as `tests/ui/duplicate/`. + +## `tests/ui/inline-const/` + +These tests revolve around the inline `const` block that forces the compiler to const-eval its content. + +## `tests/ui/instrument-coverage/`: `-Cinstrument-coverage` command line flag + +See [Instrument coverage | The rustc book](https://doc.rust-lang.org/rustc/instrument-coverage.html). + +## `tests/ui/instrument-xray/`: `-Z instrument-xray` + +See [Tracking issue for `-Z instrument-xray` #102921](https://github.com/rust-lang/rust/issues/102921). + +## `tests/ui/interior-mutability/` + +**FIXME**: contains a single test, probably better rehomed. + +## `tests/ui/internal/` + +Tests for `internal_unstable` and the attribute header `#![feature(allow_internal_unstable)]`, which lets compiler developers mark features as internal to the compiler, and unstable for standard library use. + +## `tests/ui/internal-lints/` + +Tests for rustc-internal lints. + +## `tests/ui/intrinsics/` + +Tests for the `{std,core}::intrinsics`, internal implementation detail. + +## `tests/ui/invalid/` + +Various tests related to rejecting invalid inputs. + +**FIXME**: This is rather uninformative, possibly rehome into more meaningful directories. + +## `tests/ui/invalid-compile-flags/` + +Tests for checking that invalid usage of compiler flags are rejected. + +## `tests/ui/invalid-module-declaration/` + +**FIXME**: Consider merging into module/resolve directories. + +## `tests/ui/invalid-self-argument/`: `self` as a function argument incorrectly + +Tests with erroneous ways of using `self`, such as having it not be the first argument, or using it in a non-associated function (no `impl` or `trait`). + +**FIXME**: Maybe merge with `ui/self`. + +## `tests/ui/io-checks/` + +Contains a single test. The test tries to output a file into an invalid directory with `-o`, then checks that the result is an error, not an internal compiler error. + +**FIXME**: Rehome to invalid compiler flags maybe. + +## `tests/ui/issues/`: Tests directly related to GitHub issues + +**FIXME (#133895)**: Random collection of regression tests and tests for issues, tests in this directory should be audited and rehomed. + +## `tests/ui/iterators/` + +These tests revolve around anything to do with iterators, e.g. mismatched types. + +**FIXME**: Check for potential overlap with `ui/for-loop-while`. + +## `tests/ui/json/` + +These tests revolve around the `--json` compiler flag. See [JSON Output](https://doc.rust-lang.org/rustc/json.html#json-output). + +## `tests/ui/keyword/` + +Tests exercising keywords, such as attempting to use them as identifiers when not contextual keywords. + +## `tests/ui/kindck/` + +**FIXME**: `kindck` is no longer a thing, these tests probably need to be audited and rehomed. + +## `tests/ui/label/` + +Exercises block and loop `'label`s. + +## `tests/ui/lang-items/` + +See [Lang items | The Unstable book](https://doc.rust-lang.org/unstable-book/language-features/lang-items.html). + +## `tests/ui/late-bound-lifetimes/` + +See [Early vs Late bound parameters | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/early_late_parameters.html#early-vs-late-bound-parameters). + +## `tests/ui/layout/` + +See [Type Layout | Reference](https://doc.rust-lang.org/reference/type-layout.html). + +## `tests/ui/lazy-type-alias/` + +Tests for `#![feature(lazy_type_alias)]`. See [Tracking issue for lazy type aliases #112792 +](https://github.com/rust-lang/rust/issues/112792). + +## `tests/ui/lazy-type-alias-impl-trait/` + +This feature allows use of an `impl Trait` in multiple locations while actually using the same concrete type (`type Alias = impl Trait;`) everywhere, keeping the original `impl Trait` hidden. + +**FIXME**: merge this with `tests/ui/type-alias-impl-trait/`? + +## `tests/ui/let-else/` + +Exercises let-else constructs. + +## `tests/ui/lexer/` + +Exercises of the lexer. + +## `tests/ui/lifetimes/` + +Broad directory on lifetimes, including proper specifiers, lifetimes not living long enough, or undeclared lifetime names. + +## `tests/ui/limits/` + +These tests exercises numerical limits, such as `[[u8; 1518599999]; 1518600000]`. + +## `tests/ui/linkage-attr/` + +Tests for the linkage attribute `#[linkage]` of `#![feature(linkage)]`. + +**FIXME**: Some of these tests do not use the feature at all, which should be moved under `ui/linking` instead. + +## `tests/ui/linking/` + +Tests on code which fails during the linking stage, or which contain arguments and lines that have been known to cause unjustified errors in the past, such as specifying an unusual `#[export_name]`. + +See [Linkage | Reference](https://doc.rust-lang.org/reference/linkage.html). + +## `tests/ui/link-native-libs/` + +Tests for `#[link(name = "", kind = "")]` and `-l` command line flag. + +See [Tracking Issue for linking modifiers for native libraries #81490](https://github.com/rust-lang/rust/issues/81490). + +## `tests/ui/lint/` + +Tests for the lint infrastructure, lint levels, lint reasons, etc. + +See: + +- [Lints | The rustc book](https://doc.rust-lang.org/rustc/lints/index.html) +- [Lint reasons | Reference](https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-reasons) + +## `tests/ui/liveness/` + +Tests exercising analysis for unused variables, unreachable statements, functions which are supposed to return a value but do not, as well as values moved elsewhere before they could be used by a function. + +**FIXME**: This seems unrelated to "liveness" as defined in the rustc compiler guide. Is this misleadingly named? https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/lifetime_parameters.html#liveness-and-universal-regions + +## `tests/ui/loops/` + +Tests on the `loop` construct. + +**FIXME**: Consider merging with `ui/for-loop-while`. + +## `tests/ui/lowering/` + +Tests on [AST lowering](https://rustc-dev-guide.rust-lang.org/ast-lowering.html). + +## `tests/ui/lto/` + +Exercise *Link-Time Optimization* (LTO), involving the flags `-C lto` or `-Z thinlto`. + +## `tests/ui/lub-glb/`: LUB/GLB algorithm update + +Tests on changes to inference variable lattice LUB/GLB, see . + +## `tests/ui/macro_backtrace/`: `-Zmacro-backtrace` + +Contains a single test, checking the unstable command-line flag to enable detailed macro backtraces. + +**FIXME**: This could be merged with `ui/macros`, which already contains other macro backtrace tests. + +## `tests/ui/macros/` + +Broad category of tests on macros. + +## `tests/ui/malformed/` + +Broad category of tests on malformed inputs. + +**FIXME**: this is kinda vague, probably best to audit and rehome tests. + +## `tests/ui/marker_trait_attr/` + +See [Tracking issue for allowing overlapping implementations for marker trait #29864](https://github.com/rust-lang/rust/issues/29864). + +## `tests/ui/match/` + +Broad category of tests on `match` constructs. + +## `tests/ui/meta/`: Tests for compiletest itself + +These tests check the function of the UI test suite at large and Compiletest in itself. + +**FIXME**: This should absolutely be merged with `tests/ui/compiletest-self-test/`. + +## `tests/ui/methods/` + +A broad category for anything related to methods and method resolution. + +## `tests/ui/mir/` + +Certain mir-opt regression tests. + +## `tests/ui/mir-dataflow` + +Tests for MIR dataflow analysis. + +See [MIR Dataflow | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/mir/dataflow.html). + +## `tests/ui/mismatched_types/` + +Exercises on mismatched type diagnostics. + +## `tests/ui/missing/` + +Something is missing which could be added to fix (e.g. suggestions). + +**FIXME**: this is way too vague, tests should be rehomed. + +## `tests/ui/missing_non_modrs_mod/` + +This directory is a small tree of `mod` dependencies, but the root, `foo.rs`, is looking for a file which does not exist. The test checks that the error is reported at the top-level module. + +**FIXME**: Merge with `tests/ui/modules/`. + +## `tests/ui/missing-trait-bounds/` + +Tests for checking missing trait bounds, and their diagnostics. + +**FIMXE**: Maybe a subdirectory of `ui/trait-bounds` would be more appropriate. + +## `tests/ui/modules/` + +Tests on the module system. + +**FIXME**: `tests/ui/imports/` should probably be merged with this. + +## `tests/ui/modules_and_files_visibility/` + +**FIXME**: Merge with `tests/ui/modules/`. + +## `tests/ui/moves` + +Tests on moves (destructive moves). + +## `tests/ui/mut/` + +Broad category of tests on mutability, such as the `mut` keyword, borrowing a value as both immutable and mutable (and the associated error), or adding mutable references to `const` declarations. + +## `tests/ui/namespace/` + +Contains a single test. It imports a massive amount of very similar types from a crate, then attempts various permutations of their namespace paths, checking for errors or the lackthereof. + +**FIXME**: Move under either `tests/ui/modules/` or `tests/ui/resolve/`. + +## `tests/ui/never_type/` + +See [Tracking issue for promoting `!` to a type (RFC 1216) #35121](https://github.com/rust-lang/rust/issues/35121). + +## `tests/ui/new-range/` + +See [RFC 3550 New Range](https://github.com/rust-lang/rfcs/blob/master/text/3550-new-range.md). + +## `tests/ui/nll/`: Non-lexical lifetimes + +Tests for Non-lexical lifetimes. See [RFC 2094 NLL](https://rust-lang.github.io/rfcs/2094-nll.html). + +## `tests/ui/non_modrs_mods/` + +Despite the size of the directory, this is a single test, spawning a sprawling `mod` dependency tree and checking its successful build. + +**FIXME**: Consider merge with `tests/ui/modules/`, keeping the directory structure. + +## `tests/ui/non_modrs_mods_and_inline_mods/` + +A very similar principle as `non_modrs_mods`, but with an added inline `mod` statement inside another `mod`'s code block. + +**FXIME**: Consider merge with `tests/ui/modules/`, keeping the directory structure. + +## `tests/ui/no_std/` + +Tests for where the standard library is disabled through `#![no_std]`. + +## `tests/ui/not-panic/` + +Tests checking various types, such as `&RefCell`, and whether they are not `UnwindSafe` as expected. + +## `tests/ui/numbers-arithmetic/` + +Tests that exercises edge cases, such as specific floats, large or very small numbers, or bit conversion, and check that the arithmetic results are as expected. + +## `tests/ui/numeric/` + +Tests that checks numeric types and their interactions, such as casting among them with `as` or providing the wrong numeric suffix. + +## `tests/ui/object-lifetime/` + +Tests on lifetimes on objects, such as a lifetime bound not being able to be deduced from context, or checking that lifetimes are inherited properly. + +**FIXME**: Just a more specific subset of `ui/lifetimes`. + +## `tests/ui/obsolete-in-place/` + +Contains a single test. Check that we reject the ancient Rust syntax `x <- y` and `in(BINDING) {}` construct. + +**FIXME**: Definitely should be rehomed, maybe to `tests/ui/deprecation/`. + +## `tests/ui/offset-of/` + +Exercises the [`std::mem::offset_of` macro](https://doc.rust-lang.org/beta/std/mem/macro.offset_of.html). + +## `tests/ui/on-unimplemented/` + +Exercises the `#[rustc_on_unimplemented]`. + +## `tests/ui/operator-recovery/` + +**FIXME**: Probably move under `tests/ui/binop/` or `tests/ui/parser/`. + +## `tests/ui/or-patterns/` + +Exercises `||` and `|` in patterns. + +## `tests/ui/overloaded/` + +Exercises operator overloading via [`std::ops`](https://doc.rust-lang.org/std/ops/index.html). + +## `tests/ui/packed/` + +See [`repr(packed)` | Nomicon](https://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked-reprpackedn). + +## `tests/ui/panic-handler/` + +See [panic handler | Nomicon](https://doc.rust-lang.org/nomicon/panic-handler.html). + +## `tests/ui/panic-runtime/` + +Exercises `#![panic_runtime]`, `-C panic`, panic runtimes and panic unwind strategy. + +See [RFC 1513 Less unwinding](https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md). + +## `tests/ui/panics/` + +Broad category of tests about panics in general, often but not necessarily using the `panic!` macro. + +## `tests/ui/parallel-rustc/` + +Efforts towards a [Parallel Rustc Front-end](https://github.com/rust-lang/rust/issues/113349). Includes `-Zthreads=`. + +## `tests/ui/parser/` + +Various parser tests + +**FIXME**: Maybe move `tests/ui/keywords/` under this? + +## `tests/ui/patchable-function-entry/` + +See [Patchable function entry | The Unstable book](https://doc.rust-lang.org/unstable-book/compiler-flags/patchable-function-entry.html). + +## `tests/ui/pattern/` + +Broad category of tests surrounding patterns. See [Patterns | Reference](https://doc.rust-lang.org/reference/patterns.html). + +**FIXME**: Some overlap with `tests/ui/match/`. + +## `tests/ui/pin-macro/` + +See [`std::pin`](https://doc.rust-lang.org/std/pin/). + +## `tests/ui/precondition-checks/` + +Exercises on some unsafe precondition checks. + +## `tests/ui/print-request/` + +Tests on `--print` compiler flag. See [print options | The rustc book](https://doc.rust-lang.org/rustc/command-line-arguments/print-options.html). + +## `tests/ui/print_type_sizes/` + +Exercises the `-Z print-type-sizes` flag. + +## `tests/ui/privacy/` + +Exercises on name privacy. E.g. the meaning of `pub`, `pub(crate)`, etc. + +## `tests/ui/process/` + +Some standard library process tests which are hard to write within standard library crate tests. + +## `tests/ui/process-termination/` + +Some standard library process termination tests which are hard to write within standard library crate tests. + +## `tests/ui/proc-macro/` + +Broad category of tests on proc-macros. See [Procedural Macros | Reference](https://doc.rust-lang.org/reference/procedural-macros.html). + +## `tests/ui/ptr_ops/`: Using operations on a pointer + +Contains only 2 tests, related to a single issue, which was about an error caused by using addition on a pointer to `i8`. + +**FIXME**: Probably rehome under some typecheck / binop directory. + +## `tests/ui/pub/`: `pub` keyword + +A large category about function and type public/private visibility, and its impact when using features across crates. Checks both visibility-related error messages and previously buggy cases. + +**FIXME**: merge with `tests/ui/privacy/`. + +## `tests/ui/qualified/` + +Contains few tests on qualified paths where a type parameter is provided at the end: `type A = ::A::f;`. The tests check if this fails during type checking, not parsing. + +**FIXME**: Should be rehomed to `ui/typeck`. + +## `tests/ui/query-system/` + +Tests on Rust methods and functions which use the query system, such as `std::mem::size_of`. These compute information about the current runtime and return it. See [Query system | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/query.html). + +## `tests/ui/range/` + +Broad category of tests ranges, both in their `..` or `..=` form, as well as the standard library `Range`, `RangeTo`, `RangeFrom` or `RangeBounds` types. + +**FIXME**: May have some duplicate tests with `ui/new-range`. + +## `tests/ui/raw-ref-op/`: Using operators on `&raw` values + +Exercises `&raw mut ` and `&raw const `. See [RFC 2582 Raw reference MIR operator](https://github.com/rust-lang/rfcs/blob/master/text/2582-raw-reference-mir-operator.md). + +## `tests/ui/reachable` + +Reachability tests, primarily unreachable code and coercions into the never type `!` from diverging expressions. + +**FIXME**: Check for overlap with `ui/liveness`. + +## `tests/ui/recursion/` + +Broad category of tests exercising recursions (compile test and run time), in functions, macros, `type` definitions, and more. + +Also exercises the `#![recursion_limit = ""]` attribute. + +## `tests/ui/recursion_limit/`: `#![recursion_limit = ""]` + +Sets a recursion limit on recursive code. + +**FIXME**: Should be merged with `tests/ui/recursion/`. + +## `tests/ui/regions/` + +**FIXME**: Maybe merge with `ui/lifetimes`. + +## `tests/ui/repeat-expr/` + +Exercises `[Type; n]` syntax for creating arrays with repeated types across a set size. + +**FIXME**: Maybe make this a subdirectory of `ui/array-slice-vec`. + +## `tests/ui/repr/`: `#[repr(_)]` + +Tests on the `#[repr(..)]` attribute. See [Representations | Reference](https://doc.rust-lang.org/reference/type-layout.html#representations). + +## `tests/ui/reserved/` + +Reserved keywords and attribute names. + +See e.g. [Reserved keywords | Reference](https://doc.rust-lang.org/reference/keywords.html). + +**FIXME**: maybe merge under `tests/ui/keyword/`. + +## `tests/ui/resolve/`: Name resolution + +See [Name resolution | rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/name-resolution.html). + +## `tests/ui/return/` + +Exercises the `return` keyword, return expressions and statements. + +## `tests/ui/rfcs/` + +Tests that accompanies an implementation for an RFC. + +## `tests/ui/rmeta/` + +Exercises `.rmeta` crate metadata and the `--emit=metadata` cli flag. + +## `tests/ui/runtime/` + +Tests for runtime environment on which Rust programs are executed. E.g. Unix `SIGPIPE`. + +## `tests/ui/rust-{2018,2021,2024}/` + +Tests that exercise behaviors and features that are specific to editions. + +## `tests/ui/rustc-env` + +Tests on environmental variables that affect `rustc`. + +## `tests/ui/rustdoc` + +Hybrid tests that exercises `rustdoc`, and also some joint `rustdoc`/`rustc` interactions. + +## `tests/ui/sanitizer/` + +Exercises sanitizer support. See [Sanitizer | The rustc book](https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html). + +## `tests/ui/self/`: `self` keyword + +Tests with erroneous ways of using `self`, such as using `this.x` syntax as seen in other languages, having it not be the first argument, or using it in a non-associated function (no `impl` or `trait`). It also contains correct uses of `self` which have previously been observed to cause ICEs. + +## `tests/ui/sepcomp/`: Separate Compilation + +In this directory, multiple crates are compiled, but some of them have `inline` functions, meaning they must be inlined into a different crate despite having been compiled separately. + +**FIXME**: this directory might need some better docs, also this directory might want a better name. + +## `tests/ui/shadowed/` + +Tests on name shadowing. + +## `tests/ui/shell-argfiles/`: `-Z shell-argfiles` command line flag + +The `-Zshell-argfiles` compiler flag allows argfiles to be parsed using POSIX "shell-style" quoting. When enabled, the compiler will use shlex to parse the arguments from argfiles specified with `@shell:`. + +Because this feature controls the parsing of input arguments, the `-Zshell-argfiles` flag must be present before the argument specifying the shell-style argument file. + +**FIXME**: maybe group this with `tests/ui/argfile/` + +## `tests/ui/simd/` + +Some tests exercising SIMD support. + +## `tests/ui/single-use-lifetime/` + +This is a test directory for the specific error case where a lifetime never gets used beyond a single annotation on, for example, a `struct`. + +## `tests/ui/sized/`: `Sized` trait, sized types + +While many tests here involve the `Sized` trait directly, some instead test, for example the slight variations between returning a zero-sized `Vec` and a `Vec` with one item, where one has no known type and the other does. + +## `tests/ui/span/` + +An assorted collection of tests that involves specific diagnostic spans. + +**FIXME**: This is a big directory with numerous only-tangentially related tests. Maybe some moving is in order. + +## `tests/ui/specialization` + +See [Tracking issue for specialization (RFC 1210) #31844](https://github.com/rust-lang/rust/issues/31844). + +## `tests/ui/stability-attribute/` + +Stability attributes used internally by the standard library: `#[stable()]` and `#[unstable()]`. + +## `tests/ui/stable-mir-print/` + +Some tests for pretty printing of StableMIR. + +## `tests/ui/stack-protector/`: `-Z stack-protector` command line flag + +See [Tracking Issue for stabilizing stack smashing protection (i.e., `-Z stack-protector`) #114903](https://github.com/rust-lang/rust/issues/114903). + +## `tests/ui/static/` + +Tests on static items. + +## `tests/ui/statics/` + +**FIXME**: should probably be merged with `tests/ui/static/`. + +## `tests/ui/stats/` + +Tests for compiler-internal stats; `-Z meta-stats` and `-Z input-stats` flags. + +## `tests/ui/std/`: Tests which use features from the standard library + +A catch-all category about anything that can come from `std`. + +**FIXME**: this directory is probably too vague, tests might need to be audited and rehomed. + +## `tests/ui/stdlib-unit-tests/` + +Some standard library tests which are too inconvenient or annoying to implement as std crate tests. + +## `tests/ui/str/` + +Exercise `str` keyword and string slices. + +## `tests/ui/structs/` + +Assorted tests surrounding the `struct` keyword, struct type definitions and usages. + +## `tests/ui/structs-enums/` + +Tests on both structs and enums. + +**FIXME**: maybe coalesce {`tests/ui/structs/`, `tests/ui/structs-enums/`, `tests/ui/enums/`} into one `tests/ui/adts` directory... + +## `tests/ui/suggestions/` + +Generic collection of tests for suggestions, when no more specific directories are applicable. + +**FIXME**: Some overlap with `tests/ui/did_you_mean/`, that directory should probably be moved under here. + +## `tests/ui/svh/`: Strict Version Hash + +Tests on the *Strict Version Hash* (SVH, also known as the "crate hash"). + +See [Strict Version Hash](https://rustc-dev-guide.rust-lang.org/backend/libs-and-metadata.html#strict-version-hash). + +## `tests/ui/symbol-mangling-version/`: `-Csymbol-mangling-version` command line flag + +**FIXME**: Should be merged with `ui/symbol-names`. + +## `tests/ui/symbol-names/`: Symbol mangling and related attributes + +These tests revolve around `#[no_mangle]` attribute, as well as consistently mangled symbol names (checked with the `rustc_symbol_name` attribute), which is important to build reproducible binaries. + +## `tests/ui/sync/`: `Sync` trait + +Exercises `Sync` trait and auto-derive thereof. + +## `tests/ui/target-cpu/`: `-C target-cpu` command line flag + +This command line option instructs rustc to generate code specifically for a particular processor. + +**FIXME**: Contains a single test, maybe put it in a directory about misc codegen options? + +## `tests/ui/target-feature/`: `#[target_feature(enable = "relaxed-simd")]` + +Exercises the `#[target_feature(..)]` attribute. See [Target feature attribute | Reference](https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute). + +## `tests/ui/target_modifiers/` + +Tests for [RFC 3716: Target Modifiers](https://github.com/rust-lang/rfcs/pull/3716). + +See [Tracking Issue for target modifiers #136966](https://github.com/rust-lang/rust/issues/136966). + +## `tests/ui/test-attrs/` + +Exercises the [`#[test]` attribute](https://doc.rust-lang.org/reference/attributes/testing.html#testing-attributes). + +## `tests/ui/thir-print/` + +Pretty print of THIR trees via `-Zunpretty=thir-tree`. + +## `tests/ui/thread-local/` + +Exercises thread local values and `#[thread_local]` attribute. + +See [Tracking issue for thread_local stabilization #29594](https://github.com/rust-lang/rust/issues/29594). + +## `tests/ui/threads-sendsync/` + +Broad category for parallelism and multi-threaded tests, including attempting to send types across threads which are not thread-safe. + +## `tests/ui/tool-attributes/`: External tool attributes + +Exercises [tool attributes](https://doc.rust-lang.org/reference/attributes.html#tool-attributes). + +## `tests/ui/track-diagnostics/` + +Exercises `#[track_caller]` and `-Z track-diagnostics`. + +## `tests/ui/trait-bounds/` + +Collection of tests for [trait bounds](https://doc.rust-lang.org/reference/trait-bounds.html). + +## `tests/ui/traits/` + +Broad collection of tests on traits in general. + +**FIXME**: This could be better organized in subdirectories containing tests such as `ui/traits/trait-bounds`. + +## `tests/ui/transmutability/`: `#![feature(transmutability)]` + +See [Tracking Issue for Transmutability Trait: `#[transmutability]` #99571](https://github.com/rust-lang/rust/issues/99571). + +See also [Project Safe Transmute](https://github.com/rust-lang/project-safe-transmute). + +## `tests/ui/transmute/` + +Tests surrounding [`std::mem::transmute`](https://doc.rust-lang.org/std/mem/fn.transmute.html). + +## `tests/ui/treat-err-as-bug/` + +Exercises compiler development support flag `-Z treat-err-as-bug`. + +## `tests/ui/trivial-bounds/` + +`#![feature(trivial_bounds)]`. See [RFC 2056 Allow trivial where clause constraints](https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md). + +## `tests/ui/try-block/` + +`#![feature(try_blocks)]`. See [Tracking issue for `?` operator and `try` blocks (RFC 243, `question_mark` & `try_blocks` features)](https://github.com/rust-lang/rust/issues/31436). + +## `tests/ui/try-trait/` + +`#![feature(try_trait_v2)]`. See [RFC 3058 Try Trait v2](https://github.com/rust-lang/rfcs/blob/master/text/3058-try-trait-v2.md). + +## `tests/ui/tuple/` + +Tests surrounding the tuple type `()`. + +## `tests/ui/type/` + +Assorted collection of tests surrounding the concept of a "type". + +**FIXME**: There is very little consistency across tests of this category, and should probably be sent to other subdirectories. + +## `tests/ui/type-alias/` + +Exercises [type aliases](https://doc.rust-lang.org/reference/items/type-aliases.html). + +## `tests/ui/type-alias-enum-variants/` + +Tests for `type` aliases in the context of `enum` variants, such as that applied type arguments of enums are respected independently of being the original type or the `type` alias. + +## `tests/ui/type-alias-impl-trait/` + +`#![feature(type_alias_impl_trait)]`. See [Type Alias Impl Trait | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/type-alias-impl-trait.html). + +## `tests/ui/typeck/` + +General collection of type checking related tests. + +## `tests/ui/type-inference/` + +General collection of type inference related tests. + +## `tests/ui/typeof/` + +`typeof` keyword, reserved but unimplemented. + +## `tests/ui/ufcs/` + +See [RFC 0132 Unified Function Call Syntax](https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md). + +## `tests/ui/unboxed-closures/` + +`#![feature(unboxed_closures)]`, `Fn`, `FnMut` and `FnOnce` traits + +See [Tracking issue for Fn traits (`unboxed_closures` & `fn_traits` feature)](https://github.com/rust-lang/rust/issues/29625). + +## `tests/ui/underscore-imports/` + +See [Underscore imports | Reference](https://doc.rust-lang.org/reference/items/use-declarations.html#underscore-imports). + +**FIXME**: should become a subdirectory of `tests/ui/imports/`. + +## `tests/ui/underscore-lifetime/`: `'_` elided lifetime + +Exercises [anonymous elided lifetimes](https://doc.rust-lang.org/reference/lifetime-elision.html). + +## `tests/ui/uniform-paths/` + +In uniform paths, if a submodule and an external dependencies have the same name, to depend on the external dependency, one needs to disambiguate it from the submodule using `use ::foo`. Tests revolve around this, for example, check that `self::foo` and `::foo` are not considered ambiguously identical by the compiler. + +Remark: As they are an important Rust 2018 feature, they also get a big subdirectory in `ui/rust-2018/uniform-paths` + +## `tests/ui/uninhabited/`: Uninhabited types + +See [Uninhabited | Reference](https://doc.rust-lang.org/reference/glossary.html?highlight=Uninhabit#uninhabited). + +## `tests/ui/union/` + +See [Unions | Reference](https://doc.rust-lang.org/reference/items/unions.html). + +## `tests/ui/unknown-unstable-lints/`: Attempting to refer to an unstable lint which does not exist + +Tests for trying to use non-existent unstable lints. + +**FIXME**: move this under `tests/ui/lints/`. + +## `tests/ui/unop/`: Unary operators `-`, `*` and `!` + +Tests the three unary operators for negating, dereferencing and inverting, across different contexts. + +## `tests/ui/unpretty/`: `-Z unpretty` command line flag + +The `-Z unpretty` flag outputs various representations of a program's tree in a certain way. + +## `tests/ui/unresolved/` + +Exercises various unresolved errors, ranging from earlier name resolution failures to later method resolution failures. + +## `tests/ui/unsafe/` + +A broad category of tests about unsafe Rust code. + +## `tests/ui/unsafe-binders/`: `#![feature(unsafe_binders)]` + +See [Tracking issue for unsafe binder types #130516](https://github.com/rust-lang/rust/issues/130516). + +## `tests/ui/unsafe-fields/`: `struct`s and `enum`s with an `unsafe` field + +See [Tracking issue for RFC 3458: Unsafe fields #132922](https://github.com/rust-lang/rust/issues/132922). + +## `tests/ui/unsized/`: Zero-sized types, `Sized` trait, object has no known size at compile time + +**FIXME**: between `tests/ui/zero-sized/`, `tests/ui/sized/` and this directory, might need to reorganize them a bit. + +## `tests/ui/unsized-locals/`: `#![feature(unsized_locals, unsized_fn_params)]` + +See: + +- [RFC 1909 Unsized rvalues](https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md) +- [de-RFC 3829: Remove unsized_locals](https://github.com/rust-lang/rfcs/pull/3829) +- [Tracking issue for RFC #1909: Unsized Rvalues (`unsized_locals`, `unsized_fn_params`)](https://github.com/rust-lang/rust/issues/48055) + +**FIXME**: Seems to also contain more generic tests that fit in `tests/ui/unsized/`. + +## `tests/ui/unused-crate-deps/` + +Exercises the `unused_crate_dependencies` lint. + +## `tests/ui/unwind-abis/` + +**FIXME**: Contains a single test, should likely be rehomed to `tests/ui/abi/`. + +## `tests/ui/use/` + +**FIXME**: merge with `ui/imports`. + +## `tests/ui/variance/`: Covariants, invariants and contravariants + +See [Variance | Reference](https://doc.rust-lang.org/reference/subtyping.html#variance). + +## `tests/ui/variants/`: `enum` variants + +Tests on `enum` variants. + +**FIXME**: Should be rehomed with `tests/ui/enum/`. + +## `tests/ui/version/` + +**FIXME**: Contains a single test described as "Check that rustc accepts various version info flags.", should be rehomed. + +## `tests/ui/warnings/` + +**FIXME**: Contains a single test on non-explicit paths (`::one()`). Should be rehomed probably to `tests/ui/resolve/`. + +## `tests/ui/wasm/` + +These tests target the `wasm32` architecture specifically. They are usually regression tests for WASM-specific bugs which were observed in the past. + +## `tests/ui/wf/`: Well-formedness checking + +Tests on various well-formedness checks, e.g. [Type-checking normal functions](https://rustc-dev-guide.rust-lang.org/traits/lowering-to-logic.html). + +## `tests/ui/where-clauses/` + +Tests on `where` clauses. See [Where clauses | Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses). + +## `tests/ui/while/` + +Tests on the `while` keyword and the `while` construct. + +**FIXME**: merge with `ui/for-loop-while`. + +## `tests/ui/windows-subsystem/`: `#![windows_subsystem = ""]` + +See [the `windows_subsystem` attribute](https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute). + +## `tests/ui/zero-sized/`: Zero-sized types + +See [Zero-Sized Types | Reference](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts). From 2084831cd54eb603fec6cd85ebd9d1426b09f628 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 22 Jun 2025 12:14:38 +0200 Subject: [PATCH 260/356] Port `#[no_mangle]` to new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- .../src/attributes.rs | 3 ++ .../src/attributes/codegen_attrs.rs | 18 +++++++ compiler/rustc_attr_parsing/src/context.rs | 3 +- compiler/rustc_codegen_ssa/messages.ftl | 2 + .../rustc_codegen_ssa/src/codegen_attrs.rs | 48 +++++++++---------- compiler/rustc_codegen_ssa/src/errors.rs | 8 ++++ compiler/rustc_lint/src/builtin.rs | 21 ++++---- compiler/rustc_lint/src/nonstandard_style.rs | 12 +++-- compiler/rustc_passes/src/check_attr.rs | 15 +++--- src/librustdoc/clean/types.rs | 22 ++++----- src/librustdoc/html/render/mod.rs | 4 +- src/librustdoc/html/render/print_item.rs | 2 +- src/librustdoc/json/conversions.rs | 2 +- src/rustdoc-json-types/lib.rs | 4 +- .../clippy_lints/src/functions/must_use.rs | 5 +- .../src/no_mangle_with_rust_abi.rs | 7 +-- .../lint/unused/unused-attr-duplicate.stderr | 24 +++++----- 17 files changed, 120 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index ce1d80802623..c7487847e6f2 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -244,6 +244,9 @@ pub enum AttributeKind { reason: Option, }, + /// Represents `#[no_mangle]` + NoMangle(Span), + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 1b03525a5ce8..ba4e2935004c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -56,3 +56,21 @@ impl SingleAttributeParser for ColdParser { Some(AttributeKind::Cold(cx.attr_span)) } } + +pub(crate) struct NoMangleParser; + +impl SingleAttributeParser for NoMangleParser { + const PATH: &[rustc_span::Symbol] = &[sym::no_mangle]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if !args.no_args() { + cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + return None; + }; + + Some(AttributeKind::NoMangle(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index fbe874d606cc..171995dc9cbd 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,7 +15,7 @@ use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; -use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser}; +use crate::attributes::codegen_attrs::{ColdParser, NoMangleParser, OptimizeParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -114,6 +114,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 2bd8644e0d7f..b2e86414d902 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -221,6 +221,8 @@ codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple time codegen_ssa_no_field = no field `{$name}` +codegen_ssa_no_mangle_nameless = `#[no_mangle]` cannot be used on {$definition} as it has no name + codegen_ssa_no_module_named = no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 39818be5bde5..b554ccfac50e 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -23,6 +23,7 @@ use rustc_span::{Ident, Span, sym}; use rustc_target::spec::SanitizerSet; use crate::errors; +use crate::errors::NoMangleNameless; use crate::target_features::{ check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr, }; @@ -87,7 +88,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let mut link_ordinal_span = None; let mut no_sanitize_span = None; let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); - let mut no_mangle_span = None; for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -122,6 +122,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), + AttributeKind::NoMangle(attr_span) => { + if tcx.opt_item_name(did.to_def_id()).is_some() { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + mixed_export_name_no_mangle_lint_state.track_no_mangle( + *attr_span, + tcx.local_def_id_to_hir_id(did), + attr, + ); + } else { + tcx.dcx().emit_err(NoMangleNameless { + span: *attr_span, + definition: format!( + "{} {}", + tcx.def_descr_article(did.to_def_id()), + tcx.def_descr(did.to_def_id()) + ), + }); + } + } _ => {} } } @@ -141,28 +160,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, - sym::no_mangle => { - no_mangle_span = Some(attr.span()); - if tcx.opt_item_name(did.to_def_id()).is_some() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - mixed_export_name_no_mangle_lint_state.track_no_mangle( - attr.span(), - tcx.local_def_id_to_hir_id(did), - attr, - ); - } else { - tcx.dcx() - .struct_span_err( - attr.span(), - format!( - "`#[no_mangle]` cannot be used on {} {} as it has no name", - tcx.def_descr_article(did.to_def_id()), - tcx.def_descr(did.to_def_id()), - ), - ) - .emit(); - } - } sym::rustc_std_internal_symbol => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } @@ -544,12 +541,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) && codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + let no_mangle_span = + find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span) + .unwrap_or_default(); let lang_item = lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name)); let mut err = tcx .dcx() .struct_span_err( - no_mangle_span.unwrap_or_default(), + no_mangle_span, "`#[no_mangle]` cannot be used on internal language items", ) .with_note("Rustc requires this item to have a specific mangled name.") diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 72e71b97a174..caac0f83f9d9 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1310,3 +1310,11 @@ impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_ diag } } + +#[derive(Diagnostic)] +#[diag(codegen_ssa_no_mangle_nameless)] +pub(crate) struct NoMangleNameless { + #[primary_span] + pub span: Span, + pub definition: String, +} diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index dedea54f8e08..ac405277c4ed 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,6 +21,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::expr_to_string; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::{Applicability, LintDiagnostic}; use rustc_feature::GateIssue; use rustc_hir as hir; @@ -954,7 +955,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(it.hir_id()); - let check_no_mangle_on_generic_fn = |attr: &hir::Attribute, + let check_no_mangle_on_generic_fn = |attr_span: Span, impl_generics: Option<&hir::Generics<'_>>, generics: &hir::Generics<'_>, span| { @@ -967,7 +968,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.emit_span_lint( NO_MANGLE_GENERIC_ITEMS, span, - BuiltinNoMangleGeneric { suggestion: attr.span() }, + BuiltinNoMangleGeneric { suggestion: attr_span }, ); break; } @@ -976,14 +977,15 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn { generics, .. } => { - if let Some(attr) = attr::find_by_name(attrs, sym::export_name) - .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) + if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name) + .map(|at| at.span()) + .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span)) { - check_no_mangle_on_generic_fn(attr, None, generics, it.span); + check_no_mangle_on_generic_fn(attr_span, None, generics, it.span); } } hir::ItemKind::Const(..) => { - if attr::contains_name(attrs, sym::no_mangle) { + if find_attr!(attrs, AttributeKind::NoMangle(..)) { // account for "pub const" (#45562) let start = cx .tcx @@ -1008,11 +1010,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { let attrs = cx.tcx.hir_attrs(it.id.hir_id()); - if let Some(attr) = attr::find_by_name(attrs, sym::export_name) - .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) + if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name) + .map(|at| at.span()) + .or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span)) { check_no_mangle_on_generic_fn( - attr, + attr_span, Some(generics), cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(), it.span, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 1b60466a589d..f39e1506390d 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,5 +1,5 @@ use rustc_abi::ExternAbi; -use rustc_attr_data_structures::{AttributeKind, ReprAttr}; +use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; use rustc_attr_parsing::AttributeParser; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; @@ -396,7 +396,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { match &fk { FnKind::Method(ident, sig, ..) => match method_context(cx, id) { MethodLateContext::PlainImpl => { - if sig.header.abi != ExternAbi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { + if sig.header.abi != ExternAbi::Rust + && find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..)) + { return; } self.check_snake_case(cx, "method", ident); @@ -408,7 +410,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { }, FnKind::ItemFn(ident, _, header) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != ExternAbi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { + if header.abi != ExternAbi::Rust + && find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..)) + { return; } self.check_snake_case(cx, "function", ident); @@ -514,7 +518,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { let attrs = cx.tcx.hir_attrs(it.hir_id()); match it.kind { hir::ItemKind::Static(_, ident, ..) - if !ast::attr::contains_name(attrs, sym::no_mangle) => + if !find_attr!(attrs, AttributeKind::NoMangle(..)) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e11ec2ed47ab..ad1a2a042737 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -174,6 +174,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::MustUse { span, .. }) => { self.check_must_use(hir_id, *span, target) } + Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => { + self.check_no_mangle(hir_id, *attr_span, span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -261,7 +264,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::link, ..] => self.check_link(hir_id, attr, span, target), [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), - [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) } @@ -698,6 +700,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. } | AttributeKind::Align { .. } + | AttributeKind::NoMangle(..) | AttributeKind::Cold(..) | AttributeKind::MustUse { .. }, ) => { @@ -1952,7 +1955,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[no_mangle]` is applied to a function or static. - fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_no_mangle(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { match target { Target::Static | Target::Fn => {} Target::Method(..) if self.is_impl_item(hir_id) => {} @@ -1961,7 +1964,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_mangle"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "no_mangle"); } // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error // The error should specify that the item that is wrong is specifically a *foreign* fn/static @@ -1975,8 +1978,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), - errors::NoMangleForeign { span, attr_span: attr.span(), foreign_item_kind }, + attr_span, + errors::NoMangleForeign { span, attr_span, foreign_item_kind }, ); } _ => { @@ -1985,7 +1988,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::NoMangle { span }, ); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c0a9d8c84f6c..0aedc7f5219c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -746,15 +746,17 @@ impl Item { Some(tcx.visibility(def_id)) } - pub(crate) fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { + fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { const ALLOWED_ATTRIBUTES: &[Symbol] = &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; - self.attrs .other_attrs .iter() .filter_map(|attr| { - if is_json { + // NoMangle is special-cased because cargo-semver-checks uses it + if matches!(attr, hir::Attribute::Parsed(AttributeKind::NoMangle(..))) { + Some("#[no_mangle]".to_string()) + } else if is_json { match attr { // rustdoc-json stores this in `Item::deprecation`, so we // don't want it it `Item::attrs`. @@ -767,26 +769,22 @@ impl Item { s }), } - } else if attr.has_any_name(ALLOWED_ATTRIBUTES) { + } else { + if !attr.has_any_name(ALLOWED_ATTRIBUTES) { + return None; + } Some( rustc_hir_pretty::attribute_to_string(&tcx, attr) .replace("\\\n", "") .replace('\n', "") .replace(" ", " "), ) - } else { - None } }) .collect() } - pub(crate) fn attributes_and_repr( - &self, - tcx: TyCtxt<'_>, - cache: &Cache, - is_json: bool, - ) -> Vec { + pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec { let mut attrs = self.attributes_without_repr(tcx, is_json); if let Some(repr_attr) = self.repr(tcx, cache, is_json) { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 66d5aafa3c1e..ed58bae70bd4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1194,7 +1194,7 @@ fn render_assoc_item( // a whitespace prefix and newline. fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display { fmt::from_fn(move |f| { - for a in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { + for a in it.attributes(cx.tcx(), cx.cache(), false) { writeln!(f, "{prefix}{a}")?; } Ok(()) @@ -1210,7 +1210,7 @@ fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) { // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { - for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { + for attr in it.attributes(cx.tcx(), cx.cache(), false) { render_code_attribute(CodeAttribute(attr), w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index a75088d27ccd..515424cbef19 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1491,7 +1491,7 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { writeln!(f, "{repr}")?; }; } else { - for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) { + for a in self.it.attributes(self.cx.tcx(), self.cx.cache(), false) { writeln!(f, "{a}")?; } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index abad6e480291..0778b5b56f5d 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -40,7 +40,7 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes_and_repr(self.tcx, &self.cache, true); + let attrs = item.attributes(self.tcx, &self.cache, true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index e5c246cb69c3..0e72ddd9db1e 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Pretty printing of must_use attributes changed -pub const FORMAT_VERSION: u32 = 52; +// Latest feature: Pretty printing of no_mangle attributes changed +pub const FORMAT_VERSION: u32 = 53; /// The root of the emitted JSON blob. /// diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index ea9ed4ddade7..c0c23e217fd4 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -15,9 +15,8 @@ use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; -use rustc_attr_data_structures::AttributeKind; use rustc_span::Symbol; -use rustc_attr_data_structures::find_attr; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use core::ops::ControlFlow; @@ -36,7 +35,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some((attr_span, reason)) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig); - } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { + } else if is_public && !is_proc_macro(attrs) && !find_attr!(attrs, AttributeKind::NoMangle(..)) { check_must_use_candidate( cx, sig.decl, diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index b71dde906918..0159c5d2ac1b 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -6,6 +6,8 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Pos}; +use rustc_attr_data_structures::AttributeKind; +use rustc_hir::Attribute; declare_clippy_lint! { /// ### What it does @@ -44,8 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { let mut app = Applicability::MaybeIncorrect; let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(ident.span.lo()), "..", &mut app); for attr in attrs { - if let Some(ident) = attr.ident() - && ident.name == rustc_span::sym::no_mangle + if let Attribute::Parsed(AttributeKind::NoMangle(attr_span)) = attr && fn_sig.header.abi == ExternAbi::Rust && let Some((fn_attrs, _)) = fn_snippet.rsplit_once("fn") && !fn_attrs.contains("extern") @@ -54,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { .span .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) .shrink_to_lo(); - let attr_snippet = snippet(cx, attr.span(), ".."); + let attr_snippet = snippet(cx, *attr_span, ".."); span_lint_and_then( cx, diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 6fdd0adf4cff..4abf7dd134e6 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -114,18 +114,6 @@ LL | #[export_name = "exported_symbol_name2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:98:1 - | -LL | #[no_mangle] - | ^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:97:1 - | -LL | #[no_mangle] - | ^^^^^^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:102:1 | @@ -289,5 +277,17 @@ note: attribute also specified here LL | #[cold] | ^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:98:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:97:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ + error: aborting due to 23 previous errors From b946d0667740ea2a8727b08f22e807eea55fc118 Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Sun, 22 Jun 2025 15:31:39 -0700 Subject: [PATCH 261/356] phantom_variance_markers: fix identifier usage in macro This shouldn't have worked originally, as far as we can tell. --- library/core/src/marker/variance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs index f9638fea225b..55fdacb014e6 100644 --- a/library/core/src/marker/variance.rs +++ b/library/core/src/marker/variance.rs @@ -18,7 +18,7 @@ macro_rules! phantom_type { pub struct $name:ident <$t:ident> ($($inner:tt)*); )*) => {$( $(#[$attr])* - pub struct $name<$t>($($inner)*) where T: ?Sized; + pub struct $name<$t>($($inner)*) where $t: ?Sized; impl $name where T: ?Sized From 74973d72fd12b6a0e0949b09004b1df54e057a03 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 22 Jun 2025 17:43:06 -0700 Subject: [PATCH 262/356] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 2251525ae503..84709f085062 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 2251525ae503fa196f6d7f9ce6d32eccb2d5f044 +Subproject commit 84709f085062cbf3c51fa507527c1b2334015178 From 707a6f54631c322e8c8ccff363fe024d67d93aa2 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 7 Mar 2025 11:17:39 +0000 Subject: [PATCH 263/356] update to literal-escaper 0.0.4 for better API without `unreachable` and faster string parsing --- Cargo.lock | 4 +- Cargo.toml | 5 + compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_ast/src/util/literal.rs | 15 ++- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_parse/src/lexer/mod.rs | 94 +++++++------------ compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_parse_format/src/lib.rs | 3 +- compiler/rustc_proc_macro/Cargo.toml | 2 +- library/Cargo.lock | 5 +- library/Cargo.toml | 3 +- library/proc_macro/Cargo.toml | 2 +- library/proc_macro/src/lib.rs | 13 ++- .../clippy/clippy_dev/src/update_lints.rs | 3 +- src/tools/lint-docs/Cargo.toml | 2 +- src/tools/lint-docs/src/lib.rs | 4 +- 16 files changed, 67 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df2842bddb38..4fc363a04e22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3166,9 +3166,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-literal-escaper" -version = "0.0.2" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04" +checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" [[package]] name = "rustc-main" diff --git a/Cargo.toml b/Cargo.toml index c4d2a06f4cb1..bfe95a82ed2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,3 +89,8 @@ codegen-units = 1 # FIXME: LTO cannot be enabled for binaries in a workspace # # lto = true + +# If you want to use a crate with local modifications, you can set a path or git dependency here. +# For git dependencies, also add your source to ALLOWED_SOURCES in src/tools/tidy/src/extdeps.rs. +#[patch.crates-io] + diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index b2d3b90fc449..5de2e69072fa 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" memchr = "2.7.4" -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index b8526cf9d952..ad9e5d1468b0 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -3,7 +3,7 @@ use std::{ascii, fmt, str}; use rustc_literal_escaper::{ - MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, + MixedUnit, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, unescape_str, }; use rustc_span::{Span, Symbol, kw, sym}; use tracing::debug; @@ -87,11 +87,10 @@ impl LitKind { // Force-inlining here is aggressive but the closure is // called on every char in the string, so it can be hot in // programs with many long strings containing escapes. - unescape_unicode( + unescape_str( s, - Mode::Str, - &mut #[inline(always)] - |_, c| match c { + #[inline(always)] + |_, res| match res { Ok(c) => buf.push(c), Err(err) => { assert!(!err.is_fatal(), "failed to unescape string literal") @@ -111,8 +110,8 @@ impl LitKind { token::ByteStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - unescape_unicode(s, Mode::ByteStr, &mut |_, c| match c { - Ok(c) => buf.push(byte_from_char(c)), + unescape_byte_str(s, |_, res| match res { + Ok(b) => buf.push(b), Err(err) => { assert!(!err.is_fatal(), "failed to unescape string literal") } @@ -128,7 +127,7 @@ impl LitKind { token::CStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - unescape_mixed(s, Mode::CStr, &mut |_span, c| match c { + unescape_c_str(s, |_span, c| match c { Ok(MixedUnit::Char(c)) => { buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) } diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 6504081f0b9c..c4a0ae2ce9dd 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 2845bbed1c0e..60d275bf2b40 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,5 +1,3 @@ -use std::ops::Range; - use diagnostics::make_unclosed_delims_error; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; @@ -10,7 +8,7 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; use rustc_lexer::{ Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_whitespace, }; -use rustc_literal_escaper::{EscapeError, Mode, unescape_mixed, unescape_unicode}; +use rustc_literal_escaper::{EscapeError, Mode, check_for_errors}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, @@ -702,7 +700,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } err.emit() } - self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' ' + self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' ' } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { @@ -714,7 +712,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0763) .emit() } - self.cook_unicode(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' + self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { @@ -726,7 +724,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0765) .emit() } - self.cook_unicode(token::Str, Mode::Str, start, end, 1, 1) // " " + self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " " } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { @@ -738,7 +736,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0766) .emit() } - self.cook_unicode(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " + self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) + // b" " } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { @@ -750,13 +749,14 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0767) .emit() } - self.cook_mixed(token::CStr, Mode::CStr, start, end, 2, 1) // c" " + self.cook_quoted(token::CStr, Mode::CStr, start, end, 2, 1) // c" " } rustc_lexer::LiteralKind::RawStr { n_hashes } => { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::StrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "## + self.cook_quoted(kind, Mode::RawStr, start, end, 2 + n, 1 + n) + // r##" "## } else { self.report_raw_str_error(start, 1); } @@ -765,7 +765,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::ByteStrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "## + self.cook_quoted(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) + // br##" "## } else { self.report_raw_str_error(start, 2); } @@ -774,7 +775,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::CStrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "## + self.cook_quoted(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) + // cr##" "## } else { self.report_raw_str_error(start, 2); } @@ -1091,7 +1093,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { self.dcx().emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num }); } - fn cook_common( + fn cook_quoted( &self, mut kind: token::LitKind, mode: Mode, @@ -1099,32 +1101,28 @@ impl<'psess, 'src> Lexer<'psess, 'src> { end: BytePos, prefix_len: u32, postfix_len: u32, - unescape: fn(&str, Mode, &mut dyn FnMut(Range, Result<(), EscapeError>)), ) -> (token::LitKind, Symbol) { let content_start = start + BytePos(prefix_len); let content_end = end - BytePos(postfix_len); let lit_content = self.str_from_to(content_start, content_end); - unescape(lit_content, mode, &mut |range, result| { - // Here we only check for errors. The actual unescaping is done later. - if let Err(err) = result { - let span_with_quotes = self.mk_sp(start, end); - let (start, end) = (range.start as u32, range.end as u32); - let lo = content_start + BytePos(start); - let hi = lo + BytePos(end - start); - let span = self.mk_sp(lo, hi); - let is_fatal = err.is_fatal(); - if let Some(guar) = emit_unescape_error( - self.dcx(), - lit_content, - span_with_quotes, - span, - mode, - range, - err, - ) { - assert!(is_fatal); - kind = token::Err(guar); - } + check_for_errors(lit_content, mode, |range, err| { + let span_with_quotes = self.mk_sp(start, end); + let (start, end) = (range.start as u32, range.end as u32); + let lo = content_start + BytePos(start); + let hi = lo + BytePos(end - start); + let span = self.mk_sp(lo, hi); + let is_fatal = err.is_fatal(); + if let Some(guar) = emit_unescape_error( + self.dcx(), + lit_content, + span_with_quotes, + span, + mode, + range, + err, + ) { + assert!(is_fatal); + kind = token::Err(guar); } }); @@ -1137,34 +1135,6 @@ impl<'psess, 'src> Lexer<'psess, 'src> { }; (kind, sym) } - - fn cook_unicode( - &self, - kind: token::LitKind, - mode: Mode, - start: BytePos, - end: BytePos, - prefix_len: u32, - postfix_len: u32, - ) -> (token::LitKind, Symbol) { - self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape_unicode(src, mode, &mut |span, result| callback(span, result.map(drop))) - }) - } - - fn cook_mixed( - &self, - kind: token::LitKind, - mode: Mode, - start: BytePos, - end: BytePos, - prefix_len: u32, - postfix_len: u32, - ) -> (token::LitKind, Symbol) { - self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape_mixed(src, mode, &mut |span, result| callback(span, result.map(drop))) - }) - } } pub fn nfc_normalize(string: &str) -> Symbol { diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 52f23c00d4bc..0666ae294092 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 42bd0f5d847f..8e4da7923fcb 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -20,7 +20,6 @@ use std::ops::Range; pub use Alignment::*; pub use Count::*; pub use Position::*; -use rustc_literal_escaper::{Mode, unescape_unicode}; /// The type of format string that we are parsing. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -320,7 +319,7 @@ impl<'input> Parser<'input> { let without_quotes = &snippet[1..snippet.len() - 1]; let (mut ok, mut vec) = (true, vec![]); let mut chars = input.chars(); - unescape_unicode(without_quotes, Mode::Str, &mut |range, res| match res { + rustc_literal_escaper::unescape_str(without_quotes, |range, res| match res { Ok(ch) if ok && chars.next().is_some_and(|c| ch == c) => { vec.push((range, ch)); } diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index 4a7c0d78ede8..748fa944e286 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -15,7 +15,7 @@ test = false doctest = false [dependencies] -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" [features] rustc-dep-of-std = [] diff --git a/library/Cargo.lock b/library/Cargo.lock index 1bd97e7b5273..522a81325fb1 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -273,10 +273,11 @@ dependencies = [ [[package]] name = "rustc-literal-escaper" -version = "0.0.2" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04" +checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" dependencies = [ + "rustc-std-workspace-core", "rustc-std-workspace-std", ] diff --git a/library/Cargo.toml b/library/Cargo.toml index 35480b9319d7..2fbc0775c327 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -45,8 +45,7 @@ rustc-demangle.debug = 0 rustc-demangle.opt-level = "s" [patch.crates-io] -# See comments in `library/rustc-std-workspace-core/README.md` for what's going on -# here +# See comments in `library/rustc-std-workspace-core/README.md` for what's going on here rustc-std-workspace-core = { path = 'rustc-std-workspace-core' } rustc-std-workspace-alloc = { path = 'rustc-std-workspace-alloc' } rustc-std-workspace-std = { path = 'rustc-std-workspace-std' } diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index 1d79246356a3..8ea92088a84a 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -9,7 +9,7 @@ std = { path = "../std" } # `core` when resolving doc links. Without this line a different `core` will be # loaded from sysroot causing duplicate lang items and other similar errors. core = { path = "../core" } -rustc-literal-escaper = { version = "0.0.2", features = ["rustc-dep-of-std"] } +rustc-literal-escaper = { version = "0.0.4", features = ["rustc-dep-of-std"] } [features] default = ["rustc-dep-of-std"] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 32c306be94ec..652aa05d6f1f 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -55,7 +55,7 @@ use std::{error, fmt}; pub use diagnostic::{Diagnostic, Level, MultiSpan}; #[unstable(feature = "proc_macro_value", issue = "136652")] pub use rustc_literal_escaper::EscapeError; -use rustc_literal_escaper::{MixedUnit, Mode, byte_from_char, unescape_mixed, unescape_unicode}; +use rustc_literal_escaper::{MixedUnit, unescape_byte_str, unescape_c_str, unescape_str}; #[unstable(feature = "proc_macro_totokens", issue = "130977")] pub use to_tokens::ToTokens; @@ -1439,10 +1439,9 @@ impl Literal { // Force-inlining here is aggressive but the closure is // called on every char in the string, so it can be hot in // programs with many long strings containing escapes. - unescape_unicode( + unescape_str( symbol, - Mode::Str, - &mut #[inline(always)] + #[inline(always)] |_, c| match c { Ok(c) => buf.push(c), Err(err) => { @@ -1471,7 +1470,7 @@ impl Literal { let mut error = None; let mut buf = Vec::with_capacity(symbol.len()); - unescape_mixed(symbol, Mode::CStr, &mut |_span, c| match c { + unescape_c_str(symbol, |_span, c| match c { Ok(MixedUnit::Char(c)) => { buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) } @@ -1510,8 +1509,8 @@ impl Literal { let mut buf = Vec::with_capacity(symbol.len()); let mut error = None; - unescape_unicode(symbol, Mode::ByteStr, &mut |_, c| match c { - Ok(c) => buf.push(byte_from_char(c)), + unescape_byte_str(symbol, |_, res| match res { + Ok(b) => buf.push(b), Err(err) => { if err.is_fatal() { error = Some(ConversionErrorKind::FailedToUnescape(err)); diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 08592f2521f7..3b827cc5603e 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -2,6 +2,7 @@ use crate::utils::{ ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, expect_action, update_text_region_fn, }; use itertools::Itertools; +use rustc_lexer::{LiteralKind, TokenKind, tokenize}; use std::collections::HashSet; use std::fmt::Write; use std::ops::Range; @@ -342,7 +343,7 @@ fn parse_str_lit(s: &str) -> String { .and_then(|s| s.strip_suffix('"')) .unwrap_or_else(|| panic!("expected quoted string, found `{s}`")); let mut res = String::with_capacity(s.len()); - rustc_literal_escaper::unescape_unicode(s, mode, &mut |_, ch| { + rustc_literal_escaper::unescape_str(s, |range, ch| { if let Ok(ch) = ch { res.push(ch); } diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index f1ffda75ac0f..e914a2df2bad 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc-literal-escaper = "0.0.2" +rustc-literal-escaper = "0.0.4" serde_json = "1.0.57" tempfile = "3.1.0" walkdir = "2.3.1" diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 6bb18c2bced7..b33344ca5dda 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -4,7 +4,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use rustc_literal_escaper::{Mode, unescape_unicode}; +use rustc_literal_escaper::unescape_str; use walkdir::WalkDir; mod groups; @@ -218,7 +218,7 @@ impl<'a> LintExtractor<'a> { } else if let Some(text) = line.strip_prefix("#[doc = \"") { let escaped = text.strip_suffix("\"]").unwrap(); let mut buf = String::new(); - unescape_unicode(escaped, Mode::Str, &mut |_, c| match c { + unescape_str(escaped, |_, res| match res { Ok(c) => buf.push(c), Err(err) => { assert!(!err.is_fatal(), "failed to unescape string literal") From 332ae3b7e632eb23c39b9844f44e2f9e7409e622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 20 Jun 2025 15:49:18 +0200 Subject: [PATCH 264/356] Add codegen timing section --- compiler/rustc_errors/src/json.rs | 1 + compiler/rustc_errors/src/timings.rs | 47 +++++++++++++++++++++++-- compiler/rustc_interface/src/passes.rs | 3 ++ compiler/rustc_interface/src/queries.rs | 3 +- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index d67e2ba2d60e..a413f0243b3c 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -144,6 +144,7 @@ impl Emitter for JsonEmitter { }; let name = match record.section { TimingSection::Linking => "link", + TimingSection::Codegen => "codegen", }; let data = SectionTimestamp { name, event, timestamp: record.timestamp }; let result = self.emit(EmitTyped::SectionTiming(data)); diff --git a/compiler/rustc_errors/src/timings.rs b/compiler/rustc_errors/src/timings.rs index 27fc9df8d796..0d82f3e8db8b 100644 --- a/compiler/rustc_errors/src/timings.rs +++ b/compiler/rustc_errors/src/timings.rs @@ -1,10 +1,15 @@ use std::time::Instant; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sync::Lock; + use crate::DiagCtxtHandle; /// A high-level section of the compilation process. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum TimingSection { + /// Time spent doing codegen. + Codegen, /// Time spent linking. Linking, } @@ -36,23 +41,59 @@ pub struct TimingSectionHandler { /// Time when the compilation session started. /// If `None`, timing is disabled. origin: Option, + /// Sanity check to ensure that we open and close sections correctly. + opened_sections: Lock>, } impl TimingSectionHandler { pub fn new(enabled: bool) -> Self { let origin = if enabled { Some(Instant::now()) } else { None }; - Self { origin } + Self { origin, opened_sections: Lock::new(FxHashSet::default()) } } /// Returns a RAII guard that will immediately emit a start the provided section, and then emit /// its end when it is dropped. - pub fn start_section<'a>( + pub fn section_guard<'a>( &self, diag_ctxt: DiagCtxtHandle<'a>, section: TimingSection, ) -> TimingSectionGuard<'a> { + if self.is_enabled() && self.opened_sections.borrow().contains(§ion) { + diag_ctxt + .bug(format!("Section `{section:?}` was started again before it was finished")); + } + TimingSectionGuard::create(diag_ctxt, section, self.origin) } + + /// Start the provided section. + pub fn start_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) { + if let Some(origin) = self.origin { + let mut opened = self.opened_sections.borrow_mut(); + if !opened.insert(section) { + diag_ctxt + .bug(format!("Section `{section:?}` was started again before it was finished")); + } + + diag_ctxt.emit_timing_section_start(TimingRecord::from_origin(origin, section)); + } + } + + /// End the provided section. + pub fn end_section(&self, diag_ctxt: DiagCtxtHandle<'_>, section: TimingSection) { + if let Some(origin) = self.origin { + let mut opened = self.opened_sections.borrow_mut(); + if !opened.remove(§ion) { + diag_ctxt.bug(format!("Section `{section:?}` was ended before being started")); + } + + diag_ctxt.emit_timing_section_end(TimingRecord::from_origin(origin, section)); + } + } + + fn is_enabled(&self) -> bool { + self.origin.is_some() + } } /// RAII wrapper for starting and ending section timings. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 70ae9147fb1d..b18776c9f411 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -11,6 +11,7 @@ use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal}; use rustc_data_structures::{parallel, thousands}; +use rustc_errors::timings::TimingSection; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; @@ -1176,6 +1177,8 @@ pub(crate) fn start_codegen<'tcx>( codegen_backend: &dyn CodegenBackend, tcx: TyCtxt<'tcx>, ) -> (Box, EncodedMetadata) { + tcx.sess.timings.start_section(tcx.sess.dcx(), TimingSection::Codegen); + // Hook for tests. if let Some((def_id, _)) = tcx.entry_fn(()) && tcx.has_attr(def_id, sym::rustc_delayed_bug_from_inside_query) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 877440ec7d2c..2bc30fa7cb04 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -48,6 +48,7 @@ impl Linker { let (codegen_results, work_products) = sess.time("finish_ongoing_codegen", || { codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames) }); + sess.timings.end_section(sess.dcx(), TimingSection::Codegen); sess.dcx().abort_if_errors(); @@ -89,7 +90,7 @@ impl Linker { } let _timer = sess.prof.verbose_generic_activity("link_crate"); - let _timing = sess.timings.start_section(sess.dcx(), TimingSection::Linking); + let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking); codegen_backend.link(sess, codegen_results, self.metadata, &self.output_filenames) } } From 993344257d8d2ba2ea808c5f22f0648b5f3a7fdf Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 20 Jun 2025 14:44:20 +0000 Subject: [PATCH 265/356] Make `PartialEq` a `const_trait` --- library/core/src/cmp.rs | 25 ++- tests/ui/consts/const_cmp_type_id.rs | 5 +- tests/ui/consts/const_cmp_type_id.stderr | 26 +-- tests/ui/consts/fn_trait_refs.stderr | 18 +- .../ui/consts/issue-73976-monomorphic.stderr | 8 +- tests/ui/consts/issue-90870.rs | 15 +- tests/ui/consts/issue-90870.stderr | 58 ++++- .../call-const-trait-method-pass.rs | 3 +- .../call-const-trait-method-pass.stderr | 20 -- .../const-traits/call-generic-in-impl.rs | 3 +- .../const-traits/call-generic-in-impl.stderr | 30 --- .../const-traits/call-generic-method-chain.rs | 3 +- .../call-generic-method-chain.stderr | 66 ------ .../call-generic-method-dup-bound.rs | 3 +- .../call-generic-method-dup-bound.stderr | 74 ------- .../const-traits/call-generic-method-fail.rs | 2 +- .../call-generic-method-fail.stderr | 6 +- .../const-traits/call-generic-method-pass.rs | 3 +- .../call-generic-method-pass.stderr | 47 ---- .../const-traits/const-impl-trait.stderr | 202 +----------------- .../const_derives/derive-const-use.stderr | 58 +---- .../const_derives/derive-const-with-params.rs | 3 +- .../derive-const-with-params.stderr | 35 --- .../ice-112822-expected-type-for-param.rs | 1 - .../ice-112822-expected-type-for-param.stderr | 11 +- 25 files changed, 118 insertions(+), 607 deletions(-) delete mode 100644 tests/ui/traits/const-traits/call-const-trait-method-pass.stderr delete mode 100644 tests/ui/traits/const-traits/call-generic-in-impl.stderr delete mode 100644 tests/ui/traits/const-traits/call-generic-method-chain.stderr delete mode 100644 tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr delete mode 100644 tests/ui/traits/const-traits/call-generic-method-pass.stderr delete mode 100644 tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 5cb1a1484770..0aa8f47462db 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -247,6 +247,8 @@ use crate::ops::ControlFlow; append_const_msg )] #[rustc_diagnostic_item = "PartialEq"] +#[const_trait] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] pub trait PartialEq: PointeeSized { /// Tests for `self` and `other` values to be equal, and is used by `==`. #[must_use] @@ -1811,7 +1813,8 @@ mod impls { macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl const PartialEq for $t { #[inline] fn eq(&self, other: &Self) -> bool { *self == *other } #[inline] @@ -2018,9 +2021,10 @@ mod impls { // & pointers #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq<&B> for &A + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl const PartialEq<&B> for &A where - A: PartialEq, + A: ~const PartialEq, { #[inline] fn eq(&self, other: &&B) -> bool { @@ -2089,9 +2093,10 @@ mod impls { // &mut pointers #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq<&mut B> for &mut A + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl const PartialEq<&mut B> for &mut A where - A: PartialEq, + A: ~const PartialEq, { #[inline] fn eq(&self, other: &&mut B) -> bool { @@ -2158,9 +2163,10 @@ mod impls { impl Eq for &mut A where A: Eq {} #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq<&mut B> for &A + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl const PartialEq<&mut B> for &A where - A: PartialEq, + A: ~const PartialEq, { #[inline] fn eq(&self, other: &&mut B) -> bool { @@ -2173,9 +2179,10 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq<&B> for &mut A + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl const PartialEq<&B> for &mut A where - A: PartialEq, + A: ~const PartialEq, { #[inline] fn eq(&self, other: &&B) -> bool { diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index e89b8d377878..dca0615083a7 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -6,11 +6,10 @@ use std::any::TypeId; fn main() { const { assert!(TypeId::of::() == TypeId::of::()); - //~^ ERROR cannot call non-const operator in constants + //~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied assert!(TypeId::of::<()>() != TypeId::of::()); - //~^ ERROR cannot call non-const operator in constants + //~^ ERROR the trait bound `TypeId: const PartialEq` is not satisfied let _a = TypeId::of::() < TypeId::of::(); - //~^ ERROR cannot call non-const operator in constants // can't assert `_a` because it is not deterministic // FIXME(const_trait_impl) make it pass } diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index 62f8d42c0e68..a8242a200eff 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -1,33 +1,15 @@ -error[E0015]: cannot call non-const operator in constants +error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied --> $DIR/const_cmp_type_id.rs:8:17 | LL | assert!(TypeId::of::() == TypeId::of::()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0015]: cannot call non-const operator in constants +error[E0277]: the trait bound `TypeId: const PartialEq` is not satisfied --> $DIR/const_cmp_type_id.rs:10:17 | LL | assert!(TypeId::of::<()>() != TypeId::of::()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0015]: cannot call non-const operator in constants - --> $DIR/const_cmp_type_id.rs:12:18 - | -LL | let _a = TypeId::of::() < TypeId::of::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants +error: aborting due to 2 previous errors -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index d688bfbde2bc..7dc080498896 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -4,12 +4,6 @@ error[E0635]: unknown feature `const_fn_trait_ref_impls` LL | #![feature(const_fn_trait_ref_impls)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0635]: unknown feature `const_cmp` - --> $DIR/fn_trait_refs.rs:7:12 - | -LL | #![feature(const_cmp)] - | ^^^^^^^^^ - error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:14:8 | @@ -155,21 +149,17 @@ note: `FnMut` can't be used with `~const` because it isn't annotated with `#[con --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0015]: cannot call non-const operator in constants +error[E0277]: the trait bound `(i32, i32, i32): const PartialEq` is not satisfied --> $DIR/fn_trait_refs.rs:71:17 | LL | assert!(test_one == (1, 1, 1)); | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0015]: cannot call non-const operator in constants +error[E0277]: the trait bound `(i32, i32): const PartialEq` is not satisfied --> $DIR/fn_trait_refs.rs:74:17 | LL | assert!(test_two == (2, 2)); | ^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const closure in constant functions --> $DIR/fn_trait_refs.rs:16:5 @@ -195,7 +185,7 @@ LL | f() | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 22 previous errors +error: aborting due to 21 previous errors -Some errors have detailed explanations: E0015, E0635. +Some errors have detailed explanations: E0015, E0277, E0635. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-73976-monomorphic.stderr b/tests/ui/consts/issue-73976-monomorphic.stderr index ef754b23ff06..e5b32e0c4adf 100644 --- a/tests/ui/consts/issue-73976-monomorphic.stderr +++ b/tests/ui/consts/issue-73976-monomorphic.stderr @@ -1,13 +1,9 @@ -error[E0015]: cannot call non-const operator in constant functions +error[E0277]: the trait bound `TypeId: ~const PartialEq` is not satisfied --> $DIR/issue-73976-monomorphic.rs:21:5 | LL | GetTypeId::::VALUE == GetTypeId::::VALUE | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs index b62769a33f8e..f807ae75ee5e 100644 --- a/tests/ui/consts/issue-90870.rs +++ b/tests/ui/consts/issue-90870.rs @@ -3,22 +3,31 @@ #![allow(dead_code)] const fn f(a: &u8, b: &u8) -> bool { + //~^ HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable + //~| HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable + //~| HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable a == b - //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~^ ERROR: cannot call conditionally-const operator in constant functions + //~| ERROR: `PartialEq` is not yet stable as a const trait //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable } const fn g(a: &&&&i64, b: &&&&i64) -> bool { a == b - //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~^ ERROR: cannot call conditionally-const operator in constant functions + //~| ERROR: `PartialEq` is not yet stable as a const trait //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable } const fn h(mut a: &[u8], mut b: &[u8]) -> bool { while let ([l, at @ ..], [r, bt @ ..]) = (a, b) { if l == r { - //~^ ERROR: cannot call non-const operator in constant functions [E0015] + //~^ ERROR: cannot call conditionally-const operator in constant functions + //~| ERROR: `PartialEq` is not yet stable as a const trait //~| HELP: consider dereferencing here + //~| HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable a = at; b = bt; } else { diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr index ea987920d7d3..8d6f21fd82fb 100644 --- a/tests/ui/consts/issue-90870.stderr +++ b/tests/ui/consts/issue-90870.stderr @@ -1,39 +1,81 @@ -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-90870.rs:6:5 +error[E0658]: cannot call conditionally-const operator in constant functions + --> $DIR/issue-90870.rs:9:5 | LL | a == b | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = 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 help: consider dereferencing here | LL | *a == *b | + + -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-90870.rs:12:5 +error: `PartialEq` is not yet stable as a const trait + --> $DIR/issue-90870.rs:9:5 + | +LL | a == b + | ^^^^^^ + | +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | + +error[E0658]: cannot call conditionally-const operator in constant functions + --> $DIR/issue-90870.rs:17:5 | LL | a == b | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = 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 help: consider dereferencing here | LL | ****a == ****b | ++++ ++++ -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-90870.rs:19:12 +error: `PartialEq` is not yet stable as a const trait + --> $DIR/issue-90870.rs:17:5 + | +LL | a == b + | ^^^^^^ + | +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | + +error[E0658]: cannot call conditionally-const operator in constant functions + --> $DIR/issue-90870.rs:26:12 | LL | if l == r { | ^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = 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 help: consider dereferencing here | LL | if *l == *r { | + + -error: aborting due to 3 previous errors +error: `PartialEq` is not yet stable as a const trait + --> $DIR/issue-90870.rs:26:12 + | +LL | if l == r { + | ^^^^^^ + | +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/call-const-trait-method-pass.rs b/tests/ui/traits/const-traits/call-const-trait-method-pass.rs index 3004647ede07..d66a11490c59 100644 --- a/tests/ui/traits/const-traits/call-const-trait-method-pass.rs +++ b/tests/ui/traits/const-traits/call-const-trait-method-pass.rs @@ -1,6 +1,5 @@ -//@ known-bug: #110395 - #![feature(const_trait_impl, const_ops)] +//@ check-pass struct Int(i32); diff --git a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr deleted file mode 100644 index 7746f103ac36..000000000000 --- a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/call-const-trait-method-pass.rs:15:12 - | -LL | impl const PartialEq for Int { - | ^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error[E0015]: cannot call non-const method `::eq` in constant functions - --> $DIR/call-const-trait-method-pass.rs:20:15 - | -LL | !self.eq(other) - | ^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -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/call-generic-in-impl.rs b/tests/ui/traits/const-traits/call-generic-in-impl.rs index 6149dc3d1263..b63458b39e95 100644 --- a/tests/ui/traits/const-traits/call-generic-in-impl.rs +++ b/tests/ui/traits/const-traits/call-generic-in-impl.rs @@ -1,5 +1,4 @@ -//@ known-bug: #110395 -// FIXME(const_trait_impl) check-pass +//@ check-pass #![feature(const_trait_impl)] #[const_trait] diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr deleted file mode 100644 index a45dfd95b4a4..000000000000 --- a/tests/ui/traits/const-traits/call-generic-in-impl.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-in-impl.rs:10:9 - | -LL | impl const MyPartialEq for T { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-in-impl.rs:10:9 - | -LL | impl const MyPartialEq for T { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const method `::eq` in constant functions - --> $DIR/call-generic-in-impl.rs:12:9 - | -LL | PartialEq::eq(self, other) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.rs b/tests/ui/traits/const-traits/call-generic-method-chain.rs index 74beab71208a..b515c0e711da 100644 --- a/tests/ui/traits/const-traits/call-generic-method-chain.rs +++ b/tests/ui/traits/const-traits/call-generic-method-chain.rs @@ -1,8 +1,7 @@ //! Basic test for calling methods on generic type parameters in `const fn`. -//@ known-bug: #110395 //@ compile-flags: -Znext-solver -// FIXME(const_trait_impl) check-pass +//@ check-pass #![feature(const_trait_impl)] diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr deleted file mode 100644 index 40b4f14733f0..000000000000 --- a/tests/ui/traits/const-traits/call-generic-method-chain.stderr +++ /dev/null @@ -1,66 +0,0 @@ -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/call-generic-method-chain.rs:11:12 - | -LL | impl const PartialEq for S { - | ^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:20:25 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:20:25 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:24:33 - | -LL | const fn equals_self_wrapper(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-chain.rs:24:33 - | -LL | const fn equals_self_wrapper(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/call-generic-method-chain.rs:21:5 - | -LL | *t == *t - | ^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const method `::eq` in constant functions - --> $DIR/call-generic-method-chain.rs:16:15 - | -LL | !self.eq(other) - | ^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs index ec615d8484cd..fdc439845ace 100644 --- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs +++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Znext-solver -//@ known-bug: #110395 -// FIXME(const_trait_impl) check-pass +//@ check-pass #![feature(const_trait_impl)] diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr deleted file mode 100644 index c74f5cf786c1..000000000000 --- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr +++ /dev/null @@ -1,74 +0,0 @@ -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/call-generic-method-dup-bound.rs:9:12 - | -LL | impl const PartialEq for S { - | ^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:20:37 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:20:37 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:27:30 - | -LL | const fn equals_self2(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-dup-bound.rs:27:30 - | -LL | const fn equals_self2(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/call-generic-method-dup-bound.rs:21:5 - | -LL | *t == *t - | ^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const method `::eq` in constant functions - --> $DIR/call-generic-method-dup-bound.rs:14:15 - | -LL | !self.eq(other) - | ^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/call-generic-method-dup-bound.rs:28:5 - | -LL | *t == *t - | ^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 8 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.rs b/tests/ui/traits/const-traits/call-generic-method-fail.rs index 66881334a298..3ab5cc58ce3c 100644 --- a/tests/ui/traits/const-traits/call-generic-method-fail.rs +++ b/tests/ui/traits/const-traits/call-generic-method-fail.rs @@ -3,7 +3,7 @@ pub const fn equals_self(t: &T) -> bool { *t == *t - //~^ ERROR cannot call non-const operator in constant functions + //~^ ERROR the trait bound `T: ~const PartialEq` is not satisfied } fn main() {} diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.stderr b/tests/ui/traits/const-traits/call-generic-method-fail.stderr index 6bacb986fef0..9facf80ee876 100644 --- a/tests/ui/traits/const-traits/call-generic-method-fail.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-fail.stderr @@ -1,11 +1,9 @@ -error[E0015]: cannot call non-const operator in constant functions +error[E0277]: the trait bound `T: ~const PartialEq` is not satisfied --> $DIR/call-generic-method-fail.rs:5:5 | LL | *t == *t | ^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.rs b/tests/ui/traits/const-traits/call-generic-method-pass.rs index af793b8da031..bc671c897f07 100644 --- a/tests/ui/traits/const-traits/call-generic-method-pass.rs +++ b/tests/ui/traits/const-traits/call-generic-method-pass.rs @@ -1,8 +1,7 @@ //! Basic test for calling methods on generic type parameters in `const fn`. //@ compile-flags: -Znext-solver -//@ known-bug: #110395 -// FIXME(const_trait_impl) check-pass +//@ check-pass #![feature(const_trait_impl)] diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr deleted file mode 100644 index 1a33ff5ab450..000000000000 --- a/tests/ui/traits/const-traits/call-generic-method-pass.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/call-generic-method-pass.rs:11:12 - | -LL | impl const PartialEq for S { - | ^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-pass.rs:20:25 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/call-generic-method-pass.rs:20:25 - | -LL | const fn equals_self(t: &T) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/call-generic-method-pass.rs:21:5 - | -LL | *t == *t - | ^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const method `::eq` in constant functions - --> $DIR/call-generic-method-pass.rs:16:15 - | -LL | !self.eq(other) - | ^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const-impl-trait.stderr b/tests/ui/traits/const-traits/const-impl-trait.stderr index 6783cec3960d..ee922f9689ed 100644 --- a/tests/ui/traits/const-traits/const-impl-trait.stderr +++ b/tests/ui/traits/const-traits/const-impl-trait.stderr @@ -1,197 +1,17 @@ -error[E0635]: unknown feature `const_cmp` - --> $DIR/const-impl-trait.rs:7:30 +error[E0277]: the trait bound `(): const PartialEq` is not satisfied + --> $DIR/const-impl-trait.rs:34:17 | -LL | #![feature(const_trait_impl, const_cmp, const_destruct)] - | ^^^^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits +LL | assert!(cmp(&())); + | --- ^^^ + | | + | required by a bound introduced by this call + | +note: required by a bound in `cmp` --> $DIR/const-impl-trait.rs:11:23 | LL | const fn cmp(a: &impl ~const PartialEq) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL + | ^^^^^^^^^^^^^^^^ required by this bound in `cmp` -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:11:23 - | -LL | const fn cmp(a: &impl ~const PartialEq) -> bool { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: aborting due to 1 previous error -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:16:13 - | -LL | x: impl ~const PartialEq + ~const Destruct, - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:16:13 - | -LL | x: impl ~const PartialEq + ~const Destruct, - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:17:11 - | -LL | ) -> impl ~const PartialEq + ~const Destruct { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:17:11 - | -LL | ) -> impl ~const PartialEq + ~const Destruct { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:23:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:27:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:17:11 - | -LL | ) -> impl ~const PartialEq + ~const Destruct { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:27:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:27:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:23:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:23:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:23:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:23:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:23:22 - | -LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; - | ^^^^^^ can't be applied to `PartialEq` - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const operator in constants - --> $DIR/const-impl-trait.rs:35:13 - | -LL | assert!(wrap(123) == wrap(123)); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constants - --> $DIR/const-impl-trait.rs:36:13 - | -LL | assert!(wrap(123) != wrap(456)); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constants - --> $DIR/const-impl-trait.rs:38:13 - | -LL | assert!(x == x); - | ^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/const-impl-trait.rs:12:5 - | -LL | a == a - | ^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 21 previous errors - -Some errors have detailed explanations: E0015, E0635. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr index 8297911a3f3c..87ac78908bba 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr @@ -1,9 +1,3 @@ -error[E0635]: unknown feature `const_cmp` - --> $DIR/derive-const-use.rs:3:30 - | -LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const)] - | ^^^^^^^^^ - error[E0635]: unknown feature `const_default_impls` --> $DIR/derive-const-use.rs:3:41 | @@ -28,23 +22,13 @@ LL | #[derive_const(Default, PartialEq)] = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/derive-const-use.rs:11:12 - | -LL | impl const PartialEq for A { - | ^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/derive-const-use.rs:15:25 +error[E0277]: the trait bound `(): ~const PartialEq` is not satisfied + --> $DIR/derive-const-use.rs:16:14 | LL | #[derive_const(Default, PartialEq)] - | ^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change + | --------- in this derive macro expansion +LL | pub struct S((), A); + | ^^ error[E0015]: cannot call non-const associated function `::default` in constants --> $DIR/derive-const-use.rs:18:35 @@ -54,14 +38,6 @@ LL | const _: () = assert!(S((), A) == S::default()); | = note: calls in constants are limited to constant functions, tuple structs and tuple variants -error[E0015]: cannot call non-const operator in constants - --> $DIR/derive-const-use.rs:18:23 - | -LL | const _: () = assert!(S((), A) == S::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - error[E0015]: cannot call non-const associated function `<() as Default>::default` in constant functions --> $DIR/derive-const-use.rs:16:14 | @@ -82,27 +58,7 @@ LL | pub struct S((), A); | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/derive-const-use.rs:16:14 - | -LL | #[derive_const(Default, PartialEq)] - | --------- in this derive macro expansion -LL | pub struct S((), A); - | ^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error: aborting due to 7 previous errors -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/derive-const-use.rs:16:18 - | -LL | #[derive_const(Default, PartialEq)] - | --------- in this derive macro expansion -LL | pub struct S((), A); - | ^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 12 previous errors - -Some errors have detailed explanations: E0015, E0635. +Some errors have detailed explanations: E0015, E0277, E0635. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs index 18b224af2780..b39f97b59382 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs +++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs @@ -1,5 +1,4 @@ -//@ known-bug: #110395 -// FIXME(const_trait_impl) check-pass +//@ check-pass #![feature(derive_const)] #![feature(const_trait_impl)] diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr deleted file mode 100644 index d1dbf62d5666..000000000000 --- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]` - --> $DIR/derive-const-with-params.rs:7:16 - | -LL | #[derive_const(PartialEq)] - | ^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: `~const` can only be applied to `#[const_trait]` traits - | -note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/cmp.rs:LL:COL - -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/derive-const-with-params.rs:8:23 - | -LL | #[derive_const(PartialEq)] - | --------- in this derive macro expansion -LL | pub struct Reverse(T); - | ^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/derive-const-with-params.rs:11:5 - | -LL | a == b - | ^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs index 4cb013b93230..4312d295b113 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs @@ -11,7 +11,6 @@ const fn test() -> impl ~const Fn() { [first, remainder @ ..] => { assert_eq!(first, &b'f'); //~^ ERROR cannot call non-const function - //~| ERROR cannot call non-const operator } [] => panic!(), } diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr index 8d9371bf9f69..f06bacdeb4e2 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr @@ -37,15 +37,6 @@ note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_ --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/ice-112822-expected-type-for-param.rs:12:17 - | -LL | assert_eq!(first, &b'f'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0015]: cannot call non-const function `core::panicking::assert_failed::<&u8, &u8>` in constant functions --> $DIR/ice-112822-expected-type-for-param.rs:12:17 | @@ -55,7 +46,7 @@ LL | assert_eq!(first, &b'f'); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0015, E0658. For more information about an error, try `rustc --explain E0015`. From 9dd7bcb75ac9e513268eb3b20ec10212c777e4c7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 23 Jun 2025 11:33:23 +0200 Subject: [PATCH 266/356] notify me when rdg is touched --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 4d13eaf1c84c..6385528e7b6e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1168,7 +1168,7 @@ cc = ["@ehuss"] [mentions."src/doc/rustc-dev-guide"] message = "The rustc-dev-guide subtree was changed. If this PR *only* touches the dev guide consider submitting a PR directly to [rust-lang/rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide/pulls) otherwise thank you for updating the dev guide with your changes." -cc = ["@BoxyUwU", "@jieyouxu", "@kobzol"] +cc = ["@BoxyUwU", "@jieyouxu", "@kobzol", "@tshepang"] [mentions."compiler/rustc_codegen_ssa/src/codegen_attrs.rs"] cc = ["@jdonszelmann"] From 9f5fc01b8b50348091ba3143a4db7dd3e116eda2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Jun 2025 10:08:13 +0000 Subject: [PATCH 267/356] Rustup to rustc 1.89.0-nightly (be19eda0d 2025-06-22) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index f09a2628777d..a379f9c7e486 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-06-19" +channel = "nightly-2025-06-23" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 2313d4c5718957fd1ce7ae41edee253ca8975663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 22 Jun 2025 22:45:28 +0200 Subject: [PATCH 268/356] test for lint on root node crash --- tests/ui/attributes/lint_on_root.rs | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/ui/attributes/lint_on_root.rs diff --git a/tests/ui/attributes/lint_on_root.rs b/tests/ui/attributes/lint_on_root.rs new file mode 100644 index 000000000000..0ede97c033c7 --- /dev/null +++ b/tests/ui/attributes/lint_on_root.rs @@ -0,0 +1,3 @@ +#![inline = ""] + +fn main() {} From 269b67d6b8529850233b60817773b75c54206962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 22 Jun 2025 22:49:22 +0200 Subject: [PATCH 269/356] fix 142891 --- compiler/rustc_middle/src/hir/map.rs | 10 +++++++++- tests/ui/attributes/lint_on_root.rs | 4 ++++ tests/ui/attributes/lint_on_root.stderr | 12 ++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/ui/attributes/lint_on_root.stderr diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 03bb97095a4b..291707878a34 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1254,10 +1254,18 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems { body_owners, opaques, nested_bodies, - delayed_lint_items, + mut delayed_lint_items, .. } = collector; + // The crate could have delayed lints too, but would not be picked up by the visitor. + // The `delayed_lint_items` list is smart - it only contains items which we know from + // earlier passes is guaranteed to contain lints. It's a little harder to determine that + // for sure here, so we simply always add the crate to the list. If it has no lints, + // we'll discover that later. The cost of this should be low, there's only one crate + // after all compared to the many items we have we wouldn't want to iterate over later. + delayed_lint_items.push(CRATE_OWNER_ID); + ModuleItems { add_root: true, submodules: submodules.into_boxed_slice(), diff --git a/tests/ui/attributes/lint_on_root.rs b/tests/ui/attributes/lint_on_root.rs index 0ede97c033c7..93d47bf0d714 100644 --- a/tests/ui/attributes/lint_on_root.rs +++ b/tests/ui/attributes/lint_on_root.rs @@ -1,3 +1,7 @@ +// NOTE: this used to panic in debug builds (by a sanity assertion) +// and not emit any lint on release builds. See https://github.com/rust-lang/rust/issues/142891. #![inline = ""] +//~^ ERROR valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() {} diff --git a/tests/ui/attributes/lint_on_root.stderr b/tests/ui/attributes/lint_on_root.stderr new file mode 100644 index 000000000000..aaa46e6f54ba --- /dev/null +++ b/tests/ui/attributes/lint_on_root.stderr @@ -0,0 +1,12 @@ +error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` + --> $DIR/lint_on_root.rs:3:1 + | +LL | #![inline = ""] + | ^^^^^^^^^^^^^^^ + | + = 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 #57571 + = note: `#[deny(ill_formed_attribute_input)]` on by default + +error: aborting due to 1 previous error + From 82cbc3a35e23a804682922d1c04ac51a00b35137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 13 Jun 2025 01:36:52 +0200 Subject: [PATCH 270/356] rewrite #[naked] parser --- .../src/attributes.rs | 3 +++ .../src/attributes/codegen_attrs.rs | 19 ++++++++++++++++++- compiler/rustc_attr_parsing/src/context.rs | 3 ++- .../rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 3 ++- compiler/rustc_hir_typeck/src/expr.rs | 3 ++- compiler/rustc_hir_typeck/src/lib.rs | 5 +++-- .../rustc_hir_typeck/src/naked_functions.rs | 5 +++-- compiler/rustc_passes/src/check_attr.rs | 14 ++++++++------ compiler/rustc_passes/src/liveness.rs | 3 ++- 10 files changed, 44 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index c7487847e6f2..63db0d0c9882 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -244,6 +244,9 @@ pub enum AttributeKind { reason: Option, }, + /// Represents #[naked] + Naked(Span), + /// Represents `#[no_mangle]` NoMangle(Span), diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index ba4e2935004c..cf31dd0ace79 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -51,12 +51,29 @@ impl SingleAttributeParser for ColdParser { if !args.no_args() { cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); return None; - }; + } Some(AttributeKind::Cold(cx.attr_span)) } } +pub(crate) struct NakedParser; + +impl SingleAttributeParser for NakedParser { + const PATH: &[rustc_span::Symbol] = &[sym::naked]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if !args.no_args() { + cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + return None; + } + Some(AttributeKind::Naked(cx.attr_span)) + } +} + pub(crate) struct NoMangleParser; impl SingleAttributeParser for NoMangleParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 171995dc9cbd..bf289c6aae80 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,7 +15,7 @@ use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; -use crate::attributes::codegen_attrs::{ColdParser, NoMangleParser, OptimizeParser}; +use crate::attributes::codegen_attrs::{ColdParser, NakedParser, NoMangleParser, OptimizeParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -114,6 +114,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index b006fdbb6586..fbcfcaa706ca 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -121,6 +121,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .max(); } AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, + AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::NoMangle(attr_span) => { if tcx.opt_item_name(did.to_def_id()).is_some() { @@ -165,7 +166,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::rustc_allocator_zeroed => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } - sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, sym::rustc_std_internal_symbol => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 752cc2eff973..3a2dfa8e9857 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -4,6 +4,7 @@ use std::ops::ControlFlow; use rustc_abi::FieldIdx; use rustc_attr_data_structures::AttributeKind; use rustc_attr_data_structures::ReprAttr::ReprPacked; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{EmissionGuarantee, MultiSpan}; @@ -104,7 +105,7 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) { if fn_sig.abi == ExternAbi::Custom { // Function definitions that use `extern "custom"` must be naked functions. - if !tcx.has_attr(def_id, sym::naked) { + if !find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Naked(_)) { tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction { span: fn_sig_span, naked_span: tcx.def_span(def_id).shrink_to_lo(), diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index bd3ca8317eb4..672f3bc67cef 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -7,6 +7,7 @@ use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_ast::util::parser::ExprPrecedence; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; @@ -3779,7 +3780,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) -> Ty<'tcx> { if let rustc_ast::AsmMacro::NakedAsm = asm.asm_macro { - if !self.tcx.has_attr(self.body_id, sym::naked) { + if !find_attr!(self.tcx.get_all_attrs(self.body_id), AttributeKind::Naked(..)) { self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span }); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 043a687914b7..1cc618e2aeec 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -42,6 +42,7 @@ mod writeback; pub use coercion::can_coerce; use fn_ctxt::FnCtxt; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; @@ -55,8 +56,8 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config; +use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, sym}; use tracing::{debug, instrument}; use typeck_root_ctxt::TypeckRootCtxt; @@ -173,7 +174,7 @@ fn typeck_with_inspect<'tcx>( .map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)), ); - if tcx.has_attr(def_id, sym::naked) { + if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Naked(..)) { naked_functions::typeck_naked_fn(tcx, def_id, body); } diff --git a/compiler/rustc_hir_typeck/src/naked_functions.rs b/compiler/rustc_hir_typeck/src/naked_functions.rs index 2518d6478e65..d055fa68fc34 100644 --- a/compiler/rustc_hir_typeck/src/naked_functions.rs +++ b/compiler/rustc_hir_typeck/src/naked_functions.rs @@ -1,12 +1,13 @@ //! Checks validity of naked functions. +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirIdSet, StmtKind}; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; -use rustc_span::{Span, sym}; +use rustc_span::Span; use crate::errors::{ NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed, @@ -20,7 +21,7 @@ pub(crate) fn typeck_naked_fn<'tcx>( def_id: LocalDefId, body: &'tcx hir::Body<'tcx>, ) { - debug_assert!(tcx.has_attr(def_id, sym::naked)); + debug_assert!(find_attr!(tcx.get_all_attrs(def_id), AttributeKind::Naked(..))); check_no_patterns(tcx, body.params); check_no_parameters_use(tcx, body); check_asm(tcx, def_id, body); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ad1a2a042737..1990b46adbb7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -160,6 +160,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => { self.check_align(span, target, *align, *repr_span) } + Attribute::Parsed(AttributeKind::Naked(attr_span)) => { + self.check_naked(hir_id, *attr_span, span, target, attrs) + } Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -217,7 +220,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_std_internal_symbol, ..] => { self.check_rustc_std_internal_symbol(attr, span, target) } - [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), [sym::rustc_no_implicit_autorefs, ..] => { self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target) } @@ -623,7 +625,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_naked( &self, hir_id: HirId, - attr: &Attribute, + attr_span: Span, span: Span, target: Target, attrs: &[Attribute], @@ -659,7 +661,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::link_section, sym::linkage, sym::no_mangle, - sym::naked, sym::instruction_set, sym::repr, sym::align, @@ -703,13 +704,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::NoMangle(..) | AttributeKind::Cold(..) | AttributeKind::MustUse { .. }, + | AttributeKind::Naked(..), ) => { continue; } Attribute::Parsed(AttributeKind::Inline(.., span)) => { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: *span, - naked_span: attr.span(), + naked_span: attr_span, attr: sym::inline.to_string(), }); @@ -746,7 +748,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: other_attr.span(), - naked_span: attr.span(), + naked_span: attr_span, attr: other_attr_name, }); @@ -756,7 +758,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span(), + attr_span, defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 763d9fda8049..125730377ef8 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -85,6 +85,7 @@ use std::io; use std::io::prelude::*; use std::rc::Rc; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def::*; @@ -145,7 +146,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) { } // Don't run unused pass for #[naked] - if tcx.has_attr(def_id.to_def_id(), sym::naked) { + if find_attr!(tcx.get_all_attrs(def_id.to_def_id()), AttributeKind::Naked(..)) { return; } From 73bcf4c117681b95fe591e1d468ac0bf84b8d792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 19 Jun 2025 08:26:18 +0200 Subject: [PATCH 271/356] make warnings methods on cx so it's easier to emit them elsewhere too --- .../rustc_attr_parsing/src/attributes/mod.rs | 10 ++----- compiler/rustc_attr_parsing/src/context.rs | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 3162c1fc7279..bfdd61384e5c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -189,14 +189,8 @@ impl OnDuplicate { unused: Span, ) { match self { - OnDuplicate::Warn => cx.emit_lint( - AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: false }, - unused, - ), - OnDuplicate::WarnButFutureError => cx.emit_lint( - AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: true }, - unused, - ), + OnDuplicate::Warn => cx.warn_unused_duplicate(used, unused), + OnDuplicate::WarnButFutureError => cx.warn_unused_duplicate_future_error(used, unused), OnDuplicate::Error => { cx.emit_err(UnusedMultiple { this: used, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index bf289c6aae80..570151eae9d5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -201,6 +201,32 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { (self.emit_lint)(AttributeLint { id, span, kind: lint }); } + pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) { + self.emit_lint( + AttributeLintKind::UnusedDuplicate { + this: unused_span, + other: used_span, + warning: false, + }, + unused_span, + ) + } + + pub(crate) fn warn_unused_duplicate_future_error( + &mut self, + used_span: Span, + unused_span: Span, + ) { + self.emit_lint( + AttributeLintKind::UnusedDuplicate { + this: unused_span, + other: used_span, + warning: true, + }, + unused_span, + ) + } + pub(crate) fn unknown_key( &self, span: Span, From 5c0a6252058e01fc17527039333c70f17290b5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 13 Jun 2025 02:28:33 +0200 Subject: [PATCH 272/356] move naked checks out of check_attr.rs --- .../src/attributes.rs | 2 +- compiler/rustc_attr_parsing/messages.ftl | 4 + .../src/attributes/codegen_attrs.rs | 120 +++++++++++++++-- .../src/attributes/inline.rs | 6 +- .../rustc_attr_parsing/src/attributes/mod.rs | 1 - compiler/rustc_attr_parsing/src/context.rs | 71 +++++++--- compiler/rustc_attr_parsing/src/parser.rs | 8 ++ .../src/session_diagnostics.rs | 11 ++ .../rustc_hir_analysis/src/check/check.rs | 1 - compiler/rustc_passes/messages.ftl | 5 - compiler/rustc_passes/src/check_attr.rs | 121 +----------------- compiler/rustc_passes/src/errors.rs | 11 -- tests/ui/asm/naked-functions-inline.stderr | 14 +- tests/ui/asm/naked-invalid-attr.stderr | 18 +-- ...gate-naked_functions_target_feature.stderr | 4 +- .../error-with-naked.stderr | 8 +- 16 files changed, 211 insertions(+), 194 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 63db0d0c9882..9227b81f12fa 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -244,7 +244,7 @@ pub enum AttributeKind { reason: Option, }, - /// Represents #[naked] + /// Represents `#[naked]` Naked(Span), /// Represents `#[no_mangle]` diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 0891afc003e1..2bb27ede8605 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -89,6 +89,10 @@ attr_parsing_missing_since = attr_parsing_multiple_stability_levels = multiple stability levels +attr_parsing_naked_functions_incompatible_attribute = + attribute incompatible with `#[unsafe(naked)]` + .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]` + .naked_attribute = function marked with `#[unsafe(naked)]` here attr_parsing_non_ident_feature = 'feature' is not an identifier diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index cf31dd0ace79..24c40c301fe0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,10 +1,12 @@ use rustc_attr_data_structures::{AttributeKind, OptimizeAttr}; use rustc_feature::{AttributeTemplate, template}; -use rustc_span::sym; +use rustc_session::parse::feature_err; +use rustc_span::{Span, sym}; -use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; +use crate::session_diagnostics::NakedFunctionIncompatibleAttribute; pub(crate) struct OptimizeParser; @@ -57,20 +59,110 @@ impl SingleAttributeParser for ColdParser { } } -pub(crate) struct NakedParser; +#[derive(Default)] +pub(crate) struct NakedParser { + span: Option, +} -impl SingleAttributeParser for NakedParser { - const PATH: &[rustc_span::Symbol] = &[sym::naked]; - const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const TEMPLATE: AttributeTemplate = template!(Word); +impl AttributeParser for NakedParser { + const ATTRIBUTES: AcceptMapping = + &[(&[sym::naked], template!(Word), |this, cx, args| { + if !args.no_args() { + cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); + return; + } - fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { - if !args.no_args() { - cx.expected_no_args(args.span().unwrap_or(cx.attr_span)); - return None; + if let Some(earlier) = this.span { + let span = cx.attr_span; + cx.warn_unused_duplicate(earlier, span); + } else { + this.span = Some(cx.attr_span); + } + })]; + + fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option { + // FIXME(jdonszelmann): upgrade this list to *parsed* attributes + // once all of these have parsed forms. That'd make the check much nicer... + // + // many attributes don't make sense in combination with #[naked]. + // Notable attributes that are incompatible with `#[naked]` are: + // + // * `#[inline]` + // * `#[track_caller]` + // * `#[test]`, `#[ignore]`, `#[should_panic]` + // + // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains + // accurate. + const ALLOW_LIST: &[rustc_span::Symbol] = &[ + // conditional compilation + sym::cfg_trace, + sym::cfg_attr_trace, + // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`) + sym::test, + sym::ignore, + sym::should_panic, + sym::bench, + // diagnostics + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::deprecated, + sym::must_use, + // abi, linking and FFI + sym::cold, + sym::export_name, + sym::link_section, + sym::linkage, + sym::no_mangle, + sym::instruction_set, + sym::repr, + sym::rustc_std_internal_symbol, + sym::align, + // obviously compatible with self + sym::naked, + // documentation + sym::doc, + ]; + + let span = self.span?; + + // only if we found a naked attribute do we do the somewhat expensive check + 'outer: for other_attr in cx.all_attrs { + for allowed_attr in ALLOW_LIST { + if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) { + // effectively skips the error message being emitted below + // if it's a tool attribute + continue 'outer; + } + if other_attr.word_is(*allowed_attr) { + // effectively skips the error message being emitted below + // if its an allowed attribute + continue 'outer; + } + + if other_attr.word_is(sym::target_feature) { + if !cx.features().naked_functions_target_feature() { + feature_err( + &cx.sess(), + sym::naked_functions_target_feature, + other_attr.span(), + "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions", + ).emit(); + } + + continue 'outer; + } + } + + cx.emit_err(NakedFunctionIncompatibleAttribute { + span: other_attr.span(), + naked_span: span, + attr: other_attr.get_attribute_path().to_string(), + }); } - Some(AttributeKind::Naked(cx.attr_span)) + + Some(AttributeKind::Naked(span)) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 25efc3ae49b9..11844f4cd950 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -45,10 +45,8 @@ impl SingleAttributeParser for InlineParser { ArgParser::NameValue(_) => { let suggestions = >::TEMPLATE.suggestions(false, "inline"); - cx.emit_lint( - AttributeLintKind::IllFormedAttributeInput { suggestions }, - cx.attr_span, - ); + let span = cx.attr_span; + cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index bfdd61384e5c..738d8735b692 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -17,7 +17,6 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; -use rustc_attr_data_structures::lints::AttributeLintKind; use rustc_feature::AttributeTemplate; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 570151eae9d5..457e073c488b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -28,7 +28,7 @@ use crate::attributes::stability::{ }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; -use crate::parser::{ArgParser, MetaItemParser}; +use crate::parser::{ArgParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; macro_rules! group_type { @@ -97,6 +97,7 @@ attribute_parsers!( BodyStabilityParser, ConfusablesParser, ConstStabilityParser, + NakedParser, StabilityParser, // tidy-alphabetical-end @@ -114,7 +115,6 @@ attribute_parsers!( Single, Single, Single, - Single, Single, Single, Single, @@ -175,7 +175,7 @@ pub struct Late; /// /// Gives [`AttributeParser`]s enough information to create errors, for example. pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { - pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>, + pub(crate) shared: SharedContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, @@ -188,7 +188,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { pub(crate) attr_path: AttrPath, } -impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { +impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { S::emit_err(&self.sess, diag) } @@ -226,7 +226,9 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { unused_span, ) } +} +impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { pub(crate) fn unknown_key( &self, span: Span, @@ -359,16 +361,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { - type Target = FinalizeContext<'f, 'sess, S>; + type Target = SharedContext<'f, 'sess, S>; fn deref(&self) -> &Self::Target { - &self.finalize_cx + &self.shared } } impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.finalize_cx + &mut self.shared } } @@ -376,7 +378,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { /// /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create /// errors, for example. -pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { +pub(crate) struct SharedContext<'p, 'sess, S: Stage> { /// The parse context, gives access to the session and the /// diagnostics context. pub(crate) cx: &'p mut AttributeParser<'sess, S>, @@ -385,10 +387,40 @@ pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to pub(crate) target_id: S::Id, - pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint), + emit_lint: &'p mut dyn FnMut(AttributeLint), +} + +/// Context given to every attribute parser during finalization. +/// +/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create +/// errors, for example. +pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { + pub(crate) shared: SharedContext<'p, 'sess, S>, + + /// A list of all attribute on this syntax node. + /// + /// Useful for compatibility checks with other attributes in [`finalize`](crate::attributes::AttributeParser::finalize) + /// + /// Usually, you should use normal attribute parsing logic instead, + /// especially when making a *denylist* of other attributes. + pub(crate) all_attrs: &'p [PathParser<'p>], } impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { + type Target = SharedContext<'p, 'sess, S>; + + fn deref(&self) -> &Self::Target { + &self.shared + } +} + +impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.shared + } +} + +impl<'p, 'sess: 'p, S: Stage> Deref for SharedContext<'p, 'sess, S> { type Target = AttributeParser<'sess, S>; fn deref(&self) -> &Self::Target { @@ -396,7 +428,7 @@ impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { } } -impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> { +impl<'p, 'sess: 'p, S: Stage> DerefMut for SharedContext<'p, 'sess, S> { fn deref_mut(&mut self) -> &mut Self::Target { self.cx } @@ -411,8 +443,7 @@ pub enum OmitDoc { /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. pub struct AttributeParser<'sess, S: Stage = Late> { - #[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes - tools: Vec, + pub(crate) tools: Vec, features: Option<&'sess Features>, sess: &'sess Session, stage: PhantomData, @@ -500,6 +531,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { mut emit_lint: impl FnMut(AttributeLint), ) -> Vec { let mut attributes = Vec::new(); + let mut attr_paths = Vec::new(); for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. @@ -543,6 +575,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { // })) // } ast::AttrKind::Normal(n) => { + attr_paths.push(PathParser::Ast(&n.item.path)); + let parser = MetaItemParser::from_attr(n, self.dcx()); let path = parser.path(); let args = parser.args(); @@ -551,7 +585,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { if let Some(accepts) = S::parsers().0.get(parts.as_slice()) { for (template, accept) in accepts { let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { - finalize_cx: FinalizeContext { + shared: SharedContext { cx: self, target_span, target_id, @@ -595,10 +629,13 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let mut parsed_attributes = Vec::new(); for f in &S::parsers().1 { if let Some(attr) = f(&mut FinalizeContext { - cx: self, - target_span, - target_id, - emit_lint: &mut emit_lint, + shared: SharedContext { + cx: self, + target_span, + target_id, + emit_lint: &mut emit_lint, + }, + all_attrs: &attr_paths, }) { parsed_attributes.push(Attribute::Parsed(attr)); } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 1edbe3a9d27a..e02dc098127c 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -87,6 +87,14 @@ impl<'a> PathParser<'a> { pub fn word_is(&self, sym: Symbol) -> bool { self.word().map(|i| i.name == sym).unwrap_or(false) } + + /// Checks whether the first segments match the givens. + /// + /// Unlike [`segments_is`](Self::segments_is), + /// `self` may contain more segments than the number matched against. + pub fn starts_with(&self, segments: &[Symbol]) -> bool { + segments.len() < self.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b) + } } impl Display for PathParser<'_> { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2a020770e5d3..808e452799d3 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -482,6 +482,17 @@ pub(crate) struct UnrecognizedReprHint { pub span: Span, } +#[derive(Diagnostic)] +#[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)] +pub(crate) struct NakedFunctionIncompatibleAttribute { + #[primary_span] + #[label] + pub span: Span, + #[label(attr_parsing_naked_attribute)] + pub naked_span: Span, + pub attr: String, +} + pub(crate) enum AttributeParseErrorReason { ExpectedNoArgs, ExpectedStringLiteral { byte_string: Option }, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3a2dfa8e9857..60b691e0f751 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2,7 +2,6 @@ use std::cell::LazyCell; use std::ops::ControlFlow; use rustc_abi::FieldIdx; -use rustc_attr_data_structures::AttributeKind; use rustc_attr_data_structures::ReprAttr::ReprPacked; use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::unord::{UnordMap, UnordSet}; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index c1a2b3b29733..29526817257b 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -491,11 +491,6 @@ passes_must_not_suspend = passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} -passes_naked_functions_incompatible_attribute = - attribute incompatible with `#[unsafe(naked)]` - .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]` - .naked_attribute = function marked with `#[unsafe(naked)]` here - passes_no_link = attribute should be applied to an `extern crate` item .label = not an `extern crate` item diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1990b46adbb7..c2a58b4cd7d5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; @@ -161,7 +161,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_align(span, target, *align, *repr_span) } Attribute::Parsed(AttributeKind::Naked(attr_span)) => { - self.check_naked(hir_id, *attr_span, span, target, attrs) + self.check_naked(hir_id, *attr_span, span, target) } Attribute::Parsed( AttributeKind::BodyStability { .. } @@ -622,53 +622,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[naked]` is applied to a function definition. - fn check_naked( - &self, - hir_id: HirId, - attr_span: Span, - span: Span, - target: Target, - attrs: &[Attribute], - ) { - // many attributes don't make sense in combination with #[naked]. - // Notable attributes that are incompatible with `#[naked]` are: - // - // * `#[inline]` - // * `#[track_caller]` - // * `#[test]`, `#[ignore]`, `#[should_panic]` - // - // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains - // accurate. - const ALLOW_LIST: &[rustc_span::Symbol] = &[ - // conditional compilation - sym::cfg_trace, - sym::cfg_attr_trace, - // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`) - sym::test, - sym::ignore, - sym::should_panic, - sym::bench, - // diagnostics - sym::allow, - sym::warn, - sym::deny, - sym::forbid, - // FIXME(jdonszelmann): not used, because already a new-style attr (ugh) - sym::deprecated, - sym::must_use, - // abi, linking and FFI - sym::export_name, - sym::link_section, - sym::linkage, - sym::no_mangle, - sym::instruction_set, - sym::repr, - sym::align, - sym::rustc_std_internal_symbol, - // documentation - sym::doc, - ]; - + fn check_naked(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { @@ -686,75 +640,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) .emit(); } - - for other_attr in attrs { - // this covers "sugared doc comments" of the form `/// ...` - // it does not cover `#[doc = "..."]`, which is handled below - if other_attr.is_doc_comment() { - continue; - } - - // FIXME(jdonszelmann): once naked uses new-style parsing, - // this check can be part of the parser and be removed here - match other_attr { - Attribute::Parsed( - AttributeKind::Deprecation { .. } - | AttributeKind::Repr { .. } - | AttributeKind::Align { .. } - | AttributeKind::NoMangle(..) - | AttributeKind::Cold(..) - | AttributeKind::MustUse { .. }, - | AttributeKind::Naked(..), - ) => { - continue; - } - Attribute::Parsed(AttributeKind::Inline(.., span)) => { - self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { - span: *span, - naked_span: attr_span, - attr: sym::inline.to_string(), - }); - - return; - } - // FIXME(jdonszelmann): make exhaustive - _ => {} - } - - if other_attr.has_name(sym::target_feature) { - if !self.tcx.features().naked_functions_target_feature() { - feature_err( - &self.tcx.sess, - sym::naked_functions_target_feature, - other_attr.span(), - "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions", - ).emit(); - - return; - } else { - continue; - } - } - - if !other_attr.has_any_name(ALLOW_LIST) - && !matches!(other_attr.path().as_slice(), [sym::rustfmt, ..]) - { - let path = other_attr.path(); - let path: Vec<_> = path - .iter() - .map(|s| if *s == kw::PathRoot { "" } else { s.as_str() }) - .collect(); - let other_attr_name = path.join("::"); - - self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { - span: other_attr.span(), - naked_span: attr_span, - attr: other_attr_name, - }); - - return; - } - } } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 587d9170f067..94c8ae77ed76 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1070,17 +1070,6 @@ pub(crate) struct FeaturePreviouslyDeclared<'a> { pub prev_declared: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_naked_functions_incompatible_attribute, code = E0736)] -pub(crate) struct NakedFunctionIncompatibleAttribute { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_naked_attribute)] - pub naked_span: Span, - pub attr: String, -} - #[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub(crate) struct AttrOnlyInFunctions { diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr index 07d5f3bc49a9..91140a301edc 100644 --- a/tests/ui/asm/naked-functions-inline.stderr +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -1,26 +1,26 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:12:1 + --> $DIR/naked-functions-inline.rs:12:3 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here LL | #[inline] - | ^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` + | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:19:1 + --> $DIR/naked-functions-inline.rs:19:3 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` + | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-functions-inline.rs:26:1 + --> $DIR/naked-functions-inline.rs:26:3 | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` + | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-functions-inline.rs:33:19 @@ -28,7 +28,7 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]` LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here LL | #[cfg_attr(all(), inline(never))] - | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` + | ^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]` error: aborting due to 4 previous errors diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index 6661084861ee..915b54b3fc23 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -4,6 +4,15 @@ error[E0433]: failed to resolve: use of unresolved module or unlinked crate `a` LL | #[::a] | ^ use of unresolved module or unlinked crate `a` +error[E0736]: attribute incompatible with `#[unsafe(naked)]` + --> $DIR/naked-invalid-attr.rs:56:3 + | +LL | #[::a] + | ^^^ the `{{root}}::a` attribute is incompatible with `#[unsafe(naked)]` +... +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here + error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:13:1 | @@ -33,15 +42,6 @@ LL | #[unsafe(naked)] LL | || {}; | ----- not a function definition -error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-invalid-attr.rs:56:1 - | -LL | #[::a] - | ^^^^^^ the `::a` attribute is incompatible with `#[unsafe(naked)]` -... -LL | #[unsafe(naked)] - | ---------------- function marked with `#[unsafe(naked)]` here - error: attribute should be applied to a function definition --> $DIR/naked-invalid-attr.rs:22:5 | diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr index 8e601a14753b..e57ec9cc59b2 100644 --- a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr +++ b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr @@ -1,8 +1,8 @@ error[E0658]: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions - --> $DIR/feature-gate-naked_functions_target_feature.rs:7:1 + --> $DIR/feature-gate-naked_functions_target_feature.rs:7:3 | LL | #[target_feature(enable = "avx2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = note: see issue #138568 for more information = help: add `#![feature(naked_functions_target_feature)]` to the crate attributes to enable diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr index d3cafbc63508..303608061388 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr @@ -1,17 +1,17 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/error-with-naked.rs:5:1 + --> $DIR/error-with-naked.rs:5:3 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` + | ^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` LL | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/error-with-naked.rs:17:5 + --> $DIR/error-with-naked.rs:17:7 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` + | ^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]` LL | LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here From 66060e64753b0ca41bda90130054e261fa5523be Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 21 Jun 2025 15:57:09 +0200 Subject: [PATCH 273/356] Create new `CiInfo` type in tidy checks to centralize CI related checks --- src/tools/tidy/src/lib.rs | 61 ++++++++++++++++++++++++++++++ src/tools/tidy/src/main.rs | 6 ++- src/tools/tidy/src/rustdoc_json.rs | 48 +++-------------------- 3 files changed, 71 insertions(+), 44 deletions(-) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 28aa80225b17..237737f0f169 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -3,6 +3,12 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. +use std::ffi::OsStr; +use std::process::Command; + +use build_helper::ci::CiEnv; +use build_helper::git::{GitConfig, get_closest_upstream_commit}; +use build_helper::stage0_parser::{Stage0Config, parse_stage0_file}; use termcolor::WriteColor; macro_rules! static_regex { @@ -63,6 +69,61 @@ fn tidy_error(args: &str) -> std::io::Result<()> { Ok(()) } +pub struct CiInfo { + pub git_merge_commit_email: String, + pub nightly_branch: String, + pub base_commit: Option, + pub ci_env: CiEnv, +} + +impl CiInfo { + pub fn new(bad: &mut bool) -> Self { + let stage0 = parse_stage0_file(); + let Stage0Config { nightly_branch, git_merge_commit_email, .. } = stage0.config; + + let mut info = Self { + nightly_branch, + git_merge_commit_email, + ci_env: CiEnv::current(), + base_commit: None, + }; + let base_commit = match get_closest_upstream_commit(None, &info.git_config(), info.ci_env) { + Ok(Some(commit)) => Some(commit), + Ok(None) => { + info.error_if_in_ci("no base commit found", bad); + None + } + Err(error) => { + info.error_if_in_ci(&format!("failed to retrieve base commit: {error}"), bad); + None + } + }; + info.base_commit = base_commit; + info + } + + pub fn git_config(&self) -> GitConfig<'_> { + GitConfig { + nightly_branch: &self.nightly_branch, + git_merge_commit_email: &self.git_merge_commit_email, + } + } + + pub fn error_if_in_ci(&self, msg: &str, bad: &mut bool) { + if self.ci_env.is_running_in_ci() { + *bad = true; + eprintln!("tidy check error: {msg}"); + } else { + eprintln!("tidy check warning: {msg}. Some checks will be skipped."); + } + } +} + +pub fn git_diff>(base_commit: &str, extra_arg: S) -> Option { + let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?; + Some(String::from_utf8_lossy(&output.stdout).into()) +} + pub mod alphabetical; pub mod bins; pub mod debug_artifacts; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 0b66017b8652..6bc557b36fd6 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -48,7 +48,9 @@ fn main() { let extra_checks = cfg_args.iter().find(|s| s.starts_with("--extra-checks=")).map(String::as_str); - let bad = std::sync::Arc::new(AtomicBool::new(false)); + let mut bad = false; + let ci_info = CiInfo::new(&mut bad); + let bad = std::sync::Arc::new(AtomicBool::new(bad)); let drain_handles = |handles: &mut VecDeque>| { // poll all threads for completion before awaiting the oldest one @@ -110,7 +112,7 @@ fn main() { check!(rustdoc_css_themes, &librustdoc_path); check!(rustdoc_templates, &librustdoc_path); check!(rustdoc_js, &librustdoc_path, &tools_path, &src_path); - check!(rustdoc_json, &src_path); + check!(rustdoc_json, &src_path, &ci_info); check!(known_bug, &crashes_path); check!(unknown_revision, &tests_path); diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs index 2377356e14dc..dfbb35d69f17 100644 --- a/src/tools/tidy/src/rustdoc_json.rs +++ b/src/tools/tidy/src/rustdoc_json.rs @@ -1,56 +1,20 @@ //! Tidy check to ensure that `FORMAT_VERSION` was correctly updated if `rustdoc-json-types` was //! updated as well. -use std::ffi::OsStr; use std::path::Path; -use std::process::Command; use std::str::FromStr; -use build_helper::ci::CiEnv; -use build_helper::git::{GitConfig, get_closest_upstream_commit}; -use build_helper::stage0_parser::parse_stage0_file; - const RUSTDOC_JSON_TYPES: &str = "src/rustdoc-json-types"; -fn git_diff>(base_commit: &str, extra_arg: S) -> Option { - let output = Command::new("git").arg("diff").arg(base_commit).arg(extra_arg).output().ok()?; - Some(String::from_utf8_lossy(&output.stdout).into()) -} - -fn error_if_in_ci(ci_env: CiEnv, msg: &str, bad: &mut bool) { - if ci_env.is_running_in_ci() { - *bad = true; - eprintln!("error in `rustdoc_json` tidy check: {msg}"); - } else { - eprintln!("{msg}. Skipping `rustdoc_json` tidy check"); - } -} - -pub fn check(src_path: &Path, bad: &mut bool) { +pub fn check(src_path: &Path, ci_info: &crate::CiInfo, bad: &mut bool) { println!("Checking tidy rustdoc_json..."); - let stage0 = parse_stage0_file(); - let ci_env = CiEnv::current(); - let base_commit = match get_closest_upstream_commit( - None, - &GitConfig { - nightly_branch: &stage0.config.nightly_branch, - git_merge_commit_email: &stage0.config.git_merge_commit_email, - }, - ci_env, - ) { - Ok(Some(commit)) => commit, - Ok(None) => { - error_if_in_ci(ci_env, "no base commit found", bad); - return; - } - Err(error) => { - error_if_in_ci(ci_env, &format!("failed to retrieve base commit: {error}"), bad); - return; - } + let Some(base_commit) = &ci_info.base_commit else { + eprintln!("No base commit, skipping rustdoc_json check"); + return; }; // First we check that `src/rustdoc-json-types` was modified. - match git_diff(&base_commit, "--name-status") { + match crate::git_diff(&base_commit, "--name-status") { Some(output) => { if !output .lines() @@ -68,7 +32,7 @@ pub fn check(src_path: &Path, bad: &mut bool) { } } // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated. - match git_diff(&base_commit, src_path.join("rustdoc-json-types")) { + match crate::git_diff(&base_commit, src_path.join("rustdoc-json-types")) { Some(output) => { let mut format_version_updated = false; let mut latest_feature_comment_updated = false; From 4780f21fe5b3f35c356a5c4a1d05ab3393d40e78 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 21 Jun 2025 16:14:52 +0200 Subject: [PATCH 274/356] Move error code explanation removal check into tidy --- .../host-x86_64/mingw-check-1/Dockerfile | 2 -- .../mingw-check-1/validate-error-codes.sh | 20 ------------ .../host-x86_64/mingw-check-tidy/Dockerfile | 1 - src/tools/tidy/src/error_codes.rs | 32 ++++++++++++++++++- src/tools/tidy/src/main.rs | 2 +- 5 files changed, 32 insertions(+), 25 deletions(-) delete mode 100755 src/ci/docker/host-x86_64/mingw-check-1/validate-error-codes.sh diff --git a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile index a877de1f7b24..9bdcf00dccc1 100644 --- a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile @@ -39,7 +39,6 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require COPY host-x86_64/mingw-check-1/check-default-config-profiles.sh /scripts/ COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/ -COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/ # Check library crates on all tier 1 targets. # We disable optimized compiler built-ins because that requires a C toolchain for the target. @@ -52,7 +51,6 @@ ENV SCRIPT \ python3 ../x.py check --stage 1 --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py check --stage 1 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/validate-toolstate.sh && \ - /scripts/validate-error-codes.sh && \ reuse --include-submodules lint && \ python3 ../x.py test collect-license-metadata && \ # Runs checks to ensure that there are no issues in our JS code. diff --git a/src/ci/docker/host-x86_64/mingw-check-1/validate-error-codes.sh b/src/ci/docker/host-x86_64/mingw-check-1/validate-error-codes.sh deleted file mode 100755 index e9aa948eb877..000000000000 --- a/src/ci/docker/host-x86_64/mingw-check-1/validate-error-codes.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Checks that no error code explanation is removed. - -set -eo pipefail - -if [[ -z "$BASE_COMMIT" ]]; then - echo "not checking error code explanations removal" - exit 0 -fi - -echo "Check if an error code explanation was removed..." - -if (git diff "$BASE_COMMIT" --name-status | grep '^D' \ - | grep --quiet "compiler/rustc_error_codes/src/error_codes/"); then - echo "Error code explanations should never be removed!" - echo "Take a look at E0001 to see how to handle it." - exit 1 -fi - -echo "No error code explanation was removed!" diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index 8d2c5e004e47..62cd8a312129 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile @@ -39,7 +39,6 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require && pip3 install virtualenv COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/ -COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/ RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)' diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index e2d1b85797ff..bb61412f6788 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -43,9 +43,18 @@ macro_rules! verbose_print { }; } -pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut bool) { +pub fn check( + root_path: &Path, + search_paths: &[&Path], + verbose: bool, + ci_info: &crate::CiInfo, + bad: &mut bool, +) { let mut errors = Vec::new(); + // Check that no error code explanation was removed. + check_removed_error_code_explanation(ci_info, bad); + // Stage 1: create list let error_codes = extract_error_codes(root_path, &mut errors); if verbose { @@ -68,6 +77,27 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut } } +fn check_removed_error_code_explanation(ci_info: &crate::CiInfo, bad: &mut bool) { + let Some(base_commit) = &ci_info.base_commit else { + eprintln!("Skipping error code explanation removal check"); + return; + }; + let Some(diff) = crate::git_diff(base_commit, "--name-status") else { + *bad = true; + eprintln!("removed error code explanation tidy check: Failed to run git diff"); + return; + }; + if diff.lines().any(|line| { + line.starts_with('D') && line.contains("compiler/rustc_error_codes/src/error_codes/") + }) { + *bad = true; + eprintln!("tidy check error: Error code explanations should never be removed!"); + eprintln!("Take a look at E0001 to see how to handle it."); + return; + } + println!("No error code explanation was removed!"); +} + /// Stage 1: Parses a list of error codes from `error_codes.rs`. fn extract_error_codes(root_path: &Path, errors: &mut Vec) -> Vec { let path = root_path.join(Path::new(ERROR_CODES_PATH)); diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 6bc557b36fd6..ef6ff5c9277a 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -117,7 +117,7 @@ fn main() { check!(unknown_revision, &tests_path); // Checks that only make sense for the compiler. - check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); + check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose, &ci_info); check!(fluent_alphabetical, &compiler_path, bless); check!(fluent_period, &compiler_path); check!(target_policy, &root_path); From c7bfb114b7f1dca70cd14d476646cd68f35ef886 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Mon, 23 Jun 2025 13:16:08 +0200 Subject: [PATCH 275/356] Fix install-template.sh for Solaris tr --- src/tools/rust-installer/install-template.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-installer/install-template.sh b/src/tools/rust-installer/install-template.sh index f7f408be882e..337aaa95b9a2 100644 --- a/src/tools/rust-installer/install-template.sh +++ b/src/tools/rust-installer/install-template.sh @@ -160,7 +160,7 @@ valopt() { local doc="$*" if [ $HELP -eq 0 ] then - local uop=$(echo $op | tr 'a-z-' 'A-Z_') + local uop=$(echo $op | tr '[a-z]-' '[A-Z]_') local v="CFG_${uop}" eval $v="$default" for arg in $CFG_ARGS @@ -206,8 +206,8 @@ opt() { do if [ "$arg" = "--${flag}-${op}" ] then - op=$(echo $op | tr 'a-z-' 'A-Z_') - flag=$(echo $flag | tr 'a-z' 'A-Z') + op=$(echo $op | tr '[a-z]-' '[A-Z]_') + flag=$(echo $flag | tr '[a-z]' '[A-Z]') local v="CFG_${flag}_${op}" eval $v=1 putvar $v @@ -235,7 +235,7 @@ flag() { do if [ "$arg" = "--${op}" ] then - op=$(echo $op | tr 'a-z-' 'A-Z_') + op=$(echo $op | tr '[a-z]-' '[A-Z]_') local v="CFG_${op}" eval $v=1 putvar $v From 793607059bcd49cbafc3d75f8438b496cd793970 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sun, 8 Jun 2025 19:09:38 +0500 Subject: [PATCH 276/356] cleaned up some tests --- tests/ui/defaults-well-formedness.rs | 27 ---------- .../deprecated_main_function.rs} | 2 +- tests/ui/deref-rc.rs | 8 --- tests/ui/deref.rs | 6 --- tests/ui/derive-uninhabited-enum-38885.rs | 19 ------- .../derives/derive-debug-uninhabited-enum.rs | 23 +++++++++ .../derive-debug-uninhabited-enum.stderr} | 2 +- tests/ui/destructure-trait-ref.rs | 46 ----------------- tests/ui/diverging-fallback-method-chain.rs | 20 -------- tests/ui/diverging-fallback-option.rs | 14 ------ .../default-type-params-well-formedness.rs | 50 +++++++++++++++++++ .../never_type/never-type-fallback-option.rs | 22 ++++++++ tests/ui/traits/trait-object-destructure.rs | 29 +++++++++++ .../trait-object-destructure.stderr} | 12 ++--- ...ference-method-chain-diverging-fallback.rs | 19 +++++++ 15 files changed, 151 insertions(+), 148 deletions(-) delete mode 100644 tests/ui/defaults-well-formedness.rs rename tests/ui/{deprecation-in-force-unstable.rs => deprecation/deprecated_main_function.rs} (90%) delete mode 100644 tests/ui/deref-rc.rs delete mode 100644 tests/ui/deref.rs delete mode 100644 tests/ui/derive-uninhabited-enum-38885.rs create mode 100644 tests/ui/derives/derive-debug-uninhabited-enum.rs rename tests/ui/{derive-uninhabited-enum-38885.stderr => derives/derive-debug-uninhabited-enum.stderr} (89%) delete mode 100644 tests/ui/destructure-trait-ref.rs delete mode 100644 tests/ui/diverging-fallback-method-chain.rs delete mode 100644 tests/ui/diverging-fallback-option.rs create mode 100644 tests/ui/generics/default-type-params-well-formedness.rs create mode 100644 tests/ui/never_type/never-type-fallback-option.rs create mode 100644 tests/ui/traits/trait-object-destructure.rs rename tests/ui/{destructure-trait-ref.stderr => traits/trait-object-destructure.stderr} (87%) create mode 100644 tests/ui/typeck/inference-method-chain-diverging-fallback.rs diff --git a/tests/ui/defaults-well-formedness.rs b/tests/ui/defaults-well-formedness.rs deleted file mode 100644 index e5e48edad88f..000000000000 --- a/tests/ui/defaults-well-formedness.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -trait Trait {} -struct Foo(U, V) where U: Trait; - -trait Marker {} -struct TwoParams(T, U); -impl Marker for TwoParams {} - -// Clauses with more than 1 param are not checked. -struct IndividuallyBogus(TwoParams) where TwoParams: Marker; -struct BogusTogether(T, U) where TwoParams: Marker; -// Clauses with non-defaulted params are not checked. -struct NonDefaultedInClause(TwoParams) where TwoParams: Marker; -struct DefaultedLhs(U, V) where V: Trait; -// Dependent defaults are not checked. -struct Dependent(T, U) where U: Copy; -trait SelfBound {} -// Not even for well-formedness. -struct WellFormedProjection::Item>(A, T); - -// Issue #49344, predicates with lifetimes should not be checked. -trait Scope<'a> {} -struct Request<'a, S: Scope<'a> = i32>(S, &'a ()); - -fn main() {} diff --git a/tests/ui/deprecation-in-force-unstable.rs b/tests/ui/deprecation/deprecated_main_function.rs similarity index 90% rename from tests/ui/deprecation-in-force-unstable.rs rename to tests/ui/deprecation/deprecated_main_function.rs index 6aaf29b069a6..398046637d80 100644 --- a/tests/ui/deprecation-in-force-unstable.rs +++ b/tests/ui/deprecation/deprecated_main_function.rs @@ -2,4 +2,4 @@ //@ compile-flags:-Zforce-unstable-if-unmarked #[deprecated] // should work even with -Zforce-unstable-if-unmarked -fn main() { } +fn main() {} diff --git a/tests/ui/deref-rc.rs b/tests/ui/deref-rc.rs deleted file mode 100644 index 92fdd9003592..000000000000 --- a/tests/ui/deref-rc.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass - -use std::rc::Rc; - -fn main() { - let x = Rc::new([1, 2, 3, 4]); - assert_eq!(*x, [1, 2, 3, 4]); -} diff --git a/tests/ui/deref.rs b/tests/ui/deref.rs deleted file mode 100644 index 0a6f3cc81f6c..000000000000 --- a/tests/ui/deref.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - -pub fn main() { - let x: Box = Box::new(10); - let _y: isize = *x; -} diff --git a/tests/ui/derive-uninhabited-enum-38885.rs b/tests/ui/derive-uninhabited-enum-38885.rs deleted file mode 100644 index 2259a542706e..000000000000 --- a/tests/ui/derive-uninhabited-enum-38885.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ check-pass -//@ compile-flags: -Wunused - -// ensure there are no special warnings about uninhabited types -// when deriving Debug on an empty enum - -#[derive(Debug)] -enum Void {} - -#[derive(Debug)] -enum Foo { - Bar(#[allow(dead_code)] u8), - Void(Void), //~ WARN variant `Void` is never constructed -} - -fn main() { - let x = Foo::Bar(42); - println!("{:?}", x); -} diff --git a/tests/ui/derives/derive-debug-uninhabited-enum.rs b/tests/ui/derives/derive-debug-uninhabited-enum.rs new file mode 100644 index 000000000000..be7b3ab348d6 --- /dev/null +++ b/tests/ui/derives/derive-debug-uninhabited-enum.rs @@ -0,0 +1,23 @@ +//! Regression test for `#[derive(Debug)]` on enums with uninhabited variants. +//! +//! Ensures there are no special warnings about uninhabited types when deriving +//! Debug on an enum with uninhabited variants, only standard unused warnings. +//! +//! Issue: https://github.com/rust-lang/rust/issues/38885 + +//@ check-pass +//@ compile-flags: -Wunused + +#[derive(Debug)] +enum Void {} + +#[derive(Debug)] +enum Foo { + Bar(#[allow(dead_code)] u8), + Void(Void), //~ WARN variant `Void` is never constructed +} + +fn main() { + let x = Foo::Bar(42); + println!("{:?}", x); +} diff --git a/tests/ui/derive-uninhabited-enum-38885.stderr b/tests/ui/derives/derive-debug-uninhabited-enum.stderr similarity index 89% rename from tests/ui/derive-uninhabited-enum-38885.stderr rename to tests/ui/derives/derive-debug-uninhabited-enum.stderr index bcd8f6b7b536..4911b6b6cded 100644 --- a/tests/ui/derive-uninhabited-enum-38885.stderr +++ b/tests/ui/derives/derive-debug-uninhabited-enum.stderr @@ -1,5 +1,5 @@ warning: variant `Void` is never constructed - --> $DIR/derive-uninhabited-enum-38885.rs:13:5 + --> $DIR/derive-debug-uninhabited-enum.rs:17:5 | LL | enum Foo { | --- variant in this enum diff --git a/tests/ui/destructure-trait-ref.rs b/tests/ui/destructure-trait-ref.rs deleted file mode 100644 index daa0ca30d687..000000000000 --- a/tests/ui/destructure-trait-ref.rs +++ /dev/null @@ -1,46 +0,0 @@ -// The regression test for #15031 to make sure destructuring trait -// reference work properly. - -//@ dont-require-annotations: NOTE - -#![feature(box_patterns)] - -trait T { fn foo(&self) {} } -impl T for isize {} - - -fn main() { - // For an expression of the form: - // - // let &...&x = &..&SomeTrait; - // - // Say we have n `&` at the left hand and m `&` right hand, then: - // if n < m, we are golden; - // if n == m, it's a derefing non-derefable type error; - // if n > m, it's a type mismatch error. - - // n < m - let &x = &(&1isize as &dyn T); - let &x = &&(&1isize as &dyn T); - let &&x = &&(&1isize as &dyn T); - - // n == m - let &x = &1isize as &dyn T; //~ ERROR type `&dyn T` cannot be dereferenced - let &&x = &(&1isize as &dyn T); //~ ERROR type `&dyn T` cannot be dereferenced - let box x = Box::new(1isize) as Box; - //~^ ERROR type `Box` cannot be dereferenced - - // n > m - let &&x = &1isize as &dyn T; - //~^ ERROR mismatched types - //~| NOTE expected trait object `dyn T` - //~| NOTE found reference `&_` - let &&&x = &(&1isize as &dyn T); - //~^ ERROR mismatched types - //~| NOTE expected trait object `dyn T` - //~| NOTE found reference `&_` - let box box x = Box::new(1isize) as Box; - //~^ ERROR mismatched types - //~| NOTE expected trait object `dyn T` - //~| NOTE found struct `Box<_>` -} diff --git a/tests/ui/diverging-fallback-method-chain.rs b/tests/ui/diverging-fallback-method-chain.rs deleted file mode 100644 index aa8eba1191b9..000000000000 --- a/tests/ui/diverging-fallback-method-chain.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ run-pass - -#![allow(unused_imports)] -// Test a regression found when building compiler. The `produce()` -// error type `T` winds up getting unified with result of `x.parse()`; -// the type of the closure given to `unwrap_or_else` needs to be -// inferred to `usize`. - -use std::num::ParseIntError; - -fn produce() -> Result<&'static str, T> { - Ok("22") -} - -fn main() { - let x: usize = produce() - .and_then(|x| x.parse()) - .unwrap_or_else(|_| panic!()); - println!("{}", x); -} diff --git a/tests/ui/diverging-fallback-option.rs b/tests/ui/diverging-fallback-option.rs deleted file mode 100644 index aa793ebd0178..000000000000 --- a/tests/ui/diverging-fallback-option.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass - -#![allow(warnings)] - -// Here the type of `c` is `Option`, where `?T` is unconstrained. -// Because there is data-flow from the `{ return; }` block, which -// diverges and hence has type `!`, into `c`, we will default `?T` to -// `!`, and hence this code compiles rather than failing and requiring -// a type annotation. - -fn main() { - let c = Some({ return; }); - c.unwrap(); -} diff --git a/tests/ui/generics/default-type-params-well-formedness.rs b/tests/ui/generics/default-type-params-well-formedness.rs new file mode 100644 index 000000000000..22b8f5011f7e --- /dev/null +++ b/tests/ui/generics/default-type-params-well-formedness.rs @@ -0,0 +1,50 @@ +//! Test for well-formedness checking of default type parameters. +//! +//! Regression Test for: https://github.com/rust-lang/rust/issues/49344 + +//@ run-pass + +#![allow(dead_code)] + +trait Trait {} +struct Foo(U, V) +where + U: Trait; + +trait Marker {} +struct TwoParams(T, U); +impl Marker for TwoParams {} + +// Clauses with more than 1 param are not checked. +struct IndividuallyBogus(TwoParams) +where + TwoParams: Marker; + +struct BogusTogether(T, U) +where + TwoParams: Marker; + +// Clauses with non-defaulted params are not checked. +struct NonDefaultedInClause(TwoParams) +where + TwoParams: Marker; + +struct DefaultedLhs(U, V) +where + V: Trait; + +// Dependent defaults are not checked. +struct Dependent(T, U) +where + U: Copy; + +trait SelfBound {} + +// Not even for well-formedness. +struct WellFormedProjection::Item>(A, T); + +// Issue #49344, predicates with lifetimes should not be checked. +trait Scope<'a> {} +struct Request<'a, S: Scope<'a> = i32>(S, &'a ()); + +fn main() {} diff --git a/tests/ui/never_type/never-type-fallback-option.rs b/tests/ui/never_type/never-type-fallback-option.rs new file mode 100644 index 000000000000..9c8103aa0a4c --- /dev/null +++ b/tests/ui/never_type/never-type-fallback-option.rs @@ -0,0 +1,22 @@ +//@ run-pass + +#![allow(warnings)] + +//! Tests type inference fallback to `!` (never type) in `Option` context. +//! +//! Regression test for issues: +//! - https://github.com/rust-lang/rust/issues/39808 +//! - https://github.com/rust-lang/rust/issues/39984 +//! +//! Here the type of `c` is `Option`, where `?T` is unconstrained. +//! Because there is data-flow from the `{ return; }` block, which +//! diverges and hence has type `!`, into `c`, we will default `?T` to +//! `!`, and hence this code compiles rather than failing and requiring +//! a type annotation. + +fn main() { + let c = Some({ + return; + }); + c.unwrap(); +} diff --git a/tests/ui/traits/trait-object-destructure.rs b/tests/ui/traits/trait-object-destructure.rs new file mode 100644 index 000000000000..6c091677c8ce --- /dev/null +++ b/tests/ui/traits/trait-object-destructure.rs @@ -0,0 +1,29 @@ +//! Regression test for destructuring trait references (`&dyn T`/`Box`). +//! Checks cases where number of `&`/`Box` patterns (n) matches/doesn't match references (m). +//! +//! Issue: https://github.com/rust-lang/rust/issues/15031 + +#![feature(box_patterns)] + +trait T { + fn foo(&self) {} +} + +impl T for isize {} + +fn main() { + // Valid cases: n < m (can dereference) + let &x = &(&1isize as &dyn T); + let &x = &&(&1isize as &dyn T); + let &&x = &&(&1isize as &dyn T); + + // Error cases: n == m (cannot dereference trait object) + let &x = &1isize as &dyn T; //~ ERROR type `&dyn T` cannot be dereferenced + let &&x = &(&1isize as &dyn T); //~ ERROR type `&dyn T` cannot be dereferenced + let box x = Box::new(1isize) as Box; //~ ERROR type `Box` cannot be dereferenced + + // Error cases: n > m (type mismatch) + let &&x = &1isize as &dyn T; //~ ERROR mismatched types + let &&&x = &(&1isize as &dyn T); //~ ERROR mismatched types + let box box x = Box::new(1isize) as Box; //~ ERROR mismatched types +} diff --git a/tests/ui/destructure-trait-ref.stderr b/tests/ui/traits/trait-object-destructure.stderr similarity index 87% rename from tests/ui/destructure-trait-ref.stderr rename to tests/ui/traits/trait-object-destructure.stderr index 0b5ea551a578..c7c832dc40af 100644 --- a/tests/ui/destructure-trait-ref.stderr +++ b/tests/ui/traits/trait-object-destructure.stderr @@ -1,23 +1,23 @@ error[E0033]: type `&dyn T` cannot be dereferenced - --> $DIR/destructure-trait-ref.rs:28:9 + --> $DIR/trait-object-destructure.rs:21:9 | LL | let &x = &1isize as &dyn T; | ^^ type `&dyn T` cannot be dereferenced error[E0033]: type `&dyn T` cannot be dereferenced - --> $DIR/destructure-trait-ref.rs:29:10 + --> $DIR/trait-object-destructure.rs:22:10 | LL | let &&x = &(&1isize as &dyn T); | ^^ type `&dyn T` cannot be dereferenced error[E0033]: type `Box` cannot be dereferenced - --> $DIR/destructure-trait-ref.rs:30:9 + --> $DIR/trait-object-destructure.rs:23:9 | LL | let box x = Box::new(1isize) as Box; | ^^^^^ type `Box` cannot be dereferenced error[E0308]: mismatched types - --> $DIR/destructure-trait-ref.rs:34:10 + --> $DIR/trait-object-destructure.rs:26:10 | LL | let &&x = &1isize as &dyn T; | ^^ ----------------- this expression has type `&dyn T` @@ -33,7 +33,7 @@ LL + let &x = &1isize as &dyn T; | error[E0308]: mismatched types - --> $DIR/destructure-trait-ref.rs:38:11 + --> $DIR/trait-object-destructure.rs:27:11 | LL | let &&&x = &(&1isize as &dyn T); | ^^ -------------------- this expression has type `&&dyn T` @@ -49,7 +49,7 @@ LL + let &&x = &(&1isize as &dyn T); | error[E0308]: mismatched types - --> $DIR/destructure-trait-ref.rs:42:13 + --> $DIR/trait-object-destructure.rs:28:13 | LL | let box box x = Box::new(1isize) as Box; | ^^^^^ ------------------------------ this expression has type `Box` diff --git a/tests/ui/typeck/inference-method-chain-diverging-fallback.rs b/tests/ui/typeck/inference-method-chain-diverging-fallback.rs new file mode 100644 index 000000000000..8f549b7d9d68 --- /dev/null +++ b/tests/ui/typeck/inference-method-chain-diverging-fallback.rs @@ -0,0 +1,19 @@ +//! Test type inference in method chains with diverging fallback. +//! Verifies that closure type in `unwrap_or_else` is properly inferred +//! when chained with other combinators and contains a diverging path. + +//@ run-pass + +fn produce() -> Result<&'static str, T> { + Ok("22") +} + +fn main() { + // The closure's error type `T` must unify with `ParseIntError`, + // while the success type must be `usize` (from parse()) + let x: usize = produce() + .and_then(|x| x.parse::()) // Explicit turbofish for clarity + .unwrap_or_else(|_| panic!()); // Diverging fallback + + assert_eq!(x, 22); +} From a3ede1038f19262b746f21080acd90ec5f703b3f Mon Sep 17 00:00:00 2001 From: gstjepan2 Date: Wed, 11 Jun 2025 10:55:46 +0200 Subject: [PATCH 277/356] Fixes firefox copy paste issue --- src/librustdoc/html/static/js/main.js | 30 ++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 7b1a61a3ffa4..2de8f836da3b 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1,6 +1,6 @@ // Local js definitions: /* global addClass, getSettingValue, hasClass, updateLocalStorage */ -/* global onEachLazy, removeClass, getVar */ +/* global onEachLazy, removeClass, getVar, nonnull */ "use strict"; @@ -2138,3 +2138,31 @@ function preLoadCss(cssUrl) { elem.addEventListener("click", showHideCodeExampleButtons); }); }()); + +// This section is a bugfix for firefox: when copying text with `user-select: none`, it adds +// extra backline characters. +// +// Rustdoc issue: Workaround for https://github.com/rust-lang/rust/issues/141464 +// Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836 +(function() { + document.body.addEventListener("copy", event => { + let target = nonnull(event.target); + let isInsideCode = false; + while (target && target !== document.body) { + // @ts-expect-error + if (target.tagName === "CODE") { + isInsideCode = true; + break; + } + // @ts-expect-error + target = target.parentElement; + } + if (!isInsideCode) { + return; + } + const selection = document.getSelection(); + // @ts-expect-error + nonnull(event.clipboardData).setData("text/plain", selection.toString()); + event.preventDefault(); + }); +}()); From 2f4a55b41d437e5496a51cf7ba0e7a0b751bc6ad Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 31 May 2025 17:32:49 -0700 Subject: [PATCH 278/356] compiler: plug unsupported ABI leakage from the AST We modify rustc_ast_lowering to prevent all unsupported ABIs from leaking through the HIR without being checked for target support. Previously ad-hoc checking on various HIR items required making sure we check every HIR item which could contain an `extern "{abi}"` string. This is a losing proposition compared to gating the lowering itself. As a consequence, unsupported ABI strings will now hard-error instead of triggering the FCW `unsupported_fn_ptr_calling_conventions`. This FCW was upgraded to warn in dependencies in Rust 1.87 which was released on 2025 May 17, and it is now 2025 June, so it has become active within a stable Rust version. As we already had errored on these ABIs in most other positions, and have warned for fn ptrs, this breakage has had reasonable foreshadowing. However, this does cause errors for usages of `extern "{abi}"` that were theoretically writeable within source but could not actually be applied in any useful way by Rust programmers without either warning or error. For instance, trait declarations without impls were never checked. These are the exact kinds of leakages that this new approach prevents. A deprecation cycle is not useful for these marginal cases as upon impl, even default impls within traits, different HIR objects would be used. Details of our HIR analysis meant that those objects did get checked. We choose to error twice if an ABI is also barred by a feature gate on the presumption that usage of a target-incorrect ABI is intentional. Co-authored-by: Ralf Jung --- compiler/rustc_ast_lowering/src/item.rs | 28 +++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ef27d0ef69b1..8acb51057730 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,7 +2,7 @@ use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; @@ -1644,9 +1644,29 @@ impl<'hir> LoweringContext<'_, 'hir> { self.error_on_invalid_abi(abi_str); ExternAbi::Rust }); - let sess = self.tcx.sess; - let features = self.tcx.features(); - gate_unstable_abi(sess, features, span, extern_abi); + let tcx = self.tcx; + + // we can't do codegen for unsupported ABIs, so error now so we won't get farther + if !tcx.sess.target.is_abi_supported(extern_abi) { + let mut err = struct_span_code_err!( + tcx.dcx(), + span, + E0570, + "{extern_abi} is not a supported ABI for the current target", + ); + + if let ExternAbi::Stdcall { unwind } = extern_abi { + let c_abi = ExternAbi::C { unwind }; + let system_abi = ExternAbi::System { unwind }; + err.help(format!("if you need `extern {extern_abi}` on win32 and `extern {c_abi}` everywhere else, \ + use `extern {system_abi}`" + )); + } + err.emit(); + } + // Show required feature gate even if we already errored, as the user is likely to build the code + // for the actually intended target next and then they will need the feature gate. + gate_unstable_abi(tcx.sess, tcx.features(), span, extern_abi); extern_abi } From e93a99b3243e1864bab279476f935d944a2229eb Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 13 Jun 2025 12:47:29 -0700 Subject: [PATCH 279/356] hir_analysis: Avoid repeating unsupported ABI errors --- compiler/rustc_hir_analysis/src/check/check.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 60b691e0f751..ea570f127213 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -58,15 +58,9 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) { AbiMapping::Direct(..) => (), + // already erred in rustc_ast_lowering AbiMapping::Invalid => { - let mut err = struct_span_code_err!( - tcx.dcx(), - span, - E0570, - "`{abi}` is not a supported ABI for the current target", - ); - add_abi_diag_help(abi, &mut err); - err.emit(); + tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering")); } AbiMapping::Deprecated(..) => { tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { From b34c52043f8df344b32789e0a4b26fd0f9965643 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 13:04:03 -0700 Subject: [PATCH 280/356] compiler: Remove unsupported_fn_ptr_calling_conventions lint --- .../rustc_hir_analysis/src/check/check.rs | 28 ++----------------- compiler/rustc_hir_analysis/src/check/mod.rs | 4 +-- .../src/hir_ty_lowering/mod.rs | 4 +-- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint_defs/src/builtin.rs | 1 - 5 files changed, 7 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index ea570f127213..40e08dcdb55c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,7 +1,7 @@ use std::cell::LazyCell; use std::ops::ControlFlow; -use rustc_abi::FieldIdx; +use rustc_abi::{ExternAbi, FieldIdx}; use rustc_attr_data_structures::ReprAttr::ReprPacked; use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::unord::{UnordMap, UnordSet}; @@ -13,7 +13,6 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode}; use rustc_lint_defs::builtin::{ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS, - UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, }; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; @@ -71,30 +70,6 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi } } -pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) { - // This is always an FCW, even for `AbiMapping::Invalid`, since we started linting later than - // in `check_abi` above. - match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) { - AbiMapping::Direct(..) => (), - // This is not a redundant match arm: these ABIs started linting after introducing - // UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS already existed and we want to - // avoid expanding the scope of that lint so it can move to a hard error sooner. - AbiMapping::Deprecated(..) => { - tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.primary_message("use of calling convention not supported on this target"); - add_abi_diag_help(abi, lint); - }); - } - AbiMapping::Invalid => { - tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.primary_message(format!( - "the calling convention {abi} is not supported on this target" - )); - }); - } - } -} - pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) { if fn_sig.abi == ExternAbi::Custom { // Function definitions that use `extern "custom"` must be naked functions. @@ -862,6 +837,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let hir::ItemKind::ForeignMod { abi, items } = it.kind else { return; }; + check_abi(tcx, it.hir_id(), it.span, abi); for item in items { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index bf2d4f662efe..5cec3331bb19 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -72,8 +72,8 @@ pub mod wfcheck; use std::num::NonZero; -pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi}; -use rustc_abi::{ExternAbi, VariantIdx}; +pub use check::{check_abi, check_custom_abi}; +use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::LangItem; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index b99f7b44661e..baf3b9b5bc9e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; -use crate::check::check_abi_fn_ptr; +use crate::check::check_abi; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; @@ -2660,7 +2660,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(bare_fn_ty), span, .. }) = tcx.hir_node(hir_id) { - check_abi_fn_ptr(tcx, hir_id, *span, bare_fn_ty.abi); + check_abi(tcx, hir_id, *span, bare_fn_ty.abi); } // reject function types that violate cmse ABI requirements diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 20568f35a471..48982bda0a08 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -608,6 +608,7 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see issue #127323 \ for more information", ); + store.register_removed("unsupported_fn_ptr_calling_conventions", "converted into hard error"); store.register_removed( "undefined_naked_function_abi", "converted into hard error, see PR #139001 \ diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b0ea9689e50d..5fa00fcc4a0c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -122,7 +122,6 @@ declare_lint_pass! { UNSAFE_OP_IN_UNSAFE_FN, UNSTABLE_NAME_COLLISIONS, UNSTABLE_SYNTAX_PRE_EXPANSION, - UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, UNUSED_ASSIGNMENTS, UNUSED_ASSOCIATED_TYPE_BOUNDS, UNUSED_ATTRIBUTES, From 267ecd132bbafc2651bfa69cd8bdb958d677132b Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 12 Jun 2025 09:56:29 -0700 Subject: [PATCH 281/356] Clarify note in rustc_ast_lowering still applies Co-authored-by: Ralf Jung --- compiler/rustc_hir_analysis/src/check/check.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 40e08dcdb55c..0bdccb02a71b 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -52,8 +52,9 @@ fn add_abi_diag_help(abi: ExternAbi, diag: &mut Diag<'_, T } pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) { - // FIXME: this should be checked earlier, e.g. in `rustc_ast_lowering`, to fix - // things like #86232. + // FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this + // currently only guards function imports, function definitions, and function pointer types. + // Functions in trait declarations can still use "deprecated" ABIs without any warning. match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) { AbiMapping::Direct(..) => (), From 7c6b50cd5be12fcf3cb97f1cd041f1f4d7fb242f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Jun 2025 17:50:51 +0200 Subject: [PATCH 282/356] unsupported_calling_conventions: print which ABI this is about --- compiler/rustc_hir_analysis/src/check/check.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0bdccb02a71b..485dd1d22044 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -64,7 +64,9 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi } AbiMapping::Deprecated(..) => { tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.primary_message("use of calling convention not supported on this target"); + lint.primary_message(format!( + "{abi} is not a supported ABI for the current target" + )); add_abi_diag_help(abi, lint); }); } From a69aeaf1e3f4dd530763850d1ae91291e6245c95 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 1 Jun 2025 13:38:02 -0700 Subject: [PATCH 283/356] tests: Bless abi_gpu_kernel feature gate test --- .../feature-gate-abi_gpu_kernel.AMDGPU.stderr | 8 +- .../feature-gate-abi_gpu_kernel.HOST.stderr | 103 ++++++++---------- .../feature-gate-abi_gpu_kernel.NVPTX.stderr | 8 +- .../feature-gate-abi_gpu_kernel.rs | 4 +- 4 files changed, 57 insertions(+), 66 deletions(-) diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr index fca32c5c1e6f..4fa3fee942ea 100644 --- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.AMDGPU.stderr @@ -19,7 +19,7 @@ LL | extern "gpu-kernel" fn m1(_: ()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:24:12 | LL | extern "gpu-kernel" fn dm1(_: ()) {} | ^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | extern "gpu-kernel" fn dm1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12 | LL | extern "gpu-kernel" fn m1(_: ()) {} | ^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | extern "gpu-kernel" fn m1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:38:12 | LL | extern "gpu-kernel" fn im1(_: ()) {} | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | extern "gpu-kernel" fn im1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 + --> $DIR/feature-gate-abi_gpu_kernel.rs:43:18 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr index cc81289f6b78..88734bc9d225 100644 --- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.HOST.stderr @@ -1,3 +1,9 @@ +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8 + | +LL | extern "gpu-kernel" fn f1(_: ()) {} + | ^^^^^^^^^^^^ + error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change --> $DIR/feature-gate-abi_gpu_kernel.rs:16:8 | @@ -8,6 +14,12 @@ LL | extern "gpu-kernel" fn f1(_: ()) {} = help: add `#![feature(abi_gpu_kernel)]` 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[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12 + | +LL | extern "gpu-kernel" fn m1(_: ()); + | ^^^^^^^^^^^^ + error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change --> $DIR/feature-gate-abi_gpu_kernel.rs:21:12 | @@ -18,8 +30,14 @@ LL | extern "gpu-kernel" fn m1(_: ()); = help: add `#![feature(abi_gpu_kernel)]` 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[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/feature-gate-abi_gpu_kernel.rs:24:12 + | +LL | extern "gpu-kernel" fn dm1(_: ()) {} + | ^^^^^^^^^^^^ + error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:24:12 | LL | extern "gpu-kernel" fn dm1(_: ()) {} | ^^^^^^^^^^^^ @@ -28,8 +46,14 @@ LL | extern "gpu-kernel" fn dm1(_: ()) {} = help: add `#![feature(abi_gpu_kernel)]` 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[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12 + | +LL | extern "gpu-kernel" fn m1(_: ()) {} + | ^^^^^^^^^^^^ + error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12 | LL | extern "gpu-kernel" fn m1(_: ()) {} | ^^^^^^^^^^^^ @@ -38,8 +62,14 @@ LL | extern "gpu-kernel" fn m1(_: ()) {} = help: add `#![feature(abi_gpu_kernel)]` 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[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/feature-gate-abi_gpu_kernel.rs:38:12 + | +LL | extern "gpu-kernel" fn im1(_: ()) {} + | ^^^^^^^^^^^^ + error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:38:12 | LL | extern "gpu-kernel" fn im1(_: ()) {} | ^^^^^^^^^^^^ @@ -48,8 +78,14 @@ LL | extern "gpu-kernel" fn im1(_: ()) {} = help: add `#![feature(abi_gpu_kernel)]` 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[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/feature-gate-abi_gpu_kernel.rs:43:18 + | +LL | type A1 = extern "gpu-kernel" fn(_: ()); + | ^^^^^^^^^^^^ + error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 + --> $DIR/feature-gate-abi_gpu_kernel.rs:43:18 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^ @@ -58,6 +94,12 @@ LL | type A1 = extern "gpu-kernel" fn(_: ()); = help: add `#![feature(abi_gpu_kernel)]` 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[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8 + | +LL | extern "gpu-kernel" {} + | ^^^^^^^^^^^^ + error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change --> $DIR/feature-gate-abi_gpu_kernel.rs:47:8 | @@ -68,58 +110,7 @@ LL | extern "gpu-kernel" {} = help: add `#![feature(abi_gpu_kernel)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: the calling convention "gpu-kernel" is not supported on this target - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11 - | -LL | type A1 = extern "gpu-kernel" fn(_: ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:47:1 - | -LL | extern "gpu-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:16:1 - | -LL | extern "gpu-kernel" fn f1(_: ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:23:5 - | -LL | extern "gpu-kernel" fn dm1(_: ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:31:5 - | -LL | extern "gpu-kernel" fn m1(_: ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:5 - | -LL | extern "gpu-kernel" fn im1(_: ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 12 previous errors; 1 warning emitted +error: aborting due to 14 previous errors Some errors have detailed explanations: E0570, E0658. For more information about an error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "gpu-kernel" is not supported on this target - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:11 - | -LL | type A1 = extern "gpu-kernel" fn(_: ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr index fca32c5c1e6f..4fa3fee942ea 100644 --- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.NVPTX.stderr @@ -19,7 +19,7 @@ LL | extern "gpu-kernel" fn m1(_: ()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:23:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:24:12 | LL | extern "gpu-kernel" fn dm1(_: ()) {} | ^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | extern "gpu-kernel" fn dm1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:31:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:32:12 | LL | extern "gpu-kernel" fn m1(_: ()) {} | ^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | extern "gpu-kernel" fn m1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:37:12 + --> $DIR/feature-gate-abi_gpu_kernel.rs:38:12 | LL | extern "gpu-kernel" fn im1(_: ()) {} | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | extern "gpu-kernel" fn im1(_: ()) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the extern "gpu-kernel" ABI is experimental and subject to change - --> $DIR/feature-gate-abi_gpu_kernel.rs:42:18 + --> $DIR/feature-gate-abi_gpu_kernel.rs:43:18 | LL | type A1 = extern "gpu-kernel" fn(_: ()); | ^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs index 7b1ee681dd7e..988fbd83afcc 100644 --- a/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs +++ b/tests/ui/feature-gates/feature-gate-abi_gpu_kernel.rs @@ -19,6 +19,7 @@ extern "gpu-kernel" fn f1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental a // Methods in trait definition trait Tr { extern "gpu-kernel" fn m1(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change + //[HOST]~^ ERROR is not a supported ABI extern "gpu-kernel" fn dm1(_: ()) {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change //[HOST]~^ ERROR is not a supported ABI @@ -40,8 +41,7 @@ impl S { // Function pointer types type A1 = extern "gpu-kernel" fn(_: ()); //~ ERROR "gpu-kernel" ABI is experimental and subject to change -//[HOST]~^ WARNING the calling convention "gpu-kernel" is not supported on this target [unsupported_fn_ptr_calling_conventions] -//[HOST]~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//[HOST]~^ ERROR is not a supported ABI // Foreign modules extern "gpu-kernel" {} //~ ERROR "gpu-kernel" ABI is experimental and subject to change From 7e35b284e12c7174a77ed24952cfd1f13eb1bb6d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 13 Jun 2025 12:37:55 -0700 Subject: [PATCH 284/356] tests: Enhance unsupported ABI tests We have fairly different error messages now and handle more cases, so we augment the test in tests/ui/abi/unsupported.rs with more examples to handle structs, traits, and impls on same when those feature the unsupported ABIs of interest. --- tests/crashes/132430.rs | 10 - tests/ui/abi/unsupported.aarch64.stderr | 505 +++++++++--------------- tests/ui/abi/unsupported.arm.stderr | 467 +++++++++------------- tests/ui/abi/unsupported.i686.stderr | 309 +++++---------- tests/ui/abi/unsupported.riscv32.stderr | 471 +++++++++------------- tests/ui/abi/unsupported.riscv64.stderr | 471 +++++++++------------- tests/ui/abi/unsupported.rs | 65 +-- tests/ui/abi/unsupported.x64.stderr | 421 ++++++++------------ tests/ui/abi/unsupported.x64_win.stderr | 383 +++++++----------- 9 files changed, 1171 insertions(+), 1931 deletions(-) delete mode 100644 tests/crashes/132430.rs diff --git a/tests/crashes/132430.rs b/tests/crashes/132430.rs deleted file mode 100644 index 81c8c6d6f7d3..000000000000 --- a/tests/crashes/132430.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #132430 - -//@ compile-flags: --crate-type=lib -//@ edition: 2018 -#![feature(cmse_nonsecure_entry)] -struct Test; - -impl Test { - pub async unsafe extern "C-cmse-nonsecure-entry" fn test(val: &str) {} -} diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 7b9b9d5c978c..d2970cb4dd96 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -1,136 +1,235 @@ -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:36:8 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:38:22 | LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^ -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44:8 + | +LL | extern "gpu-kernel" fn gpu() {} + | ^^^^^^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:47:8 + | +LL | extern "aapcs" fn aapcs() {} + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:49:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^ -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:55:1 +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" {} - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:56:8 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:58:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:8 | LL | extern "msp430-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:65:8 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:67:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 | LL | extern "avr-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:74:8 + | +LL | extern "riscv-interrupt-m" fn riscv() {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:24 | LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:81:8 | LL | extern "riscv-interrupt-m" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:91:15 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:84:8 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:91:8 | LL | extern "x86-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:94:8 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:96:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^ -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:1 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:100:8 | LL | extern "thiscall" {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:103:8 | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 - | -LL | extern "stdcall" {} - | ^^^^^^^^^^^^^^^^^^^ +LL | extern "stdcall" fn stdcall() {} + | ^^^^^^^^^ | = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` -error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:1 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:107:26 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:113:8 + | +LL | extern "stdcall" {} + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:117:8 | LL | extern "stdcall-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:133:17 +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:137:8 + | +LL | extern "vectorcall" fn vectorcall() {} + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:139:29 + | +LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:143:8 + | +LL | extern "vectorcall" {} + | ^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:28 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:151:8 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:153:29 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:157:8 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:167:17 + | +LL | ptr: extern "thiscall" fn(), + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:172:16 + | +LL | pub extern "thiscall" fn inherent_fn(self) { + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:179:12 + | +LL | extern "thiscall" fn trait_fn(self); + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:184:12 + | +LL | extern "thiscall" fn trait_fn(self) { + | ^^^^^^^^^^ + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:125:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -140,8 +239,8 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` on by default -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:138:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -150,8 +249,8 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:141:1 +warning: "cdecl-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:133:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,103 +259,8 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:147:22 - | -LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:152:1 - | -LL | extern "vectorcall" {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:168:1 - | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 - | -LL | extern "ptx-kernel" fn ptx() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 - | -LL | extern "gpu-kernel" fn gpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 - | -LL | extern "aapcs" fn aapcs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:1 - | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:68:1 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:1 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:89:1 - | -LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:1 - | -LL | extern "thiscall" fn thiscall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:110:1 - | -LL | extern "stdcall" fn stdcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:130:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:122:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -265,139 +269,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:145:1 - | -LL | extern "vectorcall" fn vectorcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:161:1 - | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 22 previous errors; 15 warnings emitted +error: aborting due to 37 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 - | -LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 - | -LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:91:15 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 - | -LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 - | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:147:22 - | -LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 5b057bdcbaeb..543abe703d67 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -1,121 +1,217 @@ -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:36:8 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:38:22 | LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^ -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44:8 + | +LL | extern "gpu-kernel" fn gpu() {} + | ^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:56:8 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:58:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:8 | LL | extern "msp430-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:65:8 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:67:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 | LL | extern "avr-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:74:8 + | +LL | extern "riscv-interrupt-m" fn riscv() {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:24 | LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:81:8 | LL | extern "riscv-interrupt-m" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:91:15 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:84:8 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:91:8 | LL | extern "x86-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:94:8 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:96:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^ -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:1 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:100:8 | LL | extern "thiscall" {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:103:8 | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 - | -LL | extern "stdcall" {} - | ^^^^^^^^^^^^^^^^^^^ +LL | extern "stdcall" fn stdcall() {} + | ^^^^^^^^^ | = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` -error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:1 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:107:26 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:113:8 + | +LL | extern "stdcall" {} + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:117:8 | LL | extern "stdcall-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:133:17 +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:137:8 + | +LL | extern "vectorcall" fn vectorcall() {} + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:139:29 + | +LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:143:8 + | +LL | extern "vectorcall" {} + | ^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:28 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:151:8 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:153:29 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:157:8 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:167:17 + | +LL | ptr: extern "thiscall" fn(), + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:172:16 + | +LL | pub extern "thiscall" fn inherent_fn(self) { + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:179:12 + | +LL | extern "thiscall" fn trait_fn(self); + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:184:12 + | +LL | extern "thiscall" fn trait_fn(self) { + | ^^^^^^^^^^ + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:125:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -125,8 +221,8 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` on by default -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:138:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -135,8 +231,8 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:141:1 +warning: "cdecl-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:133:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,97 +241,8 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:147:22 - | -LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:152:1 - | -LL | extern "vectorcall" {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:168:1 - | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 - | -LL | extern "ptx-kernel" fn ptx() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 - | -LL | extern "gpu-kernel" fn gpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:1 - | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:68:1 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:1 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:89:1 - | -LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:1 - | -LL | extern "thiscall" fn thiscall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:110:1 - | -LL | extern "stdcall" fn stdcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:130:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:122:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,128 +251,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:145:1 - | -LL | extern "vectorcall" fn vectorcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:161:1 - | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 20 previous errors; 14 warnings emitted +error: aborting due to 34 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 - | -LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:91:15 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 - | -LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 - | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:147:22 - | -LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 568841660199..2939ae10b0e2 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -1,234 +1,135 @@ -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 - | -LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 - | -LL | extern "ptx-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 - | -LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:55:1 - | -LL | extern "aapcs" {} - | ^^^^^^^^^^^^^^^^^ - -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:1 - | -LL | extern "msp430-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:1 - | -LL | extern "avr-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:1 - | -LL | extern "riscv-interrupt-m" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:168:1 - | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:36:8 | LL | extern "ptx-kernel" fn ptx() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:38:22 + | +LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^ + +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44:8 | LL | extern "gpu-kernel" fn gpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:47:8 | LL | extern "aapcs" fn aapcs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^ -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:1 +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:49:24 + | +LL | fn aapcs_ptr(f: extern "aapcs" fn()) { + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:53:8 + | +LL | extern "aapcs" {} + | ^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:56:8 | LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:68:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:58:25 + | +LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:8 + | +LL | extern "msp430-interrupt" {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:65:8 | LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:67:22 + | +LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 + | +LL | extern "avr-interrupt" {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:74:8 | LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:24 + | +LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:81:8 + | +LL | extern "riscv-interrupt-m" {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:28 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:151:8 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:153:29 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:157:8 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/unsupported.rs:94:5 + --> $DIR/unsupported.rs:88:5 | LL | f() | ^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/unsupported.rs:94:5 + --> $DIR/unsupported.rs:88:5 | LL | f() | ^^^ -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:161:1 - | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 14 previous errors; 7 warnings emitted +error: aborting due to 21 previous errors For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 - | -LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 - | -LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index 124ba13cc236..ead32f573d73 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -1,121 +1,217 @@ -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:36:8 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:38:22 | LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^ -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44:8 + | +LL | extern "gpu-kernel" fn gpu() {} + | ^^^^^^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:47:8 + | +LL | extern "aapcs" fn aapcs() {} + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:49:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^ -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:55:1 +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" {} - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:56:8 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:58:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:8 | LL | extern "msp430-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:65:8 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:67:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 | LL | extern "avr-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:91:15 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:84:8 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:91:8 | LL | extern "x86-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:94:8 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:96:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^ -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:1 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:100:8 | LL | extern "thiscall" {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:103:8 | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 - | -LL | extern "stdcall" {} - | ^^^^^^^^^^^^^^^^^^^ +LL | extern "stdcall" fn stdcall() {} + | ^^^^^^^^^ | = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` -error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:1 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:107:26 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:113:8 + | +LL | extern "stdcall" {} + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:117:8 | LL | extern "stdcall-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:133:17 +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:137:8 + | +LL | extern "vectorcall" fn vectorcall() {} + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:139:29 + | +LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:143:8 + | +LL | extern "vectorcall" {} + | ^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:28 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:151:8 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:153:29 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:157:8 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:167:17 + | +LL | ptr: extern "thiscall" fn(), + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:172:16 + | +LL | pub extern "thiscall" fn inherent_fn(self) { + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:179:12 + | +LL | extern "thiscall" fn trait_fn(self); + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:184:12 + | +LL | extern "thiscall" fn trait_fn(self) { + | ^^^^^^^^^^ + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:125:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -125,8 +221,8 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` on by default -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:138:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -135,8 +231,8 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:141:1 +warning: "cdecl-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:133:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,109 +241,20 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:147:22 - | -LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:152:1 - | -LL | extern "vectorcall" {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:168:1 - | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 - | -LL | extern "ptx-kernel" fn ptx() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 - | -LL | extern "gpu-kernel" fn gpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 - | -LL | extern "aapcs" fn aapcs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:1 - | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:68:1 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/unsupported.rs:83:5 + --> $DIR/unsupported.rs:78:5 | LL | f() | ^^^ | note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/unsupported.rs:83:5 + --> $DIR/unsupported.rs:78:5 | LL | f() | ^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:89:1 - | -LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:1 - | -LL | extern "thiscall" fn thiscall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:110:1 - | -LL | extern "stdcall" fn stdcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:130:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:122:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -256,128 +263,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:145:1 - | -LL | extern "vectorcall" fn vectorcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:161:1 - | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 21 previous errors; 14 warnings emitted +error: aborting due to 35 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 - | -LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 - | -LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:91:15 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 - | -LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 - | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:147:22 - | -LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index 124ba13cc236..ead32f573d73 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -1,121 +1,217 @@ -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:36:8 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:38:22 | LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^ -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44:8 + | +LL | extern "gpu-kernel" fn gpu() {} + | ^^^^^^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:47:8 + | +LL | extern "aapcs" fn aapcs() {} + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:49:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^ -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:55:1 +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" {} - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:56:8 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:58:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:8 | LL | extern "msp430-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:65:8 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:67:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 | LL | extern "avr-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:91:15 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:84:8 + | +LL | extern "x86-interrupt" fn x86() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:86:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:91:8 | LL | extern "x86-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:94:8 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:96:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^ -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:1 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:100:8 | LL | extern "thiscall" {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:103:8 | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 - | -LL | extern "stdcall" {} - | ^^^^^^^^^^^^^^^^^^^ +LL | extern "stdcall" fn stdcall() {} + | ^^^^^^^^^ | = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` -error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:1 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:107:26 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:113:8 + | +LL | extern "stdcall" {} + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:117:8 | LL | extern "stdcall-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:133:17 +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:137:8 + | +LL | extern "vectorcall" fn vectorcall() {} + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:139:29 + | +LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:143:8 + | +LL | extern "vectorcall" {} + | ^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:28 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:151:8 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:153:29 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:157:8 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:167:17 + | +LL | ptr: extern "thiscall" fn(), + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:172:16 + | +LL | pub extern "thiscall" fn inherent_fn(self) { + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:179:12 + | +LL | extern "thiscall" fn trait_fn(self); + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:184:12 + | +LL | extern "thiscall" fn trait_fn(self) { + | ^^^^^^^^^^ + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:125:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -125,8 +221,8 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` on by default -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:138:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -135,8 +231,8 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:141:1 +warning: "cdecl-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:133:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,109 +241,20 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:147:22 - | -LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:152:1 - | -LL | extern "vectorcall" {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:168:1 - | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 - | -LL | extern "ptx-kernel" fn ptx() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 - | -LL | extern "gpu-kernel" fn gpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 - | -LL | extern "aapcs" fn aapcs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:1 - | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:68:1 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/unsupported.rs:83:5 + --> $DIR/unsupported.rs:78:5 | LL | f() | ^^^ | note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/unsupported.rs:83:5 + --> $DIR/unsupported.rs:78:5 | LL | f() | ^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:89:1 - | -LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:1 - | -LL | extern "thiscall" fn thiscall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:110:1 - | -LL | extern "stdcall" fn stdcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:130:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:122:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -256,128 +263,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:145:1 - | -LL | extern "vectorcall" fn vectorcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:161:1 - | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 21 previous errors; 14 warnings emitted +error: aborting due to 35 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 - | -LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 - | -LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/unsupported.rs:91:15 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 - | -LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 - | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:147:22 - | -LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 4ddcbae409bc..98f9ccbd78cd 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -36,8 +36,7 @@ use minicore::*; extern "ptx-kernel" fn ptx() {} //~^ ERROR is not a supported ABI fn ptx_ptr(f: extern "ptx-kernel" fn()) { - //~^ WARN unsupported_fn_ptr_calling_conventions - //~^^ WARN this was previously accepted +//~^ ERROR is not a supported ABI f() } extern "ptx-kernel" {} @@ -48,8 +47,7 @@ extern "gpu-kernel" fn gpu() {} extern "aapcs" fn aapcs() {} //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI fn aapcs_ptr(f: extern "aapcs" fn()) { - //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions - //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted + //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI f() } extern "aapcs" {} @@ -58,8 +56,7 @@ extern "aapcs" {} extern "msp430-interrupt" fn msp430() {} //~^ ERROR is not a supported ABI fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - //~^ WARN unsupported_fn_ptr_calling_conventions - //~^^ WARN this was previously accepted +//~^ ERROR is not a supported ABI f() } extern "msp430-interrupt" {} @@ -68,8 +65,7 @@ extern "msp430-interrupt" {} extern "avr-interrupt" fn avr() {} //~^ ERROR is not a supported ABI fn avr_ptr(f: extern "avr-interrupt" fn()) { - //~^ WARN unsupported_fn_ptr_calling_conventions - //~^^ WARN this was previously accepted +//~^ ERROR is not a supported ABI f() } extern "avr-interrupt" {} @@ -78,8 +74,7 @@ extern "avr-interrupt" {} extern "riscv-interrupt-m" fn riscv() {} //[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - //[x64,x64_win,i686,arm,aarch64]~^ WARN unsupported_fn_ptr_calling_conventions - //[x64,x64_win,i686,arm,aarch64]~^^ WARN this was previously accepted + //[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI f() //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called } @@ -89,8 +84,7 @@ extern "riscv-interrupt-m" {} extern "x86-interrupt" fn x86() {} //[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI fn x86_ptr(f: extern "x86-interrupt" fn()) { - //[aarch64,arm,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions - //[aarch64,arm,riscv32,riscv64]~^^ WARN this was previously accepted + //[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI f() //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called } @@ -100,8 +94,7 @@ extern "x86-interrupt" {} extern "thiscall" fn thiscall() {} //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI fn thiscall_ptr(f: extern "thiscall" fn()) { - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted + //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI f() } extern "thiscall" {} @@ -112,10 +105,9 @@ extern "stdcall" fn stdcall() {} //[x64_win]~^^ WARN unsupported_calling_conventions //[x64_win]~^^^ WARN this was previously accepted fn stdcall_ptr(f: extern "stdcall" fn()) { - //[x64_win]~^ WARN unsupported_calling_conventions - //[x64_win]~| WARN this was previously accepted - //[x64,arm,aarch64,riscv32,riscv64]~^^^ WARN unsupported_fn_ptr_calling_conventions - //[x64,arm,aarch64,riscv32,riscv64]~| WARN this was previously accepted + //[x64,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI + //[x64_win]~^^ WARN unsupported_calling_conventions + //[x64_win]~| WARN this was previously accepted f() } extern "stdcall" {} @@ -132,7 +124,7 @@ extern "cdecl" fn cdecl() {} //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted fn cdecl_ptr(f: extern "cdecl" fn()) { //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_calling_conventions - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted + //[x64,x64_win,arm,aarch64,riscv32,riscv64]~| WARN this was previously accepted f() } extern "cdecl" {} @@ -145,24 +137,21 @@ extern "cdecl-unwind" {} extern "vectorcall" fn vectorcall() {} //[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI fn vectorcall_ptr(f: extern "vectorcall" fn()) { - //[arm,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions - //[arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted + //[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI f() } extern "vectorcall" {} //[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - //~^ WARN unsupported_fn_ptr_calling_conventions - //~^^ WARN this was previously accepted +//~^ ERROR is not a supported ABI f() } extern "C-cmse-nonsecure-entry" fn cmse_entry() {} //~^ ERROR is not a supported ABI fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - //~^ WARN unsupported_fn_ptr_calling_conventions - //~^^ WARN this was previously accepted +//~^ ERROR is not a supported ABI f() } extern "C-cmse-nonsecure-entry" {} @@ -171,5 +160,29 @@ extern "C-cmse-nonsecure-entry" {} #[cfg(windows)] #[link(name = "foo", kind = "raw-dylib")] extern "cdecl" {} -//[x64_win]~^ WARN use of calling convention not supported on this target +//[x64_win]~^ WARN unsupported_calling_conventions //[x64_win]~^^ WARN this was previously accepted + +struct FnPtrBearer { + ptr: extern "thiscall" fn(), + //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI +} + +impl FnPtrBearer { + pub extern "thiscall" fn inherent_fn(self) { + //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI + (self.ptr)() + } +} + +trait Trait { + extern "thiscall" fn trait_fn(self); + //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI +} + +impl Trait for FnPtrBearer { + extern "thiscall" fn trait_fn(self) { + //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI + self.inherent_fn() + } +} diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 737c4c670b83..3888bc00a968 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -1,121 +1,199 @@ -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:36:8 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:38:22 | LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^ -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44:8 + | +LL | extern "gpu-kernel" fn gpu() {} + | ^^^^^^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:47:8 + | +LL | extern "aapcs" fn aapcs() {} + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:49:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^ -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:55:1 +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" {} - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:56:8 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:58:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:8 | LL | extern "msp430-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:65:8 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:67:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 | LL | extern "avr-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:74:8 + | +LL | extern "riscv-interrupt-m" fn riscv() {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:24 | LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:81:8 | LL | extern "riscv-interrupt-m" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:94:8 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:96:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^ -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:1 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:100:8 | LL | extern "thiscall" {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:103:8 | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 - | -LL | extern "stdcall" {} - | ^^^^^^^^^^^^^^^^^^^ +LL | extern "stdcall" fn stdcall() {} + | ^^^^^^^^^ | = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` -error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:1 +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:107:26 + | +LL | fn stdcall_ptr(f: extern "stdcall" fn()) { + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:113:8 + | +LL | extern "stdcall" {} + | ^^^^^^^^^ + | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + +error[E0570]: "stdcall-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:117:8 | LL | extern "stdcall-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:133:17 +error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:28 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:151:8 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:153:29 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:157:8 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:167:17 + | +LL | ptr: extern "thiscall" fn(), + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:172:16 + | +LL | pub extern "thiscall" fn inherent_fn(self) { + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:179:12 + | +LL | extern "thiscall" fn trait_fn(self); + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:184:12 + | +LL | extern "thiscall" fn trait_fn(self) { + | ^^^^^^^^^^ + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:125:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -125,8 +203,8 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` on by default -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:138:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -135,8 +213,8 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:141:1 +warning: "cdecl-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:133:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,94 +223,20 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:168:1 - | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 - | -LL | extern "ptx-kernel" fn ptx() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 - | -LL | extern "gpu-kernel" fn gpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 - | -LL | extern "aapcs" fn aapcs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:1 - | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:68:1 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:1 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/unsupported.rs:94:5 + --> $DIR/unsupported.rs:88:5 | LL | f() | ^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/unsupported.rs:94:5 + --> $DIR/unsupported.rs:88:5 | LL | f() | ^^^ -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:1 - | -LL | extern "thiscall" fn thiscall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:110:1 - | -LL | extern "stdcall" fn stdcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:130:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:122:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,111 +245,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:161:1 - | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 19 previous errors; 13 warnings emitted +error: aborting due to 32 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 - | -LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 - | -LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 - | -LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:114:19 - | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index f201a089d3f9..d093ae86b9f6 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -1,96 +1,167 @@ -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:36:8 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:38:22 | LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^ -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44:8 + | +LL | extern "gpu-kernel" fn gpu() {} + | ^^^^^^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:47:8 + | +LL | extern "aapcs" fn aapcs() {} + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:49:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^ -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:55:1 +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" {} - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:56:8 + | +LL | extern "msp430-interrupt" fn msp430() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:58:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:62:8 | LL | extern "msp430-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:65:8 + | +LL | extern "avr-interrupt" fn avr() {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:67:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 | LL | extern "avr-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:74:8 + | +LL | extern "riscv-interrupt-m" fn riscv() {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:24 | LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:81:8 | LL | extern "riscv-interrupt-m" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:94:8 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:96:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 + | ^^^^^^^^^^ -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:1 +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:100:8 | LL | extern "thiscall" {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:114:19 +error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:28 + | +LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:151:8 + | +LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:153:29 + | +LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:157:8 + | +LL | extern "C-cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:167:17 + | +LL | ptr: extern "thiscall" fn(), + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:172:16 + | +LL | pub extern "thiscall" fn inherent_fn(self) { + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:179:12 + | +LL | extern "thiscall" fn trait_fn(self); + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:184:12 + | +LL | extern "thiscall" fn trait_fn(self) { + | ^^^^^^^^^^ + +warning: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:107:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -100,8 +171,8 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = note: `#[warn(unsupported_calling_conventions)]` on by default -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:121:1 +warning: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:113:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -110,8 +181,8 @@ LL | extern "stdcall" {} = note: for more information, see issue #137018 = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:125:1 +warning: "stdcall-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:117:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,8 +191,8 @@ LL | extern "stdcall-unwind" {} = note: for more information, see issue #137018 = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:133:17 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:125:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -130,8 +201,8 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: for more information, see issue #137018 = help: use `extern "C"` instead -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:138:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:130:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -140,8 +211,8 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:141:1 +warning: "cdecl-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:133:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -150,32 +221,8 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:168:1 - | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:173:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:162:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -184,62 +231,20 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 - | -LL | extern "ptx-kernel" fn ptx() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"gpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:1 - | -LL | extern "gpu-kernel" fn gpu() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:1 - | -LL | extern "aapcs" fn aapcs() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:1 - | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:68:1 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:1 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/unsupported.rs:94:5 + --> $DIR/unsupported.rs:88:5 | LL | f() | ^^^ | note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/unsupported.rs:94:5 + --> $DIR/unsupported.rs:88:5 | LL | f() | ^^^ -error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:1 - | -LL | extern "thiscall" fn thiscall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:110:1 +warning: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:103:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -248,8 +253,8 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #137018 = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:130:1 +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:122:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -258,100 +263,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:161:1 - | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 16 previous errors; 17 warnings emitted +error: aborting due to 28 previous errors; 9 warnings emitted For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "ptx-kernel" is not supported on this target - --> $DIR/unsupported.rs:38:15 - | -LL | fn ptx_ptr(f: extern "ptx-kernel" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "aapcs" is not supported on this target - --> $DIR/unsupported.rs:50:17 - | -LL | fn aapcs_ptr(f: extern "aapcs" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/unsupported.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/unsupported.rs:70:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/unsupported.rs:80:17 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "thiscall" is not supported on this target - --> $DIR/unsupported.rs:102:20 - | -LL | fn thiscall_ptr(f: extern "thiscall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:155:21 - | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:163:22 - | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - From a3a6d9bf71ace4b5011e4af318f5fb5dc23d19b4 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 13 Jun 2025 12:39:13 -0700 Subject: [PATCH 285/356] tests: Update raw-dylib unsupported ABI test --- tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs | 2 +- tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs index 9babc20d1a15..9ccc9ce4fdb8 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs @@ -11,7 +11,7 @@ extern crate minicore; #[link(name = "foo", kind = "raw-dylib")] extern "stdcall" { -//~^ WARN: calling convention not supported on this target +//~^ WARN: unsupported_calling_conventions //~| WARN: previously accepted fn f(x: i32); //~^ ERROR ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr index 95ea90804867..91e42f2909e0 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr @@ -1,4 +1,4 @@ -warning: use of calling convention not supported on this target +warning: "stdcall" is not a supported ABI for the current target --> $DIR/unsupported-abi.rs:13:1 | LL | / extern "stdcall" { From 0dd29e1a86683ec2ff439cd41c1a1765f617b520 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 1 Jun 2025 14:19:02 -0700 Subject: [PATCH 286/356] tests: Update and bless cmse-nonsecure ABI tests --- .../cmse-nonsecure-call/gate_test.rs | 4 ++-- .../cmse-nonsecure-call/gate_test.stderr | 23 ++++++++----------- .../cmse-nonsecure-entry/gate_test.rs | 4 ++-- .../cmse-nonsecure-entry/gate_test.stderr | 12 +++++----- .../trustzone-only.aarch64.stderr | 6 ++--- .../trustzone-only.thumb7.stderr | 6 ++--- .../trustzone-only.x86.stderr | 6 ++--- 7 files changed, 29 insertions(+), 32 deletions(-) diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs index 2d0ed5d2a307..40e2da8d1cd0 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs @@ -1,9 +1,9 @@ // gate-test-abi_c_cmse_nonsecure_call -#[allow(unsupported_fn_ptr_calling_conventions)] fn main() { let non_secure_function = unsafe { core::mem::transmute:: i32>( - //~^ ERROR [E0658] + //~^ ERROR: is not a supported ABI for the current target [E0570] + //~| ERROR: ABI is experimental and subject to change [E0658] 0x10000004, ) }; diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr index beb0ab70cc7e..dcbe09d8b365 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr @@ -1,5 +1,11 @@ +error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/gate_test.rs:4:46 + | +LL | core::mem::transmute:: i32>( + | ^^^^^^^^^^^^^^^^^^^^^^^ + error[E0658]: the extern "C-cmse-nonsecure-call" ABI is experimental and subject to change - --> $DIR/gate_test.rs:5:46 + --> $DIR/gate_test.rs:4:46 | LL | core::mem::transmute:: i32>( | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,16 +14,7 @@ LL | core::mem::transmute:: $DIR/gate_test.rs:5:39 - | -LL | core::mem::transmute:: i32>( - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 +error: aborting due to 2 previous errors +Some errors have detailed explanations: E0570, E0658. +For more information about an error, try `rustc --explain E0570`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs index 6061451b2e97..de68097e139c 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs @@ -2,8 +2,8 @@ #[no_mangle] pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - //~^ ERROR [E0570] - //~| ERROR [E0658] + //~^ ERROR: is not a supported ABI for the current target [E0570] + //~| ERROR: ABI is experimental and subject to change [E0658] input + 6 } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr index 0afbbe647af0..312f57591f97 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr @@ -1,3 +1,9 @@ +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/gate_test.rs:4:12 + | +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0658]: the extern "C-cmse-nonsecure-entry" ABI is experimental and subject to change --> $DIR/gate_test.rs:4:12 | @@ -8,12 +14,6 @@ LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { = help: add `#![feature(cmse_nonsecure_entry)]` 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[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/gate_test.rs:4:1 - | -LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: aborting due to 2 previous errors Some errors have detailed explanations: E0570, E0658. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr index 6a90dc8d635b..3072d3a3abfe 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr @@ -1,8 +1,8 @@ -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/trustzone-only.rs:17:1 +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/trustzone-only.rs:17:12 | LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr index 6a90dc8d635b..3072d3a3abfe 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr @@ -1,8 +1,8 @@ -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/trustzone-only.rs:17:1 +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/trustzone-only.rs:17:12 | LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr index 6a90dc8d635b..3072d3a3abfe 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr @@ -1,8 +1,8 @@ -error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/trustzone-only.rs:17:1 +error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/trustzone-only.rs:17:12 | LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error From 7632fab6689770d0f482851781e9735d7b8f5f5e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 1 Jun 2025 15:20:27 -0700 Subject: [PATCH 287/356] tests: Adopt ABI transmute tests from crashtests --- tests/auxiliary/minicore.rs | 7 +++++++ tests/crashes/138738.rs | 7 ------- tests/ui/abi/unsupported-abi-transmute.rs | 15 +++++++++++++++ tests/ui/abi/unsupported-abi-transmute.stderr | 9 +++++++++ 4 files changed, 31 insertions(+), 7 deletions(-) delete mode 100644 tests/crashes/138738.rs create mode 100644 tests/ui/abi/unsupported-abi-transmute.rs create mode 100644 tests/ui/abi/unsupported-abi-transmute.stderr diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index db11549382fc..3e9841b179cb 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -16,6 +16,7 @@ #![feature( no_core, + intrinsics, lang_items, auto_traits, freeze_impls, @@ -196,3 +197,9 @@ impl<'a, 'b: 'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<&'a trait Drop { fn drop(&mut self); } + +pub mod mem { + #[rustc_nounwind] + #[rustc_intrinsic] + pub unsafe fn transmute(src: Src) -> Dst; +} diff --git a/tests/crashes/138738.rs b/tests/crashes/138738.rs deleted file mode 100644 index 74e5effa56f5..000000000000 --- a/tests/crashes/138738.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #138738 -//@ only-x86_64 - -#![feature(abi_ptx)] -fn main() { - let a = unsafe { core::mem::transmute::(4) }(2); -} diff --git a/tests/ui/abi/unsupported-abi-transmute.rs b/tests/ui/abi/unsupported-abi-transmute.rs new file mode 100644 index 000000000000..31501bc6d108 --- /dev/null +++ b/tests/ui/abi/unsupported-abi-transmute.rs @@ -0,0 +1,15 @@ +//@ add-core-stubs +//@ compile-flags: --crate-type=lib --target x86_64-unknown-none +//@ needs-llvm-components: x86 +//@ edition: 2018 +#![no_core] +#![feature(no_core, lang_items)] +extern crate minicore; +use minicore::*; + +// Check we error before unsupported ABIs reach codegen stages. + +fn anything() { + let a = unsafe { mem::transmute::(4) }(2); + //~^ ERROR: is not a supported ABI for the current target [E0570] +} diff --git a/tests/ui/abi/unsupported-abi-transmute.stderr b/tests/ui/abi/unsupported-abi-transmute.stderr new file mode 100644 index 000000000000..63056180c71c --- /dev/null +++ b/tests/ui/abi/unsupported-abi-transmute.stderr @@ -0,0 +1,9 @@ +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported-abi-transmute.rs:13:53 + | +LL | let a = unsafe { mem::transmute::(4) }(2); + | ^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. From 78528bc0e69d57182cadd802ad099d381a0e2621 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 12:02:01 -0700 Subject: [PATCH 288/356] tests: Verify varargs with unsupported fn ptr ABIs must error --- tests/ui/abi/unsupported-varargs-fnptr.rs | 18 ++++++++++++++++++ tests/ui/abi/unsupported-varargs-fnptr.stderr | 9 +++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/ui/abi/unsupported-varargs-fnptr.rs create mode 100644 tests/ui/abi/unsupported-varargs-fnptr.stderr diff --git a/tests/ui/abi/unsupported-varargs-fnptr.rs b/tests/ui/abi/unsupported-varargs-fnptr.rs new file mode 100644 index 000000000000..733e16c7e4bd --- /dev/null +++ b/tests/ui/abi/unsupported-varargs-fnptr.rs @@ -0,0 +1,18 @@ +// FIXME(workingjubilee): add revisions and generalize to other platform-specific varargs ABIs, +// preferably after the only-arch directive is enhanced with an "or pattern" syntax +//@ only-x86_64 + +// We have to use this flag to force ABI computation of an invalid ABI +//@ compile-flags: -Clink-dead-code + +#![feature(extended_varargs_abi_support)] + +// sometimes fn ptrs with varargs make layout and ABI computation ICE +// as found in https://github.com/rust-lang/rust/issues/142107 + +fn aapcs(f: extern "aapcs" fn(usize, ...)) { +//~^ ERROR [E0570] +// Note we DO NOT have to actually make a call to trigger the ICE! +} + +fn main() {} diff --git a/tests/ui/abi/unsupported-varargs-fnptr.stderr b/tests/ui/abi/unsupported-varargs-fnptr.stderr new file mode 100644 index 000000000000..445e57df9d86 --- /dev/null +++ b/tests/ui/abi/unsupported-varargs-fnptr.stderr @@ -0,0 +1,9 @@ +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported-varargs-fnptr.rs:13:20 + | +LL | fn aapcs(f: extern "aapcs" fn(usize, ...)) { + | ^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. From aa25b9b116fd5f6e86ae01207c3b2e76104513fa Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 21 Jun 2025 12:15:15 -0700 Subject: [PATCH 289/356] tests: Bless cannot-be-called and dedup with unsupported ABI test --- tests/ui/abi/cannot-be-called.avr.stderr | 159 ++++++---------- tests/ui/abi/cannot-be-called.i686.stderr | 159 ++++++---------- tests/ui/abi/cannot-be-called.msp430.stderr | 159 ++++++---------- tests/ui/abi/cannot-be-called.riscv32.stderr | 181 +++++++------------ tests/ui/abi/cannot-be-called.riscv64.stderr | 181 +++++++------------ tests/ui/abi/cannot-be-called.rs | 30 +-- tests/ui/abi/cannot-be-called.x64.stderr | 159 ++++++---------- tests/ui/abi/cannot-be-called.x64_win.stderr | 159 ++++++---------- tests/ui/abi/unsupported.aarch64.stderr | 100 +++------- tests/ui/abi/unsupported.arm.stderr | 100 +++------- tests/ui/abi/unsupported.i686.stderr | 62 +------ tests/ui/abi/unsupported.riscv32.stderr | 98 +++------- tests/ui/abi/unsupported.riscv64.stderr | 98 +++------- tests/ui/abi/unsupported.rs | 26 --- tests/ui/abi/unsupported.x64.stderr | 92 +++------- tests/ui/abi/unsupported.x64_win.stderr | 94 +++------- 16 files changed, 562 insertions(+), 1295 deletions(-) diff --git a/tests/ui/abi/cannot-be-called.avr.stderr b/tests/ui/abi/cannot-be-called.avr.stderr index 64ce3efe52b2..a0f7f18f7011 100644 --- a/tests/ui/abi/cannot-be-called.avr.stderr +++ b/tests/ui/abi/cannot-be-called.avr.stderr @@ -1,132 +1,75 @@ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 - | -LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 - | -LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:88:15 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:36:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:8 | LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:1 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:1 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:46:8 | LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error: functions with the "avr-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:50:5 - | -LL | avr(); - | ^^^^^ - | -note: an `extern "avr-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:50:5 - | -LL | avr(); - | ^^^^^ - -error: functions with the "avr-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:70:5 - | -LL | f() - | ^^^ - | -note: an `extern "avr-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:70:5 - | -LL | f() - | ^^^ - -error: aborting due to 6 previous errors; 4 warnings emitted - -For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:65:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:77:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:83:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:88:15 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:89:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ +error: functions with the "avr-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:53:5 + | +LL | avr(); + | ^^^^^ + | +note: an `extern "avr-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:53:5 + | +LL | avr(); + | ^^^^^ + +error: functions with the "avr-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:73:5 + | +LL | f() + | ^^^ + | +note: an `extern "avr-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:73:5 + | +LL | f() + | ^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.i686.stderr b/tests/ui/abi/cannot-be-called.i686.stderr index 113b40eb67b8..f59fdba2f357 100644 --- a/tests/ui/abi/cannot-be-called.i686.stderr +++ b/tests/ui/abi/cannot-be-called.i686.stderr @@ -1,132 +1,75 @@ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 - | -LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 - | -LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:36:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:8 | LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:8 | LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:1 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:56:5 - | -LL | x86(); - | ^^^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:56:5 - | -LL | x86(); - | ^^^^^ - -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:91:5 - | -LL | f() - | ^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:91:5 - | -LL | f() - | ^^^ - -error: aborting due to 6 previous errors; 4 warnings emitted - -For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:65:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:71:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:77:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:83:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:59:5 + | +LL | x86(); + | ^^^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:59:5 + | +LL | x86(); + | ^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.msp430.stderr b/tests/ui/abi/cannot-be-called.msp430.stderr index d7630d96f8ce..fa339f0dd2a6 100644 --- a/tests/ui/abi/cannot-be-called.msp430.stderr +++ b/tests/ui/abi/cannot-be-called.msp430.stderr @@ -1,132 +1,75 @@ -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 - | -LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 - | -LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:88:15 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:8 | LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:1 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:1 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:46:8 | LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error: functions with the "msp430-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:48:5 - | -LL | msp430(); - | ^^^^^^^^ - | -note: an `extern "msp430-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:48:5 - | -LL | msp430(); - | ^^^^^^^^ - -error: functions with the "msp430-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:63:5 - | -LL | f() - | ^^^ - | -note: an `extern "msp430-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:63:5 - | -LL | f() - | ^^^ - -error: aborting due to 6 previous errors; 4 warnings emitted - -For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:71:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:77:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:83:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:88:15 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:89:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ +error: functions with the "msp430-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:51:5 + | +LL | msp430(); + | ^^^^^^^^ + | +note: an `extern "msp430-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:51:5 + | +LL | msp430(); + | ^^^^^^^^ + +error: functions with the "msp430-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:67:5 + | +LL | f() + | ^^^ + | +note: an `extern "msp430-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:67:5 + | +LL | f() + | ^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.riscv32.stderr b/tests/ui/abi/cannot-be-called.riscv32.stderr index 9fadbd639b8b..040b60c76573 100644 --- a/tests/ui/abi/cannot-be-called.riscv32.stderr +++ b/tests/ui/abi/cannot-be-called.riscv32.stderr @@ -1,130 +1,87 @@ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:88:15 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:36:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:8 | LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:8 | LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:1 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:46:8 | LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/cannot-be-called.rs:52:5 - | -LL | riscv_m(); - | ^^^^^^^^^ - | -note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:52:5 - | -LL | riscv_m(); - | ^^^^^^^^^ - -error: functions with the "riscv-interrupt-s" ABI cannot be called - --> $DIR/cannot-be-called.rs:54:5 - | -LL | riscv_s(); - | ^^^^^^^^^ - | -note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:54:5 - | -LL | riscv_s(); - | ^^^^^^^^^ - -error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/cannot-be-called.rs:77:5 - | -LL | f() - | ^^^ - | -note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:77:5 - | -LL | f() - | ^^^ - -error: functions with the "riscv-interrupt-s" ABI cannot be called - --> $DIR/cannot-be-called.rs:84:5 - | -LL | f() - | ^^^ - | -note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:84:5 - | -LL | f() - | ^^^ - -error: aborting due to 7 previous errors; 3 warnings emitted - -For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:65:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:71:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:88:15 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:89:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/cannot-be-called.rs:55:5 + | +LL | riscv_m(); + | ^^^^^^^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:55:5 + | +LL | riscv_m(); + | ^^^^^^^^^ + +error: functions with the "riscv-interrupt-s" ABI cannot be called + --> $DIR/cannot-be-called.rs:57:5 + | +LL | riscv_s(); + | ^^^^^^^^^ + | +note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:57:5 + | +LL | riscv_s(); + | ^^^^^^^^^ + +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/cannot-be-called.rs:79:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:79:5 + | +LL | f() + | ^^^ + +error: functions with the "riscv-interrupt-s" ABI cannot be called + --> $DIR/cannot-be-called.rs:85:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:85:5 + | +LL | f() + | ^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.riscv64.stderr b/tests/ui/abi/cannot-be-called.riscv64.stderr index 9fadbd639b8b..040b60c76573 100644 --- a/tests/ui/abi/cannot-be-called.riscv64.stderr +++ b/tests/ui/abi/cannot-be-called.riscv64.stderr @@ -1,130 +1,87 @@ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:88:15 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:36:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:8 | LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:8 | LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:44:1 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:46:8 | LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/cannot-be-called.rs:52:5 - | -LL | riscv_m(); - | ^^^^^^^^^ - | -note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:52:5 - | -LL | riscv_m(); - | ^^^^^^^^^ - -error: functions with the "riscv-interrupt-s" ABI cannot be called - --> $DIR/cannot-be-called.rs:54:5 - | -LL | riscv_s(); - | ^^^^^^^^^ - | -note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:54:5 - | -LL | riscv_s(); - | ^^^^^^^^^ - -error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/cannot-be-called.rs:77:5 - | -LL | f() - | ^^^ - | -note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:77:5 - | -LL | f() - | ^^^ - -error: functions with the "riscv-interrupt-s" ABI cannot be called - --> $DIR/cannot-be-called.rs:84:5 - | -LL | f() - | ^^^ - | -note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:84:5 - | -LL | f() - | ^^^ - -error: aborting due to 7 previous errors; 3 warnings emitted - -For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:65:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:71:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "x86-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:88:15 +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:89:22 | LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/cannot-be-called.rs:55:5 + | +LL | riscv_m(); + | ^^^^^^^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:55:5 + | +LL | riscv_m(); + | ^^^^^^^^^ + +error: functions with the "riscv-interrupt-s" ABI cannot be called + --> $DIR/cannot-be-called.rs:57:5 + | +LL | riscv_s(); + | ^^^^^^^^^ + | +note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:57:5 + | +LL | riscv_s(); + | ^^^^^^^^^ + +error: functions with the "riscv-interrupt-m" ABI cannot be called + --> $DIR/cannot-be-called.rs:79:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:79:5 + | +LL | f() + | ^^^ + +error: functions with the "riscv-interrupt-s" ABI cannot be called + --> $DIR/cannot-be-called.rs:85:5 + | +LL | f() + | ^^^ + | +note: an `extern "riscv-interrupt-s"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:85:5 + | +LL | f() + | ^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.rs b/tests/ui/abi/cannot-be-called.rs index 89173655a4ac..6918c2f56a33 100644 --- a/tests/ui/abi/cannot-be-called.rs +++ b/tests/ui/abi/cannot-be-called.rs @@ -1,3 +1,8 @@ +/*! Tests entry-point ABIs cannot be called + +Interrupt ABIs share similar semantics, in that they are special entry-points unusable by Rust. +So we test that they error in essentially all of the same places. +*/ //@ add-core-stubs //@ revisions: x64 x64_win i686 riscv32 riscv64 avr msp430 // @@ -18,21 +23,18 @@ #![no_core] #![feature( no_core, - lang_items, - abi_ptx, abi_msp430_interrupt, abi_avr_interrupt, abi_gpu_kernel, abi_x86_interrupt, abi_riscv_interrupt, - abi_c_cmse_nonsecure_call, - abi_vectorcall, - cmse_nonsecure_entry )] extern crate minicore; use minicore::*; +/* extern "interrupt" definition */ + extern "msp430-interrupt" fn msp430() {} //[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI extern "avr-interrupt" fn avr() {} @@ -44,6 +46,7 @@ extern "riscv-interrupt-s" fn riscv_s() {} extern "x86-interrupt" fn x86() {} //[riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI +/* extern "interrupt" calls */ fn call_the_interrupts() { msp430(); //[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called @@ -57,37 +60,34 @@ fn call_the_interrupts() { //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called } +/* extern "interrupt" fnptr calls */ + fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - //[x64,x64_win,i686,riscv32,riscv64,avr]~^ WARN unsupported_fn_ptr_calling_conventions - //[x64,x64_win,i686,riscv32,riscv64,avr]~^^ WARN this was previously accepted + //[x64,x64_win,i686,riscv32,riscv64,avr]~^ ERROR is not a supported ABI f() //[msp430]~^ ERROR functions with the "msp430-interrupt" ABI cannot be called } fn avr_ptr(f: extern "avr-interrupt" fn()) { - //[x64,x64_win,i686,riscv32,riscv64,msp430]~^ WARN unsupported_fn_ptr_calling_conventions - //[x64,x64_win,i686,riscv32,riscv64,msp430]~^^ WARN this was previously accepted + //[x64,x64_win,i686,riscv32,riscv64,msp430]~^ ERROR is not a supported ABI f() //[avr]~^ ERROR functions with the "avr-interrupt" ABI cannot be called } fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - //[x64,x64_win,i686,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions - //[x64,x64_win,i686,avr,msp430]~^^ WARN this was previously accepted + //[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI f() //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called } fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - //[x64,x64_win,i686,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions - //[x64,x64_win,i686,avr,msp430]~^^ WARN this was previously accepted + //[x64,x64_win,i686,avr,msp430]~^ ERROR is not a supported ABI f() //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-s" ABI cannot be called } fn x86_ptr(f: extern "x86-interrupt" fn()) { - //[riscv32,riscv64,avr,msp430]~^ WARN unsupported_fn_ptr_calling_conventions - //[riscv32,riscv64,avr,msp430]~^^ WARN this was previously accepted + //[riscv32,riscv64,avr,msp430]~^ ERROR is not a supported ABI f() //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called } diff --git a/tests/ui/abi/cannot-be-called.x64.stderr b/tests/ui/abi/cannot-be-called.x64.stderr index 113b40eb67b8..f59fdba2f357 100644 --- a/tests/ui/abi/cannot-be-called.x64.stderr +++ b/tests/ui/abi/cannot-be-called.x64.stderr @@ -1,132 +1,75 @@ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 - | -LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 - | -LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:36:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:8 | LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:8 | LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:1 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:56:5 - | -LL | x86(); - | ^^^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:56:5 - | -LL | x86(); - | ^^^^^ - -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:91:5 - | -LL | f() - | ^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:91:5 - | -LL | f() - | ^^^ - -error: aborting due to 6 previous errors; 4 warnings emitted - -For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:65:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:71:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:77:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:83:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:59:5 + | +LL | x86(); + | ^^^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:59:5 + | +LL | x86(); + | ^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/cannot-be-called.x64_win.stderr b/tests/ui/abi/cannot-be-called.x64_win.stderr index 113b40eb67b8..f59fdba2f357 100644 --- a/tests/ui/abi/cannot-be-called.x64_win.stderr +++ b/tests/ui/abi/cannot-be-called.x64_win.stderr @@ -1,132 +1,75 @@ -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 - | -LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 - | -LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - -error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:36:1 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:38:8 | LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ -error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:38:1 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:40:8 | LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:40:1 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:42:8 | LL | extern "riscv-interrupt-m" fn riscv_m() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: `"riscv-interrupt-s"` is not a supported ABI for the current target - --> $DIR/cannot-be-called.rs:42:1 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:44:8 | LL | extern "riscv-interrupt-s" fn riscv_s() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:56:5 - | -LL | x86(); - | ^^^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:56:5 - | -LL | x86(); - | ^^^^^ - -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/cannot-be-called.rs:91:5 - | -LL | f() - | ^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/cannot-be-called.rs:91:5 - | -LL | f() - | ^^^ - -error: aborting due to 6 previous errors; 4 warnings emitted - -For more information about this error, try `rustc --explain E0570`. -Future incompatibility report: Future breakage diagnostic: -warning: the calling convention "msp430-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:60:18 +error[E0570]: "msp430-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:65:25 | LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "avr-interrupt" is not supported on this target - --> $DIR/cannot-be-called.rs:67:15 +error[E0570]: "avr-interrupt" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:71:22 | LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-m" is not supported on this target - --> $DIR/cannot-be-called.rs:74:19 +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:77:26 | LL | fn riscv_m_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ -Future breakage diagnostic: -warning: the calling convention "riscv-interrupt-s" is not supported on this target - --> $DIR/cannot-be-called.rs:81:19 +error[E0570]: "riscv-interrupt-s" is not a supported ABI for the current target + --> $DIR/cannot-be-called.rs:83:26 | LL | fn riscv_s_ptr(f: extern "riscv-interrupt-s" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default + | ^^^^^^^^^^^^^^^^^^^ +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:59:5 + | +LL | x86(); + | ^^^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:59:5 + | +LL | x86(); + | ^^^^^ + +error: functions with the "x86-interrupt" ABI cannot be called + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + | +note: an `extern "x86-interrupt"` function can only be called using inline assembly + --> $DIR/cannot-be-called.rs:91:5 + | +LL | f() + | ^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index d2970cb4dd96..85e251a65d20 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -43,95 +43,47 @@ LL | extern "aapcs" {} error[E0570]: "msp430-interrupt" is not a supported ABI for the current target --> $DIR/unsupported.rs:56:8 | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:25 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:62:8 - | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:8 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:22 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:74:8 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:76:24 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:81:8 + --> $DIR/unsupported.rs:62:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:84:8 - | -LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:22 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:91:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:94:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:96:27 + --> $DIR/unsupported.rs:70:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:103:8 + --> $DIR/unsupported.rs:77:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -139,7 +91,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:26 + --> $DIR/unsupported.rs:81:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -147,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:113:8 + --> $DIR/unsupported.rs:87:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -155,7 +107,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:8 + --> $DIR/unsupported.rs:91:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -163,73 +115,73 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:137:8 + --> $DIR/unsupported.rs:111:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:139:29 + --> $DIR/unsupported.rs:113:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:143:8 + --> $DIR/unsupported.rs:117:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:28 + --> $DIR/unsupported.rs:120:28 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:151:8 + --> $DIR/unsupported.rs:125:8 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:29 + --> $DIR/unsupported.rs:127:29 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:167:17 + --> $DIR/unsupported.rs:141:17 | LL | ptr: extern "thiscall" fn(), | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:172:16 + --> $DIR/unsupported.rs:146:16 | LL | pub extern "thiscall" fn inherent_fn(self) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:179:12 + --> $DIR/unsupported.rs:153:12 | LL | extern "thiscall" fn trait_fn(self); | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:184:12 + --> $DIR/unsupported.rs:158:12 | LL | extern "thiscall" fn trait_fn(self) { | ^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:17 + --> $DIR/unsupported.rs:99:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -240,7 +192,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:1 + --> $DIR/unsupported.rs:104:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -250,7 +202,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:133:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -260,7 +212,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:1 + --> $DIR/unsupported.rs:96:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -269,6 +221,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 37 previous errors; 4 warnings emitted +error: aborting due to 29 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 543abe703d67..a4274d0ac603 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -25,95 +25,47 @@ LL | extern "gpu-kernel" fn gpu() {} error[E0570]: "msp430-interrupt" is not a supported ABI for the current target --> $DIR/unsupported.rs:56:8 | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:25 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:62:8 - | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:8 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:22 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:74:8 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:76:24 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:81:8 + --> $DIR/unsupported.rs:62:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:84:8 - | -LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:22 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:91:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:94:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:96:27 + --> $DIR/unsupported.rs:70:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:103:8 + --> $DIR/unsupported.rs:77:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -121,7 +73,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:26 + --> $DIR/unsupported.rs:81:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -129,7 +81,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:113:8 + --> $DIR/unsupported.rs:87:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -137,7 +89,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:8 + --> $DIR/unsupported.rs:91:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -145,73 +97,73 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:137:8 + --> $DIR/unsupported.rs:111:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:139:29 + --> $DIR/unsupported.rs:113:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:143:8 + --> $DIR/unsupported.rs:117:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:28 + --> $DIR/unsupported.rs:120:28 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:151:8 + --> $DIR/unsupported.rs:125:8 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:29 + --> $DIR/unsupported.rs:127:29 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:167:17 + --> $DIR/unsupported.rs:141:17 | LL | ptr: extern "thiscall" fn(), | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:172:16 + --> $DIR/unsupported.rs:146:16 | LL | pub extern "thiscall" fn inherent_fn(self) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:179:12 + --> $DIR/unsupported.rs:153:12 | LL | extern "thiscall" fn trait_fn(self); | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:184:12 + --> $DIR/unsupported.rs:158:12 | LL | extern "thiscall" fn trait_fn(self) { | ^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:17 + --> $DIR/unsupported.rs:99:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -222,7 +174,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:1 + --> $DIR/unsupported.rs:104:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -232,7 +184,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:133:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -242,7 +194,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:1 + --> $DIR/unsupported.rs:96:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -251,6 +203,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 34 previous errors; 4 warnings emitted +error: aborting due to 26 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 2939ae10b0e2..5e5d74c1d989 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -43,93 +43,45 @@ LL | extern "aapcs" {} error[E0570]: "msp430-interrupt" is not a supported ABI for the current target --> $DIR/unsupported.rs:56:8 | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:25 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:62:8 - | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:8 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:22 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:74:8 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:76:24 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:81:8 + --> $DIR/unsupported.rs:62:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:28 + --> $DIR/unsupported.rs:120:28 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:151:8 + --> $DIR/unsupported.rs:125:8 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:29 + --> $DIR/unsupported.rs:127:29 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/unsupported.rs:88:5 - | -LL | f() - | ^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/unsupported.rs:88:5 - | -LL | f() - | ^^^ - -error: aborting due to 21 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index ead32f573d73..7ef7cae5057e 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -43,77 +43,41 @@ LL | extern "aapcs" {} error[E0570]: "msp430-interrupt" is not a supported ABI for the current target --> $DIR/unsupported.rs:56:8 | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:25 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:62:8 - | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:8 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:22 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:84:8 - | -LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:22 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:91:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:94:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:96:27 + --> $DIR/unsupported.rs:70:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:103:8 + --> $DIR/unsupported.rs:77:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -121,7 +85,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:26 + --> $DIR/unsupported.rs:81:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -129,7 +93,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:113:8 + --> $DIR/unsupported.rs:87:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -137,7 +101,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:8 + --> $DIR/unsupported.rs:91:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -145,73 +109,73 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:137:8 + --> $DIR/unsupported.rs:111:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:139:29 + --> $DIR/unsupported.rs:113:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:143:8 + --> $DIR/unsupported.rs:117:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:28 + --> $DIR/unsupported.rs:120:28 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:151:8 + --> $DIR/unsupported.rs:125:8 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:29 + --> $DIR/unsupported.rs:127:29 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:167:17 + --> $DIR/unsupported.rs:141:17 | LL | ptr: extern "thiscall" fn(), | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:172:16 + --> $DIR/unsupported.rs:146:16 | LL | pub extern "thiscall" fn inherent_fn(self) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:179:12 + --> $DIR/unsupported.rs:153:12 | LL | extern "thiscall" fn trait_fn(self); | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:184:12 + --> $DIR/unsupported.rs:158:12 | LL | extern "thiscall" fn trait_fn(self) { | ^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:17 + --> $DIR/unsupported.rs:99:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -222,7 +186,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:1 + --> $DIR/unsupported.rs:104:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -232,7 +196,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:133:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,20 +205,8 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/unsupported.rs:78:5 - | -LL | f() - | ^^^ - | -note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/unsupported.rs:78:5 - | -LL | f() - | ^^^ - warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:1 + --> $DIR/unsupported.rs:96:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,6 +215,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 35 previous errors; 4 warnings emitted +error: aborting due to 28 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index ead32f573d73..7ef7cae5057e 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -43,77 +43,41 @@ LL | extern "aapcs" {} error[E0570]: "msp430-interrupt" is not a supported ABI for the current target --> $DIR/unsupported.rs:56:8 | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:25 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:62:8 - | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:8 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:22 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:84:8 - | -LL | extern "x86-interrupt" fn x86() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:22 - | -LL | fn x86_ptr(f: extern "x86-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:91:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:94:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:96:27 + --> $DIR/unsupported.rs:70:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:103:8 + --> $DIR/unsupported.rs:77:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -121,7 +85,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:26 + --> $DIR/unsupported.rs:81:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -129,7 +93,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:113:8 + --> $DIR/unsupported.rs:87:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -137,7 +101,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:8 + --> $DIR/unsupported.rs:91:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -145,73 +109,73 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:137:8 + --> $DIR/unsupported.rs:111:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:139:29 + --> $DIR/unsupported.rs:113:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:143:8 + --> $DIR/unsupported.rs:117:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:28 + --> $DIR/unsupported.rs:120:28 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:151:8 + --> $DIR/unsupported.rs:125:8 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:29 + --> $DIR/unsupported.rs:127:29 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:167:17 + --> $DIR/unsupported.rs:141:17 | LL | ptr: extern "thiscall" fn(), | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:172:16 + --> $DIR/unsupported.rs:146:16 | LL | pub extern "thiscall" fn inherent_fn(self) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:179:12 + --> $DIR/unsupported.rs:153:12 | LL | extern "thiscall" fn trait_fn(self); | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:184:12 + --> $DIR/unsupported.rs:158:12 | LL | extern "thiscall" fn trait_fn(self) { | ^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:17 + --> $DIR/unsupported.rs:99:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -222,7 +186,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:1 + --> $DIR/unsupported.rs:104:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -232,7 +196,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:133:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,20 +205,8 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -error: functions with the "riscv-interrupt-m" ABI cannot be called - --> $DIR/unsupported.rs:78:5 - | -LL | f() - | ^^^ - | -note: an `extern "riscv-interrupt-m"` function can only be called using inline assembly - --> $DIR/unsupported.rs:78:5 - | -LL | f() - | ^^^ - warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:1 + --> $DIR/unsupported.rs:96:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,6 +215,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 35 previous errors; 4 warnings emitted +error: aborting due to 28 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 98f9ccbd78cd..4bb732c94ac3 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -53,41 +53,15 @@ fn aapcs_ptr(f: extern "aapcs" fn()) { extern "aapcs" {} //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI -extern "msp430-interrupt" fn msp430() {} -//~^ ERROR is not a supported ABI -fn msp430_ptr(f: extern "msp430-interrupt" fn()) { -//~^ ERROR is not a supported ABI - f() -} extern "msp430-interrupt" {} //~^ ERROR is not a supported ABI -extern "avr-interrupt" fn avr() {} -//~^ ERROR is not a supported ABI -fn avr_ptr(f: extern "avr-interrupt" fn()) { -//~^ ERROR is not a supported ABI - f() -} extern "avr-interrupt" {} //~^ ERROR is not a supported ABI -extern "riscv-interrupt-m" fn riscv() {} -//[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI -fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - //[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI - f() - //[riscv32,riscv64]~^ ERROR functions with the "riscv-interrupt-m" ABI cannot be called -} extern "riscv-interrupt-m" {} //[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI -extern "x86-interrupt" fn x86() {} -//[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI -fn x86_ptr(f: extern "x86-interrupt" fn()) { - //[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI - f() - //[x64,x64_win,i686]~^ ERROR functions with the "x86-interrupt" ABI cannot be called -} extern "x86-interrupt" {} //[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 3888bc00a968..7b021dff7c90 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -43,77 +43,41 @@ LL | extern "aapcs" {} error[E0570]: "msp430-interrupt" is not a supported ABI for the current target --> $DIR/unsupported.rs:56:8 | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:25 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:62:8 - | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:8 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:22 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:74:8 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:76:24 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:81:8 + --> $DIR/unsupported.rs:62:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:94:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:96:27 + --> $DIR/unsupported.rs:70:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:103:8 + --> $DIR/unsupported.rs:77:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -121,7 +85,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:26 + --> $DIR/unsupported.rs:81:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -129,7 +93,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:113:8 + --> $DIR/unsupported.rs:87:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -137,7 +101,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: "stdcall-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:8 + --> $DIR/unsupported.rs:91:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -145,55 +109,55 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:28 + --> $DIR/unsupported.rs:120:28 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:151:8 + --> $DIR/unsupported.rs:125:8 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:29 + --> $DIR/unsupported.rs:127:29 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:167:17 + --> $DIR/unsupported.rs:141:17 | LL | ptr: extern "thiscall" fn(), | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:172:16 + --> $DIR/unsupported.rs:146:16 | LL | pub extern "thiscall" fn inherent_fn(self) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:179:12 + --> $DIR/unsupported.rs:153:12 | LL | extern "thiscall" fn trait_fn(self); | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:184:12 + --> $DIR/unsupported.rs:158:12 | LL | extern "thiscall" fn trait_fn(self) { | ^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:17 + --> $DIR/unsupported.rs:99:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -204,7 +168,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:1 + --> $DIR/unsupported.rs:104:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -214,7 +178,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:133:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,20 +187,8 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 = help: use `extern "C-unwind"` instead -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/unsupported.rs:88:5 - | -LL | f() - | ^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/unsupported.rs:88:5 - | -LL | f() - | ^^^ - warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:1 + --> $DIR/unsupported.rs:96:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,6 +197,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 32 previous errors; 4 warnings emitted +error: aborting due to 25 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index d093ae86b9f6..4ce5b3340d12 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -43,125 +43,89 @@ LL | extern "aapcs" {} error[E0570]: "msp430-interrupt" is not a supported ABI for the current target --> $DIR/unsupported.rs:56:8 | -LL | extern "msp430-interrupt" fn msp430() {} - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:25 - | -LL | fn msp430_ptr(f: extern "msp430-interrupt" fn()) { - | ^^^^^^^^^^^^^^^^^^ - -error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:62:8 - | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:65:8 - | -LL | extern "avr-interrupt" fn avr() {} - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:22 - | -LL | fn avr_ptr(f: extern "avr-interrupt" fn()) { - | ^^^^^^^^^^^^^^^ - -error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:74:8 - | -LL | extern "riscv-interrupt-m" fn riscv() {} - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:76:24 - | -LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - -error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:81:8 + --> $DIR/unsupported.rs:62:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:94:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:96:27 + --> $DIR/unsupported.rs:70:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:28 + --> $DIR/unsupported.rs:120:28 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:151:8 + --> $DIR/unsupported.rs:125:8 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:29 + --> $DIR/unsupported.rs:127:29 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:167:17 + --> $DIR/unsupported.rs:141:17 | LL | ptr: extern "thiscall" fn(), | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:172:16 + --> $DIR/unsupported.rs:146:16 | LL | pub extern "thiscall" fn inherent_fn(self) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:179:12 + --> $DIR/unsupported.rs:153:12 | LL | extern "thiscall" fn trait_fn(self); | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:184:12 + --> $DIR/unsupported.rs:158:12 | LL | extern "thiscall" fn trait_fn(self) { | ^^^^^^^^^^ warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:107:19 + --> $DIR/unsupported.rs:81:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -172,7 +136,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_calling_conventions)]` on by default warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:113:1 + --> $DIR/unsupported.rs:87:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -182,7 +146,7 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: "stdcall-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:1 + --> $DIR/unsupported.rs:91:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -192,7 +156,7 @@ LL | extern "stdcall-unwind" {} = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:17 + --> $DIR/unsupported.rs:99:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -202,7 +166,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = help: use `extern "C"` instead warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:1 + --> $DIR/unsupported.rs:104:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -212,7 +176,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:133:1 + --> $DIR/unsupported.rs:107:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -222,7 +186,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:162:1 + --> $DIR/unsupported.rs:136:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -231,20 +195,8 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: functions with the "x86-interrupt" ABI cannot be called - --> $DIR/unsupported.rs:88:5 - | -LL | f() - | ^^^ - | -note: an `extern "x86-interrupt"` function can only be called using inline assembly - --> $DIR/unsupported.rs:88:5 - | -LL | f() - | ^^^ - warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:103:1 + --> $DIR/unsupported.rs:77:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -254,7 +206,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:1 + --> $DIR/unsupported.rs:96:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,6 +215,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 28 previous errors; 9 warnings emitted +error: aborting due to 21 previous errors; 9 warnings emitted For more information about this error, try `rustc --explain E0570`. From bec2679e4e24aeed5e367ab710dc4fe8555f9eb8 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Mon, 23 Jun 2025 17:02:13 +0000 Subject: [PATCH 290/356] rustdoc-json: Add test for `#[optimize(..)]` Follow up to https://www.github.com/rust-lang/rust/pull/138291 --- tests/rustdoc-json/attrs/optimize.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/rustdoc-json/attrs/optimize.rs diff --git a/tests/rustdoc-json/attrs/optimize.rs b/tests/rustdoc-json/attrs/optimize.rs new file mode 100644 index 000000000000..0bed0ad18c31 --- /dev/null +++ b/tests/rustdoc-json/attrs/optimize.rs @@ -0,0 +1,13 @@ +#![feature(optimize_attribute)] + +//@ is "$.index[?(@.name=='speed')].attrs" '["#[attr = Optimize(Speed)]"]' +#[optimize(speed)] +pub fn speed() {} + +//@ is "$.index[?(@.name=='size')].attrs" '["#[attr = Optimize(Size)]"]' +#[optimize(size)] +pub fn size() {} + +//@ is "$.index[?(@.name=='none')].attrs" '["#[attr = Optimize(DoNotOptimize)]"]' +#[optimize(none)] +pub fn none() {} From 6ea79a13b58d7e62b6aebbbc8ba56042daa3c493 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 23 Jun 2025 20:24:54 +0200 Subject: [PATCH 291/356] Fix comment on NoMangle Signed-off-by: Jonathan Brouwer --- src/librustdoc/clean/types.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0aedc7f5219c..69899539b452 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -753,7 +753,8 @@ impl Item { .other_attrs .iter() .filter_map(|attr| { - // NoMangle is special-cased because cargo-semver-checks uses it + // NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing. + // It is also used by cargo-semver-checks. if matches!(attr, hir::Attribute::Parsed(AttributeKind::NoMangle(..))) { Some("#[no_mangle]".to_string()) } else if is_json { From 81476465311b1b89cd70f3ade586faa322891a0c Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 23 Jun 2025 20:24:59 +0200 Subject: [PATCH 292/356] fix `-Zmin-function-alignment` without attributes the minimum function alignment was skipped on functions without attributes. That is because in our testing we generally apply `#[no_mangle]` to functions that are tested. I've added a test now that deliberately has no attributes --- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 10 ++++------ tests/codegen/min-function-alignment.rs | 10 ++++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index b006fdbb6586..afdd2e7692dd 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -145,12 +145,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } - // Apply the minimum function alignment here, so that individual backends don't have to. - codegen_fn_attrs.alignment = Ord::max( - codegen_fn_attrs.alignment, - tcx.sess.opts.unstable_opts.min_function_alignment, - ); - let Some(Ident { name, .. }) = attr.ident() else { continue; }; @@ -454,6 +448,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); + // Apply the minimum function alignment here, so that individual backends don't have to. + codegen_fn_attrs.alignment = + Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment); + let inline_span; (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) = find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span)) diff --git a/tests/codegen/min-function-alignment.rs b/tests/codegen/min-function-alignment.rs index 75f845572a4a..78989ec5df23 100644 --- a/tests/codegen/min-function-alignment.rs +++ b/tests/codegen/min-function-alignment.rs @@ -1,17 +1,19 @@ //@ revisions: align16 align1024 -//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 -Clink-dead-code //@ [align16] compile-flags: -Zmin-function-alignment=16 //@ [align1024] compile-flags: -Zmin-function-alignment=1024 #![crate_type = "lib"] #![feature(fn_align)] -// functions without explicit alignment use the global minimum +// Functions without explicit alignment use the global minimum. // -// CHECK-LABEL: @no_explicit_align +// NOTE: this function deliberately has zero (0) attributes! That is to make sure that +// `-Zmin-function-alignment` is applied regardless of whether attributes are used. +// +// CHECK-LABEL: no_explicit_align // align16: align 16 // align1024: align 1024 -#[no_mangle] pub fn no_explicit_align() {} // CHECK-LABEL: @lower_align From 7a4f09c2240ef2eb4d1e383f0d471b85ce8d0720 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 3 May 2025 15:53:52 +0300 Subject: [PATCH 293/356] compiletest: Improve diagnostics for line annotation mismatches --- src/tools/compiletest/src/errors.rs | 46 +++--- src/tools/compiletest/src/header.rs | 2 +- src/tools/compiletest/src/json.rs | 40 ++--- src/tools/compiletest/src/runtest.rs | 147 ++++++++++++++---- tests/incremental/issue-61323.rs | 2 +- tests/ui/argument-suggestions/issue-100478.rs | 4 +- ...correct-move-async-order-issue-79694.fixed | 2 +- .../incorrect-move-async-order-issue-79694.rs | 2 +- .../line-annotation-mismatches.rs | 42 +++++ .../line-annotation-mismatches.stderr | 61 ++++++++ .../feature-gate-cfi_encoding.rs | 2 +- .../feature-gate-unsized_tuple_coercion.rs | 2 +- .../assoc-type.rs | 2 +- tests/ui/imports/issue-28134.rs | 2 +- .../hint-closure-signature-119266.rs | 2 +- tests/ui/integral-indexing.rs | 16 +- tests/ui/issues/issue-92741.rs | 6 +- tests/ui/lifetimes/no_lending_iterators.rs | 6 +- .../transforming-option-ref-issue-127545.rs | 8 +- .../ui/sanitizer/cfi/invalid-attr-encoding.rs | 2 +- tests/ui/suggestions/issue-105645.rs | 2 +- ...gest-full-enum-variant-for-local-module.rs | 2 +- tests/ui/type/option-ref-advice.rs | 4 +- tests/ui/typeck/issue-100246.rs | 2 +- tests/ui/typeck/issue-89275.rs | 2 +- 25 files changed, 297 insertions(+), 111 deletions(-) create mode 100644 tests/ui/compiletest-self-test/line-annotation-mismatches.rs create mode 100644 tests/ui/compiletest-self-test/line-annotation-mismatches.stderr diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index b5a2b7feac9d..9fa26305f6b0 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -16,6 +16,8 @@ pub enum ErrorKind { Suggestion, Warning, Raw, + /// Used for better recovery and diagnostics in compiletest. + Unknown, } impl ErrorKind { @@ -31,21 +33,25 @@ impl ErrorKind { /// Either the canonical uppercase string, or some additional versions for compatibility. /// FIXME: consider keeping only the canonical versions here. - pub fn from_user_str(s: &str) -> ErrorKind { - match s { + fn from_user_str(s: &str) -> Option { + Some(match s { "HELP" | "help" => ErrorKind::Help, "ERROR" | "error" => ErrorKind::Error, - // `MONO_ITEM` makes annotations in `codegen-units` tests syntactically correct, - // but those tests never use the error kind later on. - "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note, + "NOTE" | "note" => ErrorKind::Note, "SUGGESTION" => ErrorKind::Suggestion, "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning, "RAW" => ErrorKind::Raw, - _ => panic!( + _ => return None, + }) + } + + pub fn expect_from_user_str(s: &str) -> ErrorKind { + ErrorKind::from_user_str(s).unwrap_or_else(|| { + panic!( "unexpected diagnostic kind `{s}`, expected \ - `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`" - ), - } + `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` or `RAW`" + ) + }) } } @@ -58,6 +64,7 @@ impl fmt::Display for ErrorKind { ErrorKind::Suggestion => write!(f, "SUGGESTION"), ErrorKind::Warning => write!(f, "WARN"), ErrorKind::Raw => write!(f, "RAW"), + ErrorKind::Unknown => write!(f, "UNKNOWN"), } } } @@ -65,6 +72,7 @@ impl fmt::Display for ErrorKind { #[derive(Debug)] pub struct Error { pub line_num: Option, + pub column_num: Option, /// What kind of message we expect (e.g., warning, error, suggestion). pub kind: ErrorKind, pub msg: String, @@ -74,17 +82,6 @@ pub struct Error { pub require_annotation: bool, } -impl Error { - pub fn render_for_expected(&self) -> String { - use colored::Colorize; - format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan()) - } - - pub fn line_num_str(&self) -> String { - self.line_num.map_or("?".to_string(), |line_num| line_num.to_string()) - } -} - /// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE" /// The former is a "follow" that inherits its target from the preceding line; /// the latter is an "adjusts" that goes that many lines up. @@ -168,8 +165,10 @@ fn parse_expected( let rest = line[tag.end()..].trim_start(); let (kind_str, _) = rest.split_once(|c: char| c != '_' && !c.is_ascii_alphabetic()).unwrap_or((rest, "")); - let kind = ErrorKind::from_user_str(kind_str); - let untrimmed_msg = &rest[kind_str.len()..]; + let (kind, untrimmed_msg) = match ErrorKind::from_user_str(kind_str) { + Some(kind) => (kind, &rest[kind_str.len()..]), + None => (ErrorKind::Unknown, rest), + }; let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned(); let line_num_adjust = &captures["adjust"]; @@ -182,6 +181,7 @@ fn parse_expected( } else { (false, Some(line_num - line_num_adjust.len())) }; + let column_num = Some(tag.start() + 1); debug!( "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}", @@ -191,7 +191,7 @@ fn parse_expected( kind, msg ); - Some((follow_prev, Error { line_num, kind, msg, require_annotation: true })) + Some((follow_prev, Error { line_num, column_num, kind, msg, require_annotation: true })) } #[cfg(test)] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 8bee9caacc94..2b203bb309c6 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -593,7 +593,7 @@ impl TestProps { config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) { self.dont_require_annotations - .insert(ErrorKind::from_user_str(err_kind.trim())); + .insert(ErrorKind::expect_from_user_str(err_kind.trim())); } }, ); diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 6ed2b52c66d2..a8e6416e56c8 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -36,9 +36,7 @@ struct UnusedExternNotification { struct DiagnosticSpan { file_name: String, line_start: usize, - line_end: usize, column_start: usize, - column_end: usize, is_primary: bool, label: Option, suggested_replacement: Option, @@ -148,6 +146,7 @@ pub fn parse_output(file_name: &str, output: &str) -> Vec { Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name), Err(_) => errors.push(Error { line_num: None, + column_num: None, kind: ErrorKind::Raw, msg: line.to_string(), require_annotation: false, @@ -193,25 +192,9 @@ fn push_actual_errors( // also ensure that `//~ ERROR E123` *always* works. The // assumption is that these multi-line error messages are on their // way out anyhow. - let with_code = |span: Option<&DiagnosticSpan>, text: &str| { - // FIXME(#33000) -- it'd be better to use a dedicated - // UI harness than to include the line/col number like - // this, but some current tests rely on it. - // - // Note: Do NOT include the filename. These can easily - // cause false matches where the expected message - // appears in the filename, and hence the message - // changes but the test still passes. - let span_str = match span { - Some(DiagnosticSpan { line_start, column_start, line_end, column_end, .. }) => { - format!("{line_start}:{column_start}: {line_end}:{column_end}") - } - None => format!("?:?: ?:?"), - }; - match &diagnostic.code { - Some(code) => format!("{span_str}: {text} [{}]", code.code), - None => format!("{span_str}: {text}"), - } + let with_code = |text| match &diagnostic.code { + Some(code) => format!("{text} [{}]", code.code), + None => format!("{text}"), }; // Convert multi-line messages into multiple errors. @@ -225,8 +208,9 @@ fn push_actual_errors( || Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap(); errors.push(Error { line_num: None, + column_num: None, kind, - msg: with_code(None, first_line), + msg: with_code(first_line), require_annotation: diagnostic.level != "failure-note" && !RE.get_or_init(re_init).is_match(first_line), }); @@ -234,8 +218,9 @@ fn push_actual_errors( for span in primary_spans { errors.push(Error { line_num: Some(span.line_start), + column_num: Some(span.column_start), kind, - msg: with_code(Some(span), first_line), + msg: with_code(first_line), require_annotation: true, }); } @@ -244,16 +229,18 @@ fn push_actual_errors( if primary_spans.is_empty() { errors.push(Error { line_num: None, + column_num: None, kind, - msg: with_code(None, next_line), + msg: with_code(next_line), require_annotation: false, }); } else { for span in primary_spans { errors.push(Error { line_num: Some(span.line_start), + column_num: Some(span.column_start), kind, - msg: with_code(Some(span), next_line), + msg: with_code(next_line), require_annotation: false, }); } @@ -266,6 +253,7 @@ fn push_actual_errors( for (index, line) in suggested_replacement.lines().enumerate() { errors.push(Error { line_num: Some(span.line_start + index), + column_num: Some(span.column_start), kind: ErrorKind::Suggestion, msg: line.to_string(), // Empty suggestions (suggestions to remove something) are common @@ -288,6 +276,7 @@ fn push_actual_errors( if let Some(label) = &span.label { errors.push(Error { line_num: Some(span.line_start), + column_num: Some(span.column_start), kind: ErrorKind::Note, msg: label.clone(), // Empty labels (only underlining spans) are common and do not need annotations. @@ -310,6 +299,7 @@ fn push_backtrace( if Path::new(&expansion.span.file_name) == Path::new(&file_name) { errors.push(Error { line_num: Some(expansion.span.line_start), + column_num: Some(expansion.span.column_start), kind: ErrorKind::Note, msg: format!("in this expansion of {}", expansion.macro_decl_name), require_annotation: true, diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 42c851ea9991..980e89889abb 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -11,7 +11,7 @@ use std::{env, iter, str}; use build_helper::fs::remove_and_create_dir_all; use camino::{Utf8Path, Utf8PathBuf}; -use colored::Colorize; +use colored::{Color, Colorize}; use regex::{Captures, Regex}; use tracing::*; @@ -677,9 +677,6 @@ impl<'test> TestCx<'test> { return; } - // On Windows, translate all '\' path separators to '/' - let file_name = self.testpaths.file.to_string().replace(r"\", "/"); - // On Windows, keep all '\' path separators to match the paths reported in the JSON output // from the compiler let diagnostic_file_name = if self.props.remap_src_base { @@ -704,6 +701,7 @@ impl<'test> TestCx<'test> { .map(|e| Error { msg: self.normalize_output(&e.msg, &[]), ..e }); let mut unexpected = Vec::new(); + let mut unimportant = Vec::new(); let mut found = vec![false; expected_errors.len()]; for actual_error in actual_errors { for pattern in &self.props.error_patterns { @@ -738,14 +736,9 @@ impl<'test> TestCx<'test> { && expected_kinds.contains(&actual_error.kind) && !self.props.dont_require_annotations.contains(&actual_error.kind) { - self.error(&format!( - "{}:{}: unexpected {}: '{}'", - file_name, - actual_error.line_num_str(), - actual_error.kind, - actual_error.msg - )); unexpected.push(actual_error); + } else { + unimportant.push(actual_error); } } } @@ -755,39 +748,140 @@ impl<'test> TestCx<'test> { // anything not yet found is a problem for (index, expected_error) in expected_errors.iter().enumerate() { if !found[index] { - self.error(&format!( - "{}:{}: expected {} not found: {}", - file_name, - expected_error.line_num_str(), - expected_error.kind, - expected_error.msg - )); not_found.push(expected_error); } } if !unexpected.is_empty() || !not_found.is_empty() { self.error(&format!( - "{} unexpected errors found, {} expected errors not found", + "{} unexpected diagnostics reported, {} expected diagnostics not reported", unexpected.len(), not_found.len() )); - println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline); + + // Emit locations in a format that is short (relative paths) but "clickable" in editors. + // Also normalize path separators to `/`. + let file_name = self + .testpaths + .file + .strip_prefix(self.config.src_root.as_str()) + .unwrap_or(&self.testpaths.file) + .to_string() + .replace(r"\", "/"); + let line_str = |e: &Error| { + let line_num = e.line_num.map_or("?".to_string(), |line_num| line_num.to_string()); + // `file:?:NUM` may be confusing to editors and unclickable. + let opt_col_num = match e.column_num { + Some(col_num) if line_num != "?" => format!(":{col_num}"), + _ => "".to_string(), + }; + format!("{file_name}:{line_num}{opt_col_num}") + }; + let print_error = |e| println!("{}: {}: {}", line_str(e), e.kind, e.msg.cyan()); + let push_suggestion = + |suggestions: &mut Vec<_>, e: &Error, kind, line, msg, color, rank| { + let mut ret = String::new(); + if kind { + ret += &format!("{} {}", "with kind".color(color), e.kind); + } + if line { + if !ret.is_empty() { + ret.push(' '); + } + ret += &format!("{} {}", "on line".color(color), line_str(e)); + } + if msg { + if !ret.is_empty() { + ret.push(' '); + } + ret += &format!("{} {}", "with message".color(color), e.msg.cyan()); + } + suggestions.push((ret, rank)); + }; + let show_suggestions = |mut suggestions: Vec<_>, prefix: &str, color| { + // Only show suggestions with the highest rank. + suggestions.sort_by_key(|(_, rank)| *rank); + if let Some(&(_, top_rank)) = suggestions.first() { + for (suggestion, rank) in suggestions { + if rank == top_rank { + println!(" {} {suggestion}", prefix.color(color)); + } + } + } + }; + + // Fuzzy matching quality: + // - message and line / message and kind - great, suggested + // - only message - good, suggested + // - known line and kind - ok, suggested + // - only known line - meh, but suggested + // - others are not worth suggesting if !unexpected.is_empty() { - println!("{}", "--- unexpected errors (from JSON output) ---".green()); + let header = "--- reported in JSON output but not expected in test file ---"; + println!("{}", header.green()); for error in &unexpected { - println!("{}", error.render_for_expected()); + print_error(error); + let mut suggestions = Vec::new(); + for candidate in ¬_found { + let mut push_red_suggestion = |line, msg, rank| { + push_suggestion( + &mut suggestions, + candidate, + candidate.kind != error.kind, + line, + msg, + Color::Red, + rank, + ) + }; + if error.msg.contains(&candidate.msg) { + push_red_suggestion(candidate.line_num != error.line_num, false, 0); + } else if candidate.line_num.is_some() + && candidate.line_num == error.line_num + { + push_red_suggestion(false, true, 1); + } + } + + show_suggestions(suggestions, "expected", Color::Red); } println!("{}", "---".green()); } if !not_found.is_empty() { - println!("{}", "--- not found errors (from test file) ---".red()); + let header = "--- expected in test file but not reported in JSON output ---"; + println!("{}", header.red()); for error in ¬_found { - println!("{}", error.render_for_expected()); + print_error(error); + let mut suggestions = Vec::new(); + for candidate in unexpected.iter().chain(&unimportant) { + let mut push_green_suggestion = |line, msg, rank| { + push_suggestion( + &mut suggestions, + candidate, + candidate.kind != error.kind, + line, + msg, + Color::Green, + rank, + ) + }; + if candidate.msg.contains(&error.msg) { + push_green_suggestion(candidate.line_num != error.line_num, false, 0); + } else if candidate.line_num.is_some() + && candidate.line_num == error.line_num + { + push_green_suggestion(false, true, 1); + } + } + + show_suggestions(suggestions, "reported", Color::Green); } - println!("{}", "---\n".red()); + println!("{}", "---".red()); } - panic!("errors differ from expected"); + panic!( + "errors differ from expected\nstatus: {}\ncommand: {}\n", + proc_res.status, proc_res.cmdline + ); } } @@ -2073,7 +2167,6 @@ impl<'test> TestCx<'test> { println!("{}", String::from_utf8_lossy(&output.stdout)); eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } else { - use colored::Colorize; eprintln!("warning: no pager configured, falling back to unified diff"); eprintln!( "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`" diff --git a/tests/incremental/issue-61323.rs b/tests/incremental/issue-61323.rs index b7423c81fc16..4845648d49c8 100644 --- a/tests/incremental/issue-61323.rs +++ b/tests/incremental/issue-61323.rs @@ -1,7 +1,7 @@ //@ revisions: rpass cfail enum A { - //[cfail]~^ ERROR 3:1: 3:7: recursive types `A` and `C` have infinite size [E0072] + //[cfail]~^ ERROR recursive types `A` and `C` have infinite size [E0072] B(C), } diff --git a/tests/ui/argument-suggestions/issue-100478.rs b/tests/ui/argument-suggestions/issue-100478.rs index b0a9703112e3..219870f3b237 100644 --- a/tests/ui/argument-suggestions/issue-100478.rs +++ b/tests/ui/argument-suggestions/issue-100478.rs @@ -32,8 +32,8 @@ fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} fn main() { three_diff(T2::new(0)); //~ ERROR function takes - four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR 35:5: 35:17: arguments to this function are incorrect [E0308] - four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR 36:5: 36:17: arguments to this function are incorrect [E0308] + four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR arguments to this function are incorrect [E0308] + four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR arguments to this function are incorrect [E0308] let p1 = T1::new(0); let p2 = Arc::new(T2::new(0)); diff --git a/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed b/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed index c74a32e442f3..9e5e889506c7 100644 --- a/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed +++ b/tests/ui/async-await/incorrect-move-async-order-issue-79694.fixed @@ -4,5 +4,5 @@ // Regression test for issue 79694 fn main() { - let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect + let _ = async move { }; //~ ERROR the order of `move` and `async` is incorrect } diff --git a/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs b/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs index 81ffbacc3273..9c36a6c96da6 100644 --- a/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs +++ b/tests/ui/async-await/incorrect-move-async-order-issue-79694.rs @@ -4,5 +4,5 @@ // Regression test for issue 79694 fn main() { - let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect + let _ = move async { }; //~ ERROR the order of `move` and `async` is incorrect } diff --git a/tests/ui/compiletest-self-test/line-annotation-mismatches.rs b/tests/ui/compiletest-self-test/line-annotation-mismatches.rs new file mode 100644 index 000000000000..d2a14374ed4c --- /dev/null +++ b/tests/ui/compiletest-self-test/line-annotation-mismatches.rs @@ -0,0 +1,42 @@ +//@ should-fail + +// The warning is reported with unknown line +//@ compile-flags: -D raw_pointer_derive +//~? WARN kind and unknown line match the reported warning, but we do not suggest it + +// The error is expected but not reported at all. +//~ ERROR this error does not exist + +// The error is reported but not expected at all. +// "`main` function not found in crate" (the main function is intentionally not added) + +// An "unimportant" diagnostic is expected on a wrong line. +//~ ERROR aborting due to + +// An "unimportant" diagnostic is expected with a wrong kind. +//~? ERROR For more information about an error + +fn wrong_line_or_kind() { + // A diagnostic expected on a wrong line. + unresolved1; + //~ ERROR cannot find value `unresolved1` in this scope + + // A diagnostic expected with a wrong kind. + unresolved2; //~ WARN cannot find value `unresolved2` in this scope + + // A diagnostic expected with a missing kind (treated as a wrong kind). + unresolved3; //~ cannot find value `unresolved3` in this scope + + // A diagnostic expected with a wrong line and kind. + unresolved4; + //~ WARN cannot find value `unresolved4` in this scope +} + +fn wrong_message() { + // A diagnostic expected with a wrong message, but the line is known and right. + unresolvedA; //~ ERROR stub message 1 + + // A diagnostic expected with a wrong message, but the line is known and right, + // even if the kind doesn't match. + unresolvedB; //~ WARN stub message 2 +} diff --git a/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr b/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr new file mode 100644 index 000000000000..7ca3bfaf396c --- /dev/null +++ b/tests/ui/compiletest-self-test/line-annotation-mismatches.stderr @@ -0,0 +1,61 @@ +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: `#[warn(renamed_and_removed_lints)]` on by default + +error[E0425]: cannot find value `unresolved1` in this scope + --> $DIR/line-annotation-mismatches.rs:21:5 + | +LL | unresolved1; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolved2` in this scope + --> $DIR/line-annotation-mismatches.rs:25:5 + | +LL | unresolved2; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolved3` in this scope + --> $DIR/line-annotation-mismatches.rs:28:5 + | +LL | unresolved3; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolved4` in this scope + --> $DIR/line-annotation-mismatches.rs:31:5 + | +LL | unresolved4; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolvedA` in this scope + --> $DIR/line-annotation-mismatches.rs:37:5 + | +LL | unresolvedA; + | ^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `unresolvedB` in this scope + --> $DIR/line-annotation-mismatches.rs:41:5 + | +LL | unresolvedB; + | ^^^^^^^^^^^ not found in this scope + +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0601]: `main` function not found in crate `line_annotation_mismatches` + --> $DIR/line-annotation-mismatches.rs:42:2 + | +LL | } + | ^ consider adding a `main` function to `$DIR/line-annotation-mismatches.rs` + +warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok + | + = note: requested on the command line with `-D raw_pointer_derive` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 7 previous errors; 3 warnings emitted + +Some errors have detailed explanations: E0425, E0601. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/feature-gates/feature-gate-cfi_encoding.rs b/tests/ui/feature-gates/feature-gate-cfi_encoding.rs index 3cef8156014b..b6312dd7817f 100644 --- a/tests/ui/feature-gates/feature-gate-cfi_encoding.rs +++ b/tests/ui/feature-gates/feature-gate-cfi_encoding.rs @@ -1,4 +1,4 @@ #![crate_type = "lib"] -#[cfi_encoding = "3Bar"] //~ERROR 3:1: 3:25: the `#[cfi_encoding]` attribute is an experimental feature [E0658] +#[cfi_encoding = "3Bar"] //~ ERROR the `#[cfi_encoding]` attribute is an experimental feature [E0658] pub struct Foo(i32); diff --git a/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs b/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs index b5fbcc9ccf8c..c14698637927 100644 --- a/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs +++ b/tests/ui/feature-gates/feature-gate-unsized_tuple_coercion.rs @@ -1,4 +1,4 @@ fn main() { let _ : &(dyn Send,) = &((),); - //~^ ERROR 2:28: 2:34: mismatched types [E0308] + //~^ ERROR mismatched types [E0308] } diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.rs b/tests/ui/impl-header-lifetime-elision/assoc-type.rs index db3c416540fc..14b2ea647f19 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.rs +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.rs @@ -9,7 +9,7 @@ trait MyTrait { impl MyTrait for &i32 { type Output = &i32; - //~^ ERROR 11:19: 11:20: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type } impl MyTrait for &u32 { diff --git a/tests/ui/imports/issue-28134.rs b/tests/ui/imports/issue-28134.rs index 70d3a327c1af..aef2fe8facdc 100644 --- a/tests/ui/imports/issue-28134.rs +++ b/tests/ui/imports/issue-28134.rs @@ -2,4 +2,4 @@ #![allow(soft_unstable)] #![test] -//~^ ERROR 4:1: 4:9: `test` attribute cannot be used at crate level +//~^ ERROR `test` attribute cannot be used at crate level diff --git a/tests/ui/inference/hint-closure-signature-119266.rs b/tests/ui/inference/hint-closure-signature-119266.rs index 35be600fd6ab..6e136c57ccad 100644 --- a/tests/ui/inference/hint-closure-signature-119266.rs +++ b/tests/ui/inference/hint-closure-signature-119266.rs @@ -3,7 +3,7 @@ fn main() { //~^ NOTE: the found closure let x: fn(i32) = x; - //~^ ERROR: 5:22: 5:23: mismatched types [E0308] + //~^ ERROR: mismatched types [E0308] //~| NOTE: incorrect number of function parameters //~| NOTE: expected due to this //~| NOTE: expected fn pointer `fn(i32)` diff --git a/tests/ui/integral-indexing.rs b/tests/ui/integral-indexing.rs index f076dfcb0a42..e20553af8a26 100644 --- a/tests/ui/integral-indexing.rs +++ b/tests/ui/integral-indexing.rs @@ -3,14 +3,14 @@ pub fn main() { let s: String = "abcdef".to_string(); v[3_usize]; v[3]; - v[3u8]; //~ERROR : the type `[isize]` cannot be indexed by `u8` - v[3i8]; //~ERROR : the type `[isize]` cannot be indexed by `i8` - v[3u32]; //~ERROR : the type `[isize]` cannot be indexed by `u32` - v[3i32]; //~ERROR : the type `[isize]` cannot be indexed by `i32` + v[3u8]; //~ ERROR the type `[isize]` cannot be indexed by `u8` + v[3i8]; //~ ERROR the type `[isize]` cannot be indexed by `i8` + v[3u32]; //~ ERROR the type `[isize]` cannot be indexed by `u32` + v[3i32]; //~ ERROR the type `[isize]` cannot be indexed by `i32` s.as_bytes()[3_usize]; s.as_bytes()[3]; - s.as_bytes()[3u8]; //~ERROR : the type `[u8]` cannot be indexed by `u8` - s.as_bytes()[3i8]; //~ERROR : the type `[u8]` cannot be indexed by `i8` - s.as_bytes()[3u32]; //~ERROR : the type `[u8]` cannot be indexed by `u32` - s.as_bytes()[3i32]; //~ERROR : the type `[u8]` cannot be indexed by `i32` + s.as_bytes()[3u8]; //~ ERROR the type `[u8]` cannot be indexed by `u8` + s.as_bytes()[3i8]; //~ ERROR the type `[u8]` cannot be indexed by `i8` + s.as_bytes()[3u32]; //~ ERROR the type `[u8]` cannot be indexed by `u32` + s.as_bytes()[3i32]; //~ ERROR the type `[u8]` cannot be indexed by `i32` } diff --git a/tests/ui/issues/issue-92741.rs b/tests/ui/issues/issue-92741.rs index f2e5fdafd9cb..1c5d5810a57e 100644 --- a/tests/ui/issues/issue-92741.rs +++ b/tests/ui/issues/issue-92741.rs @@ -1,17 +1,17 @@ //@ run-rustfix fn main() {} fn _foo() -> bool { - & //~ ERROR 4:5: 6:36: mismatched types [E0308] + & //~ ERROR mismatched types [E0308] mut if true { true } else { false } } fn _bar() -> bool { - & //~ ERROR 10:5: 11:40: mismatched types [E0308] + & //~ ERROR mismatched types [E0308] mut if true { true } else { false } } fn _baz() -> bool { - & mut //~ ERROR 15:5: 16:36: mismatched types [E0308] + & mut //~ ERROR mismatched types [E0308] if true { true } else { false } } diff --git a/tests/ui/lifetimes/no_lending_iterators.rs b/tests/ui/lifetimes/no_lending_iterators.rs index b3e8ad08ba18..88b8cda0898b 100644 --- a/tests/ui/lifetimes/no_lending_iterators.rs +++ b/tests/ui/lifetimes/no_lending_iterators.rs @@ -2,7 +2,7 @@ struct Data(String); impl Iterator for Data { type Item = &str; - //~^ ERROR 4:17: 4:18: associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type fn next(&mut self) -> Option { Some(&self.0) @@ -16,7 +16,7 @@ trait Bar { impl Bar for usize { type Item = &usize; - //~^ ERROR 18:17: 18:18: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + //~^ ERROR in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type fn poke(&mut self, item: Self::Item) { self += *item; @@ -25,7 +25,7 @@ impl Bar for usize { impl Bar for isize { type Item<'a> = &'a isize; - //~^ ERROR 27:14: 27:18: lifetime parameters or bounds on associated type `Item` do not match the trait declaration [E0195] + //~^ ERROR lifetime parameters or bounds on associated type `Item` do not match the trait declaration [E0195] fn poke(&mut self, item: Self::Item) { self += *item; diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs index f589e88f68e4..0632b822c55c 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -2,17 +2,17 @@ #![crate_type = "lib"] pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { - arg //~ ERROR 5:5: 5:8: mismatched types [E0308] + arg //~ ERROR mismatched types [E0308] } pub fn bar(arg: Option<&Vec>) -> &[i32] { - arg.unwrap_or(&[]) //~ ERROR 9:19: 9:22: mismatched types [E0308] + arg.unwrap_or(&[]) //~ ERROR mismatched types [E0308] } pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { - arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308] + arg.unwrap_or(v) //~ ERROR mismatched types [E0308] } pub fn convert_result(arg: Result<&Vec, ()>) -> &[i32] { - arg.unwrap_or(&[]) //~ ERROR 17:19: 17:22: mismatched types [E0308] + arg.unwrap_or(&[]) //~ ERROR mismatched types [E0308] } diff --git a/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs b/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs index 7ef6bd2f0acc..23ffabad62fe 100644 --- a/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs +++ b/tests/ui/sanitizer/cfi/invalid-attr-encoding.rs @@ -7,5 +7,5 @@ #![no_core] #![no_main] -#[cfi_encoding] //~ERROR 10:1: 10:16: malformed `cfi_encoding` attribute input +#[cfi_encoding] //~ ERROR malformed `cfi_encoding` attribute input pub struct Type1(i32); diff --git a/tests/ui/suggestions/issue-105645.rs b/tests/ui/suggestions/issue-105645.rs index 681ce1c6e37a..f3ca8ccbb3c7 100644 --- a/tests/ui/suggestions/issue-105645.rs +++ b/tests/ui/suggestions/issue-105645.rs @@ -2,7 +2,7 @@ fn main() { let mut buf = [0u8; 50]; let mut bref = buf.as_slice(); foo(&mut bref); - //~^ ERROR 4:9: 4:18: the trait bound `&[u8]: std::io::Write` is not satisfied [E0277] + //~^ ERROR the trait bound `&[u8]: std::io::Write` is not satisfied [E0277] } fn foo(_: &mut impl std::io::Write) {} diff --git a/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs b/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs index 1dfc0786668f..807fba0ab7e7 100644 --- a/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs +++ b/tests/ui/suggestions/suggest-full-enum-variant-for-local-module.rs @@ -6,5 +6,5 @@ mod option { } fn main() { - let _: option::O<()> = (); //~ ERROR 9:28: 9:30: mismatched types [E0308] + let _: option::O<()> = (); //~ ERROR mismatched types [E0308] } diff --git a/tests/ui/type/option-ref-advice.rs b/tests/ui/type/option-ref-advice.rs index 2dcee5a2eb91..435b15d01e3c 100644 --- a/tests/ui/type/option-ref-advice.rs +++ b/tests/ui/type/option-ref-advice.rs @@ -3,9 +3,9 @@ fn takes_option(_arg: Option<&String>) {} fn main() { - takes_option(&None); //~ ERROR 6:18: 6:23: mismatched types [E0308] + takes_option(&None); //~ ERROR mismatched types [E0308] let x = String::from("x"); let res = Some(x); - takes_option(&res); //~ ERROR 10:18: 10:22: mismatched types [E0308] + takes_option(&res); //~ ERROR mismatched types [E0308] } diff --git a/tests/ui/typeck/issue-100246.rs b/tests/ui/typeck/issue-100246.rs index 8f0b34bab0c8..e05bb2a1362a 100644 --- a/tests/ui/typeck/issue-100246.rs +++ b/tests/ui/typeck/issue-100246.rs @@ -25,6 +25,6 @@ fn downcast<'a, W: ?Sized>() -> std::io::Result<&'a W> { struct Other; fn main() -> std::io::Result<()> { - let other: Other = downcast()?;//~ERROR 28:24: 28:35: `?` operator has incompatible types + let other: Other = downcast()?; //~ ERROR `?` operator has incompatible types Ok(()) } diff --git a/tests/ui/typeck/issue-89275.rs b/tests/ui/typeck/issue-89275.rs index b91c00175487..6e4211de1857 100644 --- a/tests/ui/typeck/issue-89275.rs +++ b/tests/ui/typeck/issue-89275.rs @@ -25,5 +25,5 @@ fn downcast<'a, W: ?Sized>() -> &'a W { struct Other; fn main() { - let other: &mut Other = downcast();//~ERROR 28:29: 28:39: mismatched types [E0308] + let other: &mut Other = downcast();//~ ERROR mismatched types [E0308] } From ba5556d239c11232dc8d95123ea70a2783019476 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 18 Feb 2025 14:16:57 +0100 Subject: [PATCH 294/356] Add `#[loop_match]` for improved DFA codegen Co-authored-by: Folkert de Vries --- Cargo.lock | 1 + .../src/attributes.rs | 6 + .../src/attributes/loop_match.rs | 31 ++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 3 + compiler/rustc_feature/src/builtin_attrs.rs | 13 + compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir_typeck/messages.ftl | 3 + compiler/rustc_hir_typeck/src/errors.rs | 7 + compiler/rustc_hir_typeck/src/loops.rs | 70 +++- compiler/rustc_middle/src/thir.rs | 13 + compiler/rustc_middle/src/thir/visit.rs | 3 +- compiler/rustc_mir_build/Cargo.toml | 1 + compiler/rustc_mir_build/messages.ftl | 33 ++ .../src/builder/expr/as_place.rs | 2 + .../src/builder/expr/as_rvalue.rs | 2 + .../src/builder/expr/category.rs | 2 + .../rustc_mir_build/src/builder/expr/into.rs | 122 ++++++- .../rustc_mir_build/src/builder/expr/stmt.rs | 3 + .../src/builder/matches/mod.rs | 144 ++++++++- compiler/rustc_mir_build/src/builder/scope.rs | 264 ++++++++++++++- .../rustc_mir_build/src/check_unsafety.rs | 2 + compiler/rustc_mir_build/src/errors.rs | 77 +++++ compiler/rustc_mir_build/src/thir/cx/expr.rs | 143 +++++++-- .../src/thir/pattern/check_match.rs | 7 +- compiler/rustc_mir_build/src/thir/print.rs | 21 ++ compiler/rustc_passes/messages.ftl | 9 +- compiler/rustc_passes/src/check_attr.rs | 32 ++ compiler/rustc_passes/src/errors.rs | 18 ++ .../rustc_pattern_analysis/src/constructor.rs | 3 +- compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_ty_utils/src/consts.rs | 8 +- .../src/language-features/loop-match.md | 52 +++ .../feature-gates/feature-gate-loop-match.rs | 30 ++ .../feature-gate-loop-match.stderr | 33 ++ tests/ui/loop-match/break-to-block.rs | 23 ++ .../ui/loop-match/const-continue-to-block.rs | 26 ++ .../loop-match/const-continue-to-block.stderr | 8 + tests/ui/loop-match/const-continue-to-loop.rs | 27 ++ .../loop-match/const-continue-to-loop.stderr | 8 + .../const-continue-to-polymorphic-const.rs | 29 ++ ...const-continue-to-polymorphic-const.stderr | 8 + tests/ui/loop-match/drop-in-match-arm.rs | 47 +++ tests/ui/loop-match/invalid-attribute.rs | 43 +++ tests/ui/loop-match/invalid-attribute.stderr | 131 ++++++++ tests/ui/loop-match/invalid.rs | 161 ++++++++++ tests/ui/loop-match/invalid.stderr | 91 ++++++ tests/ui/loop-match/loop-match.rs | 45 +++ tests/ui/loop-match/macro.rs | 48 +++ tests/ui/loop-match/nested.rs | 83 +++++ tests/ui/loop-match/or-patterns.rs | 54 ++++ tests/ui/loop-match/unsupported-type.rs | 27 ++ tests/ui/loop-match/unsupported-type.stderr | 10 + tests/ui/loop-match/unwind.rs | 53 +++ tests/ui/loop-match/valid-patterns.rs | 117 +++++++ tests/ui/thir-print/thir-tree-loop-match.rs | 22 ++ .../ui/thir-print/thir-tree-loop-match.stdout | 301 ++++++++++++++++++ 57 files changed, 2480 insertions(+), 45 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/loop_match.rs create mode 100644 src/doc/unstable-book/src/language-features/loop-match.md create mode 100644 tests/ui/feature-gates/feature-gate-loop-match.rs create mode 100644 tests/ui/feature-gates/feature-gate-loop-match.stderr create mode 100644 tests/ui/loop-match/break-to-block.rs create mode 100644 tests/ui/loop-match/const-continue-to-block.rs create mode 100644 tests/ui/loop-match/const-continue-to-block.stderr create mode 100644 tests/ui/loop-match/const-continue-to-loop.rs create mode 100644 tests/ui/loop-match/const-continue-to-loop.stderr create mode 100644 tests/ui/loop-match/const-continue-to-polymorphic-const.rs create mode 100644 tests/ui/loop-match/const-continue-to-polymorphic-const.stderr create mode 100644 tests/ui/loop-match/drop-in-match-arm.rs create mode 100644 tests/ui/loop-match/invalid-attribute.rs create mode 100644 tests/ui/loop-match/invalid-attribute.stderr create mode 100644 tests/ui/loop-match/invalid.rs create mode 100644 tests/ui/loop-match/invalid.stderr create mode 100644 tests/ui/loop-match/loop-match.rs create mode 100644 tests/ui/loop-match/macro.rs create mode 100644 tests/ui/loop-match/nested.rs create mode 100644 tests/ui/loop-match/or-patterns.rs create mode 100644 tests/ui/loop-match/unsupported-type.rs create mode 100644 tests/ui/loop-match/unsupported-type.stderr create mode 100644 tests/ui/loop-match/unwind.rs create mode 100644 tests/ui/loop-match/valid-patterns.rs create mode 100644 tests/ui/thir-print/thir-tree-loop-match.rs create mode 100644 tests/ui/thir-print/thir-tree-loop-match.stdout diff --git a/Cargo.lock b/Cargo.lock index a170ece0a0dd..dfe1cd8852fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4117,6 +4117,7 @@ dependencies = [ "rustc_apfloat", "rustc_arena", "rustc_ast", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9227b81f12fa..4995b855f320 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -212,6 +212,9 @@ pub enum AttributeKind { first_span: Span, }, + /// Represents `#[const_continue]`. + ConstContinue(Span), + /// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`. ConstStability { stability: PartialConstStability, @@ -231,6 +234,9 @@ pub enum AttributeKind { /// Represents `#[inline]` and `#[rustc_force_inline]`. Inline(InlineAttr, Span), + /// Represents `#[loop_match]`. + LoopMatch(Span), + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs new file mode 100644 index 000000000000..f6c7ac5e3a39 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -0,0 +1,31 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct LoopMatchParser; +impl SingleAttributeParser for LoopMatchParser { + const PATH: &[Symbol] = &[sym::loop_match]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { + Some(AttributeKind::LoopMatch(cx.attr_span)) + } +} + +pub(crate) struct ConstContinueParser; +impl SingleAttributeParser for ConstContinueParser { + const PATH: &[Symbol] = &[sym::const_continue]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { + Some(AttributeKind::ConstContinue(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 738d8735b692..bc18ec8a9c03 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -32,6 +32,7 @@ pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod inline; pub(crate) mod lint_helpers; +pub(crate) mod loop_match; pub(crate) mod must_use; pub(crate) mod repr; pub(crate) mod semantics; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 457e073c488b..c89ee8131bbc 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,6 +20,7 @@ use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; +use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::must_use::MustUseParser; use crate::attributes::repr::{AlignParser, ReprParser}; use crate::attributes::semantics::MayDangleParser; @@ -110,9 +111,11 @@ attribute_parsers!( // tidy-alphabetical-start Single, Single, + Single, Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 280b33f07234..85f3f51cfdf7 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -657,6 +657,19 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const), ), + // The `#[loop_match]` and `#[const_continue]` attributes are part of the + // lang experiment for RFC 3720 tracked in: + // + // - https://github.com/rust-lang/rust/issues/132306 + gated!( + const_continue, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, loop_match, experimental!(const_continue) + ), + gated!( + loop_match, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, loop_match, experimental!(loop_match) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 91715851226b..d9d5334615a3 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -557,6 +557,8 @@ declare_features! ( /// Allows using `#[link(kind = "link-arg", name = "...")]` /// to pass custom arguments to the linker. (unstable, link_arg_attribute, "1.76.0", Some(99427)), + /// Allows fused `loop`/`match` for direct intraprocedural jumps. + (incomplete, loop_match, "CURRENT_RUSTC_VERSION", Some(132306)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 258535f3742d..c21b16c9f9f0 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -79,6 +79,9 @@ hir_typeck_cast_unknown_pointer = cannot cast {$to -> .note = the type information given here is insufficient to check whether the pointer cast is valid .label_from = the type information given here is insufficient to check whether the pointer cast is valid +hir_typeck_const_continue_bad_label = + `#[const_continue]` must break to a labeled block that participates in a `#[loop_match]` + hir_typeck_const_select_must_be_const = this argument must be a `const fn` .help = consult the documentation on `const_eval_select` for more information diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 5fea0c628433..3606c778fc40 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1167,3 +1167,10 @@ pub(crate) struct AbiCannotBeCalled { pub span: Span, pub abi: ExternAbi, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_const_continue_bad_label)] +pub(crate) struct ConstContinueBadLabel { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index b06e0704b6ff..80eab578f134 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -2,6 +2,8 @@ use std::collections::BTreeMap; use std::fmt; use Context::*; +use rustc_ast::Label; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -14,8 +16,9 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::{BytePos, Span}; use crate::errors::{ - BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, - OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, + BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ConstContinueBadLabel, + ContinueLabeledBlock, OutsideLoop, OutsideLoopSuggestion, UnlabeledCfInWhileCondition, + UnlabeledInLabeledBlock, }; /// The context in which a block is encountered. @@ -37,6 +40,11 @@ enum Context { AnonConst, /// E.g. `const { ... }`. ConstBlock, + /// E.g. `#[loop_match] loop { state = 'label: { /* ... */ } }`. + LoopMatch { + /// The label of the labeled block (not of the loop itself). + labeled_block: Label, + }, } #[derive(Clone)] @@ -141,7 +149,12 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { } } hir::ExprKind::Loop(ref b, _, source, _) => { - self.with_context(Loop(source), |v| v.visit_block(b)); + let cx = match self.is_loop_match(e, b) { + Some(labeled_block) => LoopMatch { labeled_block }, + None => Loop(source), + }; + + self.with_context(cx, |v| v.visit_block(b)); } hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, fn_decl_span, kind, .. @@ -197,6 +210,23 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { Err(hir::LoopIdError::UnresolvedLabel) => None, }; + // A `#[const_continue]` must break to a block in a `#[loop_match]`. + if find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::ConstContinue(_)) { + if let Some(break_label) = break_label.label { + let is_target_label = |cx: &Context| match cx { + Context::LoopMatch { labeled_block } => { + break_label.ident.name == labeled_block.ident.name + } + _ => false, + }; + + if !self.cx_stack.iter().rev().any(is_target_label) { + let span = break_label.ident.span; + self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span }); + } + } + } + if let Some(Node::Block(_)) = loop_id.map(|id| self.tcx.hir_node(id)) { return; } @@ -299,7 +329,7 @@ impl<'hir> CheckLoopVisitor<'hir> { cx_pos: usize, ) { match self.cx_stack[cx_pos] { - LabeledBlock | Loop(_) => {} + LabeledBlock | Loop(_) | LoopMatch { .. } => {} Closure(closure_span) => { self.tcx.dcx().emit_err(BreakInsideClosure { span, @@ -380,4 +410,36 @@ impl<'hir> CheckLoopVisitor<'hir> { }); } } + + /// Is this a loop annotated with `#[loop_match]` that looks syntactically sound? + fn is_loop_match( + &self, + e: &'hir hir::Expr<'hir>, + body: &'hir hir::Block<'hir>, + ) -> Option std::ops::CoerceUnsized for A {} - -fn main() { - format_args!("Hello, world!"); -} diff --git a/tests/crashes/134217.rs b/tests/crashes/134217.rs deleted file mode 100644 index 1b14c660e8b4..000000000000 --- a/tests/crashes/134217.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #134217 - -impl std::ops::CoerceUnsized for A {} - -fn main() { - if let _ = true - && true - {} -} diff --git a/tests/crashes/138265.rs b/tests/crashes/138265.rs deleted file mode 100644 index f6c8ea748895..000000000000 --- a/tests/crashes/138265.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #138265 - -#![feature(coerce_unsized)] -#![crate_type = "lib"] -impl std::ops::CoerceUnsized for A {} -pub fn f() { - [0; { - let mut c = &0; - c = &0; - 0 - }] -} diff --git a/tests/ui/coercion/invalid-blanket-coerce-unsized-impl.rs b/tests/ui/coercion/invalid-blanket-coerce-unsized-impl.rs new file mode 100644 index 000000000000..a4fd77107188 --- /dev/null +++ b/tests/ui/coercion/invalid-blanket-coerce-unsized-impl.rs @@ -0,0 +1,13 @@ +// Regression test minimized from #126982. +// We used to apply a coerce_unsized coercion to literally every argument since +// the blanket applied in literally all cases, even though it was incoherent. + +#![feature(coerce_unsized)] + +impl std::ops::CoerceUnsized for A {} +//~^ ERROR type parameter `A` must be used as the type parameter for some local type +//~| ERROR the trait `CoerceUnsized` may only be implemented for a coercion between structures + +const C: usize = 1; + +fn main() {} diff --git a/tests/ui/coercion/invalid-blanket-coerce-unsized-impl.stderr b/tests/ui/coercion/invalid-blanket-coerce-unsized-impl.stderr new file mode 100644 index 000000000000..377906ee334a --- /dev/null +++ b/tests/ui/coercion/invalid-blanket-coerce-unsized-impl.stderr @@ -0,0 +1,19 @@ +error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g., `MyStruct`) + --> $DIR/invalid-blanket-coerce-unsized-impl.rs:7:6 + | +LL | impl std::ops::CoerceUnsized for A {} + | ^ type parameter `A` must be used as the type parameter for some local type + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0377]: the trait `CoerceUnsized` may only be implemented for a coercion between structures + --> $DIR/invalid-blanket-coerce-unsized-impl.rs:7:1 + | +LL | impl std::ops::CoerceUnsized for A {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0210, E0377. +For more information about an error, try `rustc --explain E0210`. From 46e9d2f9fc065e33cc54ccfa0e0e3c34376ebeaa Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Tue, 24 Jun 2025 13:51:02 -0400 Subject: [PATCH 326/356] Reduce mismatched-lifetime-syntaxes suggestions to MaybeIncorrect `cargo fix` does not have a way of distinguishing a suggestion with multiple spans which should all be applied from multiple suggestions where only one should be applied (see issue 53934). `cargo fix` only works with `MachineApplicable` suggestions, so downgrading the applicability will stop `cargo` from suggesting the user run `cargo fix`. rust-analyzer does work with `MaybeIncorrect`, so interactive fixes are still available. --- compiler/rustc_lint/src/lints.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index abdf8e3853bf..c4a6695efe95 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3261,7 +3261,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit, suggestions, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, style(tool_only), ); } @@ -3276,7 +3276,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed, suggestions, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, style(tool_only), ); } @@ -3291,7 +3291,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { diag.multipart_suggestion_with_style( msg, suggestions, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, style(tool_only), ); } From 84f92f3211726c4808453a25bc9be7b91d8cca53 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Tue, 24 Jun 2025 18:13:18 +0000 Subject: [PATCH 327/356] =?UTF-8?q?rustdoc:=20Don't=20mark=20`#[target=5Ff?= =?UTF-8?q?eature]`=20functions=20as=20=E2=9A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://www.github.com/rust-lang/rust/issues/142952 --- src/librustdoc/html/render/print_item.rs | 3 +- tests/rustdoc/target-feature.rs | 38 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc/target-feature.rs diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 515424cbef19..e16acc9622fc 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -469,7 +469,8 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i let unsafety_flag = match myitem.kind { clean::FunctionItem(_) | clean::ForeignFunctionItem(..) - if myitem.fn_header(tcx).unwrap().is_unsafe() => + if myitem.fn_header(tcx).unwrap().safety + == hir::HeaderSafety::Normal(hir::Safety::Unsafe) => { "" } diff --git a/tests/rustdoc/target-feature.rs b/tests/rustdoc/target-feature.rs new file mode 100644 index 000000000000..59a08a0ca949 --- /dev/null +++ b/tests/rustdoc/target-feature.rs @@ -0,0 +1,38 @@ +#![crate_name = "foo"] + +//@ has 'foo/index.html' + +//@ has - '//dl[@class="item-table"]/dt[1]//a' 'f1_safe' +//@ has - '//dl[@class="item-table"]/dt[1]//code' 'popcnt' +//@ count - '//dl[@class="item-table"]/dt[1]//sup' 0 +//@ has - '//dl[@class="item-table"]/dt[2]//a' 'f2_not_safe' +//@ has - '//dl[@class="item-table"]/dt[2]//code' 'avx2' +//@ count - '//dl[@class="item-table"]/dt[2]//sup' 1 +//@ has - '//dl[@class="item-table"]/dt[2]//sup' '⚠' + +#[target_feature(enable = "popcnt")] +//@ has 'foo/fn.f1_safe.html' +//@ matches - '//pre[@class="rust item-decl"]' '^pub fn f1_safe' +//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available with target feature popcnt only.' +pub fn f1_safe() {} + +//@ has 'foo/fn.f2_not_safe.html' +//@ matches - '//pre[@class="rust item-decl"]' '^pub unsafe fn f2_not_safe()' +//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available with target feature avx2 only.' +#[target_feature(enable = "avx2")] +pub unsafe fn f2_not_safe() {} + +//@ has 'foo/fn.f3_multifeatures_in_attr.html' +//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available on target features popcnt and avx2 only.' +#[target_feature(enable = "popcnt", enable = "avx2")] +pub fn f3_multifeatures_in_attr() {} + +//@ has 'foo/fn.f4_multi_attrs.html' +//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'Available on target features popcnt and avx2 only.' +#[target_feature(enable = "popcnt")] +#[target_feature(enable = "avx2")] +pub fn f4_multi_attrs() {} From 1080b571ec5187e8544918f64bd45f766718266f Mon Sep 17 00:00:00 2001 From: MetaNova Date: Tue, 24 Jun 2025 15:30:32 -0400 Subject: [PATCH 328/356] Corrected spelling mistake in c_str.rs Changed "you're" to "your" on line 470. --- library/core/src/ffi/c_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 1d2e13db218e..881a7a24083c 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -467,7 +467,7 @@ impl CStr { /// // 💀 this violates `CStr::from_ptr`'s safety contract /// // 💀 leading to a dereference of a dangling pointer, /// // 💀 which is immediate undefined behavior. - /// // 💀 *BOOM*, you're dead, you're entire program has no meaning. + /// // 💀 *BOOM*, you're dead, your entire program has no meaning. /// dbg!(unsafe { CStr::from_ptr(ptr) }); /// ``` /// From 5d44fdd972ee555b499c21068a03a5b3d88b1c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 21 Jun 2025 11:29:05 +0200 Subject: [PATCH 329/356] Rewrite #[track_caller] --- Cargo.lock | 1 + compiler/rustc_ast_lowering/Cargo.toml | 1 + compiler/rustc_ast_lowering/src/expr.rs | 3 +- .../src/attributes.rs | 3 ++ .../src/attributes/codegen_attrs.rs | 24 +++++++-- compiler/rustc_attr_parsing/src/context.rs | 5 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 54 +++++++++---------- .../rustc_hir_analysis/src/check/entry.rs | 9 ++-- compiler/rustc_lint/src/builtin.rs | 4 +- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 6 +-- .../lint/unused/unused-attr-duplicate.stderr | 24 ++++----- 12 files changed, 82 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a170ece0a0dd..36c8677883da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3282,6 +3282,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 6ac258155fe9..dc571f5c3671 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -11,6 +11,7 @@ doctest = false rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index f297bf9f4cfe..c2140514e311 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_ast_pretty::pprust::expr_to_string; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::HirId; @@ -831,7 +832,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) { if self.tcx.features().async_fn_track_caller() && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) - && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) + && find_attr!(*attrs, AttributeKind::TrackCaller(_)) { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index ae3a1a413871..008fc44f3cd8 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -268,5 +268,8 @@ pub enum AttributeKind { /// Span of the attribute. span: Span, }, + + /// Represents `#[track_caller]` + TrackCaller(Span), // tidy-alphabetical-end } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 0fa69c401546..eadf8657a0fd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,7 +1,7 @@ use rustc_attr_data_structures::{AttributeKind, OptimizeAttr}; use rustc_feature::{AttributeTemplate, template}; use rustc_session::parse::feature_err; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; @@ -11,7 +11,7 @@ use crate::session_diagnostics::NakedFunctionIncompatibleAttribute; pub(crate) struct OptimizeParser; impl SingleAttributeParser for OptimizeParser { - const PATH: &[rustc_span::Symbol] = &[sym::optimize]; + const PATH: &[Symbol] = &[sym::optimize]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none"); @@ -44,7 +44,7 @@ impl SingleAttributeParser for OptimizeParser { pub(crate) struct ColdParser; impl SingleAttributeParser for ColdParser { - const PATH: &[rustc_span::Symbol] = &[sym::cold]; + const PATH: &[Symbol] = &[sym::cold]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const TEMPLATE: AttributeTemplate = template!(Word); @@ -166,6 +166,24 @@ impl AttributeParser for NakedParser { } } +pub(crate) struct TrackCallerParser; + +impl SingleAttributeParser for TrackCallerParser { + const PATH: &[Symbol] = &[sym::track_caller]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if let Err(span) = args.no_args() { + cx.expected_no_args(span); + return None; + } + + Some(AttributeKind::TrackCaller(cx.attr_span)) + } +} + pub(crate) struct NoMangleParser; impl SingleAttributeParser for NoMangleParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 43b2d07dbe10..22caf8553af8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,7 +15,9 @@ use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; -use crate::attributes::codegen_attrs::{ColdParser, NakedParser, NoMangleParser, OptimizeParser}; +use crate::attributes::codegen_attrs::{ + ColdParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser, +}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -121,6 +123,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, // tidy-alphabetical-end ]; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index f769b3935281..7bd27eb3ef1c 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -95,17 +95,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // In these cases, we bail from performing further checks that are only meaningful for // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also // report a delayed bug, just in case `check_attr` isn't doing its job. - let fn_sig = || { + let fn_sig = |attr_span| { use DefKind::*; let def_kind = tcx.def_kind(did); if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { - tcx.dcx().span_delayed_bug( - attr.span(), - "this attribute can only be applied to functions", - ); + tcx.dcx() + .span_delayed_bug(attr_span, "this attribute can only be applied to functions"); None } }; @@ -142,6 +140,29 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { }); } } + AttributeKind::TrackCaller(attr_span) => { + let is_closure = tcx.is_closure_like(did.to_def_id()); + + if !is_closure + && let Some(fn_sig) = fn_sig(*attr_span) + && fn_sig.skip_binder().abi() != ExternAbi::Rust + { + tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span }); + } + if is_closure + && !tcx.features().closure_track_caller() + && !attr_span.allows_unstable(sym::closure_track_caller) + { + feature_err( + &tcx.sess, + sym::closure_track_caller, + *attr_span, + "`#[track_caller]` on closures is currently unstable", + ) + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER + } _ => {} } } @@ -202,29 +223,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, - sym::track_caller => { - let is_closure = tcx.is_closure_like(did.to_def_id()); - - if !is_closure - && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().abi() != ExternAbi::Rust - { - tcx.dcx().emit_err(errors::RequiresRustAbi { span: attr.span() }); - } - if is_closure - && !tcx.features().closure_track_caller() - && !attr.span().allows_unstable(sym::closure_track_caller) - { - feature_err( - &tcx.sess, - sym::closure_track_caller, - attr.span(), - "`#[track_caller]` on closures is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER - } sym::export_name => { if let Some(s) = attr.value_str() { if s.as_str().contains('\0') { diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 3bad36da9990..b556683e80a5 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -1,14 +1,15 @@ use std::ops::Not; use rustc_abi::ExternAbi; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; +use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -98,8 +99,10 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { error = true; } - for attr in tcx.get_attrs(main_def_id, sym::track_caller) { - tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span(), annotated: main_span }); + if let Some(attr_span) = + find_attr!(tcx.get_all_attrs(main_def_id), AttributeKind::TrackCaller(span) => *span) + { + tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span }); error = true; } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ac405277c4ed..5bbe69c8d65d 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1184,11 +1184,11 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { if fn_kind.asyncness().is_async() && !cx.tcx.features().async_fn_track_caller() // Now, check if the function has the `#[track_caller]` attribute - && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) + && let Some(attr_span) = find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::TrackCaller(span) => *span) { cx.emit_span_lint( UNGATED_ASYNC_FN_TRACK_CALLER, - attr.span(), + attr_span, BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess }, ); } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 47e29923ee59..68d78af59431 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -301,6 +301,7 @@ fn emit_malformed_attribute( | sym::naked | sym::no_mangle | sym::must_use + | sym::track_caller ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 25b841794435..fc190b928162 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -169,6 +169,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Naked(attr_span)) => { self.check_naked(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => { + self.check_track_caller(hir_id, *attr_span, attrs, span, target) + } Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -205,9 +208,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_target_feature(hir_id, attr, span, target, attrs) } [sym::thread_local, ..] => self.check_thread_local(attr, span, target), - [sym::track_caller, ..] => { - self.check_track_caller(hir_id, attr.span(), attrs, span, target) - } [sym::doc, ..] => self.check_doc_attrs( attr, attr_item.style, diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 4abf7dd134e6..df6cada6b06f 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -89,18 +89,6 @@ note: attribute also specified here LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:79:1 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:78:1 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:92:1 | @@ -277,6 +265,18 @@ note: attribute also specified here LL | #[cold] | ^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:79:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:78:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + error: unused attribute --> $DIR/unused-attr-duplicate.rs:98:1 | From 40a33af0f3dc8e16b2b954d7af3dd782f7b13497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 21 Jun 2025 12:42:24 +0200 Subject: [PATCH 330/356] fix clippy --- src/tools/clippy/clippy_lints/src/eta_reduction.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 6ed7c87915b2..b0077a9b05fe 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -7,6 +7,7 @@ use clippy_utils::{ get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id, }; use rustc_abi::ExternAbi; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_errors::Applicability; use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind}; use rustc_infer::infer::TyCtxtInferExt; @@ -155,7 +156,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx let sig = match callee_ty_adjusted.kind() { ty::FnDef(def, _) => { // Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location` - if cx.tcx.has_attr(*def, sym::track_caller) { + if find_attr!(cx.tcx.get_all_attrs(*def), AttributeKind::TrackCaller(..)) { return; } @@ -236,7 +237,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx }, ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => { if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id) - && !cx.tcx.has_attr(method_def_id, sym::track_caller) + && !find_attr!(cx.tcx.get_all_attrs(method_def_id), AttributeKind::TrackCaller(..)) && check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder()) { let mut app = Applicability::MachineApplicable; From f9cdf3fd746bc8a20d2bfd62189180ea69029627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 21 Jun 2025 13:04:24 +0200 Subject: [PATCH 331/356] fix 142783 --- compiler/rustc_passes/src/check_attr.rs | 4 +--- .../ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr | 8 ++++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index fc190b928162..7eb74b38dabf 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -722,9 +722,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - for attr in attrs { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller"); - } + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "track_caller"); } _ => { self.dcx().emit_err(errors::TrackedCallerWrongLocation { diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr index e22d812c8b03..6088945b829c 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr @@ -1,8 +1,12 @@ -error: malformed `track_caller` attribute input +error[E0565]: malformed `track_caller` attribute input --> $DIR/error-odd-syntax.rs:1:1 | LL | #[track_caller(1)] - | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]` + | ^^^^^^^^^^^^^^---^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[track_caller]` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0565`. From 4c7f0549babffa28ed2d3f73f28fe0cb74f828e0 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Sat, 21 Jun 2025 13:06:18 -0700 Subject: [PATCH 332/356] Enable short-ice for Windows --- tests/run-make/short-ice/rmake.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/run-make/short-ice/rmake.rs b/tests/run-make/short-ice/rmake.rs index 8377954f4672..483def62fc79 100644 --- a/tests/run-make/short-ice/rmake.rs +++ b/tests/run-make/short-ice/rmake.rs @@ -5,8 +5,9 @@ // See https://github.com/rust-lang/rust/issues/107910 //@ needs-target-std -//@ ignore-windows -// Reason: the assert_eq! on line 32 fails, as error output on Windows is different. +//@ ignore-i686-pc-windows-msvc +// Reason: the assert_eq! on line 37 fails, almost seems like it missing debug info? +// Haven't been able to reproduce locally, but it happens on CI. use run_make_support::rustc; @@ -29,10 +30,16 @@ fn main() { let rustc_query_count_full = count_lines_with(rust_test_log_2, "rustc_query_"); - assert!(rust_test_log_1.lines().count() < rust_test_log_2.lines().count()); + assert!( + rust_test_log_1.lines().count() < rust_test_log_2.lines().count(), + "Short backtrace should be shorter than full backtrace.\nShort backtrace:\n\ + {rust_test_log_1}\nFull backtrace:\n{rust_test_log_2}" + ); assert_eq!( count_lines_with(rust_test_log_2, "__rust_begin_short_backtrace"), - count_lines_with(rust_test_log_2, "__rust_end_short_backtrace") + count_lines_with(rust_test_log_2, "__rust_end_short_backtrace"), + "Full backtrace should contain the short backtrace markers.\nFull backtrace:\n\ + {rust_test_log_2}" ); assert!(count_lines_with(rust_test_log_1, "rustc_query_") + 5 < rustc_query_count_full); assert!(rustc_query_count_full > 5); From e245570def155191b61f73647eb543dd45685b2f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Jun 2025 22:29:54 +0000 Subject: [PATCH 333/356] Add rust-invalid ABI --- compiler/rustc_abi/src/extern_abi.rs | 5 +++++ compiler/rustc_ast_lowering/src/stability.rs | 3 +++ compiler/rustc_middle/src/ty/layout.rs | 3 ++- compiler/rustc_smir/src/rustc_internal/internal.rs | 1 + compiler/rustc_smir/src/rustc_smir/convert/ty.rs | 1 + compiler/rustc_smir/src/stable_mir/ty.rs | 1 + compiler/rustc_target/src/spec/abi_map.rs | 3 ++- tests/ui/abi/invalid-call-abi.rs | 12 ++++++++++++ tests/ui/abi/invalid-call-abi.stderr | 9 +++++++++ tests/ui/print-calling-conventions.stdout | 1 + 10 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 tests/ui/abi/invalid-call-abi.rs create mode 100644 tests/ui/abi/invalid-call-abi.stderr diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 7457ae1f0334..1b8c2de15880 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -36,6 +36,10 @@ pub enum ExternAbi { /// Stronger than just `#[cold]` because `fn` pointers might be incompatible. RustCold, + /// An always-invalid ABI that's used to test "this ABI is not supported by this platform" + /// in a platform-agnostic way. + RustInvalid, + /// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM. /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! Unadjusted, @@ -157,6 +161,7 @@ abi_impls! { RiscvInterruptS =><= "riscv-interrupt-s", RustCall =><= "rust-call", RustCold =><= "rust-cold", + RustInvalid =><= "rust-invalid", Stdcall { unwind: false } =><= "stdcall", Stdcall { unwind: true } =><= "stdcall-unwind", System { unwind: false } =><= "system", diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index b8fa2dd3dd62..9b60807e6508 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -96,6 +96,9 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { ExternAbi::RustCold => { Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental }) } + ExternAbi::RustInvalid => { + Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail }) + } ExternAbi::GpuKernel => Err(UnstableAbi { abi, feature: sym::abi_gpu_kernel, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 13c281a61827..5cb943b0d8c6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1253,7 +1253,8 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) | CCmseNonSecureCall | CCmseNonSecureEntry | Custom - | Unadjusted => false, + | Unadjusted + | RustInvalid => false, Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, } } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index a4c6f1862221..c0d9937e34de 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -494,6 +494,7 @@ impl RustcInternal for Abi { Abi::RustCall => rustc_abi::ExternAbi::RustCall, Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted, Abi::RustCold => rustc_abi::ExternAbi::RustCold, + Abi::RustInvalid => rustc_abi::ExternAbi::RustInvalid, Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, Abi::Custom => rustc_abi::ExternAbi::Custom, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b4239ddd896e..2c652c7546e9 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -877,6 +877,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::RustCall => Abi::RustCall, ExternAbi::Unadjusted => Abi::Unadjusted, ExternAbi::RustCold => Abi::RustCold, + ExternAbi::RustInvalid => Abi::RustInvalid, ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, ExternAbi::Custom => Abi::Custom, diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 4415cd6e2e3b..1ae79491642d 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1126,6 +1126,7 @@ pub enum Abi { RustCold, RiscvInterruptM, RiscvInterruptS, + RustInvalid, Custom, } diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index 42ec10a8e157..ce1bdcbb8acc 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -156,7 +156,8 @@ impl AbiMap { | ExternAbi::Msp430Interrupt | ExternAbi::RiscvInterruptM | ExternAbi::RiscvInterruptS - | ExternAbi::X86Interrupt, + | ExternAbi::X86Interrupt + | ExternAbi::RustInvalid, _, ) => return AbiMapping::Invalid, }; diff --git a/tests/ui/abi/invalid-call-abi.rs b/tests/ui/abi/invalid-call-abi.rs new file mode 100644 index 000000000000..076ddd91ab0f --- /dev/null +++ b/tests/ui/abi/invalid-call-abi.rs @@ -0,0 +1,12 @@ +// Tests the `"rustc-invalid"` ABI, which is never canonizable. + +#![feature(rustc_attrs)] + +const extern "rust-invalid" fn foo() { + //~^ ERROR "rust-invalid" is not a supported ABI for the current target + panic!() +} + +fn main() { + foo(); +} diff --git a/tests/ui/abi/invalid-call-abi.stderr b/tests/ui/abi/invalid-call-abi.stderr new file mode 100644 index 000000000000..c4a90158dcfe --- /dev/null +++ b/tests/ui/abi/invalid-call-abi.stderr @@ -0,0 +1,9 @@ +error[E0570]: "rust-invalid" is not a supported ABI for the current target + --> $DIR/invalid-call-abi.rs:5:14 + | +LL | const extern "rust-invalid" fn foo() { + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout index 7b5ae4956606..4df6bd27f457 100644 --- a/tests/ui/print-calling-conventions.stdout +++ b/tests/ui/print-calling-conventions.stdout @@ -20,6 +20,7 @@ riscv-interrupt-m riscv-interrupt-s rust-call rust-cold +rust-invalid stdcall stdcall-unwind system From e776065164f22872e8cadf5bc5e47352c27982dc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Jun 2025 19:32:29 +0000 Subject: [PATCH 334/356] Taint body on invalid call ABI --- compiler/rustc_hir_typeck/src/callee.rs | 11 ++++++++++- tests/ui/abi/invalid-call-abi-ctfe.rs | 14 ++++++++++++++ tests/ui/abi/invalid-call-abi-ctfe.stderr | 9 +++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/ui/abi/invalid-call-abi-ctfe.rs create mode 100644 tests/ui/abi/invalid-call-abi-ctfe.stderr diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 7a3647df0c40..f790c51f8f19 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -156,7 +156,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn check_call_abi(&self, abi: ExternAbi, span: Span) { let canon_abi = match AbiMap::from_target(&self.sess().target).canonize_abi(abi, false) { AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => canon_abi, - AbiMapping::Invalid => return, + AbiMapping::Invalid => { + // This should be reported elsewhere, but we want to taint this body + // so that we don't try to evaluate calls to ABIs that are invalid. + let guar = self.dcx().span_delayed_bug( + span, + format!("invalid abi for platform should have reported an error: {abi}"), + ); + self.set_tainted_by_errors(guar); + return; + } }; let valid = match canon_abi { diff --git a/tests/ui/abi/invalid-call-abi-ctfe.rs b/tests/ui/abi/invalid-call-abi-ctfe.rs new file mode 100644 index 000000000000..343cc728fe3b --- /dev/null +++ b/tests/ui/abi/invalid-call-abi-ctfe.rs @@ -0,0 +1,14 @@ +// Fix for #142969 where an invalid ABI in a signature still had its call ABI computed +// because CTFE tried to evaluate it, despite previous errors during AST-to-HIR lowering. + +#![feature(rustc_attrs)] + +const extern "rust-invalid" fn foo() { + //~^ ERROR "rust-invalid" is not a supported ABI for the current target + panic!() +} + +const _: () = foo(); + + +fn main() {} diff --git a/tests/ui/abi/invalid-call-abi-ctfe.stderr b/tests/ui/abi/invalid-call-abi-ctfe.stderr new file mode 100644 index 000000000000..402de4b69b97 --- /dev/null +++ b/tests/ui/abi/invalid-call-abi-ctfe.stderr @@ -0,0 +1,9 @@ +error[E0570]: "rust-invalid" is not a supported ABI for the current target + --> $DIR/invalid-call-abi-ctfe.rs:6:14 + | +LL | const extern "rust-invalid" fn foo() { + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. From 4a112db96b134f5c184a6f3b14f2b1ec775014a0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Jun 2025 15:48:09 -0700 Subject: [PATCH 335/356] Update wasm-component-ld to 0.5.14 This brings in a few updates to the bundled `wasm-component-ld` dependency used by the `wasm32-wasip2` target. This primarily includes support for upcoming component model async/WASIp3 support which will be convenient to have native support for a few months from now. --- Cargo.lock | 51 +++++++++++--------------- src/tools/tidy/src/deps.rs | 1 + src/tools/wasm-component-ld/Cargo.toml | 2 +- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a170ece0a0dd..7e38cab4d017 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5798,9 +5798,9 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "31.0.0" +version = "34.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fabda09a0d89ffd1615b297b4a5d4b4d99df9598aeb24685837e63019e927b" +checksum = "aafa1e6af9a954a4bcf6ef420c33355d0ce84ddc6afbcba7bb6f05126f9120ae" [[package]] name = "wasm-bindgen" @@ -5862,9 +5862,9 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60a07a994a3538b57d8c5f8caba19f4793fb4c7156276e5e90e90acbb829e20" +checksum = "b015ec93764aa5517bc8b839efa9941b90be8ce680b1134f8224644ba1e48e3f" dependencies = [ "anyhow", "clap", @@ -5872,7 +5872,7 @@ dependencies = [ "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.229.0", + "wasmparser 0.234.0", "wat", "windows-sys 0.59.0", "winsplit", @@ -5899,12 +5899,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.229.0" +version = "0.234.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ba1d491ecacb085a2552025c10a675a6fddcbd03b1fc9b36c536010ce265d2" +checksum = "170a0157eef517a179f2d20ed7c68df9c3f7f6c1c047782d488bf5a464174684" dependencies = [ "leb128fmt", - "wasmparser 0.229.0", + "wasmparser 0.234.0", ] [[package]] @@ -5919,14 +5919,14 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.229.0" +version = "0.234.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78fdb7d29a79191ab363dc90c1ddd3a1e880ffd5348d92d48482393a9e6c5f4d" +checksum = "a42fe3f5cbfb56fc65311ef827930d06189160038e81db62188f66b4bf468e3a" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.229.0", - "wasmparser 0.229.0", + "wasm-encoder 0.234.0", + "wasmparser 0.234.0", ] [[package]] @@ -5941,9 +5941,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.229.0" +version = "0.234.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c" +checksum = "be22e5a8f600afce671dd53c8d2dd26b4b7aa810fd18ae27dfc49737f3e02fc5" dependencies = [ "bitflags", "hashbrown", @@ -5952,15 +5952,6 @@ dependencies = [ "serde", ] -[[package]] -name = "wasmparser" -version = "0.234.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be22e5a8f600afce671dd53c8d2dd26b4b7aa810fd18ae27dfc49737f3e02fc5" -dependencies = [ - "bitflags", -] - [[package]] name = "wasmparser" version = "0.235.0" @@ -6413,9 +6404,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.229.0" +version = "0.234.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f550067740e223bfe6c4878998e81cdbe2529dd9a793dc49248dd6613394e8b" +checksum = "5a8888169acf4c6c4db535beb405b570eedac13215d6821ca9bd03190f7f8b8c" dependencies = [ "anyhow", "bitflags", @@ -6424,17 +6415,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.229.0", + "wasm-encoder 0.234.0", "wasm-metadata", - "wasmparser 0.229.0", + "wasmparser 0.234.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.229.0" +version = "0.234.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459c6ba62bf511d6b5f2a845a2a736822e38059c1cfa0b644b467bbbfae4efa6" +checksum = "465492df47d8dcc015a3b7f241aed8ea03688fee7c5e04162285c5b1a3539c8b" dependencies = [ "anyhow", "id-arena", @@ -6445,7 +6436,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.229.0", + "wasmparser 0.234.0", ] [[package]] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 4e0bbcd7c6c2..bf813d2131e8 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -374,6 +374,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "scoped-tls", "scopeguard", "self_cell", + "semver", "serde", "serde_derive", "serde_json", diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index 642d48b9952e..ce718902b29f 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.13" +wasm-component-ld = "0.5.14" From 041fbe8543e2c0b351747edf5ad1af799a26eb16 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 24 Jun 2025 17:21:19 -0700 Subject: [PATCH 336/356] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 84709f085062..409fed7dc155 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 84709f085062cbf3c51fa507527c1b2334015178 +Subproject commit 409fed7dc1553d49cb9a8c0637d12d65571346ce From 066ae4cf982bb7f35933a7cc812123f05e7e1608 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Wed, 25 Jun 2025 02:08:32 +0000 Subject: [PATCH 337/356] submodule update Signed-off-by: Karan Janthe --- src/tools/enzyme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/enzyme b/src/tools/enzyme index a35f4f773118..b5098d515d5e 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit a35f4f773118ccfbd8d05102eb12a34097b1ee55 +Subproject commit b5098d515d5e1bd0f5470553bc0d18da9794ca8b From 7b1c89f2b58515bba671de38ba974edb58429973 Mon Sep 17 00:00:00 2001 From: Karan Janthe Date: Wed, 25 Jun 2025 02:06:53 +0000 Subject: [PATCH 338/356] added PrintTAFn flag for autodiff Signed-off-by: Karan Janthe --- compiler/rustc_codegen_llvm/src/back/lto.rs | 6 +++++- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 17 +++++++++++++++++ compiler/rustc_session/src/config.rs | 4 +++- compiler/rustc_session/src/options.rs | 17 +++++++++++++++-- src/doc/rustc-dev-guide/src/autodiff/flags.md | 1 + .../src/compiler-flags/autodiff.md | 1 + 6 files changed, 42 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index ee46b49a094c..9c62244f3c9f 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -587,7 +587,7 @@ fn thin_lto( } fn enable_autodiff_settings(ad: &[config::AutoDiff]) { - for &val in ad { + for val in ad { // We intentionally don't use a wildcard, to not forget handling anything new. match val { config::AutoDiff::PrintPerf => { @@ -599,6 +599,10 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) { config::AutoDiff::PrintTA => { llvm::set_print_type(true); } + config::AutoDiff::PrintTAFn(fun) => { + llvm::set_print_type(true); // Enable general type printing + llvm::set_print_type_fun(&fun); // Set specific function to analyze + } config::AutoDiff::Inline => { llvm::set_inline(true); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 2ad39fc85381..b94716b89d61 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -57,14 +57,19 @@ pub(crate) use self::Enzyme_AD::*; #[cfg(llvm_enzyme)] pub(crate) mod Enzyme_AD { + use std::ffi::{CString, c_char}; + use libc::c_void; + unsafe extern "C" { pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); + pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char); } unsafe extern "C" { static mut EnzymePrintPerf: c_void; static mut EnzymePrintActivity: c_void; static mut EnzymePrintType: c_void; + static mut EnzymeFunctionToAnalyze: c_void; static mut EnzymePrint: c_void; static mut EnzymeStrictAliasing: c_void; static mut looseTypeAnalysis: c_void; @@ -86,6 +91,15 @@ pub(crate) mod Enzyme_AD { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintType), print as u8); } } + pub(crate) fn set_print_type_fun(fun_name: &str) { + let c_fun_name = CString::new(fun_name).unwrap(); + unsafe { + EnzymeSetCLString( + std::ptr::addr_of_mut!(EnzymeFunctionToAnalyze), + c_fun_name.as_ptr() as *const c_char, + ); + } + } pub(crate) fn set_print(print: bool) { unsafe { EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrint), print as u8); @@ -132,6 +146,9 @@ pub(crate) mod Fallback_AD { pub(crate) fn set_print_type(print: bool) { unimplemented!() } + pub(crate) fn set_print_type_fun(fun_name: &str) { + unimplemented!() + } pub(crate) fn set_print(print: bool) { unimplemented!() } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 60e1b465ba96..0f3e53d03d65 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -227,13 +227,15 @@ pub enum CoverageLevel { } /// The different settings that the `-Z autodiff` flag can have. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] +#[derive(Clone, PartialEq, Hash, Debug)] pub enum AutoDiff { /// Enable the autodiff opt pipeline Enable, /// Print TypeAnalysis information PrintTA, + /// Print TypeAnalysis information for a specific function + PrintTAFn(String), /// Print ActivityAnalysis Information PrintAA, /// Print Performance Warnings from Enzyme diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 12fa05118caf..513a006e7905 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -711,7 +711,7 @@ mod desc { pub(crate) const parse_list: &str = "a space-separated list of strings"; pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; - pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; + pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; pub(crate) const parse_number: &str = "a number"; @@ -1351,9 +1351,22 @@ pub mod parse { let mut v: Vec<&str> = v.split(",").collect(); v.sort_unstable(); for &val in v.iter() { - let variant = match val { + // Split each entry on '=' if it has an argument + let (key, arg) = match val.split_once('=') { + Some((k, a)) => (k, Some(a)), + None => (val, None), + }; + + let variant = match key { "Enable" => AutoDiff::Enable, "PrintTA" => AutoDiff::PrintTA, + "PrintTAFn" => { + if let Some(fun) = arg { + AutoDiff::PrintTAFn(fun.to_string()) + } else { + return false; + } + } "PrintAA" => AutoDiff::PrintAA, "PrintPerf" => AutoDiff::PrintPerf, "PrintSteps" => AutoDiff::PrintSteps, diff --git a/src/doc/rustc-dev-guide/src/autodiff/flags.md b/src/doc/rustc-dev-guide/src/autodiff/flags.md index 65287d9ba4c1..efbb9ea3497c 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/flags.md +++ b/src/doc/rustc-dev-guide/src/autodiff/flags.md @@ -6,6 +6,7 @@ To support you while debugging or profiling, we have added support for an experi ```text PrintTA // Print TypeAnalysis information +PrintTAFn // Print TypeAnalysis information for a specific function PrintAA // Print ActivityAnalysis information Print // Print differentiated functions while they are being generated and optimized PrintPerf // Print AD related Performance warnings diff --git a/src/doc/unstable-book/src/compiler-flags/autodiff.md b/src/doc/unstable-book/src/compiler-flags/autodiff.md index 95c188d1f3b2..28d2ece1468f 100644 --- a/src/doc/unstable-book/src/compiler-flags/autodiff.md +++ b/src/doc/unstable-book/src/compiler-flags/autodiff.md @@ -10,6 +10,7 @@ Multiple options can be separated with a comma. Valid options are: `Enable` - Required flag to enable autodiff `PrintTA` - print Type Analysis Information +`PrintTAFn` - print Type Analysis Information for a specific function `PrintAA` - print Activity Analysis Information `PrintPerf` - print Performance Warnings from Enzyme `PrintSteps` - prints all intermediate transformations From 35deb5bce456439c8a1af31f6e30dc94fbf4060a Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 22:46:10 -0700 Subject: [PATCH 339/356] compiler: Trim the misleading C from ExternAbi::CCmse* --- compiler/rustc_abi/src/canon_abi.rs | 4 ++-- compiler/rustc_abi/src/extern_abi.rs | 8 ++++---- compiler/rustc_ast_lowering/src/stability.rs | 4 ++-- .../rustc_hir_analysis/src/hir_ty_lowering/cmse.rs | 8 ++++---- compiler/rustc_middle/src/ty/layout.rs | 10 +++++----- compiler/rustc_smir/src/rustc_internal/internal.rs | 4 ++-- compiler/rustc_smir/src/rustc_smir/convert/ty.rs | 4 ++-- compiler/rustc_target/src/spec/abi_map.rs | 6 +++--- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 7c020be67617..13f9a04b286f 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -63,8 +63,8 @@ impl fmt::Display for CanonAbi { CanonAbi::Custom => ExternAbi::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, - ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, - ArmCall::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, + ArmCall::CCmseNonSecureCall => ExternAbi::CmseNonSecureCall, + ArmCall::CCmseNonSecureEntry => ExternAbi::CmseNonSecureEntry, }, CanonAbi::GpuKernel => ExternAbi::GpuKernel, CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 1b8c2de15880..29a3678abf3f 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -59,9 +59,9 @@ pub enum ExternAbi { unwind: bool, }, /// extremely constrained barely-C ABI for TrustZone - CCmseNonSecureCall, + CmseNonSecureCall, /// extremely constrained barely-C ABI for TrustZone - CCmseNonSecureEntry, + CmseNonSecureEntry, /* gpu */ /// An entry-point function called by the GPU's host @@ -140,8 +140,6 @@ macro_rules! abi_impls { abi_impls! { ExternAbi = { C { unwind: false } =><= "C", - CCmseNonSecureCall =><= "C-cmse-nonsecure-call", - CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry", C { unwind: true } =><= "C-unwind", Rust =><= "Rust", Aapcs { unwind: false } =><= "aapcs", @@ -150,6 +148,8 @@ abi_impls! { AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt", Cdecl { unwind: false } =><= "cdecl", Cdecl { unwind: true } =><= "cdecl-unwind", + CmseNonSecureCall =><= "cmse-nonsecure-call", + CmseNonSecureEntry =><= "cmse-nonsecure-entry", Custom =><= "custom", EfiApi =><= "efiapi", Fastcall { unwind: false } =><= "fastcall", diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index 9b60807e6508..9bd4db7c9178 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -127,12 +127,12 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { feature: sym::abi_riscv_interrupt, explain: GateReason::Experimental, }), - ExternAbi::CCmseNonSecureCall => Err(UnstableAbi { + ExternAbi::CmseNonSecureCall => Err(UnstableAbi { abi, feature: sym::abi_c_cmse_nonsecure_call, explain: GateReason::Experimental, }), - ExternAbi::CCmseNonSecureEntry => Err(UnstableAbi { + ExternAbi::CmseNonSecureEntry => Err(UnstableAbi { abi, feature: sym::cmse_nonsecure_entry, explain: GateReason::Experimental, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index ebeb3b58208e..501c8b2b7829 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -18,7 +18,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( fn_sig: ty::PolyFnSig<'tcx>, ) { match abi { - ExternAbi::CCmseNonSecureCall => { + ExternAbi::CmseNonSecureCall => { let hir_node = tcx.hir_node(hir_id); let hir::Node::Ty(hir::Ty { span: bare_fn_span, @@ -78,7 +78,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( } }; } - ExternAbi::CCmseNonSecureEntry => { + ExternAbi::CmseNonSecureEntry => { let hir_node = tcx.hir_node(hir_id); let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else { // might happen when this ABI is used incorrectly. That will be handled elsewhere @@ -203,11 +203,11 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError match layout_err { TooGeneric(ty) => { match abi { - ExternAbi::CCmseNonSecureCall => { + ExternAbi::CmseNonSecureCall => { // prevent double reporting of this error !ty.is_impl_trait() } - ExternAbi::CCmseNonSecureEntry => true, + ExternAbi::CmseNonSecureEntry => true, _ => bug!("invalid ABI: {abi}"), } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 5cb943b0d8c6..90b832df281f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1248,13 +1248,13 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: ExternAbi) | EfiApi | AvrInterrupt | AvrNonBlockingInterrupt + | CmseNonSecureCall + | CmseNonSecureEntry + | Custom | RiscvInterruptM | RiscvInterruptS - | CCmseNonSecureCall - | CCmseNonSecureEntry - | Custom - | Unadjusted - | RustInvalid => false, + | RustInvalid + | Unadjusted => false, Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, } } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index c0d9937e34de..24351eee1c4c 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -479,6 +479,8 @@ impl RustcInternal for Abi { Abi::Vectorcall { unwind } => rustc_abi::ExternAbi::Vectorcall { unwind }, Abi::Thiscall { unwind } => rustc_abi::ExternAbi::Thiscall { unwind }, Abi::Aapcs { unwind } => rustc_abi::ExternAbi::Aapcs { unwind }, + Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CmseNonSecureCall, + Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CmseNonSecureEntry, Abi::Win64 { unwind } => rustc_abi::ExternAbi::Win64 { unwind }, Abi::SysV64 { unwind } => rustc_abi::ExternAbi::SysV64 { unwind }, Abi::PtxKernel => rustc_abi::ExternAbi::PtxKernel, @@ -488,8 +490,6 @@ impl RustcInternal for Abi { Abi::EfiApi => rustc_abi::ExternAbi::EfiApi, Abi::AvrInterrupt => rustc_abi::ExternAbi::AvrInterrupt, Abi::AvrNonBlockingInterrupt => rustc_abi::ExternAbi::AvrNonBlockingInterrupt, - Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CCmseNonSecureCall, - Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CCmseNonSecureEntry, Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind }, Abi::RustCall => rustc_abi::ExternAbi::RustCall, Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 2c652c7546e9..7abec488151c 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -871,8 +871,8 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::EfiApi => Abi::EfiApi, ExternAbi::AvrInterrupt => Abi::AvrInterrupt, ExternAbi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, - ExternAbi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, - ExternAbi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry, + ExternAbi::CmseNonSecureCall => Abi::CCmseNonSecureCall, + ExternAbi::CmseNonSecureEntry => Abi::CCmseNonSecureEntry, ExternAbi::System { unwind } => Abi::System { unwind }, ExternAbi::RustCall => Abi::RustCall, ExternAbi::Unadjusted => Abi::Unadjusted, diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index ce1bdcbb8acc..fde3adb034da 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -93,13 +93,13 @@ impl AbiMap { (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid, - (ExternAbi::CCmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => { + (ExternAbi::CmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => { CanonAbi::Arm(ArmCall::CCmseNonSecureCall) } - (ExternAbi::CCmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => { + (ExternAbi::CmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => { CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) } - (ExternAbi::CCmseNonSecureCall | ExternAbi::CCmseNonSecureEntry, ..) => { + (ExternAbi::CmseNonSecureCall | ExternAbi::CmseNonSecureEntry, ..) => { return AbiMapping::Invalid; } From 4bdf1c574a3b02daaf5793d71d089e94d192f57f Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 24 Jun 2025 13:09:55 -0700 Subject: [PATCH 340/356] compiler: remove misleading 'c' from `abi_c_cmse_nonsecure_call` feature --- compiler/rustc_ast_lowering/src/stability.rs | 2 +- compiler/rustc_feature/src/removed.rs | 1 + compiler/rustc_feature/src/unstable.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index 9bd4db7c9178..6752218fa0d4 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -129,7 +129,7 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { }), ExternAbi::CmseNonSecureCall => Err(UnstableAbi { abi, - feature: sym::abi_c_cmse_nonsecure_call, + feature: sym::abi_cmse_nonsecure_call, explain: GateReason::Experimental, }), ExternAbi::CmseNonSecureEntry => Err(UnstableAbi { diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index c54b831e2444..ddb99585bc24 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -54,6 +54,7 @@ declare_features! ( /// Allows using the `amdgpu-kernel` ABI. (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None, 120495), + (removed, abi_c_cmse_nonsecure_call, "CURRENT_RUSTC_VERSION", Some(81391), Some("renamed to abi_cmse_nonsecure_call"), 142146), (removed, advanced_slice_patterns, "1.42.0", Some(62254), Some("merged into `#![feature(slice_patterns)]`"), 67712), (removed, allocator, "1.0.0", None, None), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index d9d5334615a3..f5d128a5fb2e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -353,8 +353,8 @@ declare_features! ( /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. (unstable, abi_avr_interrupt, "1.45.0", Some(69664)), - /// Allows `extern "C-cmse-nonsecure-call" fn()`. - (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)), + /// Allows `extern "cmse-nonsecure-call" fn()`. + (unstable, abi_cmse_nonsecure_call, "CURRENT_RUSTC_VERSION", Some(81391)), /// Allows `extern "custom" fn()`. (unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)), /// Allows `extern "gpu-kernel" fn()`. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c9262d24a171..11463ad354a9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -406,6 +406,7 @@ symbols! { abi_amdgpu_kernel, abi_avr_interrupt, abi_c_cmse_nonsecure_call, + abi_cmse_nonsecure_call, abi_custom, abi_efiapi, abi_gpu_kernel, From 383d76106baa2042481de88dfff8ed2043ac50e6 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 23:05:47 -0700 Subject: [PATCH 341/356] compiler: Trim the misleading C of C-cmse from errors --- .../rustc_error_codes/src/error_codes/E0775.md | 2 +- .../rustc_error_codes/src/error_codes/E0781.md | 8 ++++---- .../rustc_error_codes/src/error_codes/E0798.md | 14 +++++++------- compiler/rustc_error_codes/src/lib.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 2 +- compiler/rustc_hir_analysis/messages.ftl | 4 ++-- .../rustc_hir_analysis/src/hir_ty_lowering/cmse.rs | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md index efbd51e89ea3..9fcd3a6eef74 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0775.md +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -8,7 +8,7 @@ Erroneous code example: ```ignore (no longer emitted) #![feature(cmse_nonsecure_entry)] -pub extern "C-cmse-nonsecure-entry" fn entry_function() {} +pub extern "cmse-nonsecure-entry" fn entry_function() {} ``` To fix this error, compile your code for a Rust target that supports the diff --git a/compiler/rustc_error_codes/src/error_codes/E0781.md b/compiler/rustc_error_codes/src/error_codes/E0781.md index 7641acfb5249..22abe0e3cb15 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0781.md +++ b/compiler/rustc_error_codes/src/error_codes/E0781.md @@ -1,12 +1,12 @@ -The `C-cmse-nonsecure-call` ABI can only be used with function pointers. +The `cmse-nonsecure-call` ABI can only be used with function pointers. Erroneous code example: ```compile_fail,E0781 -#![feature(abi_c_cmse_nonsecure_call)] +#![feature(abi_cmse_nonsecure_call)] -pub extern "C-cmse-nonsecure-call" fn test() {} +pub extern "cmse-nonsecure-call" fn test() {} ``` -The `C-cmse-nonsecure-call` ABI should be used by casting function pointers to +The `cmse-nonsecure-call` ABI should be used by casting function pointers to specific addresses. diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md index da08cde30100..e5f356ef4d50 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0798.md +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -1,4 +1,4 @@ -Functions marked as `C-cmse-nonsecure-call` place restrictions on their +Functions marked as `cmse-nonsecure-call` place restrictions on their inputs and outputs. - inputs must fit in the 4 available 32-bit argument registers. Alignment @@ -12,12 +12,12 @@ see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases). Erroneous code example: -```ignore (only fails on supported targets) -#![feature(abi_c_cmse_nonsecure_call)] +```ignore (host errors will not match for target) +#![feature(abi_cmse_nonsecure_call)] #[no_mangle] pub fn test( - f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, + f: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, ) -> u32 { f(1, 2, 3, 4, 5) } @@ -27,12 +27,12 @@ Arguments' alignment is respected. In the example below, padding is inserted so that the `u64` argument is passed in registers r2 and r3. There is then no room left for the final `f32` argument -```ignore (only fails on supported targets) -#![feature(abi_c_cmse_nonsecure_call)] +```ignore (host errors will not match for target) +#![feature(abi_cmse_nonsecure_call)] #[no_mangle] pub fn test( - f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32, + f: extern "cmse-nonsecure-call" fn(u32, u64, f32) -> u32, ) -> u32 { f(1, 2, 3.0) } diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 22cc1e894da9..0aff1c06e0a8 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -690,5 +690,5 @@ E0805: 0805, // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. // E0744, // merged into E0728 -// E0776, // Removed; cmse_nonsecure_entry is now `C-cmse-nonsecure-entry` +// E0776, // Removed; `#[cmse_nonsecure_entry]` is now `extern "cmse-nonsecure-entry"` // E0796, // unused error code. We use `static_mut_refs` lint instead. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f5d128a5fb2e..e73a4e1766ce 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -431,7 +431,7 @@ declare_features! ( (unstable, closure_lifetime_binder, "1.64.0", Some(97362)), /// Allows `#[track_caller]` on closures and coroutines. (unstable, closure_track_caller, "1.57.0", Some(87417)), - /// Allows `extern "C-cmse-nonsecure-entry" fn()`. + /// Allows `extern "cmse-nonsecure-entry" fn()`. (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)), /// Allows `async {}` expressions in const contexts. (unstable, const_async_blocks, "1.53.0", Some(85368)), diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 8c43d10b9e45..4ec2bbfc5abe 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -73,10 +73,10 @@ hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are fo .label = `for<...>` is here hir_analysis_cmse_call_generic = - function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type + function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type hir_analysis_cmse_entry_generic = - functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type + functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type hir_analysis_cmse_inputs_stack_spill = arguments for `{$abi}` function too large to pass via registers diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 501c8b2b7829..82e5f65476ff 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -38,7 +38,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( dcx, span, E0781, - "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" + "the `\"cmse-nonsecure-call\"` ABI is only allowed on function pointers" ) .emit(); return; From 1400e2d9f519005161da91d8a1e88e54bc56acab Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 23:07:41 -0700 Subject: [PATCH 342/356] tests: s/C-cmse/cmse/ --- tests/assembly/cmse.rs | 8 ++--- tests/crashes/130104.rs | 2 +- tests/crashes/132142.rs | 2 +- tests/ui/abi/unsupported.rs | 10 +++--- .../callback-as-argument.rs | 6 ++-- .../cmse-nonsecure-call/gate_test.rs | 4 +-- .../cmse-nonsecure-call/generics.rs | 28 +++++++-------- .../cmse-nonsecure-call/params-via-stack.rs | 12 +++---- .../cmse-nonsecure-call/return-via-stack.rs | 20 +++++------ .../cmse-nonsecure-call/via-registers.rs | 34 +++++++++---------- .../wrong-abi-location-1.rs | 4 +-- .../wrong-abi-location-2.rs | 4 +-- .../cmse-nonsecure-entry/gate_test.rs | 2 +- .../cmse-nonsecure-entry/generics.rs | 24 ++++++------- .../cmse-nonsecure-entry/params-via-stack.rs | 10 +++--- .../cmse-nonsecure-entry/return-via-stack.rs | 18 +++++----- .../cmse-nonsecure-entry/trustzone-only.rs | 2 +- .../cmse-nonsecure-entry/via-registers.rs | 32 ++++++++--------- 18 files changed, 110 insertions(+), 112 deletions(-) diff --git a/tests/assembly/cmse.rs b/tests/assembly/cmse.rs index 2984df92225c..a68ee99eac67 100644 --- a/tests/assembly/cmse.rs +++ b/tests/assembly/cmse.rs @@ -6,7 +6,7 @@ //@ [hard] needs-llvm-components: arm //@ [soft] needs-llvm-components: arm #![crate_type = "lib"] -#![feature(abi_c_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items)] +#![feature(abi_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items)] #![no_core] extern crate minicore; @@ -53,7 +53,7 @@ use minicore::*; // Branch back to non-secure side // CHECK: bxns lr #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn entry_point() -> i64 { +pub extern "cmse-nonsecure-entry" fn entry_point() -> i64 { 0 } @@ -95,8 +95,6 @@ pub extern "C-cmse-nonsecure-entry" fn entry_point() -> i64 { // Call to non-secure // CHECK: blxns r12 #[no_mangle] -pub fn call_nonsecure( - f: unsafe extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u64, -) -> u64 { +pub fn call_nonsecure(f: unsafe extern "cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u64) -> u64 { unsafe { f(0, 1, 2, 3) } } diff --git a/tests/crashes/130104.rs b/tests/crashes/130104.rs index 0ffc21ad3604..b961108c9233 100644 --- a/tests/crashes/130104.rs +++ b/tests/crashes/130104.rs @@ -2,5 +2,5 @@ fn main() { let non_secure_function = - core::mem::transmute:: _, extern "C-cmse-nonsecure-call" fn() -> _>; + core::mem::transmute:: _, extern "cmse-nonsecure-call" fn() -> _>; } diff --git a/tests/crashes/132142.rs b/tests/crashes/132142.rs index 9a026f3bca71..813bf0bf0a8e 100644 --- a/tests/crashes/132142.rs +++ b/tests/crashes/132142.rs @@ -1,3 +1,3 @@ //@ known-bug: #132142 -async extern "C-cmse-nonsecure-entry" fn fun(...) {} +async extern "cmse-nonsecure-entry" fn fun(...) {} diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 4bb732c94ac3..072ec62b012f 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -25,7 +25,7 @@ abi_gpu_kernel, abi_x86_interrupt, abi_riscv_interrupt, - abi_c_cmse_nonsecure_call, + abi_cmse_nonsecure_call, abi_vectorcall, cmse_nonsecure_entry )] @@ -117,18 +117,18 @@ fn vectorcall_ptr(f: extern "vectorcall" fn()) { extern "vectorcall" {} //[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI -fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { +fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { //~^ ERROR is not a supported ABI f() } -extern "C-cmse-nonsecure-entry" fn cmse_entry() {} +extern "cmse-nonsecure-entry" fn cmse_entry() {} //~^ ERROR is not a supported ABI -fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { +fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { //~^ ERROR is not a supported ABI f() } -extern "C-cmse-nonsecure-entry" {} +extern "cmse-nonsecure-entry" {} //~^ ERROR is not a supported ABI #[cfg(windows)] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs index b25a81b858be..796c2634b623 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs @@ -2,15 +2,15 @@ //@ build-pass //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items, intrinsics)] +#![feature(abi_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items, intrinsics)] #![no_core] extern crate minicore; use minicore::*; #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn test( - f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u32, +pub extern "cmse-nonsecure-entry" fn test( + f: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u32, a: u32, b: u32, c: u32, diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs index 40e2da8d1cd0..cb805309a02d 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.rs @@ -1,7 +1,7 @@ -// gate-test-abi_c_cmse_nonsecure_call +// gate-test-abi_cmse_nonsecure_call fn main() { let non_secure_function = unsafe { - core::mem::transmute:: i32>( + core::mem::transmute:: i32>( //~^ ERROR: is not a supported ABI for the current target [E0570] //~| ERROR: ABI is experimental and subject to change [E0658] 0x10000004, diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs index 84080890e080..4ce5890a2da3 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs @@ -1,7 +1,7 @@ //@ add-core-stubs //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)] +#![feature(abi_cmse_nonsecure_call, no_core, lang_items)] #![no_core] extern crate minicore; @@ -11,31 +11,31 @@ use minicore::*; struct Wrapper(T); struct Test { - f1: extern "C-cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, + f1: extern "cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, //~^ ERROR cannot find type `U` in this scope //~| ERROR function pointer types may not have generic parameters - f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, + f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, //~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters - f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798] - f4: extern "C-cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, //~ ERROR [E0798] + f3: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798] + f4: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, //~ ERROR [E0798] } -type WithReference = extern "C-cmse-nonsecure-call" fn(&usize); +type WithReference = extern "cmse-nonsecure-call" fn(&usize); trait Trait {} -type WithTraitObject = extern "C-cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait; -//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798] +type WithTraitObject = extern "cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait; +//~^ ERROR return value of `"cmse-nonsecure-call"` function too large to pass via registers [E0798] type WithStaticTraitObject = - extern "C-cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait; -//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798] + extern "cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait; +//~^ ERROR return value of `"cmse-nonsecure-call"` function too large to pass via registers [E0798] #[repr(transparent)] struct WrapperTransparent<'a>(&'a dyn Trait); type WithTransparentTraitObject = - extern "C-cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent; -//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798] + extern "cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent; +//~^ ERROR return value of `"cmse-nonsecure-call"` function too large to pass via registers [E0798] -type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...); -//~^ ERROR C-variadic functions with the "C-cmse-nonsecure-call" calling convention are not supported +type WithVarArgs = extern "cmse-nonsecure-call" fn(u32, ...); +//~^ ERROR C-variadic functions with the "cmse-nonsecure-call" calling convention are not supported diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs index 8328f9b6dd55..7036cd367e40 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs @@ -1,7 +1,7 @@ //@ add-core-stubs //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)] +#![feature(abi_cmse_nonsecure_call, no_core, lang_items)] #![no_core] extern crate minicore; @@ -13,10 +13,10 @@ pub struct AlignRelevant(u32); #[no_mangle] pub fn test( - f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32), //~ ERROR [E0798] - f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), //~ ERROR [E0798] - f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32), //~ ERROR [E0798] - f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32), //~ ERROR [E0798] - f5: extern "C-cmse-nonsecure-call" fn([u32; 5]), //~ ERROR [E0798] + f1: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32), //~ ERROR [E0798] + f2: extern "cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), //~ ERROR [E0798] + f3: extern "cmse-nonsecure-call" fn(u32, u64, u32), //~ ERROR [E0798] + f4: extern "cmse-nonsecure-call" fn(AlignRelevant, u32), //~ ERROR [E0798] + f5: extern "cmse-nonsecure-call" fn([u32; 5]), //~ ERROR [E0798] ) { } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs index 890ec4b00f6a..77347b04ede8 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs @@ -3,7 +3,7 @@ //@ needs-llvm-components: arm //@ add-core-stubs -#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)] +#![feature(abi_cmse_nonsecure_call, no_core, lang_items)] #![no_core] extern crate minicore; @@ -23,18 +23,18 @@ pub struct ReprCAlign16(u16); #[no_mangle] pub fn test( - f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, //~ ERROR [E0798] - f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, //~ ERROR [E0798] - f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, //~ ERROR [E0798] - f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, //~ ERROR [E0798] - f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], //~ ERROR [E0798] + f1: extern "cmse-nonsecure-call" fn() -> ReprCU64, //~ ERROR [E0798] + f2: extern "cmse-nonsecure-call" fn() -> ReprCBytes, //~ ERROR [E0798] + f3: extern "cmse-nonsecure-call" fn() -> U64Compound, //~ ERROR [E0798] + f4: extern "cmse-nonsecure-call" fn() -> ReprCAlign16, //~ ERROR [E0798] + f5: extern "cmse-nonsecure-call" fn() -> [u8; 5], //~ ERROR [E0798] ) { } #[allow(improper_ctypes_definitions)] struct Test { - u128: extern "C-cmse-nonsecure-call" fn() -> u128, //~ ERROR [E0798] - i128: extern "C-cmse-nonsecure-call" fn() -> i128, //~ ERROR [E0798] + u128: extern "cmse-nonsecure-call" fn() -> u128, //~ ERROR [E0798] + i128: extern "cmse-nonsecure-call" fn() -> i128, //~ ERROR [E0798] } #[repr(C)] @@ -49,7 +49,7 @@ pub union ReprRustUnionU64 { #[no_mangle] pub fn test_union( - f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ ERROR [E0798] - f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64, //~ ERROR [E0798] + f1: extern "cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ ERROR [E0798] + f2: extern "cmse-nonsecure-call" fn() -> ReprCUnionU64, //~ ERROR [E0798] ) { } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs index 7dfe6cf9672a..419d26875bcd 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs @@ -2,7 +2,7 @@ //@ build-pass //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] +#![feature(abi_cmse_nonsecure_call, no_core, lang_items, intrinsics)] #![no_core] extern crate minicore; @@ -27,26 +27,26 @@ pub struct U32Compound(u16, u16); #[no_mangle] #[allow(improper_ctypes_definitions)] pub fn params( - f1: extern "C-cmse-nonsecure-call" fn(), - f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32), - f3: extern "C-cmse-nonsecure-call" fn(u64, u64), - f4: extern "C-cmse-nonsecure-call" fn(u128), - f5: extern "C-cmse-nonsecure-call" fn(f64, f32, f32), - f6: extern "C-cmse-nonsecure-call" fn(ReprTransparentStruct, U32Compound), - f7: extern "C-cmse-nonsecure-call" fn([u32; 4]), + f1: extern "cmse-nonsecure-call" fn(), + f2: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32), + f3: extern "cmse-nonsecure-call" fn(u64, u64), + f4: extern "cmse-nonsecure-call" fn(u128), + f5: extern "cmse-nonsecure-call" fn(f64, f32, f32), + f6: extern "cmse-nonsecure-call" fn(ReprTransparentStruct, U32Compound), + f7: extern "cmse-nonsecure-call" fn([u32; 4]), ) { } #[no_mangle] pub fn returns( - f1: extern "C-cmse-nonsecure-call" fn() -> u32, - f2: extern "C-cmse-nonsecure-call" fn() -> u64, - f3: extern "C-cmse-nonsecure-call" fn() -> i64, - f4: extern "C-cmse-nonsecure-call" fn() -> f64, - f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 4], - f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct, - f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct>, - f8: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64, - f9: extern "C-cmse-nonsecure-call" fn() -> U32Compound, + f1: extern "cmse-nonsecure-call" fn() -> u32, + f2: extern "cmse-nonsecure-call" fn() -> u64, + f3: extern "cmse-nonsecure-call" fn() -> i64, + f4: extern "cmse-nonsecure-call" fn() -> f64, + f5: extern "cmse-nonsecure-call" fn() -> [u8; 4], + f6: extern "cmse-nonsecure-call" fn() -> ReprTransparentStruct, + f7: extern "cmse-nonsecure-call" fn() -> ReprTransparentStruct>, + f8: extern "cmse-nonsecure-call" fn() -> ReprTransparentEnumU64, + f9: extern "cmse-nonsecure-call" fn() -> U32Compound, ) { } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs index 5a2d2db19c54..44a1e7d69a8c 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.rs @@ -1,10 +1,10 @@ //@ add-core-stubs //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, lang_items, no_core)] +#![feature(abi_cmse_nonsecure_call, lang_items, no_core)] #![no_core] extern crate minicore; use minicore::*; -pub extern "C-cmse-nonsecure-call" fn test() {} //~ ERROR [E0781] +pub extern "cmse-nonsecure-call" fn test() {} //~ ERROR [E0781] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs index e93b153949a3..f23f45f786fb 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.rs @@ -1,12 +1,12 @@ //@ add-core-stubs //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib //@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, lang_items, no_core)] +#![feature(abi_cmse_nonsecure_call, lang_items, no_core)] #![no_core] extern crate minicore; use minicore::*; -extern "C-cmse-nonsecure-call" { //~ ERROR [E0781] +extern "cmse-nonsecure-call" { //~ ERROR [E0781] fn test(); } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs index de68097e139c..8ec22033a3df 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs @@ -1,7 +1,7 @@ // gate-test-cmse_nonsecure_entry #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { +pub extern "cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { //~^ ERROR: is not a supported ABI for the current target [E0570] //~| ERROR: ABI is experimental and subject to change [E0658] input + 6 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs index 19b6179dde75..800dd580af29 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs @@ -11,12 +11,12 @@ use minicore::*; struct Wrapper(T); impl Wrapper { - extern "C-cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 { + extern "cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 { //~^ ERROR [E0798] 0 } - extern "C-cmse-nonsecure-entry" fn ambient_generic_nested( + extern "cmse-nonsecure-entry" fn ambient_generic_nested( //~^ ERROR [E0798] _: Wrapper, _: u32, @@ -27,7 +27,7 @@ impl Wrapper { } } -extern "C-cmse-nonsecure-entry" fn introduced_generic( +extern "cmse-nonsecure-entry" fn introduced_generic( //~^ ERROR [E0798] _: U, _: u32, @@ -37,40 +37,40 @@ extern "C-cmse-nonsecure-entry" fn introduced_generic( 0 } -extern "C-cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { +extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { //~^ ERROR [E0798] 0 } -extern "C-cmse-nonsecure-entry" fn reference(x: &usize) -> usize { +extern "cmse-nonsecure-entry" fn reference(x: &usize) -> usize { *x } trait Trait {} -extern "C-cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait { - //~^ ERROR return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers [E0798] +extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait { + //~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798] x } -extern "C-cmse-nonsecure-entry" fn static_trait_object( +extern "cmse-nonsecure-entry" fn static_trait_object( x: &'static dyn Trait, ) -> &'static dyn Trait { - //~^ ERROR return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers [E0798] + //~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798] x } #[repr(transparent)] struct WrapperTransparent<'a>(&'a dyn Trait); -extern "C-cmse-nonsecure-entry" fn wrapped_trait_object( +extern "cmse-nonsecure-entry" fn wrapped_trait_object( x: WrapperTransparent, ) -> WrapperTransparent { - //~^ ERROR return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers [E0798] + //~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798] x } -extern "C-cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { +extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR requires `va_list` lang_item } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs index 4c53f9422dab..d4f722fa1938 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs @@ -12,14 +12,14 @@ use minicore::*; pub struct AlignRelevant(u32); #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {} //~ ERROR [E0798] +pub extern "cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {} //~ ERROR [E0798] #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {} //~ ERROR [E0798] +pub extern "cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {} //~ ERROR [E0798] #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} //~ ERROR [E0798] +pub extern "cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} //~ ERROR [E0798] #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} //~ ERROR [E0798] +pub extern "cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} //~ ERROR [E0798] #[no_mangle] #[allow(improper_ctypes_definitions)] -pub extern "C-cmse-nonsecure-entry" fn f5(_: [u32; 5]) {} //~ ERROR [E0798] +pub extern "cmse-nonsecure-entry" fn f5(_: [u32; 5]) {} //~ ERROR [E0798] diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs index 735eab10fa15..0052a0977ed7 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.rs @@ -22,41 +22,41 @@ pub struct U64Compound(u32, u32); pub struct ReprCAlign16(u16); #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn f1() -> ReprCU64 { +pub extern "cmse-nonsecure-entry" fn f1() -> ReprCU64 { //~^ ERROR [E0798] ReprCU64(0) } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn f2() -> ReprCBytes { +pub extern "cmse-nonsecure-entry" fn f2() -> ReprCBytes { //~^ ERROR [E0798] ReprCBytes(0, 1, 2, 3, 4) } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn f3() -> U64Compound { +pub extern "cmse-nonsecure-entry" fn f3() -> U64Compound { //~^ ERROR [E0798] U64Compound(2, 3) } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn f4() -> ReprCAlign16 { +pub extern "cmse-nonsecure-entry" fn f4() -> ReprCAlign16 { //~^ ERROR [E0798] ReprCAlign16(4) } #[no_mangle] #[allow(improper_ctypes_definitions)] -pub extern "C-cmse-nonsecure-entry" fn f5() -> [u8; 5] { +pub extern "cmse-nonsecure-entry" fn f5() -> [u8; 5] { //~^ ERROR [E0798] [0xAA; 5] } #[no_mangle] #[allow(improper_ctypes_definitions)] -pub extern "C-cmse-nonsecure-entry" fn u128() -> u128 { +pub extern "cmse-nonsecure-entry" fn u128() -> u128 { //~^ ERROR [E0798] 123 } #[no_mangle] #[allow(improper_ctypes_definitions)] -pub extern "C-cmse-nonsecure-entry" fn i128() -> i128 { +pub extern "cmse-nonsecure-entry" fn i128() -> i128 { //~^ ERROR [E0798] 456 } @@ -73,12 +73,12 @@ pub union ReprCUnionU64 { #[no_mangle] #[allow(improper_ctypes_definitions)] -pub extern "C-cmse-nonsecure-entry" fn union_rust() -> ReprRustUnionU64 { +pub extern "cmse-nonsecure-entry" fn union_rust() -> ReprRustUnionU64 { //~^ ERROR [E0798] ReprRustUnionU64 { _unused: 1 } } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn union_c() -> ReprCUnionU64 { +pub extern "cmse-nonsecure-entry" fn union_c() -> ReprCUnionU64 { //~^ ERROR [E0798] ReprCUnionU64 { _unused: 2 } } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs index 6d84dab2166e..ff5d2ec0ab6c 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs @@ -14,7 +14,7 @@ extern crate minicore; use minicore::*; #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { +pub extern "cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { //~^ ERROR [E0570] input } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/via-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/via-registers.rs index 912fc8b85ebd..343732881256 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/via-registers.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/via-registers.rs @@ -26,49 +26,49 @@ pub enum ReprTransparentEnumU64 { pub struct U32Compound(u16, u16); #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn inputs1() {} +pub extern "cmse-nonsecure-entry" fn inputs1() {} #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn inputs2(_: u32, _: u32, _: u32, _: u32) {} +pub extern "cmse-nonsecure-entry" fn inputs2(_: u32, _: u32, _: u32, _: u32) {} #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn inputs3(_: u64, _: u64) {} +pub extern "cmse-nonsecure-entry" fn inputs3(_: u64, _: u64) {} #[no_mangle] #[allow(improper_ctypes_definitions)] -pub extern "C-cmse-nonsecure-entry" fn inputs4(_: u128) {} +pub extern "cmse-nonsecure-entry" fn inputs4(_: u128) {} #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn inputs5(_: f64, _: f32, _: f32) {} +pub extern "cmse-nonsecure-entry" fn inputs5(_: f64, _: f32, _: f32) {} #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn inputs6(_: ReprTransparentStruct, _: U32Compound) {} +pub extern "cmse-nonsecure-entry" fn inputs6(_: ReprTransparentStruct, _: U32Compound) {} #[no_mangle] #[allow(improper_ctypes_definitions)] -pub extern "C-cmse-nonsecure-entry" fn inputs7(_: [u32; 4]) {} +pub extern "cmse-nonsecure-entry" fn inputs7(_: [u32; 4]) {} #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn outputs1() -> u32 { +pub extern "cmse-nonsecure-entry" fn outputs1() -> u32 { 0 } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn outputs2() -> u64 { +pub extern "cmse-nonsecure-entry" fn outputs2() -> u64 { 0 } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn outputs3() -> i64 { +pub extern "cmse-nonsecure-entry" fn outputs3() -> i64 { 0 } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn outputs4() -> f64 { +pub extern "cmse-nonsecure-entry" fn outputs4() -> f64 { 0.0 } #[no_mangle] #[allow(improper_ctypes_definitions)] -pub extern "C-cmse-nonsecure-entry" fn outputs5() -> [u8; 4] { +pub extern "cmse-nonsecure-entry" fn outputs5() -> [u8; 4] { [0xAA; 4] } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn outputs6() -> ReprTransparentStruct { +pub extern "cmse-nonsecure-entry" fn outputs6() -> ReprTransparentStruct { ReprTransparentStruct { _marker1: (), _marker2: (), field: 0xAA, _marker3: () } } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn outputs7( +pub extern "cmse-nonsecure-entry" fn outputs7( ) -> ReprTransparentStruct> { ReprTransparentStruct { _marker1: (), @@ -78,10 +78,10 @@ pub extern "C-cmse-nonsecure-entry" fn outputs7( } } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn outputs8() -> ReprTransparentEnumU64 { +pub extern "cmse-nonsecure-entry" fn outputs8() -> ReprTransparentEnumU64 { ReprTransparentEnumU64::A(0) } #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn outputs9() -> U32Compound { +pub extern "cmse-nonsecure-entry" fn outputs9() -> U32Compound { U32Compound(1, 2) } From 02a00dfbe49e03ca8ba178e3198c57b3d95f7f8a Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 9 Jun 2025 11:22:07 -0700 Subject: [PATCH 343/356] tests: bless s/C-cmse/cmse/ --- tests/ui/abi/unsupported.aarch64.stderr | 24 ++--- tests/ui/abi/unsupported.arm.stderr | 24 ++--- tests/ui/abi/unsupported.i686.stderr | 24 ++--- tests/ui/abi/unsupported.riscv32.stderr | 24 ++--- tests/ui/abi/unsupported.riscv64.stderr | 24 ++--- tests/ui/abi/unsupported.x64.stderr | 24 ++--- tests/ui/abi/unsupported.x64_win.stderr | 24 ++--- .../cmse-nonsecure-call/gate_test.stderr | 14 +-- .../cmse-nonsecure-call/generics.stderr | 70 +++++++-------- .../params-via-stack.stderr | 50 +++++------ .../return-via-stack.stderr | 90 +++++++++---------- .../wrong-abi-location-1.stderr | 6 +- .../wrong-abi-location-2.stderr | 4 +- .../cmse-nonsecure-entry/gate_test.stderr | 12 +-- .../cmse-nonsecure-entry/generics.stderr | 50 +++++------ .../params-via-stack.stderr | 54 +++++------ .../return-via-stack.stderr | 90 +++++++++---------- .../trustzone-only.aarch64.stderr | 6 +- .../trustzone-only.thumb7.stderr | 6 +- .../trustzone-only.x86.stderr | 6 +- tests/ui/print-calling-conventions.stdout | 4 +- 21 files changed, 315 insertions(+), 315 deletions(-) diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 85e251a65d20..3980fe6ef8ba 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -132,29 +132,29 @@ error[E0570]: "vectorcall" is not a supported ABI for the current target LL | extern "vectorcall" {} | ^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target --> $DIR/unsupported.rs:120:28 | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:125:8 | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:127:29 | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:131:8 | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target --> $DIR/unsupported.rs:141:17 diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index a4274d0ac603..e5d6ea6aa132 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -114,29 +114,29 @@ error[E0570]: "vectorcall" is not a supported ABI for the current target LL | extern "vectorcall" {} | ^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target --> $DIR/unsupported.rs:120:28 | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:125:8 | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:127:29 | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:131:8 | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target --> $DIR/unsupported.rs:141:17 diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 5e5d74c1d989..8478c4819416 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -58,29 +58,29 @@ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target --> $DIR/unsupported.rs:120:28 | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:125:8 | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:127:29 | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:131:8 | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index 7ef7cae5057e..b871c0a83d7a 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -126,29 +126,29 @@ error[E0570]: "vectorcall" is not a supported ABI for the current target LL | extern "vectorcall" {} | ^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target --> $DIR/unsupported.rs:120:28 | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:125:8 | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:127:29 | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:131:8 | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target --> $DIR/unsupported.rs:141:17 diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index 7ef7cae5057e..b871c0a83d7a 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -126,29 +126,29 @@ error[E0570]: "vectorcall" is not a supported ABI for the current target LL | extern "vectorcall" {} | ^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target --> $DIR/unsupported.rs:120:28 | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:125:8 | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:127:29 | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:131:8 | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target --> $DIR/unsupported.rs:141:17 diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 7b021dff7c90..f319eb32b2ad 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -108,29 +108,29 @@ LL | extern "stdcall-unwind" {} | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target --> $DIR/unsupported.rs:120:28 | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:125:8 | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:127:29 | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:131:8 | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target --> $DIR/unsupported.rs:141:17 diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 4ce5b3340d12..12342b89c6c5 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -76,29 +76,29 @@ error[E0570]: "thiscall" is not a supported ABI for the current target LL | extern "thiscall" {} | ^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target --> $DIR/unsupported.rs:120:28 | -LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:125:8 | -LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:127:29 | -LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/unsupported.rs:131:8 | -LL | extern "C-cmse-nonsecure-entry" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target --> $DIR/unsupported.rs:141:17 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr index dcbe09d8b365..ecf70e890f4c 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/gate_test.stderr @@ -1,17 +1,17 @@ -error[E0570]: "C-cmse-nonsecure-call" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target --> $DIR/gate_test.rs:4:46 | -LL | core::mem::transmute:: i32>( - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | core::mem::transmute:: i32>( + | ^^^^^^^^^^^^^^^^^^^^^ -error[E0658]: the extern "C-cmse-nonsecure-call" ABI is experimental and subject to change +error[E0658]: the extern "cmse-nonsecure-call" ABI is experimental and subject to change --> $DIR/gate_test.rs:4:46 | -LL | core::mem::transmute:: i32>( - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | core::mem::transmute:: i32>( + | ^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #81391 for more information - = help: add `#![feature(abi_c_cmse_nonsecure_call)]` to the crate attributes to enable + = help: add `#![feature(abi_cmse_nonsecure_call)]` 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 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr index 2b51f48915b3..156568535763 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr @@ -1,21 +1,21 @@ error: function pointer types may not have generic parameters - --> $DIR/generics.rs:14:42 + --> $DIR/generics.rs:14:40 | -LL | f1: extern "C-cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, - | ^^^^^^^^^ +LL | f1: extern "cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, + | ^^^^^^^^^ error[E0412]: cannot find type `U` in this scope - --> $DIR/generics.rs:14:52 + --> $DIR/generics.rs:14:50 | LL | struct Test { | - similarly named type parameter `T` defined here -LL | f1: extern "C-cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, - | ^ +LL | f1: extern "cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, + | ^ | help: a type parameter with a similar name exists | -LL - f1: extern "C-cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, -LL + f1: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, +LL - f1: extern "cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, +LL + f1: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, | help: you might be missing a type parameter | @@ -23,57 +23,57 @@ LL | struct Test { | +++ error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters - --> $DIR/generics.rs:17:43 + --> $DIR/generics.rs:17:41 | -LL | f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, - | ^^^^^^^^^ +LL | f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, + | ^^^^^^^^^ | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type +error[E0798]: function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type --> $DIR/generics.rs:19:9 | -LL | f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | f3: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type +error[E0798]: function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type --> $DIR/generics.rs:20:9 | -LL | f4: extern "C-cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | f4: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/generics.rs:26:73 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/generics.rs:26:71 | -LL | type WithTraitObject = extern "C-cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait; - | ^^^^^^^^^^ this type doesn't fit in the available registers +LL | type WithTraitObject = extern "cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait; + | ^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/generics.rs:30:62 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/generics.rs:30:60 | -LL | extern "C-cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait; - | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | extern "cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait; + | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/generics.rs:37:62 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/generics.rs:37:60 | -LL | extern "C-cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent; - | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | extern "cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent; + | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0045]: C-variadic functions with the "C-cmse-nonsecure-call" calling convention are not supported +error[E0045]: C-variadic functions with the "cmse-nonsecure-call" calling convention are not supported --> $DIR/generics.rs:40:20 | -LL | type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention +LL | type WithVarArgs = extern "cmse-nonsecure-call" fn(u32, ...); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention error: aborting due to 9 previous errors diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr index 10a5e8561075..5d59405fbd1b 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr @@ -1,42 +1,42 @@ -error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:16:63 +error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:16:61 | -LL | f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32), - | ^^^^^^^^^^^^^^ these arguments don't fit in the available registers +LL | f1: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32), + | ^^^^^^^^^^^^^^ these arguments don't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers -error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:17:63 +error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:17:61 | -LL | f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), - | ^^^ this argument doesn't fit in the available registers +LL | f2: extern "cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), + | ^^^ this argument doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers -error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:18:53 +error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:18:51 | -LL | f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32), - | ^^^ this argument doesn't fit in the available registers +LL | f3: extern "cmse-nonsecure-call" fn(u32, u64, u32), + | ^^^ this argument doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers -error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:19:58 +error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:19:56 | -LL | f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32), - | ^^^ this argument doesn't fit in the available registers +LL | f4: extern "cmse-nonsecure-call" fn(AlignRelevant, u32), + | ^^^ this argument doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers -error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/params-via-stack.rs:20:43 +error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:20:41 | -LL | f5: extern "C-cmse-nonsecure-call" fn([u32; 5]), - | ^^^^^^^^ this argument doesn't fit in the available registers +LL | f5: extern "cmse-nonsecure-call" fn([u32; 5]), + | ^^^^^^^^ this argument doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers error: aborting due to 5 previous errors diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr index d2077352900a..ddf969c1bce1 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr @@ -1,82 +1,82 @@ -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:36:50 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:36:48 | -LL | u128: extern "C-cmse-nonsecure-call" fn() -> u128, - | ^^^^ this type doesn't fit in the available registers +LL | u128: extern "cmse-nonsecure-call" fn() -> u128, + | ^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:37:50 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:37:48 | -LL | i128: extern "C-cmse-nonsecure-call" fn() -> i128, - | ^^^^ this type doesn't fit in the available registers +LL | i128: extern "cmse-nonsecure-call" fn() -> i128, + | ^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:26:48 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:26:46 | -LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, - | ^^^^^^^^ this type doesn't fit in the available registers +LL | f1: extern "cmse-nonsecure-call" fn() -> ReprCU64, + | ^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:27:48 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:27:46 | -LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, - | ^^^^^^^^^^ this type doesn't fit in the available registers +LL | f2: extern "cmse-nonsecure-call" fn() -> ReprCBytes, + | ^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:28:48 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:28:46 | -LL | f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, - | ^^^^^^^^^^^ this type doesn't fit in the available registers +LL | f3: extern "cmse-nonsecure-call" fn() -> U64Compound, + | ^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:29:48 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:29:46 | -LL | f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, - | ^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | f4: extern "cmse-nonsecure-call" fn() -> ReprCAlign16, + | ^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:30:48 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:30:46 | -LL | f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], - | ^^^^^^^ this type doesn't fit in the available registers +LL | f5: extern "cmse-nonsecure-call" fn() -> [u8; 5], + | ^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:52:48 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:52:46 | -LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, - | ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | f1: extern "cmse-nonsecure-call" fn() -> ReprRustUnionU64, + | ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/return-via-stack.rs:53:48 +error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:53:46 | -LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64, - | ^^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | f2: extern "cmse-nonsecure-call" fn() -> ReprCUnionU64, + | ^^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error: aborting due to 9 previous errors diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr index f49fab043a47..b9cccecc64bf 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr @@ -1,8 +1,8 @@ -error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers +error[E0781]: the `"cmse-nonsecure-call"` ABI is only allowed on function pointers --> $DIR/wrong-abi-location-1.rs:10:1 | -LL | pub extern "C-cmse-nonsecure-call" fn test() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "cmse-nonsecure-call" fn test() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr index bae8d20d81c5..437d7b80b1fd 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr @@ -1,7 +1,7 @@ -error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers +error[E0781]: the `"cmse-nonsecure-call"` ABI is only allowed on function pointers --> $DIR/wrong-abi-location-2.rs:10:1 | -LL | / extern "C-cmse-nonsecure-call" { +LL | / extern "cmse-nonsecure-call" { LL | | fn test(); LL | | } | |_^ diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr index 312f57591f97..e40862e74eee 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr @@ -1,14 +1,14 @@ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/gate_test.rs:4:12 | -LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0658]: the extern "C-cmse-nonsecure-entry" ABI is experimental and subject to change +error[E0658]: the extern "cmse-nonsecure-entry" ABI is experimental and subject to change --> $DIR/gate_test.rs:4:12 | -LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #75835 for more information = help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr index c314671dc297..f0190671b5a1 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr @@ -1,13 +1,13 @@ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/generics.rs:73:55 + --> $DIR/generics.rs:73:53 | -LL | extern "C-cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { - | ^^^^^^ +LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { + | ^^^^^^ -error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type --> $DIR/generics.rs:30:1 | -LL | / extern "C-cmse-nonsecure-entry" fn introduced_generic( +LL | / extern "cmse-nonsecure-entry" fn introduced_generic( LL | | LL | | _: U, LL | | _: u32, @@ -16,22 +16,22 @@ LL | | _: u32, LL | | ) -> u64 { | |________^ -error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type --> $DIR/generics.rs:40:1 | -LL | extern "C-cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type --> $DIR/generics.rs:14:5 | -LL | extern "C-cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type --> $DIR/generics.rs:19:5 | -LL | / extern "C-cmse-nonsecure-entry" fn ambient_generic_nested( +LL | / extern "cmse-nonsecure-entry" fn ambient_generic_nested( LL | | LL | | _: Wrapper, LL | | _: u32, @@ -40,38 +40,38 @@ LL | | _: u32, LL | | ) -> u64 { | |____________^ -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/generics.rs:51:67 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/generics.rs:51:65 | -LL | extern "C-cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait { - | ^^^^^^^^^^ this type doesn't fit in the available registers +LL | extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait { + | ^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers --> $DIR/generics.rs:58:6 | LL | ) -> &'static dyn Trait { | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers --> $DIR/generics.rs:68:6 | LL | ) -> WrapperTransparent { | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error: requires `va_list` lang_item - --> $DIR/generics.rs:73:55 + --> $DIR/generics.rs:73:53 | -LL | extern "C-cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { - | ^^^^^^ +LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { + | ^^^^^^ error: aborting due to 9 previous errors diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr index 24e9ddf32feb..f8b96bddc947 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr @@ -1,42 +1,42 @@ -error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:15:78 +error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/params-via-stack.rs:15:76 | -LL | pub extern "C-cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {} - | ^^^^^^^^^^^ these arguments don't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {} + | ^^^^^^^^^^^ these arguments don't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers -error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:17:78 +error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/params-via-stack.rs:17:76 | -LL | pub extern "C-cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {} - | ^^^ this argument doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {} + | ^^^ this argument doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers -error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:19:62 +error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/params-via-stack.rs:19:60 | -LL | pub extern "C-cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} +LL | pub extern "cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} + | ^^^ this argument doesn't fit in the available registers + | + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/params-via-stack.rs:21:62 + | +LL | pub extern "cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} | ^^^ this argument doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers -error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:21:64 +error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/params-via-stack.rs:25:44 | -LL | pub extern "C-cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} - | ^^^ this argument doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn f5(_: [u32; 5]) {} + | ^^^^^^^^ this argument doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers - -error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/params-via-stack.rs:25:46 - | -LL | pub extern "C-cmse-nonsecure-entry" fn f5(_: [u32; 5]) {} - | ^^^^^^^^ this argument doesn't fit in the available registers - | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers error: aborting due to 5 previous errors diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr index 9c885d953181..c5effed92ae9 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/return-via-stack.stderr @@ -1,82 +1,82 @@ -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:25:48 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:25:46 | -LL | pub extern "C-cmse-nonsecure-entry" fn f1() -> ReprCU64 { - | ^^^^^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn f1() -> ReprCU64 { + | ^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:30:48 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:30:46 | -LL | pub extern "C-cmse-nonsecure-entry" fn f2() -> ReprCBytes { - | ^^^^^^^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn f2() -> ReprCBytes { + | ^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:35:48 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:35:46 | -LL | pub extern "C-cmse-nonsecure-entry" fn f3() -> U64Compound { - | ^^^^^^^^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn f3() -> U64Compound { + | ^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:40:48 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:40:46 | -LL | pub extern "C-cmse-nonsecure-entry" fn f4() -> ReprCAlign16 { - | ^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn f4() -> ReprCAlign16 { + | ^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:47:48 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:47:46 | -LL | pub extern "C-cmse-nonsecure-entry" fn f5() -> [u8; 5] { - | ^^^^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn f5() -> [u8; 5] { + | ^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:53:50 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:53:48 | -LL | pub extern "C-cmse-nonsecure-entry" fn u128() -> u128 { - | ^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn u128() -> u128 { + | ^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:59:50 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:59:48 | -LL | pub extern "C-cmse-nonsecure-entry" fn i128() -> i128 { - | ^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn i128() -> i128 { + | ^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:76:56 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:76:54 | -LL | pub extern "C-cmse-nonsecure-entry" fn union_rust() -> ReprRustUnionU64 { - | ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn union_rust() -> ReprRustUnionU64 { + | ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size -error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/return-via-stack.rs:81:53 +error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers + --> $DIR/return-via-stack.rs:81:51 | -LL | pub extern "C-cmse-nonsecure-entry" fn union_c() -> ReprCUnionU64 { - | ^^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | pub extern "cmse-nonsecure-entry" fn union_c() -> ReprCUnionU64 { + | ^^^^^^^^^^^^^ this type doesn't fit in the available registers | - = note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error: aborting due to 9 previous errors diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr index 3072d3a3abfe..3949eac15429 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr @@ -1,8 +1,8 @@ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/trustzone-only.rs:17:12 | -LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr index 3072d3a3abfe..3949eac15429 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr @@ -1,8 +1,8 @@ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/trustzone-only.rs:17:12 | -LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr index 3072d3a3abfe..3949eac15429 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr @@ -1,8 +1,8 @@ -error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current target +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target --> $DIR/trustzone-only.rs:17:12 | -LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout index 4df6bd27f457..b8b939e1c04e 100644 --- a/tests/ui/print-calling-conventions.stdout +++ b/tests/ui/print-calling-conventions.stdout @@ -1,6 +1,4 @@ C -C-cmse-nonsecure-call -C-cmse-nonsecure-entry C-unwind Rust aapcs @@ -9,6 +7,8 @@ avr-interrupt avr-non-blocking-interrupt cdecl cdecl-unwind +cmse-nonsecure-call +cmse-nonsecure-entry custom efiapi fastcall From 9cfee735f495bdf9e7e1d0d39bac7fb7e36a199e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 24 Jun 2025 13:09:07 -0700 Subject: [PATCH 344/356] move unstable book page and account for it --- ...-cmse-nonsecure-call.md => abi-cmse-nonsecure-call.md} | 0 tests/ui/SUMMARY.md | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/doc/unstable-book/src/language-features/{abi-c-cmse-nonsecure-call.md => abi-cmse-nonsecure-call.md} (100%) diff --git a/src/doc/unstable-book/src/language-features/abi-c-cmse-nonsecure-call.md b/src/doc/unstable-book/src/language-features/abi-cmse-nonsecure-call.md similarity index 100% rename from src/doc/unstable-book/src/language-features/abi-c-cmse-nonsecure-call.md rename to src/doc/unstable-book/src/language-features/abi-cmse-nonsecure-call.md diff --git a/tests/ui/SUMMARY.md b/tests/ui/SUMMARY.md index d807e38dab28..ed352789df2c 100644 --- a/tests/ui/SUMMARY.md +++ b/tests/ui/SUMMARY.md @@ -208,14 +208,14 @@ Tests targeted at how we deduce the types of closure arguments. This process is Any closure-focused tests that does not fit in the other more specific closure subdirectories belong here. E.g. syntax, `move`, lifetimes. -## `tests/ui/cmse-nonsecure/`: `C-cmse-nonsecure` ABIs +## `tests/ui/cmse-nonsecure/`: `cmse-nonsecure` ABIs -Tests for `cmse_nonsecure_entry` and `abi_c_cmse_nonsecure_call` ABIs. Used specifically for the Armv8-M architecture, the former marks Secure functions with additional behaviours, such as adding a special symbol and constraining the number of parameters, while the latter alters function pointers to indicate they are non-secure and to handle them differently than usual. +Tests for `extern "cmse-nonsecure-call"` and `extern "cmse-nonsecure-entry"` functions. Used specifically for the Armv8-M architecture, the former marks Secure functions with additional behaviours, such as adding a special symbol and constraining the number of parameters, while the latter alters function pointers to indicate they are non-secure and to handle them differently than usual. See: -- [`cmse_nonsecure_entry` | The Unstable book](https://doc.rust-lang.org/unstable-book/language-features/cmse-nonsecure-entry.html) -- [`abi_c_cmse_nonsecure_call` | The Unstable book](https://doc.rust-lang.org/beta/unstable-book/language-features/abi-c-cmse-nonsecure-call.html) +- [`cmse_nonsecure_entry` | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/cmse-nonsecure-entry.html) +- [`abi_cmse_nonsecure_call` | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/abi-cmse-nonsecure-call.html) ## `tests/ui/codegen/`: Code Generation From 3beed38ef6712c9d6641c08a57304aa71f5fd2c6 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 6 Jun 2025 23:16:35 -0700 Subject: [PATCH 345/356] unstable-book: Update cmse feature descriptions --- .../language-features/abi-cmse-nonsecure-call.md | 16 ++++++---------- .../language-features/cmse-nonsecure-entry.md | 13 +++++-------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/abi-cmse-nonsecure-call.md b/src/doc/unstable-book/src/language-features/abi-cmse-nonsecure-call.md index 79a177cb28b1..6b653a194fe0 100644 --- a/src/doc/unstable-book/src/language-features/abi-cmse-nonsecure-call.md +++ b/src/doc/unstable-book/src/language-features/abi-cmse-nonsecure-call.md @@ -1,4 +1,4 @@ -# `abi_c_cmse_nonsecure_call` +# `abi_cmse_nonsecure_call` The tracking issue for this feature is: [#81391] @@ -14,10 +14,9 @@ LLVM, the Rust compiler and the linker are providing [support](https://developer.arm.com/documentation/ecm0359818/latest/) for the TrustZone-M feature. -One of the things provided, with this unstable feature, is the -`C-cmse-nonsecure-call` function ABI. This ABI is used on function pointers to -non-secure code to mark a non-secure function call (see [section -5.5](https://developer.arm.com/documentation/ecm0359818/latest/) for details). +One of the things provided with this unstable feature is the "cmse-nonsecure-call" function ABI. +This ABI is used on function pointers to non-secure code to mark a non-secure function call +(see [section 5.5](https://developer.arm.com/documentation/ecm0359818/latest/) for details). With this ABI, the compiler will do the following to perform the call: * save registers needed after the call to Secure memory @@ -28,19 +27,16 @@ With this ABI, the compiler will do the following to perform the call: To avoid using the non-secure stack, the compiler will constrain the number and type of parameters/return value. -The `extern "C-cmse-nonsecure-call"` ABI is otherwise equivalent to the -`extern "C"` ABI. - ``` rust,ignore #![no_std] -#![feature(abi_c_cmse_nonsecure_call)] +#![feature(abi_cmse_nonsecure_call)] #[no_mangle] pub fn call_nonsecure_function(addr: usize) -> u32 { let non_secure_function = - unsafe { core::mem::transmute:: u32>(addr) }; + unsafe { core::mem::transmute:: u32>(addr) }; non_secure_function() } ``` diff --git a/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md index ca95ccf33ac2..1d76d6516598 100644 --- a/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md +++ b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md @@ -14,10 +14,9 @@ LLVM, the Rust compiler and the linker are providing [support](https://developer.arm.com/documentation/ecm0359818/latest/) for the TrustZone-M feature. -One of the things provided, with this unstable feature, is the -`C-cmse-nonsecure-entry` ABI. This ABI marks a Secure function as an -entry function (see [section -5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details). +One of the things provided with this unstable feature is the "cmse-nonsecure-entry" ABI. +This ABI marks a Secure function as an entry function (see +[section 5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details). With this ABI, the compiler will do the following: * add a special symbol on the function which is the `__acle_se_` prefix and the standard function name @@ -28,9 +27,7 @@ With this ABI, the compiler will do the following: Because the stack can not be used to pass parameters, there will be compilation errors if: -* the total size of all parameters is too big (for example more than four 32 - bits integers) -* the entry function is not using a C ABI +* the total size of all parameters is too big (for example, more than four 32-bit integers) The special symbol `__acle_se_` will be used by the linker to generate a secure gateway veneer. @@ -42,7 +39,7 @@ gateway veneer. #![feature(cmse_nonsecure_entry)] #[no_mangle] -pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { +pub extern "cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { input + 6 } ``` From 586a9d1c25f7ff33797283e35195fdfa38cf53b2 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 24 Jun 2025 15:04:11 -0700 Subject: [PATCH 346/356] tests: split out unsupported-in-impls.rs The cross-build megatest gets extremely conflict-prone, so start cutting it into smaller pieces. --- tests/ui/abi/unsupported-in-impls.rs | 33 ++++++++++++++++++++++++ tests/ui/abi/unsupported-in-impls.stderr | 27 +++++++++++++++++++ tests/ui/abi/unsupported.aarch64.stderr | 26 +------------------ tests/ui/abi/unsupported.arm.stderr | 26 +------------------ tests/ui/abi/unsupported.riscv32.stderr | 26 +------------------ tests/ui/abi/unsupported.riscv64.stderr | 26 +------------------ tests/ui/abi/unsupported.rs | 24 ----------------- tests/ui/abi/unsupported.x64.stderr | 26 +------------------ tests/ui/abi/unsupported.x64_win.stderr | 26 +------------------ 9 files changed, 66 insertions(+), 174 deletions(-) create mode 100644 tests/ui/abi/unsupported-in-impls.rs create mode 100644 tests/ui/abi/unsupported-in-impls.stderr diff --git a/tests/ui/abi/unsupported-in-impls.rs b/tests/ui/abi/unsupported-in-impls.rs new file mode 100644 index 000000000000..65a79e7643c1 --- /dev/null +++ b/tests/ui/abi/unsupported-in-impls.rs @@ -0,0 +1,33 @@ +// Test for https://github.com/rust-lang/rust/issues/86232 +// Due to AST-to-HIR lowering nuances, we used to allow unsupported ABIs to "leak" into the HIR +// without being checked, as we would check after generating the ExternAbi. +// +// Here we test that an unsupported ABI in various impl-related positions will be rejected, +// both in the original declarations and the actual implementations. + +#![feature(rustc_attrs)] +//@ compile-flags: --crate-type lib + +pub struct FnPtrBearer { + pub ptr: extern "rust-invalid" fn(), + //~^ ERROR: is not a supported ABI +} + +impl FnPtrBearer { + pub extern "rust-invalid" fn inherent_fn(self) { + //~^ ERROR: is not a supported ABI + (self.ptr)() + } +} + +pub trait Trait { + extern "rust-invalid" fn trait_fn(self); + //~^ ERROR: is not a supported ABI +} + +impl Trait for FnPtrBearer { + extern "rust-invalid" fn trait_fn(self) { + //~^ ERROR: is not a supported ABI + self.inherent_fn() + } +} diff --git a/tests/ui/abi/unsupported-in-impls.stderr b/tests/ui/abi/unsupported-in-impls.stderr new file mode 100644 index 000000000000..d7a188f8a040 --- /dev/null +++ b/tests/ui/abi/unsupported-in-impls.stderr @@ -0,0 +1,27 @@ +error[E0570]: "rust-invalid" is not a supported ABI for the current target + --> $DIR/unsupported-in-impls.rs:15:21 + | +LL | pub ptr: extern "rust-invalid" fn(), + | ^^^^^^^^^^^^^^ + +error[E0570]: "rust-invalid" is not a supported ABI for the current target + --> $DIR/unsupported-in-impls.rs:20:16 + | +LL | pub extern "rust-invalid" fn inherent_fn(self) { + | ^^^^^^^^^^^^^^ + +error[E0570]: "rust-invalid" is not a supported ABI for the current target + --> $DIR/unsupported-in-impls.rs:27:12 + | +LL | extern "rust-invalid" fn trait_fn(self); + | ^^^^^^^^^^^^^^ + +error[E0570]: "rust-invalid" is not a supported ABI for the current target + --> $DIR/unsupported-in-impls.rs:32:12 + | +LL | extern "rust-invalid" fn trait_fn(self) { + | ^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 85e251a65d20..b89f7359b3f0 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -156,30 +156,6 @@ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current ta LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:17 - | -LL | ptr: extern "thiscall" fn(), - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:16 - | -LL | pub extern "thiscall" fn inherent_fn(self) { - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:12 - | -LL | extern "thiscall" fn trait_fn(self); - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:158:12 - | -LL | extern "thiscall" fn trait_fn(self) { - | ^^^^^^^^^^ - warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:99:17 | @@ -221,6 +197,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 29 previous errors; 4 warnings emitted +error: aborting due to 25 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index a4274d0ac603..173cbf9715b6 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -138,30 +138,6 @@ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current ta LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:17 - | -LL | ptr: extern "thiscall" fn(), - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:16 - | -LL | pub extern "thiscall" fn inherent_fn(self) { - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:12 - | -LL | extern "thiscall" fn trait_fn(self); - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:158:12 - | -LL | extern "thiscall" fn trait_fn(self) { - | ^^^^^^^^^^ - warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:99:17 | @@ -203,6 +179,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 26 previous errors; 4 warnings emitted +error: aborting due to 22 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index 7ef7cae5057e..cb9b758a7304 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -150,30 +150,6 @@ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current ta LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:17 - | -LL | ptr: extern "thiscall" fn(), - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:16 - | -LL | pub extern "thiscall" fn inherent_fn(self) { - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:12 - | -LL | extern "thiscall" fn trait_fn(self); - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:158:12 - | -LL | extern "thiscall" fn trait_fn(self) { - | ^^^^^^^^^^ - warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:99:17 | @@ -215,6 +191,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 28 previous errors; 4 warnings emitted +error: aborting due to 24 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index 7ef7cae5057e..cb9b758a7304 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -150,30 +150,6 @@ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current ta LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:17 - | -LL | ptr: extern "thiscall" fn(), - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:16 - | -LL | pub extern "thiscall" fn inherent_fn(self) { - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:12 - | -LL | extern "thiscall" fn trait_fn(self); - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:158:12 - | -LL | extern "thiscall" fn trait_fn(self) { - | ^^^^^^^^^^ - warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:99:17 | @@ -215,6 +191,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 28 previous errors; 4 warnings emitted +error: aborting due to 24 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 4bb732c94ac3..0ee310676baa 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -136,27 +136,3 @@ extern "C-cmse-nonsecure-entry" {} extern "cdecl" {} //[x64_win]~^ WARN unsupported_calling_conventions //[x64_win]~^^ WARN this was previously accepted - -struct FnPtrBearer { - ptr: extern "thiscall" fn(), - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI -} - -impl FnPtrBearer { - pub extern "thiscall" fn inherent_fn(self) { - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI - (self.ptr)() - } -} - -trait Trait { - extern "thiscall" fn trait_fn(self); - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI -} - -impl Trait for FnPtrBearer { - extern "thiscall" fn trait_fn(self) { - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR: is not a supported ABI - self.inherent_fn() - } -} diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 7b021dff7c90..1a7b01375cfb 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -132,30 +132,6 @@ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current ta LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:17 - | -LL | ptr: extern "thiscall" fn(), - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:16 - | -LL | pub extern "thiscall" fn inherent_fn(self) { - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:12 - | -LL | extern "thiscall" fn trait_fn(self); - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:158:12 - | -LL | extern "thiscall" fn trait_fn(self) { - | ^^^^^^^^^^ - warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:99:17 | @@ -197,6 +173,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 25 previous errors; 4 warnings emitted +error: aborting due to 21 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 4ce5b3340d12..82b64e45b01f 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -100,30 +100,6 @@ error[E0570]: "C-cmse-nonsecure-entry" is not a supported ABI for the current ta LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:17 - | -LL | ptr: extern "thiscall" fn(), - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:146:16 - | -LL | pub extern "thiscall" fn inherent_fn(self) { - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:153:12 - | -LL | extern "thiscall" fn trait_fn(self); - | ^^^^^^^^^^ - -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:158:12 - | -LL | extern "thiscall" fn trait_fn(self) { - | ^^^^^^^^^^ - warning: "stdcall" is not a supported ABI for the current target --> $DIR/unsupported.rs:81:19 | @@ -215,6 +191,6 @@ LL | extern "cdecl" fn cdecl() {} = note: for more information, see issue #137018 = help: use `extern "C"` instead -error: aborting due to 21 previous errors; 9 warnings emitted +error: aborting due to 17 previous errors; 9 warnings emitted For more information about this error, try `rustc --explain E0570`. From 12d05d868fd43d6d930d7d9f9648ae7443751003 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 24 Jun 2025 15:14:33 -0700 Subject: [PATCH 347/356] tests: migrate unsupported-abi-transmute.rs to extern "rust-invalid" --- tests/ui/abi/unsupported-abi-transmute.rs | 17 +++++++---------- tests/ui/abi/unsupported-abi-transmute.stderr | 8 ++++---- tests/ui/abi/unsupported-in-impls.rs | 3 +++ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/ui/abi/unsupported-abi-transmute.rs b/tests/ui/abi/unsupported-abi-transmute.rs index 31501bc6d108..42aa180e1fd8 100644 --- a/tests/ui/abi/unsupported-abi-transmute.rs +++ b/tests/ui/abi/unsupported-abi-transmute.rs @@ -1,15 +1,12 @@ -//@ add-core-stubs -//@ compile-flags: --crate-type=lib --target x86_64-unknown-none -//@ needs-llvm-components: x86 -//@ edition: 2018 -#![no_core] -#![feature(no_core, lang_items)] -extern crate minicore; -use minicore::*; - // Check we error before unsupported ABIs reach codegen stages. +//@ edition: 2018 +//@ compile-flags: --crate-type=lib +#![feature(rustc_attrs)] + +use core::mem; + fn anything() { - let a = unsafe { mem::transmute::(4) }(2); + let a = unsafe { mem::transmute::(4) }(2); //~^ ERROR: is not a supported ABI for the current target [E0570] } diff --git a/tests/ui/abi/unsupported-abi-transmute.stderr b/tests/ui/abi/unsupported-abi-transmute.stderr index 63056180c71c..f1d202b1a1c7 100644 --- a/tests/ui/abi/unsupported-abi-transmute.stderr +++ b/tests/ui/abi/unsupported-abi-transmute.stderr @@ -1,8 +1,8 @@ -error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported-abi-transmute.rs:13:53 +error[E0570]: "rust-invalid" is not a supported ABI for the current target + --> $DIR/unsupported-abi-transmute.rs:10:53 | -LL | let a = unsafe { mem::transmute::(4) }(2); - | ^^^^^^^^^^ +LL | let a = unsafe { mem::transmute::(4) }(2); + | ^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/abi/unsupported-in-impls.rs b/tests/ui/abi/unsupported-in-impls.rs index 65a79e7643c1..71797954865a 100644 --- a/tests/ui/abi/unsupported-in-impls.rs +++ b/tests/ui/abi/unsupported-in-impls.rs @@ -1,6 +1,9 @@ // Test for https://github.com/rust-lang/rust/issues/86232 // Due to AST-to-HIR lowering nuances, we used to allow unsupported ABIs to "leak" into the HIR // without being checked, as we would check after generating the ExternAbi. +// Checking afterwards only works if we examine every HIR construct that contains an ExternAbi, +// and those may be very different in HIR, even if they read the same in source. +// This made it very easy to make mistakes. // // Here we test that an unsupported ABI in various impl-related positions will be rejected, // both in the original declarations and the actual implementations. From 78652b783dd1549d4782c2daba7d12214e001b54 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 24 Jun 2025 15:22:59 -0700 Subject: [PATCH 348/356] tests: specify why extern "rust-invalid" cannot be used in varargs test --- tests/ui/abi/unsupported-varargs-fnptr.rs | 1 + tests/ui/abi/unsupported-varargs-fnptr.stderr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/abi/unsupported-varargs-fnptr.rs b/tests/ui/abi/unsupported-varargs-fnptr.rs index 733e16c7e4bd..1d23916d0390 100644 --- a/tests/ui/abi/unsupported-varargs-fnptr.rs +++ b/tests/ui/abi/unsupported-varargs-fnptr.rs @@ -1,5 +1,6 @@ // FIXME(workingjubilee): add revisions and generalize to other platform-specific varargs ABIs, // preferably after the only-arch directive is enhanced with an "or pattern" syntax +// NOTE: This deliberately tests an ABI that supports varargs, so no `extern "rust-invalid"` //@ only-x86_64 // We have to use this flag to force ABI computation of an invalid ABI diff --git a/tests/ui/abi/unsupported-varargs-fnptr.stderr b/tests/ui/abi/unsupported-varargs-fnptr.stderr index 445e57df9d86..238f2b313304 100644 --- a/tests/ui/abi/unsupported-varargs-fnptr.stderr +++ b/tests/ui/abi/unsupported-varargs-fnptr.stderr @@ -1,5 +1,5 @@ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported-varargs-fnptr.rs:13:20 + --> $DIR/unsupported-varargs-fnptr.rs:14:20 | LL | fn aapcs(f: extern "aapcs" fn(usize, ...)) { | ^^^^^^^ From 087dabfca7c39d68534bb8c23ffa78def4b24c37 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 24 Jun 2025 21:21:13 -0700 Subject: [PATCH 349/356] Sprinkle breadcrumbs around to lead people to the rust-invalid ABI --- src/doc/rustc-dev-guide/src/tests/ui.md | 5 +++++ tests/ui/SUMMARY.md | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 8f4467a5551e..09dc476d68ee 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -59,6 +59,11 @@ The output is normalized to ignore unwanted differences, see the [Normalization](#normalization) section. If the file is missing, then compiletest expects the corresponding output to be empty. +A common reason to use normalization, revisions, and most of the other following tools, +is to account for platform differences. Consider alternatives to these tools, like +e.g. using the `extern "rust-invalid"` ABI that is invalid on every platform +instead of fixing the test to use cross-compilation and testing every possibly-invalid ABI. + There can be multiple stdout/stderr files. The general form is: ```text diff --git a/tests/ui/SUMMARY.md b/tests/ui/SUMMARY.md index d807e38dab28..e44959e3564b 100644 --- a/tests/ui/SUMMARY.md +++ b/tests/ui/SUMMARY.md @@ -8,6 +8,8 @@ For now, only immediate subdirectories under `tests/ui/` are described, but thes These tests deal with *Application Binary Interfaces* (ABI), mostly relating to function name mangling (and the `#[no_mangle]` attribute), calling conventions, or compiler flags which affect ABI. +Tests for unsupported ABIs can be made cross-platform by using the `extern "rust-invalid"` ABI, which is considered unsupported on every platform. + ## `tests/ui/allocator` These tests exercise `#![feature(allocator_api)]` and the `#[global_allocator]` attribute. From c24914ec8329b22ec7bcaa6ab534a784b2bd8ab9 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 24 Jun 2025 22:09:14 -0700 Subject: [PATCH 350/356] compiler: fussily sort the huge AbiMap match --- compiler/rustc_target/src/spec/abi_map.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index ce1bdcbb8acc..e5ff3f2c31d4 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -85,11 +85,16 @@ impl AbiMap { (ExternAbi::System { .. }, _) => CanonAbi::C, // fallible lowerings + /* multi-platform */ + // always and forever + (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid, + (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C, (ExternAbi::EfiApi, _) => return AbiMapping::Invalid, + /* arm */ (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid, @@ -103,6 +108,12 @@ impl AbiMap { return AbiMapping::Invalid; } + /* gpu */ + (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel, + (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel, + (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid, + + /* x86 */ (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C, (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C), @@ -130,10 +141,7 @@ impl AbiMap { (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid, - (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel, - (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel, - (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid, - + /* interrupts */ (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr), (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => { CanonAbi::Interrupt(InterruptKind::AvrNonBlocking) @@ -156,8 +164,7 @@ impl AbiMap { | ExternAbi::Msp430Interrupt | ExternAbi::RiscvInterruptM | ExternAbi::RiscvInterruptS - | ExternAbi::X86Interrupt - | ExternAbi::RustInvalid, + | ExternAbi::X86Interrupt, _, ) => return AbiMapping::Invalid, }; From 09295af867fc116c5fae338a88f2fafa4d2da97a Mon Sep 17 00:00:00 2001 From: "Kurt Heiritz (pseudo)" Date: Wed, 25 Jun 2025 17:41:27 +0530 Subject: [PATCH 351/356] Add Sub, Mul, Div, Rem as const_traits --- library/core/src/ops/arith.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 098ce4531f0c..7ffde233da34 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -179,12 +179,14 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 /// ``` #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_ops", issue = "90080")] #[rustc_on_unimplemented( message = "cannot subtract `{Rhs}` from `{Self}`", label = "no implementation for `{Self} - {Rhs}`", append_const_msg )] #[doc(alias = "-")] +#[const_trait] pub trait Sub { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -206,7 +208,8 @@ pub trait Sub { macro_rules! sub_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl Sub for $t { + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + impl const Sub for $t { type Output = $t; #[inline] @@ -310,11 +313,13 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 /// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_ops", issue = "90080")] #[diagnostic::on_unimplemented( message = "cannot multiply `{Self}` by `{Rhs}`", label = "no implementation for `{Self} * {Rhs}`" )] #[doc(alias = "*")] +#[const_trait] pub trait Mul { /// The resulting type after applying the `*` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -336,7 +341,8 @@ pub trait Mul { macro_rules! mul_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl Mul for $t { + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + impl const Mul for $t { type Output = $t; #[inline] @@ -444,11 +450,13 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 /// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_ops", issue = "90080")] #[diagnostic::on_unimplemented( message = "cannot divide `{Self}` by `{Rhs}`", label = "no implementation for `{Self} / {Rhs}`" )] #[doc(alias = "/")] +#[const_trait] pub trait Div { /// The resulting type after applying the `/` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -476,7 +484,8 @@ macro_rules! div_impl_integer { /// #[doc = $panic] #[stable(feature = "rust1", since = "1.0.0")] - impl Div for $t { + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + impl const Div for $t { type Output = $t; #[inline] @@ -496,7 +505,8 @@ div_impl_integer! { macro_rules! div_impl_float { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl Div for $t { + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + impl const Div for $t { type Output = $t; #[inline] @@ -546,11 +556,13 @@ div_impl_float! { f16 f32 f64 f128 } /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_ops", issue = "90080")] #[diagnostic::on_unimplemented( message = "cannot calculate the remainder of `{Self}` divided by `{Rhs}`", label = "no implementation for `{Self} % {Rhs}`" )] #[doc(alias = "%")] +#[const_trait] pub trait Rem { /// The resulting type after applying the `%` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -578,7 +590,8 @@ macro_rules! rem_impl_integer { /// #[doc = $panic] #[stable(feature = "rust1", since = "1.0.0")] - impl Rem for $t { + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + impl const Rem for $t { type Output = $t; #[inline] @@ -613,6 +626,7 @@ macro_rules! rem_impl_float { /// assert_eq!(x % y, remainder); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] impl Rem for $t { type Output = $t; From d2d17c60bd62c03b91f6ded31b34da90addf2fc0 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 22 Jun 2025 00:12:13 +0800 Subject: [PATCH 352/356] Add runtime check to avoid overwrite arg easily in diag and store and restore snapshot when set subdiag arg Signed-off-by: xizheyin --- .../rustc_borrowck/src/diagnostics/mod.rs | 8 ++++- compiler/rustc_builtin_macros/src/errors.rs | 1 + compiler/rustc_const_eval/src/errors.rs | 3 ++ compiler/rustc_errors/src/diagnostic.rs | 32 ++++++++++++++++++- compiler/rustc_hir_analysis/src/errors.rs | 1 + .../src/hir_ty_lowering/errors.rs | 1 + compiler/rustc_lint/src/levels.rs | 5 +-- compiler/rustc_lint/src/lifetime_syntax.rs | 4 +-- compiler/rustc_lint/src/lints.rs | 11 ++++--- .../src/diagnostics/subdiagnostic.rs | 30 ++++++++++++++--- .../rustc_metadata/src/dependency_format.rs | 2 +- compiler/rustc_metadata/src/errors.rs | 3 +- compiler/rustc_mir_build/src/errors.rs | 17 +++++++--- .../src/thir/pattern/check_match.rs | 7 ++-- .../src/lint_tail_expr_drop_order.rs | 4 +++ compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/dead.rs | 2 +- compiler/rustc_passes/src/errors.rs | 3 +- compiler/rustc_passes/src/liveness.rs | 1 + compiler/rustc_resolve/src/diagnostics.rs | 14 ++++---- compiler/rustc_resolve/src/errors.rs | 5 +-- .../src/errors/note_and_explain.rs | 2 ++ 22 files changed, 119 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 5e3f3ffa2ea8..10dede787806 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1254,8 +1254,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { && !spans.is_empty() { let mut span: MultiSpan = spans.clone().into(); + err.arg("ty", param_ty.to_string()); + let msg = err.dcx.eagerly_translate_to_string( + fluent::borrowck_moved_a_fn_once_in_call_def, + err.args.iter(), + ); + err.remove_arg("ty"); for sp in spans { - span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def); + span.push_span_label(sp, msg.clone()); } span.push_span_label( fn_call_span, diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 3a2e96a5e5af..ec98fffb9c41 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -672,6 +672,7 @@ impl Subdiagnostic for FormatUnusedArg { fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("named", self.named); let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg); + diag.remove_arg("named"); diag.span_label(self.span, msg); } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 037cbf777e70..4ea2d6f2ebbe 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -293,6 +293,9 @@ impl Subdiagnostic for FrameNote { span.push_span_label(self.span, fluent::const_eval_frame_note_last); } let msg = diag.eagerly_translate(fluent::const_eval_frame_note); + diag.remove_arg("times"); + diag.remove_arg("where_"); + diag.remove_arg("instance"); diag.span_note(span, msg); } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a11f81b55bb8..8da7cdd93588 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -289,6 +289,9 @@ pub struct DiagInner { pub suggestions: Suggestions, pub args: DiagArgMap, + // This is used to store args and restore them after a subdiagnostic is rendered. + pub reserved_args: DiagArgMap, + /// This is not used for highlighting or rendering any error message. Rather, it can be used /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of /// `span` if there is one. Otherwise, it is `DUMMY_SP`. @@ -319,6 +322,7 @@ impl DiagInner { children: vec![], suggestions: Suggestions::Enabled(vec![]), args: Default::default(), + reserved_args: Default::default(), sort_span: DUMMY_SP, is_lint: None, long_ty_path: None, @@ -390,7 +394,27 @@ impl DiagInner { } pub(crate) fn arg(&mut self, name: impl Into, arg: impl IntoDiagArg) { - self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path)); + let name = name.into(); + let value = arg.into_diag_arg(&mut self.long_ty_path); + // This assertion is to avoid subdiagnostics overwriting an existing diagnostic arg. + debug_assert!( + !self.args.contains_key(&name) || self.args.get(&name) == Some(&value), + "arg {} already exists", + name + ); + self.args.insert(name, value); + } + + pub fn remove_arg(&mut self, name: &str) { + self.args.swap_remove(name); + } + + pub fn store_args(&mut self) { + self.reserved_args = self.args.clone(); + } + + pub fn restore_args(&mut self) { + self.args = std::mem::take(&mut self.reserved_args); } /// Fields used for Hash, and PartialEq trait. @@ -1423,6 +1447,12 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self.downgrade_to_delayed_bug(); self.emit() } + + pub fn remove_arg(&mut self, name: &str) { + if let Some(diag) = self.diag.as_mut() { + diag.remove_arg(name); + } + } } /// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 318aaab50f4d..c920e25ad376 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -127,6 +127,7 @@ pub(crate) enum AssocItemNotFoundSugg<'a> { SimilarInOtherTrait { #[primary_span] span: Span, + trait_name: &'a str, assoc_kind: &'static str, suggested_name: Symbol, }, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 0e79a8918b05..f211137ddd6a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -309,6 +309,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // change the associated item. err.sugg = Some(errors::AssocItemNotFoundSugg::SimilarInOtherTrait { span: assoc_ident.span, + trait_name: &trait_name, assoc_kind: assoc_kind_str, suggested_name, }); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index c52dbd892bf4..c72f8571153a 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -482,7 +482,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let name = lint_name.as_str(); let suggestion = RenamedLintSuggestion::WithoutSpan { replace }; let requested_level = RequestedLevel { level, lint_name }; - let lint = RenamedLintFromCommandLine { name, suggestion, requested_level }; + let lint = + RenamedLintFromCommandLine { name, replace, suggestion, requested_level }; self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint); } CheckLintNameResult::Removed(ref reason) => { @@ -824,7 +825,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { RenamedLintSuggestion::WithSpan { suggestion: sp, replace }; let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name); - let lint = RenamedLint { name: name.as_str(), suggestion }; + let lint = RenamedLint { name: name.as_str(), replace, suggestion }; self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint); } diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 95b7b69bd5a7..5465968e9847 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -422,12 +422,12 @@ fn build_mismatch_suggestion( lifetime_name: &str, infos: &[&Info<'_>], ) -> lints::MismatchedLifetimeSyntaxesSuggestion { - let lifetime_name = lifetime_name.to_owned(); + let lifetime_name_sugg = lifetime_name.to_owned(); let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect(); lints::MismatchedLifetimeSyntaxesSuggestion::Explicit { - lifetime_name, + lifetime_name_sugg, suggestions, tool_only: false, } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index abdf8e3853bf..583bd30c1a5d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1089,6 +1089,7 @@ pub(crate) struct DeprecatedLintNameFromCommandLine<'a> { #[diag(lint_renamed_lint)] pub(crate) struct RenamedLint<'a> { pub name: &'a str, + pub replace: &'a str, #[subdiagnostic] pub suggestion: RenamedLintSuggestion<'a>, } @@ -1109,6 +1110,7 @@ pub(crate) enum RenamedLintSuggestion<'a> { #[diag(lint_renamed_lint)] pub(crate) struct RenamedLintFromCommandLine<'a> { pub name: &'a str, + pub replace: &'a str, #[subdiagnostic] pub suggestion: RenamedLintSuggestion<'a>, #[subdiagnostic] @@ -3227,7 +3229,7 @@ pub(crate) enum MismatchedLifetimeSyntaxesSuggestion { }, Explicit { - lifetime_name: String, + lifetime_name_sugg: String, suggestions: Vec<(Span, String)>, tool_only: bool, }, @@ -3281,13 +3283,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { ); } - Explicit { lifetime_name, suggestions, tool_only } => { - diag.arg("lifetime_name", lifetime_name); - + Explicit { lifetime_name_sugg, suggestions, tool_only } => { + diag.arg("lifetime_name_sugg", lifetime_name_sugg); let msg = diag.eagerly_translate( fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit, ); - + diag.remove_arg("lifetime_name_sugg"); diag.multipart_suggestion_with_style( msg, suggestions, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index bc9516b2e0c6..04fdada80249 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -220,7 +220,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } /// Generates the code for a field with no attributes. - fn generate_field_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { + fn generate_field_arg(&mut self, binding_info: &BindingInfo<'_>) -> (TokenStream, TokenStream) { let diag = &self.parent.diag; let field = binding_info.ast(); @@ -230,12 +230,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let ident = field.ident.as_ref().unwrap(); let ident = format_ident!("{}", ident); // strip `r#` prefix, if present - quote! { + let args = quote! { #diag.arg( stringify!(#ident), #field_binding ); - } + }; + let remove_args = quote! { + #diag.remove_arg(stringify!(#ident)); + }; + (args, remove_args) } /// Generates the necessary code for all attributes on a field. @@ -600,8 +604,13 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { calls.extend(call); } - - let plain_args: TokenStream = self + let store_args = quote! { + #diag.store_args(); + }; + let restore_args = quote! { + #diag.restore_args(); + }; + let (plain_args, remove_args): (TokenStream, TokenStream) = self .variant .bindings() .iter() @@ -610,12 +619,23 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { .collect(); let formatting_init = &self.formatting_init; + + // For #[derive(Subdiagnostic)] + // + // - Store args of the main diagnostic for later restore. + // - add args of subdiagnostic. + // - Generate the calls, such as note, label, etc. + // - Remove the arguments for allowing Vec to be used. + // - Restore the arguments for allowing main and subdiagnostic share the same fields. Ok(quote! { #init #formatting_init #attr_args + #store_args #plain_args #calls + #remove_args + #restore_args }) } } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index fcae33c73c9c..1089c4ac71c6 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -314,7 +314,7 @@ fn add_library( crate_name: tcx.crate_name(cnum), non_static_deps: unavailable_as_static .drain(..) - .map(|cnum| NonStaticCrateDep { crate_name: tcx.crate_name(cnum) }) + .map(|cnum| NonStaticCrateDep { crate_name_: tcx.crate_name(cnum) }) .collect(), rustc_driver_help: linking_to_rustc_driver.then_some(RustcDriverHelp), }); diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 71da42901741..4a3b43167cfa 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -45,7 +45,8 @@ pub struct CrateDepMultiple { #[derive(Subdiagnostic)] #[note(metadata_crate_dep_not_static)] pub struct NonStaticCrateDep { - pub crate_name: Symbol, + /// It's different from `crate_name` in main Diagnostic. + pub crate_name_: Symbol, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index ae09db502352..23869878e068 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -994,14 +994,15 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub(crate) uncovered: Uncovered, #[subdiagnostic] pub(crate) inform: Option, - #[label(mir_build_confused)] - pub(crate) interpreted_as_const: Option, #[subdiagnostic] - pub(crate) interpreted_as_const_sugg: Option, + pub(crate) interpreted_as_const: Option, + #[subdiagnostic] + pub(crate) interpreted_as_const_sugg: Option, #[subdiagnostic] pub(crate) adt_defined_here: Option>, #[note(mir_build_privately_uninhabited)] pub(crate) witness_1_is_privately_uninhabited: bool, + pub(crate) witness_1: String, #[note(mir_build_pattern_ty)] pub(crate) _p: (), pub(crate) pattern_ty: Ty<'tcx>, @@ -1016,6 +1017,14 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { #[note(mir_build_more_information)] pub(crate) struct Inform; +#[derive(Subdiagnostic)] +#[label(mir_build_confused)] +pub(crate) struct InterpretedAsConst { + #[primary_span] + pub(crate) span: Span, + pub(crate) variable: String, +} + pub(crate) struct AdtDefinedHere<'tcx> { pub(crate) adt_def_span: Span, pub(crate) ty: Ty<'tcx>, @@ -1046,7 +1055,7 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { applicability = "maybe-incorrect", style = "verbose" )] -pub(crate) struct InterpretedAsConst { +pub(crate) struct InterpretedAsConstSugg { #[primary_span] pub(crate) span: Span, pub(crate) variable: String, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 245bd866030c..1b7866d79b77 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -685,8 +685,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let span = self.tcx.def_span(def_id); let variable = self.tcx.item_name(def_id).to_string(); // When we encounter a constant as the binding name, point at the `const` definition. - interpreted_as_const = Some(span); - interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable }); + interpreted_as_const = Some(InterpretedAsConst { span, variable: variable.clone() }); + interpreted_as_const_sugg = Some(InterpretedAsConstSugg { span: pat.span, variable }); } else if let PatKind::Constant { .. } = unpeeled_pat.kind && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) { @@ -738,6 +738,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { false }; + let witness_1 = cx.print_witness_pat(witnesses.get(0).unwrap()); + self.error = Err(self.tcx.dcx().emit_err(PatternNotCovered { span: pat.span, origin, @@ -746,6 +748,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { interpreted_as_const, interpreted_as_const_sugg, witness_1_is_privately_uninhabited, + witness_1, _p: (), pattern_ty, let_suggestion, diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 75f351f05c30..1bd770a85260 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -516,8 +516,12 @@ struct LocalLabel<'a> { /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order impl Subdiagnostic for LocalLabel<'_> { fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { + // Becuase parent uses this field , we need to remove it delay before adding it. + diag.remove_arg("name"); diag.arg("name", self.name); + diag.remove_arg("is_generated_name"); diag.arg("is_generated_name", self.is_generated_name); + diag.remove_arg("is_dropped_first_edition_2024"); diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024); let msg = diag.eagerly_translate(crate::fluent_generated::mir_transform_tail_expr_local); diag.span_label(self.span, msg); diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index c1a2b3b29733..7ae99229d257 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -291,7 +291,7 @@ passes_duplicate_lang_item_crate_depends = .second_definition_path = second definition in `{$crate_name}` loaded from {$path} passes_enum_variant_same_name = - it is impossible to refer to the {$descr} `{$dead_name}` because it is shadowed by this enum variant with the same name + it is impossible to refer to the {$dead_descr} `{$dead_name}` because it is shadowed by this enum variant with the same name passes_export_name = attribute should be applied to a free function, impl method or static diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 4257d8e8d16b..fded00684d45 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -1078,7 +1078,7 @@ impl<'tcx> DeadVisitor<'tcx> { maybe_enum.variants().iter().find(|i| i.name == dead_item.name) { Some(crate::errors::EnumVariantSameName { - descr: tcx.def_descr(dead_item.def_id.to_def_id()), + dead_descr: tcx.def_descr(dead_item.def_id.to_def_id()), dead_name: dead_item.name, variant_span: tcx.def_span(variant.def_id), }) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 587d9170f067..ca92ad5ae5cb 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1509,7 +1509,7 @@ pub(crate) struct EnumVariantSameName<'tcx> { #[primary_span] pub variant_span: Span, pub dead_name: Symbol, - pub descr: &'tcx str, + pub dead_descr: &'tcx str, } #[derive(Subdiagnostic)] @@ -1707,6 +1707,7 @@ impl Subdiagnostic for UnusedVariableStringInterp { #[derive(LintDiagnostic)] #[diag(passes_unused_variable_try_ignore)] pub(crate) struct UnusedVarTryIgnore { + pub name: String, #[subdiagnostic] pub sugg: UnusedVarTryIgnoreSugg, } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 763d9fda8049..46280b31c17a 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1743,6 +1743,7 @@ impl<'tcx> Liveness<'_, 'tcx> { .map(|(_, pat_span, _)| *pat_span) .collect::>(), errors::UnusedVarTryIgnore { + name: name.clone(), sugg: errors::UnusedVarTryIgnoreSugg { shorthands, non_shorthands, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9149974a6177..8bca350c8ba2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -256,22 +256,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let label = match new_binding.is_import_user_facing() { - true => errors::NameDefinedMultipleTimeLabel::Reimported { span, name }, - false => errors::NameDefinedMultipleTimeLabel::Redefined { span, name }, + true => errors::NameDefinedMultipleTimeLabel::Reimported { span }, + false => errors::NameDefinedMultipleTimeLabel::Redefined { span }, }; let old_binding_label = (!old_binding.span.is_dummy() && old_binding.span != span).then(|| { let span = self.tcx.sess.source_map().guess_head_span(old_binding.span); match old_binding.is_import_user_facing() { - true => errors::NameDefinedMultipleTimeOldBindingLabel::Import { - span, - name, - old_kind, - }, + true => { + errors::NameDefinedMultipleTimeOldBindingLabel::Import { span, old_kind } + } false => errors::NameDefinedMultipleTimeOldBindingLabel::Definition { span, - name, old_kind, }, } @@ -281,6 +278,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .dcx() .create_err(errors::NameDefinedMultipleTime { span, + name, descr: ns.descr(), container, label, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 7fe74378b674..6d3752c0c834 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -978,6 +978,7 @@ pub(crate) struct VariableNotInAllPatterns { pub(crate) struct NameDefinedMultipleTime { #[primary_span] pub(crate) span: Span, + pub(crate) name: Symbol, pub(crate) descr: &'static str, pub(crate) container: &'static str, #[subdiagnostic] @@ -992,13 +993,11 @@ pub(crate) enum NameDefinedMultipleTimeLabel { Reimported { #[primary_span] span: Span, - name: Symbol, }, #[label(resolve_name_defined_multiple_time_redefined)] Redefined { #[primary_span] span: Span, - name: Symbol, }, } @@ -1008,14 +1007,12 @@ pub(crate) enum NameDefinedMultipleTimeOldBindingLabel { Import { #[primary_span] span: Span, - name: Symbol, old_kind: &'static str, }, #[label(resolve_name_defined_multiple_time_old_binding_definition)] Definition { #[primary_span] span: Span, - name: Symbol, old_kind: &'static str, }, } diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index 84e7686fdd3f..ec3c1ba4a455 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -163,12 +163,14 @@ impl RegionExplanation<'_> { impl Subdiagnostic for RegionExplanation<'_> { fn add_to_diag(self, diag: &mut Diag<'_, G>) { + diag.store_args(); diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation); + diag.restore_args(); if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { From 64a1a98f47a653e620317e5172f7d87a7ce72ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 20 Jun 2025 09:49:15 +0200 Subject: [PATCH 353/356] encode_cross_crate for hir attributes --- Cargo.lock | 1 + .../src/encode_cross_crate.rs | 42 +++++++++++++++++++ .../rustc_attr_data_structures/src/lib.rs | 2 + compiler/rustc_feature/Cargo.toml | 3 +- compiler/rustc_feature/src/builtin_attrs.rs | 7 +--- compiler/rustc_metadata/src/rmeta/encoder.rs | 10 +++-- 6 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 compiler/rustc_attr_data_structures/src/encode_cross_crate.rs diff --git a/Cargo.lock b/Cargo.lock index b44dbd6ee606..e95cacf1f6d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3724,6 +3724,7 @@ dependencies = [ name = "rustc_feature" version = "0.0.0" dependencies = [ + "rustc_attr_data_structures", "rustc_data_structures", "rustc_span", "serde", diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs new file mode 100644 index 000000000000..e41dd8bde8ff --- /dev/null +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -0,0 +1,42 @@ +use crate::AttributeKind; + +#[derive(PartialEq)] +pub enum EncodeCrossCrate { + Yes, + No, +} + +impl AttributeKind { + pub fn encode_cross_crate(&self) -> EncodeCrossCrate { + use AttributeKind::*; + use EncodeCrossCrate::*; + + match self { + Align { .. } => No, + AllowConstFnUnstable(..) => No, + AllowInternalUnstable(..) => Yes, + AsPtr(..) => Yes, + BodyStability { .. } => No, + Confusables { .. } => Yes, + ConstStability { .. } => Yes, + ConstStabilityIndirect => No, + Deprecation { .. } => Yes, + DocComment { .. } => Yes, + Inline(..) => No, + MacroTransparency(..) => Yes, + Repr(..) => No, + Stability { .. } => Yes, + Cold(..) => No, + ConstContinue(..) => No, + LoopMatch(..) => No, + MayDangle(..) => No, + MustUse { .. } => Yes, + Naked(..) => No, + NoMangle(..) => No, + Optimize(..) => No, + PubTransparent(..) => Yes, + SkipDuringMethodDispatch { .. } => No, + TrackCaller(..) => Yes, + } + } +} diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index f8355be09adf..86c73f0d9a08 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -9,6 +9,7 @@ // tidy-alphabetical-end mod attributes; +mod encode_cross_crate; mod stability; mod version; @@ -17,6 +18,7 @@ pub mod lints; use std::num::NonZero; pub use attributes::*; +pub use encode_cross_crate::EncodeCrossCrate; use rustc_abi::Align; use rustc_ast::token::CommentKind; use rustc_ast::{AttrStyle, IntTy, UintTy}; diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index a5ae06473cbe..78d7b698b720 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -5,8 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_span = { path = "../rustc_span" } -serde = { version = "1.0.125", features = [ "derive" ] } +serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.59" # tidy-alphabetical-end diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 8c0f279e343b..8e1392998d40 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -5,6 +5,7 @@ use std::sync::LazyLock; use AttributeDuplicates::*; use AttributeGate::*; use AttributeType::*; +use rustc_attr_data_structures::EncodeCrossCrate; use rustc_data_structures::fx::FxHashMap; use rustc_span::edition::Edition; use rustc_span::{Symbol, sym}; @@ -368,12 +369,6 @@ macro_rules! experimental { }; } -#[derive(PartialEq)] -pub enum EncodeCrossCrate { - Yes, - No, -} - pub struct BuiltinAttribute { pub name: Symbol, /// Whether this attribute is encode cross crate. diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ed3c18a02a69..d74918235b6c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -5,7 +5,7 @@ use std::io::{Read, Seek, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use rustc_ast::attr::AttributeExt; +use rustc_attr_data_structures::EncodeCrossCrate; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::sync::{join, par_for_each_in}; @@ -839,9 +839,13 @@ struct AnalyzeAttrState<'a> { /// visibility: this is a piece of data that can be computed once per defid, and not once per /// attribute. Some attributes would only be usable downstream if they are public. #[inline] -fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> bool { +fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool { let mut should_encode = false; - if let Some(name) = attr.name() + if let hir::Attribute::Parsed(p) = attr + && p.encode_cross_crate() == EncodeCrossCrate::No + { + // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. + } else if let Some(name) = attr.name() && !rustc_feature::encode_cross_crate(name) { // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. From 3bf650f980a2ff5dcc521a7138c21f1ed67f0b8b Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Mon, 30 Jun 2025 18:03:39 -0400 Subject: [PATCH 354/356] add failing test, bless incorrect output --- tests/ui/typeck/auxiliary/private-dep.rs | 3 ++ tests/ui/typeck/auxiliary/public-dep.rs | 11 +++++ .../dont-suggest-private-dependencies.rs | 30 +++++++++++++ .../dont-suggest-private-dependencies.stderr | 43 +++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 tests/ui/typeck/auxiliary/private-dep.rs create mode 100644 tests/ui/typeck/auxiliary/public-dep.rs create mode 100644 tests/ui/typeck/dont-suggest-private-dependencies.rs create mode 100644 tests/ui/typeck/dont-suggest-private-dependencies.stderr diff --git a/tests/ui/typeck/auxiliary/private-dep.rs b/tests/ui/typeck/auxiliary/private-dep.rs new file mode 100644 index 000000000000..472b40ef6229 --- /dev/null +++ b/tests/ui/typeck/auxiliary/private-dep.rs @@ -0,0 +1,3 @@ +pub trait A { + fn foo() {} +} diff --git a/tests/ui/typeck/auxiliary/public-dep.rs b/tests/ui/typeck/auxiliary/public-dep.rs new file mode 100644 index 000000000000..438692a1caa3 --- /dev/null +++ b/tests/ui/typeck/auxiliary/public-dep.rs @@ -0,0 +1,11 @@ +//@ aux-crate:priv:private_dep=private-dep.rs +//@ compile-flags: -Zunstable-options + +extern crate private_dep; +use private_dep::A; + +pub struct B; + +impl A for B { + fn foo() {} +} diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.rs b/tests/ui/typeck/dont-suggest-private-dependencies.rs new file mode 100644 index 000000000000..afac00c52131 --- /dev/null +++ b/tests/ui/typeck/dont-suggest-private-dependencies.rs @@ -0,0 +1,30 @@ +// Don't suggest importing a function from a private dependency. +// Issues: #138191, #142676 + +// Avoid suggesting traits from std-private deps +//@ forbid-output: compiler_builtins +//@ forbid-output: object + +// Check a custom trait to withstand changes in above crates +//@ aux-crate:public_dep=public-dep.rs +//@ compile-flags: -Zunstable-options +//@ forbid-output: private_dep + +struct VecReader(Vec); + +impl std::io::Read for VecReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.0.read(buf) + //~^ ERROR no method named `read` found for struct `Vec` + } +} + +extern crate public_dep; +use public_dep::B; + +fn main() { + let _ = u8::cast_from_lossy(9); + //~^ ERROR no function or associated item named `cast_from_lossy` found for type `u8` + let _ = B::foo(); + //~^ ERROR no function or associated item named `foo` found for struct `B` +} diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.stderr b/tests/ui/typeck/dont-suggest-private-dependencies.stderr new file mode 100644 index 000000000000..18848a2c08d3 --- /dev/null +++ b/tests/ui/typeck/dont-suggest-private-dependencies.stderr @@ -0,0 +1,43 @@ +error[E0599]: no method named `read` found for struct `Vec` in the current scope + --> $DIR/dont-suggest-private-dependencies.rs:17:16 + | +LL | self.0.read(buf) + | ^^^^ + | + = help: items from traits can only be used if the trait is in scope +help: trait `ReadRef` which provides `read` is implemented but not in scope; perhaps you want to import it + | +LL + use object::read::read_ref::ReadRef; + | +help: there is a method `read_at` with a similar name + | +LL | self.0.read_at(buf) + | +++ + +error[E0599]: no function or associated item named `cast_from_lossy` found for type `u8` in the current scope + --> $DIR/dont-suggest-private-dependencies.rs:26:17 + | +LL | let _ = u8::cast_from_lossy(9); + | ^^^^^^^^^^^^^^^ function or associated item not found in `u8` + | + = help: items from traits can only be used if the trait is in scope +help: trait `CastFrom` which provides `cast_from_lossy` is implemented but not in scope; perhaps you want to import it + | +LL + use compiler_builtins::math::libm_math::support::int_traits::CastFrom; + | + +error[E0599]: no function or associated item named `foo` found for struct `B` in the current scope + --> $DIR/dont-suggest-private-dependencies.rs:28:16 + | +LL | let _ = B::foo(); + | ^^^ function or associated item not found in `B` + | + = help: items from traits can only be used if the trait is in scope +help: trait `A` which provides `foo` is implemented but not in scope; perhaps you want to import it + | +LL + use private_dep::A; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. From 1e6e4bb95ab7879283e4274bd80c3e04b1ea3f7c Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Mon, 30 Jun 2025 18:04:46 -0400 Subject: [PATCH 355/356] make compiler_builtins a private dependency --- library/rustc-std-workspace-core/Cargo.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml index bd318fc2f9e9..1ddc112380f1 100644 --- a/library/rustc-std-workspace-core/Cargo.toml +++ b/library/rustc-std-workspace-core/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["public-dependency"] + [package] name = "rustc-std-workspace-core" version = "1.99.0" @@ -11,5 +13,7 @@ edition = "2024" path = "lib.rs" [dependencies] -core = { path = "../core" } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["compiler-builtins"] } +core = { path = "../core", public = true } +compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = [ + "compiler-builtins", +] } From 6b824e8143c1dcacdbac3f14f01e2bbb85da8907 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Mon, 30 Jun 2025 20:27:33 -0400 Subject: [PATCH 356/356] avoid suggesting traits from private dependencies --- .../src/hir_ty_lowering/mod.rs | 2 +- .../rustc_hir_typeck/src/method/suggest.rs | 7 +++-- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_smir/src/rustc_smir/context.rs | 6 +++- .../traits/fulfillment_errors.rs | 2 +- src/librustdoc/clean/blanket_impl.rs | 2 +- src/librustdoc/core.rs | 2 +- .../dont-suggest-private-dependencies.rs | 7 +++++ .../dont-suggest-private-dependencies.stderr | 30 +++++-------------- 9 files changed, 28 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index baf3b9b5bc9e..51cd1b7704d8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1588,7 +1588,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &infcx_ }; - tcx.all_traits() + tcx.all_traits_including_private() .filter(|trait_def_id| { // Consider only traits with the associated type tcx.associated_items(*trait_def_id) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index b35aef13c525..f446bc468e48 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1725,7 +1725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if unsatisfied_predicates.is_empty() // ...or if we already suggested that name because of `rustc_confusable` annotation && Some(similar_candidate.name()) != confusable_suggested - // and if the we aren't in an expansion. + // and if we aren't in an expansion. && !span.from_expansion() { self.find_likely_intended_associated_item( @@ -3477,9 +3477,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diag<'_>, item_name: Ident, - valid_out_of_scope_traits: Vec, + mut valid_out_of_scope_traits: Vec, explain: bool, ) -> bool { + valid_out_of_scope_traits.retain(|id| self.tcx.is_user_visible_dep(id.krate)); if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; candidates.sort_by_key(|id| self.tcx.def_path_str(id)); @@ -4384,7 +4385,7 @@ pub(crate) struct TraitInfo { /// Retrieves all traits in this crate and any dependent crates, /// and wraps them into `TraitInfo` for custom sorting. pub(crate) fn all_traits(tcx: TyCtxt<'_>) -> Vec { - tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect() + tcx.all_traits_including_private().map(|def_id| TraitInfo { def_id }).collect() } fn print_disambiguation_help<'tcx>( diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aa5355551ce0..f8b6a30682bc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2318,7 +2318,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// All traits in the crate graph, including those not visible to the user. - pub fn all_traits(self) -> impl Iterator { + pub fn all_traits_including_private(self) -> impl Iterator { iter::once(LOCAL_CRATE) .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits(cnum).iter().copied()) diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index baa4c0681e80..3fa83cfc6a08 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -130,7 +130,11 @@ impl<'tcx> SmirCtxt<'tcx> { pub fn all_trait_decls(&self) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); - tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect() + tables + .tcx + .all_traits_including_private() + .map(|trait_def_id| tables.trait_def(trait_def_id)) + .collect() } pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 0c88bd3dcbc5..db2517a83794 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1850,7 +1850,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let trait_def_id = trait_pred.def_id(); let trait_name = self.tcx.item_name(trait_def_id); let crate_name = self.tcx.crate_name(trait_def_id.krate); - if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| { + if let Some(other_trait_def_id) = self.tcx.all_traits_including_private().find(|def_id| { trait_name == self.tcx.item_name(trait_def_id) && trait_def_id.krate != def_id.krate && crate_name == self.tcx.crate_name(def_id.krate) diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index c889f52b789a..11d5b472d738 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -23,7 +23,7 @@ pub(crate) fn synthesize_blanket_impls( let ty = tcx.type_of(item_def_id); let mut blanket_impls = Vec::new(); - for trait_def_id in tcx.all_traits() { + for trait_def_id in tcx.visible_traits() { if !cx.cache.effective_visibilities.is_reachable(tcx, trait_def_id) || cx.generated_synthetics.contains(&(ty.skip_binder(), trait_def_id)) { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index cf3c4ac97af6..bd57bb21e639 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -353,7 +353,7 @@ pub(crate) fn run_global_ctxt( rustc_passes::stability::check_unused_or_stable_features(tcx); let auto_traits = - tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect(); + tcx.visible_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect(); let mut ctxt = DocContext { tcx, diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.rs b/tests/ui/typeck/dont-suggest-private-dependencies.rs index afac00c52131..ee5224e2d821 100644 --- a/tests/ui/typeck/dont-suggest-private-dependencies.rs +++ b/tests/ui/typeck/dont-suggest-private-dependencies.rs @@ -10,6 +10,13 @@ //@ compile-flags: -Zunstable-options //@ forbid-output: private_dep +// By default, the `read` diagnostic suggests `std::os::unix::fs::FileExt::read_at`. Add +// something more likely to be recommended to make the diagnostic cross-platform. +trait DecoyRead { + fn read1(&self) {} +} +impl DecoyRead for Vec {} + struct VecReader(Vec); impl std::io::Read for VecReader { diff --git a/tests/ui/typeck/dont-suggest-private-dependencies.stderr b/tests/ui/typeck/dont-suggest-private-dependencies.stderr index 18848a2c08d3..b7b14ee6b9bb 100644 --- a/tests/ui/typeck/dont-suggest-private-dependencies.stderr +++ b/tests/ui/typeck/dont-suggest-private-dependencies.stderr @@ -1,42 +1,26 @@ error[E0599]: no method named `read` found for struct `Vec` in the current scope - --> $DIR/dont-suggest-private-dependencies.rs:17:16 + --> $DIR/dont-suggest-private-dependencies.rs:24:16 | LL | self.0.read(buf) | ^^^^ | - = help: items from traits can only be used if the trait is in scope -help: trait `ReadRef` which provides `read` is implemented but not in scope; perhaps you want to import it +help: there is a method `read1` with a similar name, but with different arguments + --> $DIR/dont-suggest-private-dependencies.rs:16:5 | -LL + use object::read::read_ref::ReadRef; - | -help: there is a method `read_at` with a similar name - | -LL | self.0.read_at(buf) - | +++ +LL | fn read1(&self) {} + | ^^^^^^^^^^^^^^^ error[E0599]: no function or associated item named `cast_from_lossy` found for type `u8` in the current scope - --> $DIR/dont-suggest-private-dependencies.rs:26:17 + --> $DIR/dont-suggest-private-dependencies.rs:33:17 | LL | let _ = u8::cast_from_lossy(9); | ^^^^^^^^^^^^^^^ function or associated item not found in `u8` - | - = help: items from traits can only be used if the trait is in scope -help: trait `CastFrom` which provides `cast_from_lossy` is implemented but not in scope; perhaps you want to import it - | -LL + use compiler_builtins::math::libm_math::support::int_traits::CastFrom; - | error[E0599]: no function or associated item named `foo` found for struct `B` in the current scope - --> $DIR/dont-suggest-private-dependencies.rs:28:16 + --> $DIR/dont-suggest-private-dependencies.rs:35:16 | LL | let _ = B::foo(); | ^^^ function or associated item not found in `B` - | - = help: items from traits can only be used if the trait is in scope -help: trait `A` which provides `foo` is implemented but not in scope; perhaps you want to import it - | -LL + use private_dep::A; - | error: aborting due to 3 previous errors