From f51fb9178e8d3648a908136d132bbfd1811481fd Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 21 Sep 2025 23:39:59 +0200 Subject: [PATCH 01/13] kcfi: only reify trait methods when dyn-compatible --- compiler/rustc_middle/src/ty/instance.rs | 4 +- .../sanitizer/kcfi/fn-ptr-reify-shim.rs | 74 +++++++++++++++++++ .../sanitizer/kcfi/naked-function.rs | 7 +- tests/ui/sanitizer/kcfi-c-variadic.rs | 20 +++++ 4 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 tests/codegen-llvm/sanitizer/kcfi/fn-ptr-reify-shim.rs create mode 100644 tests/ui/sanitizer/kcfi-c-variadic.rs diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 34ead91b4f6de..c27d47fcc0d8d 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -618,11 +618,11 @@ impl<'tcx> Instance<'tcx> { // be directly reified because it's closure-like. The reify can handle the // unresolved instance. resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args } - // Reify `Trait::method` implementations - // FIXME(maurer) only reify it if it is a vtable-safe function + // Reify `Trait::method` implementations if the trait is dyn-compatible. } else if let Some(assoc) = tcx.opt_associated_item(def_id) && let AssocContainer::Trait | AssocContainer::TraitImpl(Ok(_)) = assoc.container + && tcx.is_dyn_compatible(assoc.container_id(tcx)) { // If this function could also go in a vtable, we need to `ReifyShim` it with // KCFI because it can only attach one type per function. diff --git a/tests/codegen-llvm/sanitizer/kcfi/fn-ptr-reify-shim.rs b/tests/codegen-llvm/sanitizer/kcfi/fn-ptr-reify-shim.rs new file mode 100644 index 0000000000000..604b4c8c2f8a5 --- /dev/null +++ b/tests/codegen-llvm/sanitizer/kcfi/fn-ptr-reify-shim.rs @@ -0,0 +1,74 @@ +//@ add-core-stubs +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Cno-prepopulate-passes -Copt-level=0 + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +// A `ReifyShim` should only be created when the trait is dyn-compatible. + +extern crate minicore; +use minicore::*; + +trait DynCompatible { + fn dyn_name(&self) -> &'static str; + + fn dyn_name_default(&self) -> &'static str { + let _ = self; + "dyn_default" + } +} + +// Not dyn-compatible because the `Self: Sized` bound is missing. +trait NotDynCompatible { + fn not_dyn_name() -> &'static str; + + fn not_dyn_name_default() -> &'static str { + "not_dyn_default" + } +} + +struct S; + +impl DynCompatible for S { + fn dyn_name(&self) -> &'static str { + "dyn_compatible" + } +} + +impl NotDynCompatible for S { + fn not_dyn_name() -> &'static str { + "not_dyn_compatible" + } +} + +#[no_mangle] +pub fn main() { + let s = S; + + // `DynCompatible` is indeed dyn-compatible. + let _: &dyn DynCompatible = &s; + + // CHECK: call ::dyn_name{{.*}}reify.shim.fnptr + let dyn_name = S::dyn_name as fn(&S) -> &str; + let _unused = dyn_name(&s); + + // CHECK: call fn_ptr_reify_shim::DynCompatible::dyn_name_default{{.*}}reify.shim.fnptr + let dyn_name_default = S::dyn_name_default as fn(&S) -> &str; + let _unused = dyn_name_default(&s); + + // Check using $ (end-of-line) that these calls do not contain `reify.shim.fnptr`. + + // CHECK: call ::not_dyn_name{{$}} + let not_dyn_name = S::not_dyn_name as fn() -> &'static str; + let _unused = not_dyn_name(); + + // CHECK: call fn_ptr_reify_shim::NotDynCompatible::not_dyn_name_default{{$}} + let not_dyn_name_default = S::not_dyn_name_default as fn() -> &'static str; + let _unused = not_dyn_name_default(); +} diff --git a/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs b/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs index 2c8cdc919b85d..31f59ee01decb 100644 --- a/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs +++ b/tests/codegen-llvm/sanitizer/kcfi/naked-function.rs @@ -15,8 +15,9 @@ use minicore::*; struct Thing; trait MyTrait { + // NOTE: this test assumes that this trait is dyn-compatible. #[unsafe(naked)] - extern "C" fn my_naked_function() { + extern "C" fn my_naked_function(&self) { // the real function is defined // CHECK: .globl // CHECK-SAME: my_naked_function @@ -34,13 +35,13 @@ impl MyTrait for Thing {} #[unsafe(no_mangle)] pub fn main() { // Trick the compiler into generating an indirect call. - const F: extern "C" fn() = Thing::my_naked_function; + const F: extern "C" fn(&Thing) = Thing::my_naked_function; // main calls the shim function // CHECK: call void // CHECK-SAME: my_naked_function // CHECK-SAME: reify.shim.fnptr - (F)(); + (F)(&Thing); } // CHECK: declare !kcfi_type diff --git a/tests/ui/sanitizer/kcfi-c-variadic.rs b/tests/ui/sanitizer/kcfi-c-variadic.rs new file mode 100644 index 0000000000000..45d00a4524ebf --- /dev/null +++ b/tests/ui/sanitizer/kcfi-c-variadic.rs @@ -0,0 +1,20 @@ +//@ needs-sanitizer-kcfi +//@ no-prefer-dynamic +//@ compile-flags: -Zsanitizer=kcfi -Cpanic=abort -Cunsafe-allow-abi-mismatch=sanitizer +//@ ignore-backends: gcc +//@ run-pass + +#![feature(c_variadic)] + +trait Trait { + unsafe extern "C" fn foo(x: i32, y: i32, mut ap: ...) -> i32 { + x + y + ap.arg::() + ap.arg::() + } +} + +impl Trait for i32 {} + +fn main() { + let f = i32::foo as unsafe extern "C" fn(i32, i32, ...) -> i32; + assert_eq!(unsafe { f(1, 2, 3, 4) }, 1 + 2 + 3 + 4); +} From ce2087692f3cb6ff25a2b56f33cef20f6aa437cb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 30 Sep 2025 13:40:27 -0700 Subject: [PATCH 02/13] Add a new `wasm32-wasip3` target to Rust This commit adds a new tier 3 target to rustc, `wasm32-wasip3`. This follows in the footsteps of the previous `wasm32-wasip2` target and is used to represent binding to the WASIp3 set of APIs managed by the WASI subgroup to the WebAssembly Community Group. As of now the WASIp3 set of APIs are not finalized nor standardized. They're in the process of doing so and the current trajectory is to have the APIs published in December of this year. The goal here is to get the wheels turning in Rust to have the target in a more-ready-than-nonexistent state by the time this happens in December. For now the `wasm32-wasip3` target looks exactly the same as `wasm32-wasip2` except that `target_env = "p3"` is specified. This indicates to crates in the ecosystem that WASIp3 APIs should be used, such as the [`wasip3` crate]. Over time this target will evolve as implementation in guest toolchains progress, notably: * The standard library will use WASIp3 APIs natively once they're finalized in the WASI subgroup. * Support through `wasi-libc` will be updated to use WASIp3 natively which Rust will then transitively use. * Longer-term, features such as cooperative multithreading will be added to the WASIp3-track of targets to enable using `std::thread`, for example, on this target. These changes are all expected to be non-breaking changes for users of this target. Runtimes supporting WASIp3, currently Wasmtime and Jco, support WASIp2 APIs as well and will work with components whether or not they import WASIp2, both WASIp2 and WASIp3, or just WASIp3 APIs. This means that changing the internal implementation details of libstd over time is expected to be a non-breaking change. [`wasip3` crate]: https://crates.io/crates/wasip3 --- compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/targets/wasm32_wasip3.rs | 20 +++++ library/std/Cargo.toml | 5 ++ library/std/src/os/mod.rs | 2 +- library/std/src/sys/args/mod.rs | 2 +- library/std/src/sys/net/connection/mod.rs | 2 +- .../std/src/sys/net/connection/socket/mod.rs | 2 +- library/std/src/sys/pal/mod.rs | 2 +- library/std/src/sys/random/mod.rs | 4 +- library/std/src/sys/stdio/mod.rs | 2 +- library/std/src/sys/thread/mod.rs | 4 +- src/bootstrap/src/core/build_steps/compile.rs | 10 +++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../src/platform-support/wasm32-wasip3.md | 83 +++++++++++++++++++ tests/assembly-llvm/targets/targets-elf.rs | 3 + tests/ui/check-cfg/well-known-values.stderr | 2 +- 17 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs create mode 100644 src/doc/rustc/src/platform-support/wasm32-wasip3.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4a82a8bd888e6..e4b44e8b686c1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1624,6 +1624,7 @@ supported_targets! { ("wasm32v1-none", wasm32v1_none), ("wasm32-wasip1", wasm32_wasip1), ("wasm32-wasip2", wasm32_wasip2), + ("wasm32-wasip3", wasm32_wasip3), ("wasm32-wasip1-threads", wasm32_wasip1_threads), ("wasm32-wali-linux-musl", wasm32_wali_linux_musl), ("wasm64-unknown-unknown", wasm64_unknown_unknown), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs new file mode 100644 index 0000000000000..e3d5e6542c263 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs @@ -0,0 +1,20 @@ +//! The `wasm32-wasip3` target is the next in the chain of `wasm32-wasip1`, then +//! `wasm32-wasip2`, then WASIp3. The main feature of WASIp3 is native async +//! support in the component model itself. +//! +//! Like `wasm32-wasip2` this target produces a component by default. Support +//! for `wasm32-wasip3` is very early as of the time of this writing so +//! components produced will still import WASIp2 APIs, but that's ok since it's +//! all component-model-level imports anyway. Over time the imports of the +//! standard library will change to WASIp3. + +use crate::spec::Target; + +pub(crate) fn target() -> Target { + // As of now WASIp3 is a lightly edited wasip2 target, so start with that + // and this may grow over time as more features are supported. + let mut target = super::wasm32_wasip2::target(); + target.llvm_target = "wasm32-wasip3".into(); + target.options.env = "p3".into(); + target +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 888914a2f772e..779b07ce240a6 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -85,6 +85,11 @@ wasip2 = { version = '0.14.4', features = [ 'rustc-dep-of-std', ], default-features = false, package = 'wasi' } +[target.'cfg(all(target_os = "wasi", target_env = "p3"))'.dependencies] +wasip2 = { version = '0.14.4', features = [ + 'rustc-dep-of-std', +], default-features = false, package = 'wasi' } + [target.'cfg(target_os = "uefi")'.dependencies] r-efi = { version = "5.2.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "2.0.0", features = ['rustc-dep-of-std'] } diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 96d9bfae8ca32..fd7a11433af1b 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -103,7 +103,7 @@ pub mod linux; all(target_vendor = "fortanix", target_env = "sgx") ) )))] -#[cfg(any(target_os = "wasi", doc))] +#[cfg(any(target_os = "wasi", any(target_env = "p1", target_env = "p2"), doc))] pub mod wasi; #[cfg(any(all(target_os = "wasi", target_env = "p2"), doc))] diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index e11e8e5430f06..75c59da721e19 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -36,7 +36,7 @@ cfg_select! { mod wasip1; pub use wasip1::*; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::*; } diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs index 7f9636a8ccfd6..41e7159f909ae 100644 --- a/library/std/src/sys/net/connection/mod.rs +++ b/library/std/src/sys/net/connection/mod.rs @@ -3,7 +3,7 @@ cfg_select! { all(target_family = "unix", not(target_os = "l4re")), target_os = "windows", target_os = "hermit", - all(target_os = "wasi", target_env = "p2"), + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")), target_os = "solid_asp3", ) => { mod socket; diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 1dd06e97bbabd..e59d01bdd9bb1 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -25,7 +25,7 @@ cfg_select! { mod unix; pub use unix::*; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::*; } diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index dd5e83ee570b6..9e964540a87c1 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -49,7 +49,7 @@ cfg_select! { mod vexos; pub use self::vexos::*; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use self::wasip2::*; } diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 3c5a4c82a9f1e..ec81d89a0f3af 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -90,7 +90,7 @@ cfg_select! { mod wasip1; pub use wasip1::fill_bytes; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::{fill_bytes, hashmap_random_keys}; } @@ -115,7 +115,7 @@ cfg_select! { target_os = "linux", target_os = "android", all(target_family = "wasm", target_os = "unknown"), - all(target_os = "wasi", target_env = "p2"), + all(target_os = "wasi", not(target_env = "p1")), target_os = "xous", target_os = "vexos", )))] diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs index 404ac87792696..660317e3ea844 100644 --- a/library/std/src/sys/stdio/mod.rs +++ b/library/std/src/sys/stdio/mod.rs @@ -37,7 +37,7 @@ cfg_select! { mod wasip1; pub use wasip1::*; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::*; } diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index 3bd83dd760ac9..a20b2a3ddd8ce 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -99,7 +99,7 @@ cfg_select! { #[cfg(not(target_feature = "atomics"))] pub use unsupported::{Thread, available_parallelism}; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::{sleep, sleep_until}; #[expect(dead_code)] @@ -146,7 +146,7 @@ cfg_select! { target_os = "hurd", target_os = "fuchsia", target_os = "vxworks", - all(target_os = "wasi", target_env = "p2"), + all(target_os = "wasi", not(target_env = "p1")), )))] pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 96b4e15433f7e..715f7abe9477f 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -430,6 +430,16 @@ fn copy_self_contained_objects( target.triple ) }); + + // wasm32-wasip3 doesn't exist in wasi-libc yet, so instead use libs + // from the wasm32-wasip2 target. Once wasi-libc supports wasip3 this + // should be deleted and the native objects should be used. + let srcdir = if target == "wasm32-wasip3" { + assert!(!srcdir.exists(), "wasip3 support is in wasi-libc, this should be updated now"); + builder.wasi_libdir(TargetSelection::from_user("wasm32-wasip2")).unwrap() + } else { + srcdir + }; for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] { copy_and_stamp( builder, diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 67882bb38132a..1965a1b25498b 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -132,6 +132,7 @@ - [wasm32-wasip1](platform-support/wasm32-wasip1.md) - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md) - [wasm32-wasip2](platform-support/wasm32-wasip2.md) + - [wasm32-wasip3](platform-support/wasm32-wasip3.md) - [wasm32-wali-linux-musl](platform-support/wasm32-wali-linux.md) - [wasm32-unknown-emscripten](platform-support/wasm32-unknown-emscripten.md) - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d0b6ed51bc163..c23d7563aedb5 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -198,6 +198,7 @@ target | std | notes [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASIp1 [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads [`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ | WebAssembly with WASIp2 +[`wasm32-wasip3`](platform-support/wasm32-wasip3.md) | ✓ | WebAssembly with WASIp3 [`wasm32v1-none`](platform-support/wasm32v1-none.md) | * | WebAssembly limited to 1.0 features and no imports [`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS [`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on x86_64 diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip3.md b/src/doc/rustc/src/platform-support/wasm32-wasip3.md new file mode 100644 index 0000000000000..e8063a1bdcfed --- /dev/null +++ b/src/doc/rustc/src/platform-support/wasm32-wasip3.md @@ -0,0 +1,83 @@ +# `wasm32-wasip3` + +**Tier: 3** + +The `wasm32-wasip3` target is the next stage of evolution of the +[`wasm32-wasip2`](./wasm32-wasip2.md) target. The `wasm32-wasip3` target enables +the Rust standard library to use WASIp3 APIs to implement various pieces of +functionality. WASIp3 brings native async support over WASIp2, which integrates +well with Rust's `async` ecosystem. + +> **Note**: As of 2025-10-01 WASIp3 has not yet been approved by the WASI +> subgroup of the WebAssembly Community Group. Development is expected to +> conclude in late 2025 or early 2026. Until then the Rust standard library +> won't actually use WASIp3 APIs on the `wasm32-wasip3` target as they are not +> yet stable and would reduce the stability of this target. Once WASIp3 is +> approved, however, the standard library will update to use WASIp3 natively. + +> **Note**: This target does not yet build as of 2025-10-01 due to and update +> needed in the `libc` crate. Using it will require a `[patch]` for now. + +> **Note**: Until the standard library is fully migrated to use the `wasip3` +> crate then components produced for `wasm32-wasip3` may import WASIp2 APIs. +> This is considered a transitionary phase until fully support of libstd is +> implemented. + +## Target maintainers + +[@alexcrichton](https://github.com/alexcrichton) + +## Requirements + +This target is cross-compiled. The target supports `std` fully. + +## Platform requirements + +The WebAssembly runtime should support both WASIp2 and WASIp3. Runtimes also +are required to support components since this target outputs a component as +opposed to a core wasm module. Two example runtimes for WASIp3 are [Wasmtime] +and [Jco]. + +[Wasmtime]: https://wasmtime.dev/ +[Jco]: https://github.com/bytecodealliance/jco + +## Building the target + +To build this target first acquire a copy of +[`wasi-sdk`](https://github.com/WebAssembly/wasi-sdk/). At this time version 22 +is the minimum needed. + +Next configure the `WASI_SDK_PATH` environment variable to point to where this +is installed. For example: + +```text +export WASI_SDK_PATH=/path/to/wasi-sdk-22.0 +``` + +Next be sure to enable LLD when building Rust from source as LLVM's `wasm-ld` +driver for LLD is required when linking WebAssembly code together. Rust's build +system will automatically pick up any necessary binaries and programs from +`WASI_SDK_PATH`. + +## Testing + +This target is not tested in CI at this time. Locally it can be tested with a +`wasmtime` binary in `PATH` like so: + +```text +./x.py test --target wasm32-wasip3 tests/ui +``` + +## Conditionally compiling code + +It's recommended to conditionally compile code for this target with: + +```text +#[cfg(all(target_os = "wasi", target_env = "p3"))] +``` + +## Enabled WebAssembly features + +The default set of WebAssembly features enabled for compilation is currently the +same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the +documentation there for more information. diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index ebea9fe40f518..e26c213837066 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -586,6 +586,9 @@ //@ revisions: wasm32_wasip2 //@ [wasm32_wasip2] compile-flags: --target wasm32-wasip2 //@ [wasm32_wasip2] needs-llvm-components: webassembly +//@ revisions: wasm32_wasip3 +//@ [wasm32_wasip3] compile-flags: --target wasm32-wasip3 +//@ [wasm32_wasip3] needs-llvm-components: webassembly //@ revisions: wasm32_wali_linux_musl //@ [wasm32_wali_linux_musl] compile-flags: --target wasm32-wali-linux-musl //@ [wasm32_wali_linux_musl] needs-llvm-components: webassembly diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index e62f741b3020c..3f14c7b08eac6 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -156,7 +156,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_env` are: ``, `gnu`, `macabi`, `mlibc`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `nto80`, `ohos`, `p1`, `p2`, `relibc`, `sgx`, `sim`, `uclibc`, and `v5` + = note: expected values for `target_env` are: ``, `gnu`, `macabi`, `mlibc`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `nto71_iosock`, `nto80`, `ohos`, `p1`, `p2`, `p3`, `relibc`, `sgx`, `sim`, `uclibc`, and `v5` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From 7e1c00dbce512b260c396b4425527b00891168a7 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 17 Sep 2025 17:06:14 +0000 Subject: [PATCH 03/13] Prevent downstream impl DerefMut for Pin --- library/core/src/pin.rs | 59 ++++++++++++++++++- ...y.run2-{closure#0}.Inline.panic-abort.diff | 56 ++++++++++-------- ....run2-{closure#0}.Inline.panic-unwind.diff | 56 ++++++++++-------- tests/ui/deref/pin-impl-deref.rs | 4 +- tests/ui/deref/pin-impl-deref.stderr | 22 ++++--- .../pin-unsound-issue-85099-derefmut.rs | 4 +- .../pin-unsound-issue-85099-derefmut.stderr | 14 +++++ 7 files changed, 146 insertions(+), 69 deletions(-) create mode 100644 tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 535830f2e749f..d7e348b71e1d0 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1689,9 +1689,66 @@ impl const Deref for Pin { } } +mod helper { + /// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`. + /// + /// This type is not `#[fundamental]`, so it's possible to relax its `DerefMut` impl bounds in + /// the future, so the orphan rules reject downstream impls of `DerefMut` of `Pin`. + #[repr(transparent)] + #[unstable(feature = "pin_derefmut_internals", issue = "none")] + #[allow(missing_debug_implementations)] + pub struct Pin { + pointer: Ptr, + } + + #[unstable(feature = "pin_derefmut_internals", issue = "none")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const trait DerefMut { + type Target: ?Sized; + fn deref_mut(&mut self) -> &mut Self::Target; + } + + #[unstable(feature = "pin_derefmut_internals", issue = "none")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + impl const DerefMut for Pin + where + Ptr::Target: crate::marker::Unpin, + { + type Target = Ptr::Target; + + #[inline(always)] + fn deref_mut(&mut self) -> &mut Ptr::Target { + &mut self.pointer + } + } +} + #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl> const DerefMut for Pin { +#[cfg(not(doc))] +impl const DerefMut for Pin +where + Ptr: [const] Deref, + helper::Pin: [const] helper::DerefMut, +{ + #[inline] + fn deref_mut(&mut self) -> &mut Ptr::Target { + // SAFETY: Pin and helper::Pin have the same layout, so this is equivalent to + // `&mut self.pointer` which is safe because `Target: Unpin`. + helper::DerefMut::deref_mut(unsafe { + &mut *(self as *mut Pin as *mut helper::Pin) + }) + } +} + +#[stable(feature = "pin", since = "1.33.0")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +#[cfg(doc)] +impl const DerefMut for Pin +where + Ptr: [const] DerefMut, + Ptr::Target: Unpin, +{ fn deref_mut(&mut self) -> &mut Ptr::Target { Pin::get_mut(Pin::as_mut(self)) } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 0acb33febe52b..226a16d6eec39 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -63,27 +63,25 @@ + let mut _44: &mut std::future::Ready<()>; + let mut _45: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { -+ let mut _46: &mut &mut std::future::Ready<()>; -+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { ++ let mut _46: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>; ++ let mut _47: *mut std::pin::Pin<&mut std::future::Ready<()>>; ++ scope 15 (inlined > as pin::helper::DerefMut>::deref_mut) { ++ let mut _48: &mut &mut std::future::Ready<()>; ++ scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { + } -+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { -+ } -+ } -+ scope 17 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) { + } + } -+ scope 19 (inlined Option::<()>::take) { -+ let mut _47: std::option::Option<()>; -+ scope 20 (inlined std::mem::replace::>) { -+ scope 21 { ++ scope 17 (inlined Option::<()>::take) { ++ let mut _49: std::option::Option<()>; ++ scope 18 (inlined std::mem::replace::>) { ++ scope 19 { + } + } + } -+ scope 22 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _48: isize; -+ let mut _49: !; -+ scope 23 { ++ scope 20 (inlined #[track_caller] Option::<()>::expect) { ++ let mut _50: isize; ++ let mut _51: !; ++ scope 21 { + } + } + } @@ -217,18 +215,23 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_44); -+ StorageLive(_49); ++ StorageLive(_46); ++ StorageLive(_51); + StorageLive(_41); + StorageLive(_42); -+ _44 = copy (_19.0: &mut std::future::Ready<()>); + StorageLive(_47); -+ _47 = Option::<()>::None; -+ _42 = copy ((*_44).0: std::option::Option<()>); -+ ((*_44).0: std::option::Option<()>) = copy _47; ++ _47 = &raw mut _19; ++ _46 = copy _47 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr); + StorageDead(_47); -+ StorageLive(_48); -+ _48 = discriminant(_42); -+ switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5]; ++ _44 = copy ((*_46).0: &mut std::future::Ready<()>); ++ StorageLive(_49); ++ _49 = Option::<()>::None; ++ _42 = copy ((*_44).0: std::option::Option<()>); ++ ((*_44).0: std::option::Option<()>) = copy _49; ++ StorageDead(_49); ++ StorageLive(_50); ++ _50 = discriminant(_42); ++ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5]; } + + bb5: { @@ -291,16 +294,17 @@ + } + + bb11: { -+ _49 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; ++ _51 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; + } + + bb12: { + _41 = move ((_42 as Some).0: ()); -+ StorageDead(_48); ++ StorageDead(_50); + StorageDead(_42); + _18 = Poll::<()>::Ready(move _41); + StorageDead(_41); -+ StorageDead(_49); ++ StorageDead(_51); ++ StorageDead(_46); + StorageDead(_44); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 98ee46c29b1be..770b6e471ff8b 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -65,27 +65,25 @@ + let mut _46: &mut std::future::Ready<()>; + let mut _47: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { -+ let mut _48: &mut &mut std::future::Ready<()>; -+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { ++ let mut _48: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>; ++ let mut _49: *mut std::pin::Pin<&mut std::future::Ready<()>>; ++ scope 15 (inlined > as pin::helper::DerefMut>::deref_mut) { ++ let mut _50: &mut &mut std::future::Ready<()>; ++ scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { + } -+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { -+ } -+ } -+ scope 17 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) { + } + } -+ scope 19 (inlined Option::<()>::take) { -+ let mut _49: std::option::Option<()>; -+ scope 20 (inlined std::mem::replace::>) { -+ scope 21 { ++ scope 17 (inlined Option::<()>::take) { ++ let mut _51: std::option::Option<()>; ++ scope 18 (inlined std::mem::replace::>) { ++ scope 19 { + } + } + } -+ scope 22 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _50: isize; -+ let mut _51: !; -+ scope 23 { ++ scope 20 (inlined #[track_caller] Option::<()>::expect) { ++ let mut _52: isize; ++ let mut _53: !; ++ scope 21 { + } + } + } @@ -234,18 +232,23 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_46); -+ StorageLive(_51); ++ StorageLive(_48); ++ StorageLive(_53); + StorageLive(_43); + StorageLive(_44); -+ _46 = copy (_19.0: &mut std::future::Ready<()>); + StorageLive(_49); -+ _49 = Option::<()>::None; -+ _44 = copy ((*_46).0: std::option::Option<()>); -+ ((*_46).0: std::option::Option<()>) = copy _49; ++ _49 = &raw mut _19; ++ _48 = copy _49 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr); + StorageDead(_49); -+ StorageLive(_50); -+ _50 = discriminant(_44); -+ switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7]; ++ _46 = copy ((*_48).0: &mut std::future::Ready<()>); ++ StorageLive(_51); ++ _51 = Option::<()>::None; ++ _44 = copy ((*_46).0: std::option::Option<()>); ++ ((*_46).0: std::option::Option<()>) = copy _51; ++ StorageDead(_51); ++ StorageLive(_52); ++ _52 = discriminant(_44); ++ switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7]; } - bb6 (cleanup): { @@ -332,16 +335,17 @@ + } + + bb16: { -+ _51 = option::expect_failed(const "`Ready` polled after completion") -> bb11; ++ _53 = option::expect_failed(const "`Ready` polled after completion") -> bb11; + } + + bb17: { + _43 = move ((_44 as Some).0: ()); -+ StorageDead(_50); ++ StorageDead(_52); + StorageDead(_44); + _18 = Poll::<()>::Ready(move _43); + StorageDead(_43); -+ StorageDead(_51); ++ StorageDead(_53); ++ StorageDead(_48); + StorageDead(_46); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/ui/deref/pin-impl-deref.rs b/tests/ui/deref/pin-impl-deref.rs index b1dc8dea3f248..ccd8d0dfc72ae 100644 --- a/tests/ui/deref/pin-impl-deref.rs +++ b/tests/ui/deref/pin-impl-deref.rs @@ -22,7 +22,7 @@ impl MyPinType { fn impl_deref_mut(_: impl DerefMut) {} fn unpin_impl_ref(r_unpin: Pin<&MyUnpinType>) { impl_deref_mut(r_unpin) - //~^ ERROR: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied + //~^ ERROR: the trait bound `&MyUnpinType: DerefMut` is not satisfied } fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) { impl_deref_mut(r_unpin) @@ -30,7 +30,7 @@ fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) { fn pin_impl_ref(r_pin: Pin<&MyPinType>) { impl_deref_mut(r_pin) //~^ ERROR: `PhantomPinned` cannot be unpinned - //~| ERROR: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied + //~| ERROR: the trait bound `&MyPinType: DerefMut` is not satisfied } fn pin_impl_mut(r_pin: Pin<&mut MyPinType>) { impl_deref_mut(r_pin) diff --git a/tests/ui/deref/pin-impl-deref.stderr b/tests/ui/deref/pin-impl-deref.stderr index 106654641a117..918ff7ca91218 100644 --- a/tests/ui/deref/pin-impl-deref.stderr +++ b/tests/ui/deref/pin-impl-deref.stderr @@ -1,40 +1,36 @@ -error[E0277]: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied +error[E0277]: the trait bound `&MyUnpinType: DerefMut` is not satisfied --> $DIR/pin-impl-deref.rs:24:20 | LL | impl_deref_mut(r_unpin) - | -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyUnpinType>` + | -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `&MyUnpinType` | | | required by a bound introduced by this call | + = note: `DerefMut` is implemented for `&mut MyUnpinType`, but not for `&MyUnpinType` + = note: required for `pin::helper::Pin<&MyUnpinType>` to implement `pin::helper::DerefMut` = note: required for `Pin<&MyUnpinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 | LL | fn impl_deref_mut(_: impl DerefMut) {} | ^^^^^^^^ required by this bound in `impl_deref_mut` -help: consider mutably borrowing here - | -LL | impl_deref_mut(&mut r_unpin) - | ++++ -error[E0277]: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied +error[E0277]: the trait bound `&MyPinType: DerefMut` is not satisfied --> $DIR/pin-impl-deref.rs:31:20 | LL | impl_deref_mut(r_pin) - | -------------- ^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyPinType>` + | -------------- ^^^^^ the trait `DerefMut` is not implemented for `&MyPinType` | | | required by a bound introduced by this call | + = note: `DerefMut` is implemented for `&mut MyPinType`, but not for `&MyPinType` + = note: required for `pin::helper::Pin<&MyPinType>` to implement `pin::helper::DerefMut` = note: required for `Pin<&MyPinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 | LL | fn impl_deref_mut(_: impl DerefMut) {} | ^^^^^^^^ required by this bound in `impl_deref_mut` -help: consider mutably borrowing here - | -LL | impl_deref_mut(&mut r_pin) - | ++++ error[E0277]: `PhantomPinned` cannot be unpinned --> $DIR/pin-impl-deref.rs:31:20 @@ -51,6 +47,7 @@ note: required because it appears within the type `MyPinType` | LL | struct MyPinType(core::marker::PhantomPinned); | ^^^^^^^^^ + = note: required for `pin::helper::Pin<&MyPinType>` to implement `pin::helper::DerefMut` = note: required for `Pin<&MyPinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 @@ -73,6 +70,7 @@ note: required because it appears within the type `MyPinType` | LL | struct MyPinType(core::marker::PhantomPinned); | ^^^^^^^^^ + = note: required for `pin::helper::Pin<&mut MyPinType>` to implement `pin::helper::DerefMut` = note: required for `Pin<&mut MyPinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs index f3ece563f5403..e8c3bbba1e458 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs @@ -1,5 +1,4 @@ -//@ check-pass -//@ known-bug: #85099 +//@ check-fail // Should fail. Can coerce `Pin` into `Pin` where // `T: Deref` and `U: Deref`, using the @@ -43,6 +42,7 @@ impl<'a, Fut: Future> SomeTrait<'a, Fut> for Fut { } impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { +//~^ ERROR: conflicting implementations of trait `DerefMut` fn deref_mut<'c>( self: &'c mut Pin<&'b dyn SomeTrait<'a, Fut>>, ) -> &'c mut (dyn SomeTrait<'a, Fut> + 'b) { diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr new file mode 100644 index 0000000000000..cc56c77809eaa --- /dev/null +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `DerefMut` for type `Pin<&dyn SomeTrait<'_, _>>` + --> $DIR/pin-unsound-issue-85099-derefmut.rs:44:1 + | +LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl DerefMut for Pin + where as pin::helper::DerefMut>::Target == as Deref>::Target, Ptr: Deref, pin::helper::Pin: pin::helper::DerefMut, pin::helper::Pin: ?Sized; + = note: upstream crates may add a new impl of trait `std::pin::helper::DerefMut` for type `std::pin::helper::Pin<&dyn SomeTrait<'_, _>>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. From cd44cd0f63a7e67dcfc3618aa7bf6e2e70643561 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 25 Sep 2025 08:39:35 +0000 Subject: [PATCH 04/13] Improve docs for module --- library/core/src/pin.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index d7e348b71e1d0..fdbeaea464194 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1692,8 +1692,22 @@ impl const Deref for Pin { mod helper { /// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`. /// - /// This type is not `#[fundamental]`, so it's possible to relax its `DerefMut` impl bounds in - /// the future, so the orphan rules reject downstream impls of `DerefMut` of `Pin`. + /// The `Pin` type implements the unsafe trait `PinCoerceUnsized`, which essentially requires + /// that the type does not have a malicious `Deref` or `DerefMut` impl. However, without this + /// helper module, downstream crates are able to write `impl DerefMut for Pin` as + /// long as it does not overlap with the impl provided by stdlib. This is because `Pin` is + /// `#[fundamental]`, so stdlib promises to never implement traits for `Pin` that it does not + /// implement today. + /// + /// However, this is problematic. Downstream crates could implement `DerefMut` for + /// `Pin<&LocalType>`, and they could do so maliciously. To prevent this, the implementation for + /// `Pin` delegates to this helper module. Since `helper::Pin` is not `#[fundamental]`, the + /// orphan rules assume that stdlib might implement `helper::DerefMut` for `helper::Pin<&_>` in + /// the future. Because of this, downstream crates can no longer provide an implementation of + /// `DerefMut` for `Pin<&_>`, as it might overlap with a trait impl that, according to the + /// orphan rules, the stdlib could introduce without a breaking change in a future release. + /// + /// See for the issue this fixes. #[repr(transparent)] #[unstable(feature = "pin_derefmut_internals", issue = "none")] #[allow(missing_debug_implementations)] From f65250b3dd0eada1ab25ad4f766048f2ebe24623 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 29 Sep 2025 09:34:18 +0000 Subject: [PATCH 05/13] Document workaround in docs --- library/core/src/pin.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index fdbeaea464194..23950acd97610 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1755,13 +1755,21 @@ where } } +/// The `Target` type is restricted to `Unpin` types as it's not safe to obtain a mutable reference +/// to a pinned value. +/// +/// For soundness reasons, implementations of `DerefMut` for `Pin` are rejected even when `T` is +/// a local type not covered by this impl block. (Since `Pin` is [fundamental], such implementations +/// would normally be possible.) +/// +/// [fundamental]: ../../reference/items/implementations.html#r-items.impl.trait.fundamental #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[cfg(doc)] impl const DerefMut for Pin where Ptr: [const] DerefMut, - Ptr::Target: Unpin, + ::Target: Unpin, { fn deref_mut(&mut self) -> &mut Ptr::Target { Pin::get_mut(Pin::as_mut(self)) From 76dcb39c240382a7d62cc8ee475e0c3866ad8025 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 1 Oct 2025 11:14:08 +0000 Subject: [PATCH 06/13] Adjust error messages --- compiler/rustc_span/src/symbol.rs | 1 + .../src/error_reporting/traits/suggestions.rs | 18 ++++++++++++++++++ library/core/src/pin.rs | 15 ++++++++------- ...dy.run2-{closure#0}.Inline.panic-abort.diff | 6 +++--- ...y.run2-{closure#0}.Inline.panic-unwind.diff | 6 +++--- tests/ui/deref/pin-impl-deref.stderr | 4 ---- .../pin-unsound-issue-85099-derefmut.stderr | 4 ++-- 7 files changed, 35 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 083e04730bc37..7f1ca96b2a75b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -309,6 +309,7 @@ symbols! { PathBuf, Pending, PinCoerceUnsized, + PinDerefMutHelper, Pointer, Poll, ProcMacro, 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 37e622102e70f..5665229a4cbe6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3476,6 +3476,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // can do about it. As far as they are concerned, `?` is compiler magic. return; } + if tcx.is_diagnostic_item(sym::PinDerefMutHelper, parent_def_id) { + let parent_predicate = + self.resolve_vars_if_possible(data.derived.parent_trait_pred); + + // Skip PinDerefMutHelper in suggestions, but still show downstream suggestions. + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + body_id, + err, + parent_predicate, + param_env, + &data.derived.parent_code, + obligated_types, + seen_requirements, + ) + }); + return; + } let self_ty_str = tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); let trait_name = tcx.short_string( diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 23950acd97610..81c2dabf0d1d8 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1711,20 +1711,21 @@ mod helper { #[repr(transparent)] #[unstable(feature = "pin_derefmut_internals", issue = "none")] #[allow(missing_debug_implementations)] - pub struct Pin { + pub struct PinHelper { pointer: Ptr, } #[unstable(feature = "pin_derefmut_internals", issue = "none")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - pub const trait DerefMut { + #[rustc_diagnostic_item = "PinDerefMutHelper"] + pub const trait PinDerefMutHelper { type Target: ?Sized; fn deref_mut(&mut self) -> &mut Self::Target; } #[unstable(feature = "pin_derefmut_internals", issue = "none")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - impl const DerefMut for Pin + impl const PinDerefMutHelper for PinHelper where Ptr::Target: crate::marker::Unpin, { @@ -1743,14 +1744,14 @@ mod helper { impl const DerefMut for Pin where Ptr: [const] Deref, - helper::Pin: [const] helper::DerefMut, + helper::PinHelper: [const] helper::PinDerefMutHelper, { #[inline] fn deref_mut(&mut self) -> &mut Ptr::Target { - // SAFETY: Pin and helper::Pin have the same layout, so this is equivalent to + // SAFETY: Pin and PinHelper have the same layout, so this is equivalent to // `&mut self.pointer` which is safe because `Target: Unpin`. - helper::DerefMut::deref_mut(unsafe { - &mut *(self as *mut Pin as *mut helper::Pin) + helper::PinDerefMutHelper::deref_mut(unsafe { + &mut *(self as *mut Pin as *mut helper::PinHelper) }) } } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 226a16d6eec39..0203ff52d63f8 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -63,9 +63,9 @@ + let mut _44: &mut std::future::Ready<()>; + let mut _45: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ let mut _46: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>; ++ let mut _46: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; + let mut _47: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 15 (inlined > as pin::helper::DerefMut>::deref_mut) { ++ scope 15 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { + let mut _48: &mut &mut std::future::Ready<()>; + scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { + } @@ -221,7 +221,7 @@ + StorageLive(_42); + StorageLive(_47); + _47 = &raw mut _19; -+ _46 = copy _47 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr); ++ _46 = copy _47 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); + StorageDead(_47); + _44 = copy ((*_46).0: &mut std::future::Ready<()>); + StorageLive(_49); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 770b6e471ff8b..6c8cad3e992e7 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -65,9 +65,9 @@ + let mut _46: &mut std::future::Ready<()>; + let mut _47: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ let mut _48: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>; ++ let mut _48: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; + let mut _49: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 15 (inlined > as pin::helper::DerefMut>::deref_mut) { ++ scope 15 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { + let mut _50: &mut &mut std::future::Ready<()>; + scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { + } @@ -238,7 +238,7 @@ + StorageLive(_44); + StorageLive(_49); + _49 = &raw mut _19; -+ _48 = copy _49 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr); ++ _48 = copy _49 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); + StorageDead(_49); + _46 = copy ((*_48).0: &mut std::future::Ready<()>); + StorageLive(_51); diff --git a/tests/ui/deref/pin-impl-deref.stderr b/tests/ui/deref/pin-impl-deref.stderr index 918ff7ca91218..4143d66f42723 100644 --- a/tests/ui/deref/pin-impl-deref.stderr +++ b/tests/ui/deref/pin-impl-deref.stderr @@ -7,7 +7,6 @@ LL | impl_deref_mut(r_unpin) | required by a bound introduced by this call | = note: `DerefMut` is implemented for `&mut MyUnpinType`, but not for `&MyUnpinType` - = note: required for `pin::helper::Pin<&MyUnpinType>` to implement `pin::helper::DerefMut` = note: required for `Pin<&MyUnpinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 @@ -24,7 +23,6 @@ LL | impl_deref_mut(r_pin) | required by a bound introduced by this call | = note: `DerefMut` is implemented for `&mut MyPinType`, but not for `&MyPinType` - = note: required for `pin::helper::Pin<&MyPinType>` to implement `pin::helper::DerefMut` = note: required for `Pin<&MyPinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 @@ -47,7 +45,6 @@ note: required because it appears within the type `MyPinType` | LL | struct MyPinType(core::marker::PhantomPinned); | ^^^^^^^^^ - = note: required for `pin::helper::Pin<&MyPinType>` to implement `pin::helper::DerefMut` = note: required for `Pin<&MyPinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 @@ -70,7 +67,6 @@ note: required because it appears within the type `MyPinType` | LL | struct MyPinType(core::marker::PhantomPinned); | ^^^^^^^^^ - = note: required for `pin::helper::Pin<&mut MyPinType>` to implement `pin::helper::DerefMut` = note: required for `Pin<&mut MyPinType>` to implement `DerefMut` note: required by a bound in `impl_deref_mut` --> $DIR/pin-impl-deref.rs:22:27 diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr index cc56c77809eaa..2bcd92b76a09d 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr @@ -6,8 +6,8 @@ LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { | = note: conflicting implementation in crate `core`: - impl DerefMut for Pin - where as pin::helper::DerefMut>::Target == as Deref>::Target, Ptr: Deref, pin::helper::Pin: pin::helper::DerefMut, pin::helper::Pin: ?Sized; - = note: upstream crates may add a new impl of trait `std::pin::helper::DerefMut` for type `std::pin::helper::Pin<&dyn SomeTrait<'_, _>>` in future versions + where as pin::helper::PinDerefMutHelper>::Target == as Deref>::Target, Ptr: Deref, pin::helper::PinHelper: pin::helper::PinDerefMutHelper, pin::helper::PinHelper: ?Sized; + = note: upstream crates may add a new impl of trait `std::pin::helper::PinDerefMutHelper` for type `std::pin::helper::PinHelper<&dyn SomeTrait<'_, _>>` in future versions error: aborting due to 1 previous error From bc930cd2d101d1b0b858e9fcf981c916721e1c2d Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Mon, 6 Oct 2025 11:56:08 -0400 Subject: [PATCH 07/13] collect-license-metadata: Print a diff of the expected output Previously, `x test collect-license-metadata` gave the following message on errors: ``` gathering license information from REUSE (this might take a minute...) finished gathering the license information from REUSE in 78.69s loading existing license information The existing /home/runner/work/ferrocene/ferrocene/license-metadata.json file is out of date. Run ./x run collect-license-metadata to update it. Error: The existing /home/runner/work/ferrocene/ferrocene/license-metadata.json file doesn't match what REUSE reports. Bootstrap failed while executing `test collect-license-metadata` ``` Notable, this doesn't actually say what went wrong. Print a diff in addition so it's more clear what broke: ``` ... "license": { "copyright": [ + "2010 The Rust Project Developers", "2016, 2017, 2018, 2019, 2020, 2021 AXE Consultants. All Rights", + "License. Subject to the terms and conditions of this", "Notice", - "The Ferrocene Developers" + "The Ferrocene Developers", + "[yyyy] [name of copyright owner]" ], ... ``` Currently, this prints the entire text of the JSON file as context. That's not ideal, but it's rare for this to fail, so I think it's ok for now. I considered using `assert_json_diff` instead of `similar`, but its errors are a lot harder to read IMO, even though they are better at omitting unnecessary context: ``` Diff: json atoms at path ".files.children[0].children[10].license.copyright[0]" are not equal: lhs: "2016 The Fuchsia Authors" rhs: "2019 The Crossbeam Project Developers" json atoms at path ".files.children[0].children[10].license.spdx" are not equal: lhs: "BSD-2-Clause AND (Apache-2.0 OR MIT)" rhs: "Apache-2.0 OR MIT" json atom at path ".files.children[0].children[10].children" is missing from lhs json atoms at path ".files.children[0].children[10].name" are not equal: lhs: "library/std/src/sys/sync/mutex/fuchsia.rs" rhs: "library/std/src/sync/mpmc" ... ``` --- Cargo.lock | 1 + src/tools/collect-license-metadata/Cargo.toml | 1 + src/tools/collect-license-metadata/src/main.rs | 14 ++++++++++++++ 3 files changed, 16 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 2de9c84e3b031..68fd8a8385ecd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -686,6 +686,7 @@ dependencies = [ "anyhow", "serde", "serde_json", + "similar", "spdx-rs", ] diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml index edf9e5c5393ea..f84da24428155 100644 --- a/src/tools/collect-license-metadata/Cargo.toml +++ b/src/tools/collect-license-metadata/Cargo.toml @@ -9,4 +9,5 @@ license = "MIT OR Apache-2.0" anyhow = "1.0.65" serde = { version = "1.0.147", features = ["derive"] } serde_json = "1.0.85" +similar = "2.7.0" spdx-rs = "0.5.1" diff --git a/src/tools/collect-license-metadata/src/main.rs b/src/tools/collect-license-metadata/src/main.rs index 08a30d0b8994f..4e218ea59fda6 100644 --- a/src/tools/collect-license-metadata/src/main.rs +++ b/src/tools/collect-license-metadata/src/main.rs @@ -5,9 +5,21 @@ mod reuse; use std::path::PathBuf; use anyhow::{Context, Error}; +use similar::{ChangeTag, TextDiff}; use crate::licenses::LicensesInterner; +fn diff_text(expected: &str, actual: &str) { + for change in TextDiff::from_lines(expected, actual).iter_all_changes() { + let sign = match change.tag() { + ChangeTag::Delete => "-", + ChangeTag::Insert => "+", + ChangeTag::Equal => " ", + }; + print!("{}{}", sign, change); + } +} + /// The entry point to the binary. /// /// You should probably let `bootstrap` execute this program instead of running it directly. @@ -41,6 +53,8 @@ fn main() -> Result<(), Error> { if existing_json != output { eprintln!("The existing {} file is out of date.", dest.display()); eprintln!("Run ./x run collect-license-metadata to update it."); + eprintln!("Diff:"); + diff_text(&existing, &serde_json::to_string_pretty(&output).unwrap()); anyhow::bail!("The existing {} file doesn't match what REUSE reports.", dest.display()); } println!("license information matches"); From 525ed4cc5cfc9a8230deccf92edd4a41fbebc8ee Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 7 Oct 2025 17:26:01 +1100 Subject: [PATCH 08/13] Read the whole test file before parsing directives Few tests are larger than a handful of kilobytes, and nowadays we scan the whole file for directives anyway, so there's little reason not to just read the whole thing up-front. This avoids having to deal with I/O within `iter_directives`, which should make it easier to overhaul directive processing. --- src/tools/compiletest/src/directives.rs | 37 +++++++------------ src/tools/compiletest/src/directives/tests.rs | 36 ++++++++---------- src/tools/compiletest/src/lib.rs | 5 ++- 3 files changed, 32 insertions(+), 46 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index dab6850e0d62a..34ecbc2d59f10 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1,9 +1,6 @@ use std::collections::HashSet; -use std::env; -use std::fs::File; -use std::io::BufReader; -use std::io::prelude::*; use std::process::Command; +use std::{env, fs}; use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; @@ -54,18 +51,19 @@ pub struct EarlyProps { impl EarlyProps { pub fn from_file(config: &Config, testfile: &Utf8Path) -> Self { - let file = File::open(testfile.as_std_path()).expect("open test file to parse earlyprops"); - Self::from_reader(config, testfile, file) + let file_contents = + fs::read_to_string(testfile).expect("read test file to parse earlyprops"); + Self::from_file_contents(config, testfile, &file_contents) } - pub fn from_reader(config: &Config, testfile: &Utf8Path, rdr: R) -> Self { + pub fn from_file_contents(config: &Config, testfile: &Utf8Path, file_contents: &str) -> Self { let mut props = EarlyProps::default(); let mut poisoned = false; iter_directives( config.mode, &mut poisoned, testfile, - rdr, + file_contents, // (dummy comment to force args into vertical layout) &mut |ref ln: DirectiveLine<'_>| { parse_and_update_aux(config, ln, testfile, &mut props.aux); @@ -362,7 +360,7 @@ impl TestProps { fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config: &Config) { let mut has_edition = false; if !testfile.is_dir() { - let file = File::open(testfile.as_std_path()).unwrap(); + let file_contents = fs::read_to_string(testfile).unwrap(); let mut poisoned = false; @@ -370,7 +368,7 @@ impl TestProps { config.mode, &mut poisoned, testfile, - file, + &file_contents, &mut |ref ln: DirectiveLine<'_>| { if !ln.applies_to_test_revision(test_revision) { return; @@ -859,7 +857,7 @@ fn iter_directives( mode: TestMode, poisoned: &mut bool, testfile: &Utf8Path, - rdr: impl Read, + file_contents: &str, it: &mut dyn FnMut(DirectiveLine<'_>), ) { if testfile.is_dir() { @@ -886,16 +884,7 @@ fn iter_directives( } } - let mut rdr = BufReader::with_capacity(1024, rdr); - let mut ln = String::new(); - let mut line_number = 0; - - loop { - line_number += 1; - ln.clear(); - if rdr.read_line(&mut ln).unwrap() == 0 { - break; - } + for (line_number, ln) in (1..).zip(file_contents.lines()) { let ln = ln.trim(); let Some(directive_line) = line_directive(line_number, ln) else { @@ -1359,13 +1348,13 @@ where Some((min, max)) } -pub(crate) fn make_test_description( +pub(crate) fn make_test_description( config: &Config, cache: &DirectivesCache, name: String, path: &Utf8Path, filterable_path: &Utf8Path, - src: R, + file_contents: &str, test_revision: Option<&str>, poisoned: &mut bool, ) -> CollectedTestDesc { @@ -1380,7 +1369,7 @@ pub(crate) fn make_test_description( config.mode, &mut local_poisoned, path, - src, + file_contents, &mut |ref ln @ DirectiveLine { line_number, .. }| { if !ln.applies_to_test_revision(test_revision) { return; diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 95dd46532ba88..77080c7469371 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -1,5 +1,3 @@ -use std::io::Read; - use camino::Utf8Path; use semver::Version; @@ -10,12 +8,12 @@ use crate::directives::{ }; use crate::executor::{CollectedTestDesc, ShouldPanic}; -fn make_test_description( +fn make_test_description( config: &Config, name: String, path: &Utf8Path, filterable_path: &Utf8Path, - src: R, + file_contents: &str, revision: Option<&str>, ) -> CollectedTestDesc { let cache = DirectivesCache::load(config); @@ -26,7 +24,7 @@ fn make_test_description( name, path, filterable_path, - src, + file_contents, revision, &mut poisoned, ); @@ -226,14 +224,13 @@ fn cfg() -> ConfigBuilder { } fn parse_rs(config: &Config, contents: &str) -> EarlyProps { - let bytes = contents.as_bytes(); - EarlyProps::from_reader(config, Utf8Path::new("a.rs"), bytes) + EarlyProps::from_file_contents(config, Utf8Path::new("a.rs"), contents) } fn check_ignore(config: &Config, contents: &str) -> bool { let tn = String::new(); let p = Utf8Path::new("a.rs"); - let d = make_test_description(&config, tn, p, p, std::io::Cursor::new(contents), None); + let d = make_test_description(&config, tn, p, p, contents, None); d.ignore } @@ -243,9 +240,9 @@ fn should_fail() { let tn = String::new(); let p = Utf8Path::new("a.rs"); - let d = make_test_description(&config, tn.clone(), p, p, std::io::Cursor::new(""), None); + let d = make_test_description(&config, tn.clone(), p, p, "", None); assert_eq!(d.should_panic, ShouldPanic::No); - let d = make_test_description(&config, tn, p, p, std::io::Cursor::new("//@ should-fail"), None); + let d = make_test_description(&config, tn, p, p, "//@ should-fail", None); assert_eq!(d.should_panic, ShouldPanic::Yes); } @@ -778,9 +775,8 @@ fn threads_support() { } } -fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) { - let rdr = std::io::Cursor::new(&buf); - iter_directives(TestMode::Ui, poisoned, path, rdr, &mut |_| {}); +fn run_path(poisoned: &mut bool, path: &Utf8Path, file_contents: &str) { + iter_directives(TestMode::Ui, poisoned, path, file_contents, &mut |_| {}); } #[test] @@ -789,7 +785,7 @@ fn test_unknown_directive_check() { run_path( &mut poisoned, Utf8Path::new("a.rs"), - include_bytes!("./test-auxillary/unknown_directive.rs"), + include_str!("./test-auxillary/unknown_directive.rs"), ); assert!(poisoned); } @@ -800,7 +796,7 @@ fn test_known_directive_check_no_error() { run_path( &mut poisoned, Utf8Path::new("a.rs"), - include_bytes!("./test-auxillary/known_directive.rs"), + include_str!("./test-auxillary/known_directive.rs"), ); assert!(!poisoned); } @@ -811,7 +807,7 @@ fn test_error_annotation_no_error() { run_path( &mut poisoned, Utf8Path::new("a.rs"), - include_bytes!("./test-auxillary/error_annotation.rs"), + include_str!("./test-auxillary/error_annotation.rs"), ); assert!(!poisoned); } @@ -822,7 +818,7 @@ fn test_non_rs_unknown_directive_not_checked() { run_path( &mut poisoned, Utf8Path::new("a.Makefile"), - include_bytes!("./test-auxillary/not_rs.Makefile"), + include_str!("./test-auxillary/not_rs.Makefile"), ); assert!(!poisoned); } @@ -830,21 +826,21 @@ fn test_non_rs_unknown_directive_not_checked() { #[test] fn test_trailing_directive() { let mut poisoned = false; - run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), "//@ only-x86 only-arm"); assert!(poisoned); } #[test] fn test_trailing_directive_with_comment() { let mut poisoned = false; - run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm with comment"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), "//@ only-x86 only-arm with comment"); assert!(poisoned); } #[test] fn test_not_trailing_directive() { let mut poisoned = false; - run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ revisions: incremental"); + run_path(&mut poisoned, Utf8Path::new("a.rs"), "//@ revisions: incremental"); assert!(!poisoned); } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 2d759279f34bc..ac1a8226112a9 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -892,7 +892,8 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te // `CollectedTest` that can be handed over to the test executor. collector.tests.extend(revisions.into_iter().map(|revision| { // Create a test name and description to hand over to the executor. - let src_file = fs::File::open(&test_path).expect("open test file to parse ignores"); + let file_contents = + fs::read_to_string(&test_path).expect("read test file to parse ignores"); let (test_name, filterable_path) = make_test_name_and_filterable_path(&cx.config, testpaths, revision); // Create a description struct for the test/revision. @@ -904,7 +905,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te test_name, &test_path, &filterable_path, - src_file, + &file_contents, revision, &mut collector.poisoned, ); From a3ba8d8a9de05a04cbe4a1fa0161bbbe6a389864 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sun, 5 Oct 2025 21:47:02 -0400 Subject: [PATCH 09/13] Use globals instead of metadata, since metadata isn't emitted in debug builds --- .../src/builder/autodiff.rs | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 4a749642265df..c4ad8e4d075f7 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -13,7 +13,7 @@ use crate::builder::{Builder, PlaceRef, UNNAMED}; use crate::context::SimpleCx; use crate::declare::declare_simple_fn; use crate::llvm; -use crate::llvm::{Metadata, TRUE, Type}; +use crate::llvm::{TRUE, Type}; use crate::value::Value; pub(crate) fn adjust_activity_to_abi<'tcx>( @@ -159,32 +159,36 @@ fn match_args_from_caller_to_enzyme<'ll, 'tcx>( let mut outer_pos: usize = 0; let mut activity_pos = 0; - let enzyme_const = cx.create_metadata(b"enzyme_const"); - let enzyme_out = cx.create_metadata(b"enzyme_out"); - let enzyme_dup = cx.create_metadata(b"enzyme_dup"); - let enzyme_dupv = cx.create_metadata(b"enzyme_dupv"); - let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed"); - let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv"); + // We used to use llvm's metadata to instruct enzyme how to differentiate a function. + // In debug mode we would use incremental compilation which caused the metadata to be + // dropped. This is prevented by now using named globals, which are also understood + // by Enzyme. + let global_const = cx.declare_global("enzyme_const", cx.type_ptr()); + let global_out = cx.declare_global("enzyme_out", cx.type_ptr()); + let global_dup = cx.declare_global("enzyme_dup", cx.type_ptr()); + let global_dupv = cx.declare_global("enzyme_dupv", cx.type_ptr()); + let global_dupnoneed = cx.declare_global("enzyme_dupnoneed", cx.type_ptr()); + let global_dupnoneedv = cx.declare_global("enzyme_dupnoneedv", cx.type_ptr()); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; // Duplicated arguments received a shadow argument, into which enzyme will write the // gradient. - let (activity, duplicated): (&Metadata, bool) = match diff_activity { + let (activity, duplicated): (&llvm::Value, bool) = match diff_activity { DiffActivity::None => panic!("not a valid input activity"), - DiffActivity::Const => (enzyme_const, false), - DiffActivity::Active => (enzyme_out, false), - DiffActivity::ActiveOnly => (enzyme_out, false), - DiffActivity::Dual => (enzyme_dup, true), - DiffActivity::Dualv => (enzyme_dupv, true), - DiffActivity::DualOnly => (enzyme_dupnoneed, true), - DiffActivity::DualvOnly => (enzyme_dupnoneedv, true), - DiffActivity::Duplicated => (enzyme_dup, true), - DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true), - DiffActivity::FakeActivitySize(_) => (enzyme_const, false), + DiffActivity::Const => (global_const, false), + DiffActivity::Active => (global_out, false), + DiffActivity::ActiveOnly => (global_out, false), + DiffActivity::Dual => (global_dup, true), + DiffActivity::Dualv => (global_dupv, true), + DiffActivity::DualOnly => (global_dupnoneed, true), + DiffActivity::DualvOnly => (global_dupnoneedv, true), + DiffActivity::Duplicated => (global_dup, true), + DiffActivity::DuplicatedOnly => (global_dupnoneed, true), + DiffActivity::FakeActivitySize(_) => (global_const, false), }; let outer_arg = outer_args[outer_pos]; - args.push(cx.get_metadata_value(activity)); + args.push(activity); if matches!(diff_activity, DiffActivity::Dualv) { let next_outer_arg = outer_args[outer_pos + 1]; let elem_bytes_size: u64 = match inputs[activity_pos + 1] { @@ -244,7 +248,7 @@ fn match_args_from_caller_to_enzyme<'ll, 'tcx>( assert_eq!(cx.type_kind(next_outer_ty3), TypeKind::Integer); args.push(next_outer_arg2); } - args.push(cx.get_metadata_value(enzyme_const)); + args.push(global_const); args.push(next_outer_arg); outer_pos += 2 + 2 * iterations; activity_pos += 2; @@ -353,13 +357,13 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return"); + let global_primal_ret = cx.declare_global("enzyme_primal_return", cx.type_ptr()); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { - args.push(cx.get_metadata_value(enzyme_primal_ret)); + args.push(global_primal_ret); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata(b"enzyme_width"); - args.push(cx.get_metadata_value(enzyme_width)); + let global_width = cx.declare_global("enzyme_width", cx.type_ptr()); + args.push(global_width); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } From 5f9ee17bbade08017c1ad70376ac1c0375a84315 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sun, 5 Oct 2025 22:45:09 -0400 Subject: [PATCH 10/13] add incremental/debug test for autodiff --- tests/ui/autodiff/incremental.rs | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/ui/autodiff/incremental.rs diff --git a/tests/ui/autodiff/incremental.rs b/tests/ui/autodiff/incremental.rs new file mode 100644 index 0000000000000..a79059deaa778 --- /dev/null +++ b/tests/ui/autodiff/incremental.rs @@ -0,0 +1,41 @@ +//@ revisions: DEBUG RELEASE +//@[RELEASE] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat +//@[DEBUG] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=0 -Clto=fat -C debuginfo=2 +//@ needs-enzyme +//@ incremental +//@ no-prefer-dynamic +//@ build-pass +#![crate_type = "bin"] +#![feature(autodiff)] + +// We used to use llvm's metadata to instruct enzyme how to differentiate a function. +// In debug mode we would use incremental compilation which caused the metadata to be +// dropped. We now use globals instead and add this test to verify that incremental +// keeps working. Also testing debug mode while at it. + +use std::autodiff::autodiff_reverse; + +#[autodiff_reverse(bar, Duplicated, Duplicated)] +pub fn foo(r: &[f64; 10], res: &mut f64) { + let mut output = [0.0; 10]; + output[0] = r[0]; + output[1] = r[1] * r[2]; + output[2] = r[4] * r[5]; + output[3] = r[2] * r[6]; + output[4] = r[1] * r[7]; + output[5] = r[2] * r[8]; + output[6] = r[1] * r[9]; + output[7] = r[5] * r[6]; + output[8] = r[5] * r[7]; + output[9] = r[4] * r[8]; + *res = output.iter().sum(); +} +fn main() { + let inputs = Box::new([3.1; 10]); + let mut d_inputs = Box::new([0.0; 10]); + let mut res = Box::new(0.0); + let mut d_res = Box::new(1.0); + + bar(&inputs, &mut d_inputs, &mut res, &mut d_res); + dbg!(&d_inputs); +} From 6ce845a7776a34ce7cee7eb607a6146c2fcc9ce7 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sun, 5 Oct 2025 23:10:25 -0400 Subject: [PATCH 11/13] update ui test since the new frontend is a bit more lenient --- tests/ui/autodiff/autodiff_illegal.rs | 23 ------------- tests/ui/autodiff/autodiff_illegal.stderr | 39 +++-------------------- 2 files changed, 5 insertions(+), 57 deletions(-) diff --git a/tests/ui/autodiff/autodiff_illegal.rs b/tests/ui/autodiff/autodiff_illegal.rs index a53b6d5e58981..6bb384cc87e8d 100644 --- a/tests/ui/autodiff/autodiff_illegal.rs +++ b/tests/ui/autodiff/autodiff_illegal.rs @@ -110,15 +110,6 @@ fn f14(x: f32) -> Foo { type MyFloat = f32; -// We would like to support type alias to f32/f64 in argument type in the future, -// but that requires us to implement our checks at a later stage -// like THIR which has type information available. -#[autodiff_reverse(df15, Active, Active)] -fn f15(x: MyFloat) -> f32 { - //~^^ ERROR failed to resolve: use of undeclared type `MyFloat` [E0433] - unimplemented!() -} - // We would like to support type alias to f32/f64 in return type in the future #[autodiff_reverse(df16, Active, Active)] fn f16(x: f32) -> MyFloat { @@ -136,13 +127,6 @@ fn f17(x: f64) -> F64Trans { unimplemented!() } -// We would like to support `#[repr(transparent)]` f32/f64 wrapper in argument type in the future -#[autodiff_reverse(df18, Active, Active)] -fn f18(x: F64Trans) -> f64 { - //~^^ ERROR failed to resolve: use of undeclared type `F64Trans` [E0433] - unimplemented!() -} - // Invalid return activity #[autodiff_forward(df19, Dual, Active)] fn f19(x: f32) -> f32 { @@ -163,11 +147,4 @@ fn f21(x: f32) -> f32 { unimplemented!() } -struct DoesNotImplDefault; -#[autodiff_forward(df22, Dual)] -pub fn f22() -> DoesNotImplDefault { - //~^^ ERROR the function or associated item `default` exists for tuple `(DoesNotImplDefault, DoesNotImplDefault)`, but its trait bounds were not satisfied - unimplemented!() -} - fn main() {} diff --git a/tests/ui/autodiff/autodiff_illegal.stderr b/tests/ui/autodiff/autodiff_illegal.stderr index ad6f10af46780..848ae1155e9c4 100644 --- a/tests/ui/autodiff/autodiff_illegal.stderr +++ b/tests/ui/autodiff/autodiff_illegal.stderr @@ -107,53 +107,24 @@ LL | #[autodiff_reverse(df13, Reverse)] | ^^^^^^^ error: invalid return activity Active in Forward Mode - --> $DIR/autodiff_illegal.rs:147:1 + --> $DIR/autodiff_illegal.rs:131:1 | LL | #[autodiff_forward(df19, Dual, Active)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid return activity Dual in Reverse Mode - --> $DIR/autodiff_illegal.rs:153:1 + --> $DIR/autodiff_illegal.rs:137:1 | LL | #[autodiff_reverse(df20, Active, Dual)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid return activity Duplicated in Reverse Mode - --> $DIR/autodiff_illegal.rs:160:1 + --> $DIR/autodiff_illegal.rs:144:1 | LL | #[autodiff_reverse(df21, Active, Duplicated)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0433]: failed to resolve: use of undeclared type `MyFloat` - --> $DIR/autodiff_illegal.rs:116:1 - | -LL | #[autodiff_reverse(df15, Active, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat` - -error[E0433]: failed to resolve: use of undeclared type `F64Trans` - --> $DIR/autodiff_illegal.rs:140:1 - | -LL | #[autodiff_reverse(df18, Active, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans` - -error[E0599]: the function or associated item `default` exists for tuple `(DoesNotImplDefault, DoesNotImplDefault)`, but its trait bounds were not satisfied - --> $DIR/autodiff_illegal.rs:167:1 - | -LL | struct DoesNotImplDefault; - | ------------------------- doesn't satisfy `DoesNotImplDefault: Default` -LL | #[autodiff_forward(df22, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item cannot be called on `(DoesNotImplDefault, DoesNotImplDefault)` due to unsatisfied trait bounds - | - = note: the following trait bounds were not satisfied: - `DoesNotImplDefault: Default` - which is required by `(DoesNotImplDefault, DoesNotImplDefault): Default` -help: consider annotating `DoesNotImplDefault` with `#[derive(Default)]` - | -LL + #[derive(Default)] -LL | struct DoesNotImplDefault; - | - -error: aborting due to 21 previous errors +error: aborting due to 18 previous errors -Some errors have detailed explanations: E0428, E0433, E0599, E0658. +Some errors have detailed explanations: E0428, E0658. For more information about an error, try `rustc --explain E0428`. From 0fe466cc25975a5d531a546ec7cce2f38f3e0d6a Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Tue, 7 Oct 2025 14:47:39 +0700 Subject: [PATCH 12/13] Fix doc comment --- compiler/rustc_middle/src/thir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index f1d19800a7891..eed27345b747b 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -839,7 +839,7 @@ pub enum PatKind<'tcx> { /// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are /// much simpler. /// * raw pointers derived from integers, other raw pointers will have already resulted in an - // error. + /// error. /// * `String`, if `string_deref_patterns` is enabled. Constant { value: ty::Value<'tcx>, From 43f7eaa0ba4cbd2537260fe223ce1e7883c405fc Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Mon, 6 Oct 2025 11:38:09 +0100 Subject: [PATCH 13/13] Fix; correct placement of type inference error for method calls --- compiler/rustc_hir_typeck/src/method/probe.rs | 21 ++++++++++++++----- ...eref-ambiguity-becomes-nonambiguous.stderr | 2 +- ...tion-with-leaking-placeholders.next.stderr | 2 +- .../hidden-type-is-opaque-2.default.stderr | 4 ++-- .../hidden-type-is-opaque-2.next.stderr | 4 ++-- ...ncompat-call-after-qualified-path-0.stderr | 2 +- ...ncompat-call-after-qualified-path-1.stderr | 2 +- tests/ui/issues/issue-20261.stderr | 4 ++-- tests/ui/issues/issue-2151.stderr | 2 +- .../branches3.stderr | 8 +++---- .../call_method_unknown_pointee.stderr | 18 +++++++--------- .../call_method_unknown_referent.stderr | 8 +++---- .../ui/proc-macro/quote/not-repeatable.stderr | 4 ++-- ...opy-inference-side-effects-are-lazy.stderr | 2 +- .../issue-42234-unknown-receiver-type.stderr | 4 +--- .../closures_in_branches.stderr | 4 ++-- .../regression-issue-81317.stderr | 2 +- tests/ui/typeck/issue-13853.stderr | 4 ++-- 18 files changed, 52 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 12f80a197b1b8..45b87cee957c9 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -7,9 +7,8 @@ use rustc_attr_parsing::is_doc_alias_attrs_contain_symbol; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::HirId; use rustc_hir::def::DefKind; +use rustc_hir::{self as hir, ExprKind, HirId, Node}; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; @@ -486,13 +485,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(ty.value); let guar = match *ty.kind() { ty::Infer(ty::TyVar(_)) => { + // We want to get the variable name that the method + // is being called on. If it is a method call. + let err_span = match (mode, self.tcx.hir_node(scope_expr_id)) { + ( + Mode::MethodCall, + Node::Expr(hir::Expr { + kind: ExprKind::MethodCall(_, recv, ..), + .. + }), + ) => recv.span, + _ => span, + }; + let raw_ptr_call = bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types(); - // FIXME: Ideally we'd use the span of the self-expr here, - // not of the method path. + let mut err = self.err_ctxt().emit_inference_failure_err( self.body_id, - span, + err_span, ty.into(), TypeAnnotationNeeded::E0282, !raw_ptr_call, diff --git a/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr index 19c3c64181985..bad799b2550b9 100644 --- a/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr +++ b/tests/ui/autoref-autoderef/deref-ambiguity-becomes-nonambiguous.stderr @@ -5,7 +5,7 @@ LL | let var_fn = Value::wrap(); | ^^^^^^ ... LL | let _ = var_fn.clone(); - | ----- type must be known at this point + | ------ type must be known at this point | help: consider giving `var_fn` an explicit type, where the placeholders `_` are specified | diff --git a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr index 4bb9047b3035d..3d667f12371ab 100644 --- a/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr +++ b/tests/ui/closures/deduce-signature/obligation-with-leaking-placeholders.next.stderr @@ -5,7 +5,7 @@ LL | needs_foo(|x| { | ^ ... LL | x.to_string(); - | --------- type must be known at this point + | - type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr b/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr index cb383b2db3893..dca0a7b0a1a9f 100644 --- a/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr +++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.default.stderr @@ -5,7 +5,7 @@ LL | Thunk::new(|mut cont| { | ^^^^^^^^ LL | LL | cont.reify_as(); - | -------- type must be known at this point + | ---- type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -19,7 +19,7 @@ LL | Thunk::new(|mut cont| { | ^^^^^^^^ LL | LL | cont.reify_as(); - | -------- type must be known at this point + | ---- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr b/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr index cb383b2db3893..dca0a7b0a1a9f 100644 --- a/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr +++ b/tests/ui/impl-trait/hidden-type-is-opaque-2.next.stderr @@ -5,7 +5,7 @@ LL | Thunk::new(|mut cont| { | ^^^^^^^^ LL | LL | cont.reify_as(); - | -------- type must be known at this point + | ---- type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -19,7 +19,7 @@ LL | Thunk::new(|mut cont| { | ^^^^^^^^ LL | LL | cont.reify_as(); - | -------- type must be known at this point + | ---- type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-0.stderr b/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-0.stderr index ba1c81c4518a7..10056bdf3d4f4 100644 --- a/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-0.stderr +++ b/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-0.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/incompat-call-after-qualified-path-0.rs:21:6 | LL | f(|a, b| a.cmp(b)); - | ^ --- type must be known at this point + | ^ - type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-1.stderr b/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-1.stderr index 93bba3625b540..632a9b99f84ef 100644 --- a/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-1.stderr +++ b/tests/ui/inference/need_type_info/incompat-call-after-qualified-path-1.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/incompat-call-after-qualified-path-1.rs:25:6 | LL | f(|a, b| a.cmp(b)); - | ^ --- type must be known at this point + | ^ - type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/issues/issue-20261.stderr b/tests/ui/issues/issue-20261.stderr index 6738708ca225d..c5348abb3c501 100644 --- a/tests/ui/issues/issue-20261.stderr +++ b/tests/ui/issues/issue-20261.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/issue-20261.rs:4:11 + --> $DIR/issue-20261.rs:4:9 | LL | i.clone(); - | ^^^^^ cannot infer type + | ^ cannot infer type error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-2151.stderr b/tests/ui/issues/issue-2151.stderr index 59fef42eb5e8b..b130f162414d0 100644 --- a/tests/ui/issues/issue-2151.stderr +++ b/tests/ui/issues/issue-2151.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let x = panic!(); | ^ LL | x.clone(); - | ----- type must be known at this point + | - type must be known at this point | help: consider giving `x` an explicit type | diff --git a/tests/ui/lazy-type-alias-impl-trait/branches3.stderr b/tests/ui/lazy-type-alias-impl-trait/branches3.stderr index 539673bc343ce..117d189867bd7 100644 --- a/tests/ui/lazy-type-alias-impl-trait/branches3.stderr +++ b/tests/ui/lazy-type-alias-impl-trait/branches3.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/branches3.rs:9:10 | LL | |s| s.len() - | ^ --- type must be known at this point + | ^ - type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -13,7 +13,7 @@ error[E0282]: type annotations needed --> $DIR/branches3.rs:18:10 | LL | |s| s.len() - | ^ --- type must be known at this point + | ^ - type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -24,7 +24,7 @@ error[E0282]: type annotations needed --> $DIR/branches3.rs:26:10 | LL | |s| s.len() - | ^ --- type must be known at this point + | ^ - type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -35,7 +35,7 @@ error[E0282]: type annotations needed --> $DIR/branches3.rs:33:10 | LL | |s| s.len() - | ^ --- type must be known at this point + | ^ - type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/methods/call_method_unknown_pointee.stderr b/tests/ui/methods/call_method_unknown_pointee.stderr index 9d0f38cf6b5c1..e20c6f8e8a17c 100644 --- a/tests/ui/methods/call_method_unknown_pointee.stderr +++ b/tests/ui/methods/call_method_unknown_pointee.stderr @@ -1,11 +1,10 @@ error[E0282]: type annotations needed - --> $DIR/call_method_unknown_pointee.rs:10:41 + --> $DIR/call_method_unknown_pointee.rs:10:23 | LL | let _a: i32 = (ptr as *const _).read(); - | ^^^^ - | | - | cannot infer type - | cannot call a method on a raw pointer with an unknown pointee type + | ^^^^^^^^^^^^^^^^^ ---- cannot call a method on a raw pointer with an unknown pointee type + | | + | cannot infer type error[E0282]: type annotations needed for `*const _` --> $DIR/call_method_unknown_pointee.rs:12:13 @@ -22,13 +21,12 @@ LL | let b: *const _ = ptr as *const _; | ++++++++++ error[E0282]: type annotations needed - --> $DIR/call_method_unknown_pointee.rs:21:39 + --> $DIR/call_method_unknown_pointee.rs:21:23 | LL | let _a: i32 = (ptr as *mut _).read(); - | ^^^^ - | | - | cannot infer type - | cannot call a method on a raw pointer with an unknown pointee type + | ^^^^^^^^^^^^^^^ ---- cannot call a method on a raw pointer with an unknown pointee type + | | + | cannot infer type error[E0282]: type annotations needed for `*mut _` --> $DIR/call_method_unknown_pointee.rs:23:13 diff --git a/tests/ui/methods/call_method_unknown_referent.stderr b/tests/ui/methods/call_method_unknown_referent.stderr index 5d6974a00c695..35c7d9caf3efa 100644 --- a/tests/ui/methods/call_method_unknown_referent.stderr +++ b/tests/ui/methods/call_method_unknown_referent.stderr @@ -1,14 +1,14 @@ error[E0282]: type annotations needed - --> $DIR/call_method_unknown_referent.rs:20:31 + --> $DIR/call_method_unknown_referent.rs:20:19 | LL | let _a: i32 = (ptr as &_).read(); - | ^^^^ cannot infer type + | ^^^^^^^^^^^ cannot infer type error[E0282]: type annotations needed - --> $DIR/call_method_unknown_referent.rs:26:37 + --> $DIR/call_method_unknown_referent.rs:26:14 | LL | let _b = (rc as std::rc::Rc<_>).read(); - | ^^^^ cannot infer type + | ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type error[E0599]: no method named `read` found for struct `SmartPtr` in the current scope --> $DIR/call_method_unknown_referent.rs:46:35 diff --git a/tests/ui/proc-macro/quote/not-repeatable.stderr b/tests/ui/proc-macro/quote/not-repeatable.stderr index ff31799abb007..5943111efd585 100644 --- a/tests/ui/proc-macro/quote/not-repeatable.stderr +++ b/tests/ui/proc-macro/quote/not-repeatable.stderr @@ -21,10 +21,10 @@ note: the traits `Iterator` and `ToTokens` must be implemented --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL error[E0282]: type annotations needed - --> $DIR/not-repeatable.rs:11:13 + --> $DIR/not-repeatable.rs:11:25 | LL | let _ = quote! { $($ip)* }; - | ^^^^^^^^^^^^^^^^^^ cannot infer type + | ^^ cannot infer type error: aborting due to 2 previous errors diff --git a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr index b8a8f927542f0..c98b9bb38fdb0 100644 --- a/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr +++ b/tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.stderr @@ -5,7 +5,7 @@ LL | let x = [Foo(PhantomData); 2]; | ^ LL | LL | extract(x).max(2); - | --- type must be known at this point + | ---------- type must be known at this point | help: consider giving `x` an explicit type, where the placeholders `_` are specified | diff --git a/tests/ui/span/issue-42234-unknown-receiver-type.stderr b/tests/ui/span/issue-42234-unknown-receiver-type.stderr index 71ac4f53b3f4f..10308ec07da5a 100644 --- a/tests/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/tests/ui/span/issue-42234-unknown-receiver-type.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let x: Option<_> = None; | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` LL | x.unwrap().method_that_could_exist_on_some_type(); - | ------------------------------------ type must be known at this point + | ---------- type must be known at this point | help: consider specifying the generic argument | @@ -16,8 +16,6 @@ error[E0282]: type annotations needed | LL | .sum::<_>() | ^^^ cannot infer type of the type parameter `S` declared on the method `sum` -LL | .to_string() - | --------- type must be known at this point | error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/closures_in_branches.stderr b/tests/ui/type-alias-impl-trait/closures_in_branches.stderr index 559bc57d90638..849ffd214f07d 100644 --- a/tests/ui/type-alias-impl-trait/closures_in_branches.stderr +++ b/tests/ui/type-alias-impl-trait/closures_in_branches.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/closures_in_branches.rs:8:10 | LL | |x| x.len() - | ^ --- type must be known at this point + | ^ - type must be known at this point | help: consider giving this closure parameter an explicit type | @@ -13,7 +13,7 @@ error[E0282]: type annotations needed --> $DIR/closures_in_branches.rs:22:10 | LL | |x| x.len() - | ^ --- type must be known at this point + | ^ - type must be known at this point | help: consider giving this closure parameter an explicit type | diff --git a/tests/ui/type-inference/regression-issue-81317.stderr b/tests/ui/type-inference/regression-issue-81317.stderr index a070b50e31175..fcd3fca06e18b 100644 --- a/tests/ui/type-inference/regression-issue-81317.stderr +++ b/tests/ui/type-inference/regression-issue-81317.stderr @@ -5,7 +5,7 @@ LL | let iv = S ^ index.into(); | ^^ LL | LL | &iv.to_bytes_be(); - | ----------- type must be known at this point + | -- type must be known at this point | help: consider giving `iv` an explicit type | diff --git a/tests/ui/typeck/issue-13853.stderr b/tests/ui/typeck/issue-13853.stderr index 9b8698d6ed2c0..4a39b404770d0 100644 --- a/tests/ui/typeck/issue-13853.stderr +++ b/tests/ui/typeck/issue-13853.stderr @@ -18,10 +18,10 @@ LL | for node in graph.iter() { | ^^^^ method not found in `&G` error[E0282]: type annotations needed - --> $DIR/issue-13853.rs:28:14 + --> $DIR/issue-13853.rs:28:9 | LL | node.zomg(); - | ^^^^ cannot infer type + | ^^^^ cannot infer type error[E0308]: mismatched types --> $DIR/issue-13853.rs:37:13