From d9b90b0bff56c3547ff97a8e65b70f72e5cc0b11 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Fri, 12 Jun 2026 17:15:27 +0700 Subject: [PATCH 01/33] Rewrite safety requirements for `Allocator` impls I define the concept of "equivalent allocators", in order to be able to talk about cloning allocators, and to give commonsense guarantees about stdlib `Allocator` impls. I define the concept of "invalidating a memory block" in order to be able to talk about users not being allowed to use a block of allocated memory after its allocator is "gone". An `Allocator` implementation is now allowed to invalidate its allocations when the allocator is mutated or when a lifetime in the allocator type expires. Mutation of an `Allocator` should sensibly be allowed to invalidate its allocations. For example, the `bumpalo` crates has a `Bump::reset` method that takes `&mut self` and invalidates all past allocations. Accesses via `&` still must not invalidate past allocations since, for example, `Box` provides `&` access to the allocator. I still had the "allocator destructor" clause as a separate clause from the `&mut` clause, to avoid questions about whether drop glue of types that don't implement `Drop` but have fields that implement `Drop` counts as creating a `&mut` to the whole thing. The "lifetime expiry" clause closes a hole/ambiguity on when an allocator is considered to be "dropped" if it does not have a destructor. Additionally, this clause matches what is required for `Box::into_pin` and `{Rc, Arc}::pin` to be sound. (Those methods have an `A: 'static` bound to prevent allocating via a `&MyAllocator` and then running `MyAllocator`'s destructor.) --- library/core/src/alloc/mod.rs | 125 +++++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 33 deletions(-) diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 102fb19efc8ea..0f99969513411 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -57,20 +57,78 @@ impl fmt::Display for AllocError { /// allocator does not support this (like jemalloc) or responds by returning a null pointer /// (such as `libc::malloc`), this must be caught by the implementation. /// +/// ### Equivalent allocators +/// +/// Multiple allocator values can sometimes be interchangeable with each other. +/// When this is the case, we refer to those allocators as being *equivalent* to +/// each other. +/// +/// The following conditions are sufficient conditions for allocators to be equivalent. +/// * An allocator is equivalent to itself. (Equivalence is reflexive.) +/// * If an allocator is equivalent to a second allocator, then +/// the second allocator is also equivalent to the first. (Equivalence is symmetric.) +/// * If an allocator is equivalent to a second allocator, and +/// the second allocator is equivalent to a third allocator, then +/// the first allocator is also equivalent to the third allocator. +/// (Equivalence is transitive.) +/// * Moving, subtyping, unsize-coercing, or trait-upcasting an allocator does not change +/// what the allocator is equivalent to. +/// * Copying or cloning allocator results in an allocator that's +/// equivalent to the initial allocator. +/// +/// Additionally, implementors of `Allocator` may specify additional equivalences +/// between allocators. It is the responsibility of such implementors to make sure +/// that equivalent allocators have "compatible" `Allocator` implementations. +/// In particular, the standard library specifies the following equivalences: +/// * A reference to an allocator (either `&` or `&mut`) is equivalent to +/// the allocator being referenced. +/// * A `Box`, `Rc`, or `Arc` containing an allocator is equivalent to +/// the allocator inside. +/// * All `Global` allocator instances are equivalent with each other. +/// * All `System` allocator instances are equivalent with each other. +/// +/// Note: Currently, the interaction between cloning and unsize-coercing allocators +/// is unsound, and there is ongoing discussion on how to revise the `Allocator` trait +/// to fix this. See [#156920]. +/// +/// [#156920]: https://github.com/rust-lang/rust/issues/156920 +/// /// ### Currently allocated memory /// -/// Some of the methods require that a memory block is *currently allocated* by an allocator. +/// Some of the methods require that a memory block is *currently allocated* by specific allocator. /// This means that: -/// * the starting address for that memory block was previously -/// returned by [`allocate`], [`grow`], or [`shrink`], and -/// * the memory block has not subsequently been deallocated. +/// * the starting address for that memory block was previously +/// returned by the [`allocate`], [`allocate_zeroed`], [`grow`], or [`shrink`] methods, +/// called on an allocator that's equivalent to this specific allocator; and +/// * the memory block has not subsequently been [*invalidated*]. +/// +/// [*invalidated*]: #invalidating-memory-blocks /// -/// A memory block is deallocated by a call to [`deallocate`], -/// or by a call to [`grow`] or [`shrink`] that returns `Ok`. -/// A call to `grow` or `shrink` that returns `Err`, -/// does not deallocate the memory block passed to it. +/// ### Invalidating memory blocks +/// +/// A memory block that is currently allocated becomes *invalidated* when one +/// of the following happens: +/// * The memory block is deallocated. This occurs when the memory block +/// is passed as an argument to a [`deallocate`] call, or when it is passed +/// as an argument to a [`grow`] or [`shrink`] call that returns `Ok`. +/// * All (equivalent) allocators that this memory block is allocated with, +/// each has one of the following happen to them: +/// * The allocator's destructor runs. +/// * The allocator is mutated through public API taking `&mut` access. +/// * One of the borrow-checker lifetimes in the allocator's type expires. +/// +/// Note that these conditions imply that a collection may ensure that +/// any specific currently allocated memory block won't be invalidated, by: +/// * not deallocating that memory block, +/// * owning an allocator that memory block is allocated with, and +/// * not publicly exposing `&mut` access to that allocator. +/// +/// Also note that accessing an allocator with `&` access cannot invalidate +/// its memory blocks. Therefore, collections may safely expose `&` access +/// to its allocator. /// /// [`allocate`]: Allocator::allocate +/// [`allocate_zeroed`]: Allocator::allocate_zeroed /// [`grow`]: Allocator::grow /// [`shrink`]: Allocator::shrink /// [`deallocate`]: Allocator::deallocate @@ -89,16 +147,12 @@ impl fmt::Display for AllocError { /// /// # Safety /// -/// Memory blocks that are [*currently allocated*] by an allocator, -/// must point to valid memory, and retain their validity until either: -/// - the memory block is deallocated, or -/// - the allocator is dropped. -/// -/// Copying, cloning, or moving the allocator must not invalidate memory blocks returned from it. -/// A copied or cloned allocator must behave like the original allocator. -/// -/// A memory block which is [*currently allocated*] may be passed to -/// any method of the allocator that accepts such an argument. +/// Implementors of `Allocator` must ensure that a memory block that +/// are [*currently allocated*] by the allocator points to valid memory, +/// until that memory block is [*invalidated*]. The implementor must also +/// not violate this invariant of `Allocator` via allocator equivalences +/// that are in the implementor's control (e.g., via a misbehaving +/// `impl Clone for Box`). /// /// Additionally, any memory block returned by the allocator must /// satisfy the allocation invariants described in `core::ptr`. @@ -107,7 +161,9 @@ impl fmt::Display for AllocError { /// /// This ensures that pointer arithmetic within the allocation /// (for example, `ptr.add(len)`) cannot overflow the address space. +/// /// [*currently allocated*]: #currently-allocated-memory +/// [*invalidated*]: #invalidating-memory-blocks #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub const unsafe trait Allocator { @@ -118,11 +174,13 @@ pub const unsafe trait Allocator { /// The returned block may have a larger size than specified by `layout.size()`, and may or may /// not have its contents initialized. /// - /// The returned block of memory remains valid as long as it is [*currently allocated*] and the shorter of: - /// - the borrow-checker lifetime of the allocator type itself. - /// - as long as the allocator and all its clones have not been dropped. + /// Note that the returned block of memory is considered [*currently allocated*] + /// with this allocator (and equivalent allocators). + /// Therefore, it is the responsibility of implementors of `Allocator` to make sure that + /// this block of memory points to valid memory until the block is [*invalidated*] /// /// [*currently allocated*]: #currently-allocated-memory + /// [*invalidated*]: #invalidating-memory-blocks /// /// # Errors /// @@ -178,13 +236,12 @@ pub const unsafe trait Allocator { /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// - /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been - /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the - /// allocation was grown in-place. The newly returned pointer is the only valid pointer - /// for accessing this memory now. + /// If this returns `Ok`, then the memory block referenced by `ptr` has been [*invalidated*]. + /// Any access to the old `ptr` is Undefined Behavior, even if the allocation was grown in-place. + /// The newly returned pointer is the only valid pointer for accessing this memory now. /// - /// If this method returns `Err`, then ownership of the memory block has not been transferred to - /// this allocator, and the contents of the memory block are unaltered. + /// If this method returns `Err`, then the memory block has not been *invalidated*, + /// and the contents of the memory block are unaltered. /// /// # Safety /// @@ -196,6 +253,7 @@ pub const unsafe trait Allocator { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting + /// [*invalidated*]: #invalidating-memory-blocks /// /// # Errors /// @@ -305,13 +363,13 @@ pub const unsafe trait Allocator { /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// - /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been - /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the - /// allocation was shrunk in-place. The newly returned pointer is the only valid pointer - /// for accessing this memory now. /// - /// If this method returns `Err`, then ownership of the memory block has not been transferred to - /// this allocator, and the contents of the memory block are unaltered. + /// If this returns `Ok`, then the memory block referenced by `ptr` has been [*invalidated*]. + /// Any access to the old `ptr` is Undefined Behavior, even if the allocation was shrunk in-place. + /// The newly returned pointer is the only valid pointer for accessing this memory now. + /// + /// If this method returns `Err`, then the memory block has not been *invalidated*, + /// and the contents of the memory block are unaltered. /// /// # Safety /// @@ -323,6 +381,7 @@ pub const unsafe trait Allocator { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting + /// [*invalidated*]: #invalidating-memory-blocks /// /// # Errors /// From e9929d760f6bbfee1bfcc3488b694b34896d7693 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Mon, 15 Jun 2026 17:00:31 +0700 Subject: [PATCH 02/33] Address feedback comments. --- library/core/src/alloc/mod.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 0f99969513411..ec2f106e79364 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -95,10 +95,10 @@ impl fmt::Display for AllocError { /// /// ### Currently allocated memory /// -/// Some of the methods require that a memory block is *currently allocated* by specific allocator. +/// Some of the methods require that a memory block is *currently allocated* by some specific allocator. /// This means that: -/// * the starting address for that memory block was previously -/// returned by the [`allocate`], [`allocate_zeroed`], [`grow`], or [`shrink`] methods, +/// * the starting address for that memory block was previously returned by +/// the [`allocate`], [`allocate_zeroed`], [`grow`], [`grow_zeroed`], or [`shrink`] methods, /// called on an allocator that's equivalent to this specific allocator; and /// * the memory block has not subsequently been [*invalidated*]. /// @@ -110,7 +110,7 @@ impl fmt::Display for AllocError { /// of the following happens: /// * The memory block is deallocated. This occurs when the memory block /// is passed as an argument to a [`deallocate`] call, or when it is passed -/// as an argument to a [`grow`] or [`shrink`] call that returns `Ok`. +/// as an argument to a [`grow`], [`grow_zeroed`] or [`shrink`] call that returns `Ok`. /// * All (equivalent) allocators that this memory block is allocated with, /// each has one of the following happen to them: /// * The allocator's destructor runs. @@ -127,9 +127,19 @@ impl fmt::Display for AllocError { /// its memory blocks. Therefore, collections may safely expose `&` access /// to its allocator. /// +/// Also note that, even in cases where are other "alive" allocators known to be +/// equivalent to a given collection's allocator, most collections still should +/// not publicly expose `&mut` access to its allocator. The fact that there are +/// other "alive" allocators would prevent this `&mut` access from invalidating +/// the collection's memory block, but public `&mut` access is still likely to +/// be unsound, since a user could replace the collection's allocator with +/// a non-equivalent allocator, causing the collection to deallocate its memory +/// with the wrong allocator. +/// /// [`allocate`]: Allocator::allocate /// [`allocate_zeroed`]: Allocator::allocate_zeroed /// [`grow`]: Allocator::grow +/// [`grow_zeroed`]: Allocator::grow_zeroed /// [`shrink`]: Allocator::shrink /// [`deallocate`]: Allocator::deallocate /// @@ -140,7 +150,8 @@ impl fmt::Display for AllocError { /// * the memory block must be *currently allocated* with alignment of [`layout.align()`], and /// * [`layout.size()`] must fall in the range `min ..= max`, where: /// - `min` is the size of the layout used to allocate the block, and -/// - `max` is the actual size returned from [`allocate`], [`grow`], or [`shrink`]. +/// - `max` is the actual size returned from [`allocate`], [`allocate_zeroed`], +/// [`grow`], [`grow_zeroed`], or [`shrink`]. /// /// [`layout.align()`]: Layout::align /// [`layout.size()`]: Layout::size @@ -148,7 +159,7 @@ impl fmt::Display for AllocError { /// # Safety /// /// Implementors of `Allocator` must ensure that a memory block that -/// are [*currently allocated*] by the allocator points to valid memory, +/// is [*currently allocated*] by the allocator points to valid memory, /// until that memory block is [*invalidated*]. The implementor must also /// not violate this invariant of `Allocator` via allocator equivalences /// that are in the implementor's control (e.g., via a misbehaving @@ -237,7 +248,7 @@ pub const unsafe trait Allocator { /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then the memory block referenced by `ptr` has been [*invalidated*]. - /// Any access to the old `ptr` is Undefined Behavior, even if the allocation was grown in-place. + /// The old `ptr` must not be used to access the memory, even if the allocation was grown in-place. /// The newly returned pointer is the only valid pointer for accessing this memory now. /// /// If this method returns `Err`, then the memory block has not been *invalidated*, @@ -365,7 +376,7 @@ pub const unsafe trait Allocator { /// /// /// If this returns `Ok`, then the memory block referenced by `ptr` has been [*invalidated*]. - /// Any access to the old `ptr` is Undefined Behavior, even if the allocation was shrunk in-place. + /// The old `ptr` must not be used to access the memory, even if the allocation was shrunk in-place. /// The newly returned pointer is the only valid pointer for accessing this memory now. /// /// If this method returns `Err`, then the memory block has not been *invalidated*, From 2d79bb6d6ef86983196ab66a7dafd555605c2952 Mon Sep 17 00:00:00 2001 From: Asger Hautop Drewsen Date: Thu, 18 Jun 2026 16:50:32 +0200 Subject: [PATCH 03/33] Fix sidebar heading order --- src/librustdoc/html/render/sidebar.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index beddac0f2613f..6fa033f927c85 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -346,12 +346,18 @@ fn sidebar_trait<'a>( ); sidebar_assoc_items(cx, it, blocks, deref_id_map); + // Move the foreign impls block after dyn compatibility note to match the order of the headings + // in the main content. + let foreign_impls_block = blocks.pop_if(|b| b.heading.href == "foreign-impls"); if !t.is_dyn_compatible(cx.tcx()) { blocks.push(LinkBlock::forced( Link::new("dyn-compatibility", "Dyn Compatibility"), "dyn-compatibility-note", )); } + if let Some(foreign_impls_block) = foreign_impls_block { + blocks.push(foreign_impls_block); + } blocks.push(LinkBlock::forced(Link::new("implementors", "Implementors"), "impl")); if t.is_auto(cx.tcx()) { From 0e252dfa22dd03f8a87f665d0ebe1192a5da07bf Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Thu, 30 Apr 2026 16:11:57 +0000 Subject: [PATCH 04/33] view types: add a few tests --- tests/ui/README.md | 7 ++++ tests/ui/view-types/must-be-struct.rs | 18 ++++++++ tests/ui/view-types/must-be-struct.stderr | 16 ++++++++ tests/ui/view-types/must-exist.rs | 16 ++++++++ tests/ui/view-types/must-exist.stderr | 16 ++++++++ tests/ui/view-types/must-restrict.rs | 18 ++++++++ tests/ui/view-types/must-restrict.stderr | 16 ++++++++ tests/ui/view-types/regression-156016.rs | 15 +++++++ tests/ui/view-types/regression-156016.stderr | 13 ++++++ tests/ui/view-types/syntax-errors.rs | 24 +++++++++++ tests/ui/view-types/syntax-errors.stderr | 43 ++++++++++++++++++++ tests/ui/view-types/tuple-structs.rs | 16 ++++++++ tests/ui/view-types/tuple-structs.stderr | 25 ++++++++++++ 13 files changed, 243 insertions(+) create mode 100644 tests/ui/view-types/must-be-struct.rs create mode 100644 tests/ui/view-types/must-be-struct.stderr create mode 100644 tests/ui/view-types/must-exist.rs create mode 100644 tests/ui/view-types/must-exist.stderr create mode 100644 tests/ui/view-types/must-restrict.rs create mode 100644 tests/ui/view-types/must-restrict.stderr create mode 100644 tests/ui/view-types/regression-156016.rs create mode 100644 tests/ui/view-types/regression-156016.stderr create mode 100644 tests/ui/view-types/syntax-errors.rs create mode 100644 tests/ui/view-types/syntax-errors.stderr create mode 100644 tests/ui/view-types/tuple-structs.rs create mode 100644 tests/ui/view-types/tuple-structs.stderr diff --git a/tests/ui/README.md b/tests/ui/README.md index 6ffef1a1cd699..eb6a790b12b1f 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -1579,6 +1579,13 @@ Tests on `enum` variants. **FIXME**: Should be rehomed with `tests/ui/enum/`. +## `tests/ui/view-types` + +Anything related to view types. + +See +[Tracking Issue for view types](https://github.com/rust-lang/rust/issues/155938). + ## `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. diff --git a/tests/ui/view-types/must-be-struct.rs b/tests/ui/view-types/must-be-struct.rs new file mode 100644 index 0000000000000..e71cf3d9ba554 --- /dev/null +++ b/tests/ui/view-types/must-be-struct.rs @@ -0,0 +1,18 @@ +#![feature(view_types, view_type_macro)] +//~ ERROR unknown feature `view_type_macro` +#![allow(unused)] + +use std::view::view_type; +//~ ERROR unresolved import + +enum Foo { + Bar, + Baz, +} + +// The following types are not structs, we expect errors here. +fn f(_: view_type!(Foo.{})) {} +fn g(_: view_type!(u8.{})) {} +fn h(_: view_type!(char.{})) {} + +fn main() {} diff --git a/tests/ui/view-types/must-be-struct.stderr b/tests/ui/view-types/must-be-struct.stderr new file mode 100644 index 0000000000000..7e0f8639fb558 --- /dev/null +++ b/tests/ui/view-types/must-be-struct.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `std::view` + --> $DIR/must-be-struct.rs:7:10 + | +LL | use std::view::view_type; + | ^^^^ could not find `view` in `std` + +error[E0635]: unknown feature `view_type_macro` + --> $DIR/must-be-struct.rs:3:24 + | +LL | #![feature(view_types, view_type_macro)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0432, E0635. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/view-types/must-exist.rs b/tests/ui/view-types/must-exist.rs new file mode 100644 index 0000000000000..5f85e190f1350 --- /dev/null +++ b/tests/ui/view-types/must-exist.rs @@ -0,0 +1,16 @@ +#![feature(view_types, view_type_macro)] +//~^ ERROR unknown feature `view_type_macro` +#![allow(unused)] + +use std::view::view_type; +//~^ ERROR unresolved import `std::view` + +struct S { + foo: (), +} + +// We expect errors here, since `S` has no field `bar`. +fn f(_: view_type!(S.{ bar })) {} +fn g(_: view_type!(S.{ foo, bar })) {} + +fn main() {} diff --git a/tests/ui/view-types/must-exist.stderr b/tests/ui/view-types/must-exist.stderr new file mode 100644 index 0000000000000..98e95218af92a --- /dev/null +++ b/tests/ui/view-types/must-exist.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `std::view` + --> $DIR/must-exist.rs:5:10 + | +LL | use std::view::view_type; + | ^^^^ could not find `view` in `std` + +error[E0635]: unknown feature `view_type_macro` + --> $DIR/must-exist.rs:1:24 + | +LL | #![feature(view_types, view_type_macro)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0432, E0635. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/view-types/must-restrict.rs b/tests/ui/view-types/must-restrict.rs new file mode 100644 index 0000000000000..9086c15592adb --- /dev/null +++ b/tests/ui/view-types/must-restrict.rs @@ -0,0 +1,18 @@ +#![feature(view_types, view_type_macro)] +//~^ ERROR unknown feature `view_type_macro` +#![allow(unused)] + +use std::view::view_type; +//~^ ERROR unresolved import + +struct S { + foo: (), + bar: (), +} + +// The outermost fields are supersets of the innermost views, we expect this to trigger an error. +fn f(_: view_type!(view_type!(S.{}).{ foo })) {} +fn g(_: view_type!(view_type!(S.{ foo }).{ bar })) {} +fn h(_: view_type!(view_type!(view_type!(S.{ foo }).{}).{ foo })) {} + +fn main() {} diff --git a/tests/ui/view-types/must-restrict.stderr b/tests/ui/view-types/must-restrict.stderr new file mode 100644 index 0000000000000..18af0471dfaf1 --- /dev/null +++ b/tests/ui/view-types/must-restrict.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `std::view` + --> $DIR/must-restrict.rs:5:10 + | +LL | use std::view::view_type; + | ^^^^ could not find `view` in `std` + +error[E0635]: unknown feature `view_type_macro` + --> $DIR/must-restrict.rs:1:24 + | +LL | #![feature(view_types, view_type_macro)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0432, E0635. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/view-types/regression-156016.rs b/tests/ui/view-types/regression-156016.rs new file mode 100644 index 0000000000000..cd58f49a9355b --- /dev/null +++ b/tests/ui/view-types/regression-156016.rs @@ -0,0 +1,15 @@ +// Regression reported in https://github.com/rust-lang/rust/pull/156016#discussion_r3453131612 + +#![feature(view_types)] + +macro_rules! m { + ($ty:ty) => { + compile_error!("ty fragment matched a view type"); + //~^ ERROR ty fragment matched a view type + }; + (&().{}) => {}; +} + +m!(&().{}); + +fn main() {} diff --git a/tests/ui/view-types/regression-156016.stderr b/tests/ui/view-types/regression-156016.stderr new file mode 100644 index 0000000000000..eecbe80f068b1 --- /dev/null +++ b/tests/ui/view-types/regression-156016.stderr @@ -0,0 +1,13 @@ +error: ty fragment matched a view type + --> $DIR/regression-156016.rs:7:9 + | +LL | compile_error!("ty fragment matched a view type"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(&().{}); + | ---------- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/view-types/syntax-errors.rs b/tests/ui/view-types/syntax-errors.rs new file mode 100644 index 0000000000000..fecf772e5c721 --- /dev/null +++ b/tests/ui/view-types/syntax-errors.rs @@ -0,0 +1,24 @@ +#![feature(view_types, view_type_macro)] +//~^ ERROR unknown feature `view_type_macro` +#![allow(unused)] + +use std::view::view_type; +//~^ ERROR unresolved import + +struct Foo { + bar: usize, + baz: usize, +} + +impl Foo { + fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} + //~^ ERROR invalid `self` parameter type + + fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} + //~^ ERROR invalid `self` parameter type + + fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {} + //~^ ERROR invalid `self` parameter type +} + +fn main() {} diff --git a/tests/ui/view-types/syntax-errors.stderr b/tests/ui/view-types/syntax-errors.stderr new file mode 100644 index 0000000000000..bd50a05b91b06 --- /dev/null +++ b/tests/ui/view-types/syntax-errors.stderr @@ -0,0 +1,43 @@ +error[E0432]: unresolved import `std::view` + --> $DIR/syntax-errors.rs:5:10 + | +LL | use std::view::view_type; + | ^^^^ could not find `view` in `std` + +error[E0635]: unknown feature `view_type_macro` + --> $DIR/syntax-errors.rs:1:24 + | +LL | #![feature(view_types, view_type_macro)] + | ^^^^^^^^^^^^^^^ + +error[E0307]: invalid `self` parameter type: `&mut ()` + --> $DIR/syntax-errors.rs:14:26 + | +LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0307]: invalid `self` parameter type: `&mut ()` + --> $DIR/syntax-errors.rs:17:22 + | +LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0307]: invalid `self` parameter type: `&mut ()` + --> $DIR/syntax-errors.rs:20:23 + | +LL | fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0307, E0432, E0635. +For more information about an error, try `rustc --explain E0307`. diff --git a/tests/ui/view-types/tuple-structs.rs b/tests/ui/view-types/tuple-structs.rs new file mode 100644 index 0000000000000..54875eba0cf10 --- /dev/null +++ b/tests/ui/view-types/tuple-structs.rs @@ -0,0 +1,16 @@ +#![feature(view_types, view_type_macro)] +//~^ ERROR unknown feature `view_type_macro` +#![allow(unused)] + +use std::view::view_type; +//~^ ERROR unresolved import + +struct Pair(usize, u32); + +impl Pair { + fn foo(self: &mut view_type!(Pair.{ 0, 1 })) {} + //~^ ERROR invalid `self` parameter type + fn bar(_pair: &mut view_type!(Pair.{ 0, 1 })) {} +} + +fn main() {} diff --git a/tests/ui/view-types/tuple-structs.stderr b/tests/ui/view-types/tuple-structs.stderr new file mode 100644 index 0000000000000..a11b8785fc35b --- /dev/null +++ b/tests/ui/view-types/tuple-structs.stderr @@ -0,0 +1,25 @@ +error[E0432]: unresolved import `std::view` + --> $DIR/tuple-structs.rs:5:10 + | +LL | use std::view::view_type; + | ^^^^ could not find `view` in `std` + +error[E0635]: unknown feature `view_type_macro` + --> $DIR/tuple-structs.rs:1:24 + | +LL | #![feature(view_types, view_type_macro)] + | ^^^^^^^^^^^^^^^ + +error[E0307]: invalid `self` parameter type: `&mut ()` + --> $DIR/tuple-structs.rs:11:18 + | +LL | fn foo(self: &mut view_type!(Pair.{ 0, 1 })) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0307, E0432, E0635. +For more information about an error, try `rustc --explain E0307`. From dcdf1331ffe136e631a8d67e81c077c1a7b1757c Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Tue, 28 Apr 2026 21:10:29 +0000 Subject: [PATCH 05/33] view-types: store view types in the AST --- compiler/rustc_ast/src/ast.rs | 2 + compiler/rustc_ast/src/util/classify.rs | 3 +- compiler/rustc_ast_lowering/src/lib.rs | 4 ++ compiler/rustc_ast_passes/src/feature_gate.rs | 3 + compiler/rustc_ast_pretty/src/pprust/state.rs | 18 ++++++ compiler/rustc_ast_pretty/src/pprust/tests.rs | 31 ++++++++- compiler/rustc_builtin_macros/src/lib.rs | 2 + .../rustc_builtin_macros/src/view_type.rs | 47 ++++++++++++++ compiler/rustc_parse/src/parser/mod.rs | 4 +- compiler/rustc_parse/src/parser/ty.rs | 21 +------ compiler/rustc_passes/src/input_stats.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/lib.rs | 3 + library/core/src/view.rs | 21 +++++++ library/std/src/lib.rs | 3 + library/std/src/view.rs | 3 + .../clippy_utils/src/check_proc_macro.rs | 1 + src/tools/rustfmt/src/types.rs | 8 +++ .../feature-gates/feature-gate-view-types.rs | 17 ----- .../feature-gate-view-types.stderr | 33 ---------- .../ui/view-types/feature-gate-view-types.rs | 13 ++++ .../view-types/feature-gate-view-types.stderr | 23 +++++++ tests/ui/view-types/must-be-struct.rs | 5 +- tests/ui/view-types/must-be-struct.stderr | 16 ----- tests/ui/view-types/must-exist.rs | 5 +- tests/ui/view-types/must-exist.stderr | 16 ----- tests/ui/view-types/must-restrict.rs | 5 +- tests/ui/view-types/must-restrict.stderr | 16 ----- tests/ui/view-types/regression-156016.rs | 5 +- tests/ui/view-types/regression-156016.stderr | 13 ---- tests/ui/view-types/syntax-errors.rs | 11 ++-- tests/ui/view-types/syntax-errors.stderr | 63 +++++++++++-------- tests/ui/view-types/tuple-structs.rs | 5 +- tests/ui/view-types/tuple-structs.stderr | 25 -------- 34 files changed, 243 insertions(+), 204 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/view_type.rs create mode 100644 library/core/src/view.rs create mode 100644 library/std/src/view.rs delete mode 100644 tests/ui/feature-gates/feature-gate-view-types.rs delete mode 100644 tests/ui/feature-gates/feature-gate-view-types.stderr create mode 100644 tests/ui/view-types/feature-gate-view-types.rs create mode 100644 tests/ui/view-types/feature-gate-view-types.stderr delete mode 100644 tests/ui/view-types/must-be-struct.stderr delete mode 100644 tests/ui/view-types/must-exist.stderr delete mode 100644 tests/ui/view-types/must-restrict.stderr delete mode 100644 tests/ui/view-types/regression-156016.stderr delete mode 100644 tests/ui/view-types/tuple-structs.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 11a531353eba0..bfb005046f841 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2564,6 +2564,8 @@ pub enum TyKind { /// Usually not written directly in user code but indirectly via the macro /// `core::field::field_of!(...)`. FieldOf(Box, Option, Ident), + /// A view of a type. `T.{ field_1, field_2 }`. + View(Box, #[visitable(ignore)] ThinVec), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 0c98b0e5e7b4f..56f96f9a8a279 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -302,7 +302,8 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { | ast::TyKind::Pat(..) | ast::TyKind::FieldOf(..) | ast::TyKind::Dummy - | ast::TyKind::Err(..) => break None, + | ast::TyKind::Err(..) + | ast::TyKind::View(..) => break None, } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b8d708d42ff10..8d6a22813999e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1707,6 +1707,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::TyKind::Err(guar) } + TyKind::View(ty, _) => { + // FIXME(scrabsha): lower view types to HIR. + return self.lower_ty(ty, itctx); + } TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"), }; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index d2e3c00bb0c07..aff6dc1b33032 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -285,6 +285,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::Pat(..) => { gate!(self, pattern_types, ty.span, "pattern types are unstable"); } + ast::TyKind::View(..) => { + gate!(self, view_types, ty.span, "view types are unstable"); + } _ => {} } visit::walk_ty(self, ty) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 8b2da2acaa520..106606877e110 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1259,6 +1259,20 @@ impl<'a> State<'a> { } } + fn print_view(&mut self, fields: &[Ident]) { + self.word(".{"); + + if !fields.is_empty() { + self.space(); + self.commasep(Consistent, fields, |s, field| { + s.print_ident(*field); + }); + self.space(); + } + + self.word("}"); + } + pub fn print_assoc_item_constraint(&mut self, constraint: &ast::AssocItemConstraint) { self.print_ident(constraint.ident); if let Some(args) = constraint.gen_args.as_ref() { @@ -1441,6 +1455,10 @@ impl<'a> State<'a> { self.end(ib); self.pclose(); } + ast::TyKind::View(ty, fields) => { + self.print_type(ty); + self.print_view(fields); + } } self.end(ib); } diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs index 786de529c5b89..4ef42ae8e4c3b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_span::{DUMMY_SP, Ident, create_default_session_globals_then}; -use thin_vec::ThinVec; +use thin_vec::{ThinVec, thin_vec}; use super::*; @@ -22,6 +22,12 @@ fn variant_to_string(var: &ast::Variant) -> String { to_string(|s| s.print_variant(var)) } +fn ty_to_string(ty: &ast::Ty) -> String { + to_string(|s| { + s.print_type(ty); + }) +} + #[test] fn test_fun_to_string() { create_default_session_globals_then(|| { @@ -60,3 +66,26 @@ fn test_variant_to_string() { assert_eq!(varstr, "principal_skinner"); }) } + +#[test] +fn test_field_view() { + create_default_session_globals_then(|| { + let ty = ast::Ty { + id: ast::DUMMY_NODE_ID, + kind: ast::TyKind::View( + Box::new(ast::Ty { + id: ast::DUMMY_NODE_ID, + kind: ast::TyKind::Dummy, + span: DUMMY_SP, + tokens: None, + }), + thin_vec![Ident::from_str("milhouse"), Ident::from_str("apu")], + ), + span: DUMMY_SP, + tokens: None, + }; + + let ty_str = ty_to_string(&ty); + assert_eq!(ty_str, "(/*DUMMY*/).{ milhouse, apu }"); + }); +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4a5ff44c402ab..bd99b269ef5b6 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -47,6 +47,7 @@ mod pattern_type; mod source_util; mod test; mod trace_macros; +mod view_type; pub mod asm; pub mod cmdline_attrs; @@ -99,6 +100,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { stringify: source_util::expand_stringify, trace_macros: trace_macros::expand_trace_macros, unreachable: edition_panic::expand_unreachable, + view_type: view_type::expand, // tidy-alphabetical-end } diff --git a/compiler/rustc_builtin_macros/src/view_type.rs b/compiler/rustc_builtin_macros/src/view_type.rs new file mode 100644 index 0000000000000..090603f4f1253 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/view_type.rs @@ -0,0 +1,47 @@ +use rustc_ast::token::TokenKind; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{Ty, ast}; +use rustc_errors::PResult; +use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_parse::parser::{ExpTokenPair, TokenType}; +use rustc_span::{Ident, Span}; +use thin_vec::ThinVec; + +pub(crate) fn expand<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + let (ty, pat) = match parse_view_ty(cx, tts) { + Ok(parsed) => parsed, + Err(err) => { + return ExpandResult::Ready(DummyResult::any(sp, err.emit())); + } + }; + + ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::View(ty, pat)))) +} + +fn parse_view_ty<'a>( + cx: &mut ExtCtxt<'a>, + stream: TokenStream, +) -> PResult<'a, (Box, ThinVec)> { + let mut parser = cx.new_parser_from_tts(stream); + + let ty = parser.parse_ty()?; + + parser.expect(ExpTokenPair { tok: TokenKind::Dot, token_type: TokenType::Dot })?; + + let fields = match parser.parse_delim_comma_seq( + ExpTokenPair { tok: TokenKind::OpenBrace, token_type: TokenType::OpenBrace }, + ExpTokenPair { tok: TokenKind::CloseBrace, token_type: TokenType::CloseBrace }, + |p| p.parse_field_name(), + ) { + Ok((fields, _)) => fields, + Err(diag) => { + return Err(diag); + } + }; + + Ok((ty, fields)) +} diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 64255d51a7c69..04a9b1ff212a7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1090,7 +1090,7 @@ impl<'a> Parser<'a> { /// Parses a comma-separated sequence, including both delimiters. /// The function `f` must consume tokens until reaching the next separator or /// closing bracket. - fn parse_delim_comma_seq( + pub fn parse_delim_comma_seq( &mut self, open: ExpTokenPair, close: ExpTokenPair, @@ -1355,7 +1355,7 @@ impl<'a> Parser<'a> { /// ```enbf /// FieldName = IntLit | Ident /// ``` - fn parse_field_name(&mut self) -> PResult<'a, Ident> { + pub fn parse_field_name(&mut self) -> PResult<'a, Ident> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { if let Some(suffix) = suffix { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8a881c6f8b568..e4996a4202d03 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -19,7 +19,7 @@ use crate::errors::{ NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; -use crate::parser::{ExpTokenPair, FnContext, FnParseMode}; +use crate::parser::{FnContext, FnParseMode}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; /// Signals whether parsing a type should allow `+`. @@ -768,25 +768,6 @@ impl<'a> Parser<'a> { self.bump_with((dyn_tok, dyn_tok_sp)); } let ty = self.parse_ty_no_plus()?; - if self.token == TokenKind::Dot && self.look_ahead(1, |t| t.kind == TokenKind::OpenBrace) { - // & [mut] . { } - // ^ - // we are here - let view_start_span = self.token.span; - self.bump(); - let fields = self - .parse_delim_comma_seq( - ExpTokenPair { tok: TokenKind::OpenBrace, token_type: TokenType::OpenBrace }, - ExpTokenPair { tok: TokenKind::CloseBrace, token_type: TokenType::CloseBrace }, - |p| p.parse_ident(), - )? - .0; - // FIXME(scrabsha): actually propagate field view in the AST. - let _ = fields; - let view_end_span = self.prev_token.span; - let span = view_start_span.to(view_end_span); - self.psess.gated_spans.gate(sym::view_types, span); - } Ok(match pinned { Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }), Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }), diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 2f3fbc28ad49d..d2bcf0359342c 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -690,6 +690,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { CVarArgs, Dummy, FieldOf, + View, Err ] ); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 827e33dcd6632..ad4c161d05576 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2306,6 +2306,7 @@ symbols! { vgpr384, vgpr512, vgpr1024, + view_type, view_types, vis, visible_private_types, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a26304c46ecea..216265c2915ff 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -350,6 +350,9 @@ mod bool; mod escape; mod tuple; mod unit; +#[cfg_attr(feature = "nightly", not(bootstrap))] +#[unstable(feature = "view_type_macro", issue = "155938")] +pub mod view; #[stable(feature = "core_primitive", since = "1.43.0")] pub mod primitive; diff --git a/library/core/src/view.rs b/library/core/src/view.rs new file mode 100644 index 0000000000000..68eca3f3598d2 --- /dev/null +++ b/library/core/src/view.rs @@ -0,0 +1,21 @@ +//! Helpers module for exporting the `view_types` macro. + +/// Creates a view type. +/// ``` +/// #![feature(view_types, view_type_macro)] +// +/// struct Foo { +/// bar: usize, +/// baz: u32, +/// } +/// +/// type FooBar = std::view::view_type!(Foo.{ bar }); +/// ``` +#[macro_export] +#[rustc_builtin_macro(view_type)] +#[unstable(feature = "view_type_macro", issue = "155938")] +macro_rules! view_type { + ($($arg:tt)*) => { + /* compiler built-in */ + }; +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c9e884d89c85e..14852bfc000b9 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -639,6 +639,9 @@ pub mod process; pub mod random; pub mod sync; pub mod time; +#[cfg_attr(feature = "nightly", not(bootstrap))] +#[unstable(feature = "view_type_macro", issue = "155938")] +pub mod view; // Pull in `std_float` crate into std. The contents of // `std_float` are in a different repository: rust-lang/portable-simd. diff --git a/library/std/src/view.rs b/library/std/src/view.rs new file mode 100644 index 0000000000000..5806cf27c2cc8 --- /dev/null +++ b/library/std/src/view.rs @@ -0,0 +1,3 @@ +//! Helper module for exporting the `view_types` macro. + +pub use core::view_type; diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 7b642fcd4ff9a..7400891f75b58 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -536,6 +536,7 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) { // experimental | TyKind::Pat(..) | TyKind::FieldOf(..) + | TyKind::View(..) // unused | TyKind::CVarArgs diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 2dfb5e5b28f61..cdba2ddc36e22 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1054,6 +1054,14 @@ impl Rewrite for ast::Ty { result.push_str(&rewrite); Ok(result) } + + ast::TyKind::View(..) => { + // This doesn't normally occur in the AST because macros aren't expanded. However, + // rustfmt tries to parse macro arguments when formatting macros, so it's not + // totally impossible for rustfmt to come across this node when formatting a file. + // Also, rustfmt might get passed the output from `-Zunpretty=expanded`. + Err(RewriteError::Unknown) + } } } } diff --git a/tests/ui/feature-gates/feature-gate-view-types.rs b/tests/ui/feature-gates/feature-gate-view-types.rs deleted file mode 100644 index eb0c26d61db4a..0000000000000 --- a/tests/ui/feature-gates/feature-gate-view-types.rs +++ /dev/null @@ -1,17 +0,0 @@ -struct Foo { - a: usize, - b: usize, -} - -fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - //~^ ERROR view types are experimental - //~| ERROR view types are experimental - a.a += 1; - b.b += 1; -} - -fn main() { - let mut foo = Foo { a: 0, b: 0 }; - bar(&mut foo, &mut foo); - //~^ ERROR cannot borrow `foo` as mutable more than once at a time -} diff --git a/tests/ui/feature-gates/feature-gate-view-types.stderr b/tests/ui/feature-gates/feature-gate-view-types.stderr deleted file mode 100644 index 661783ec59202..0000000000000 --- a/tests/ui/feature-gates/feature-gate-view-types.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0658]: view types are experimental - --> $DIR/feature-gate-view-types.rs:6:19 - | -LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^^^^^^ - | - = note: see issue #155938 for more information - = help: add `#![feature(view_types)]` 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]: view types are experimental - --> $DIR/feature-gate-view-types.rs:6:38 - | -LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^^^^^^ - | - = note: see issue #155938 for more information - = help: add `#![feature(view_types)]` 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[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/feature-gate-view-types.rs:15:19 - | -LL | bar(&mut foo, &mut foo); - | --- -------- ^^^^^^^^ second mutable borrow occurs here - | | | - | | first mutable borrow occurs here - | first borrow later used by call - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0499, E0658. -For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/view-types/feature-gate-view-types.rs b/tests/ui/view-types/feature-gate-view-types.rs new file mode 100644 index 0000000000000..961f96e18bb99 --- /dev/null +++ b/tests/ui/view-types/feature-gate-view-types.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Zno-analysis + +use std::view::view_type; + +struct Foo { + bar: (), + baz: (), +} + +type FooBar = view_type!(Foo.{ bar }); +//~^ ERROR use of unstable library feature `view_type_macro` +type FooBaz = view_type!(Foo.{ baz }); +//~^ ERROR use of unstable library feature `view_type_macro` diff --git a/tests/ui/view-types/feature-gate-view-types.stderr b/tests/ui/view-types/feature-gate-view-types.stderr new file mode 100644 index 0000000000000..407bf343ca13b --- /dev/null +++ b/tests/ui/view-types/feature-gate-view-types.stderr @@ -0,0 +1,23 @@ +error[E0658]: use of unstable library feature `view_type_macro` + --> $DIR/feature-gate-view-types.rs:10:15 + | +LL | type FooBar = view_type!(Foo.{ bar }); + | ^^^^^^^^^ + | + = note: see issue #155938 for more information + = help: add `#![feature(view_type_macro)]` 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]: use of unstable library feature `view_type_macro` + --> $DIR/feature-gate-view-types.rs:12:15 + | +LL | type FooBaz = view_type!(Foo.{ baz }); + | ^^^^^^^^^ + | + = note: see issue #155938 for more information + = help: add `#![feature(view_type_macro)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/view-types/must-be-struct.rs b/tests/ui/view-types/must-be-struct.rs index e71cf3d9ba554..43dbae587e4ab 100644 --- a/tests/ui/view-types/must-be-struct.rs +++ b/tests/ui/view-types/must-be-struct.rs @@ -1,9 +1,10 @@ +//@ known-bug: unknown +//@ run-pass + #![feature(view_types, view_type_macro)] -//~ ERROR unknown feature `view_type_macro` #![allow(unused)] use std::view::view_type; -//~ ERROR unresolved import enum Foo { Bar, diff --git a/tests/ui/view-types/must-be-struct.stderr b/tests/ui/view-types/must-be-struct.stderr deleted file mode 100644 index 7e0f8639fb558..0000000000000 --- a/tests/ui/view-types/must-be-struct.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0432]: unresolved import `std::view` - --> $DIR/must-be-struct.rs:7:10 - | -LL | use std::view::view_type; - | ^^^^ could not find `view` in `std` - -error[E0635]: unknown feature `view_type_macro` - --> $DIR/must-be-struct.rs:3:24 - | -LL | #![feature(view_types, view_type_macro)] - | ^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0432, E0635. -For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/view-types/must-exist.rs b/tests/ui/view-types/must-exist.rs index 5f85e190f1350..05792b01b3265 100644 --- a/tests/ui/view-types/must-exist.rs +++ b/tests/ui/view-types/must-exist.rs @@ -1,9 +1,10 @@ +//@ known-bug: unknown +//@ run-pass + #![feature(view_types, view_type_macro)] -//~^ ERROR unknown feature `view_type_macro` #![allow(unused)] use std::view::view_type; -//~^ ERROR unresolved import `std::view` struct S { foo: (), diff --git a/tests/ui/view-types/must-exist.stderr b/tests/ui/view-types/must-exist.stderr deleted file mode 100644 index 98e95218af92a..0000000000000 --- a/tests/ui/view-types/must-exist.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0432]: unresolved import `std::view` - --> $DIR/must-exist.rs:5:10 - | -LL | use std::view::view_type; - | ^^^^ could not find `view` in `std` - -error[E0635]: unknown feature `view_type_macro` - --> $DIR/must-exist.rs:1:24 - | -LL | #![feature(view_types, view_type_macro)] - | ^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0432, E0635. -For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/view-types/must-restrict.rs b/tests/ui/view-types/must-restrict.rs index 9086c15592adb..c0e1f5115d27c 100644 --- a/tests/ui/view-types/must-restrict.rs +++ b/tests/ui/view-types/must-restrict.rs @@ -1,9 +1,10 @@ +//@ known-bug: unknown +//@ run-pass + #![feature(view_types, view_type_macro)] -//~^ ERROR unknown feature `view_type_macro` #![allow(unused)] use std::view::view_type; -//~^ ERROR unresolved import struct S { foo: (), diff --git a/tests/ui/view-types/must-restrict.stderr b/tests/ui/view-types/must-restrict.stderr deleted file mode 100644 index 18af0471dfaf1..0000000000000 --- a/tests/ui/view-types/must-restrict.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0432]: unresolved import `std::view` - --> $DIR/must-restrict.rs:5:10 - | -LL | use std::view::view_type; - | ^^^^ could not find `view` in `std` - -error[E0635]: unknown feature `view_type_macro` - --> $DIR/must-restrict.rs:1:24 - | -LL | #![feature(view_types, view_type_macro)] - | ^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0432, E0635. -For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/view-types/regression-156016.rs b/tests/ui/view-types/regression-156016.rs index cd58f49a9355b..a39a94a8752f0 100644 --- a/tests/ui/view-types/regression-156016.rs +++ b/tests/ui/view-types/regression-156016.rs @@ -1,11 +1,10 @@ -// Regression reported in https://github.com/rust-lang/rust/pull/156016#discussion_r3453131612 +//@ run-pass -#![feature(view_types)] +// Regression reported in https://github.com/rust-lang/rust/pull/156016#discussion_r3453131612 macro_rules! m { ($ty:ty) => { compile_error!("ty fragment matched a view type"); - //~^ ERROR ty fragment matched a view type }; (&().{}) => {}; } diff --git a/tests/ui/view-types/regression-156016.stderr b/tests/ui/view-types/regression-156016.stderr deleted file mode 100644 index eecbe80f068b1..0000000000000 --- a/tests/ui/view-types/regression-156016.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: ty fragment matched a view type - --> $DIR/regression-156016.rs:7:9 - | -LL | compile_error!("ty fragment matched a view type"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | m!(&().{}); - | ---------- in this macro invocation - | - = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 1 previous error - diff --git a/tests/ui/view-types/syntax-errors.rs b/tests/ui/view-types/syntax-errors.rs index fecf772e5c721..19f5061cf820a 100644 --- a/tests/ui/view-types/syntax-errors.rs +++ b/tests/ui/view-types/syntax-errors.rs @@ -1,9 +1,7 @@ #![feature(view_types, view_type_macro)] -//~^ ERROR unknown feature `view_type_macro` #![allow(unused)] use std::view::view_type; -//~^ ERROR unresolved import struct Foo { bar: usize, @@ -12,13 +10,16 @@ struct Foo { impl Foo { fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} - //~^ ERROR invalid `self` parameter type + //~^ ERROR expected identifier + //~| ERROR expected identifier fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} - //~^ ERROR invalid `self` parameter type + //~^ ERROR expected identifier + //~| ERROR expected identifier fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {} - //~^ ERROR invalid `self` parameter type + //~^ ERROR expected one of + //~| ERROR expected one of } fn main() {} diff --git a/tests/ui/view-types/syntax-errors.stderr b/tests/ui/view-types/syntax-errors.stderr index bd50a05b91b06..86c167ca9a879 100644 --- a/tests/ui/view-types/syntax-errors.stderr +++ b/tests/ui/view-types/syntax-errors.stderr @@ -1,43 +1,52 @@ -error[E0432]: unresolved import `std::view` - --> $DIR/syntax-errors.rs:5:10 +error: expected identifier, found reserved identifier `_` + --> $DIR/syntax-errors.rs:12:48 | -LL | use std::view::view_type; - | ^^^^ could not find `view` in `std` +LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} + | ^ expected identifier, found reserved identifier -error[E0635]: unknown feature `view_type_macro` - --> $DIR/syntax-errors.rs:1:24 +error: expected identifier, found reserved identifier `_` + --> $DIR/syntax-errors.rs:12:79 | -LL | #![feature(view_types, view_type_macro)] - | ^^^^^^^^^^^^^^^ +LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} + | ^ expected identifier, found reserved identifier -error[E0307]: invalid `self` parameter type: `&mut ()` - --> $DIR/syntax-errors.rs:14:26 +error: expected identifier, found keyword `where` + --> $DIR/syntax-errors.rs:16:44 | -LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} + | ^^^^^ expected identifier, found keyword | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) +help: escape `where` to use it as an identifier + | +LL | fn keyword(self: &mut view_type!(Foo.{ r#where }), _: &mut view_type!(Foo.{ for })) {} + | ++ -error[E0307]: invalid `self` parameter type: `&mut ()` - --> $DIR/syntax-errors.rs:17:22 +error: expected identifier, found keyword `for` + --> $DIR/syntax-errors.rs:16:79 | LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ expected identifier, found keyword + | +help: escape `for` to use it as an identifier | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) +LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ r#for })) {} + | ++ -error[E0307]: invalid `self` parameter type: `&mut ()` - --> $DIR/syntax-errors.rs:20:23 +error: expected one of `,` or `}`, found `baz` + --> $DIR/syntax-errors.rs:20:49 | LL | fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -^^^ expected one of `,` or `}` + | | + | help: missing `,` + +error: expected one of `,` or `}`, found `baz` + --> $DIR/syntax-errors.rs:20:86 | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) +LL | fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {} + | -^^^ expected one of `,` or `}` + | | + | help: missing `,` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0307, E0432, E0635. -For more information about an error, try `rustc --explain E0307`. diff --git a/tests/ui/view-types/tuple-structs.rs b/tests/ui/view-types/tuple-structs.rs index 54875eba0cf10..f0442d4e308fb 100644 --- a/tests/ui/view-types/tuple-structs.rs +++ b/tests/ui/view-types/tuple-structs.rs @@ -1,15 +1,14 @@ +//@ run-pass + #![feature(view_types, view_type_macro)] -//~^ ERROR unknown feature `view_type_macro` #![allow(unused)] use std::view::view_type; -//~^ ERROR unresolved import struct Pair(usize, u32); impl Pair { fn foo(self: &mut view_type!(Pair.{ 0, 1 })) {} - //~^ ERROR invalid `self` parameter type fn bar(_pair: &mut view_type!(Pair.{ 0, 1 })) {} } diff --git a/tests/ui/view-types/tuple-structs.stderr b/tests/ui/view-types/tuple-structs.stderr deleted file mode 100644 index a11b8785fc35b..0000000000000 --- a/tests/ui/view-types/tuple-structs.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0432]: unresolved import `std::view` - --> $DIR/tuple-structs.rs:5:10 - | -LL | use std::view::view_type; - | ^^^^ could not find `view` in `std` - -error[E0635]: unknown feature `view_type_macro` - --> $DIR/tuple-structs.rs:1:24 - | -LL | #![feature(view_types, view_type_macro)] - | ^^^^^^^^^^^^^^^ - -error[E0307]: invalid `self` parameter type: `&mut ()` - --> $DIR/tuple-structs.rs:11:18 - | -LL | fn foo(self: &mut view_type!(Pair.{ 0, 1 })) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: type of `self` must be `Self` or a type that dereferences to it - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0307, E0432, E0635. -For more information about an error, try `rustc --explain E0307`. From 310bfad291cc0ff04a86fa1510a46f7ebdbe3644 Mon Sep 17 00:00:00 2001 From: sgasho Date: Thu, 4 Jun 2026 00:40:11 +0900 Subject: [PATCH 06/33] Enable Enzyme for x86_64-apple --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index f58b385db87ac..74f1a0abdde8e 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -474,7 +474,7 @@ auto: - name: dist-x86_64-apple env: SCRIPT: >- - ./x.py dist bootstrap + ./x.py dist bootstrap enzyme --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin From 34e0561ec6c5ff9d6df47491a4dbee71d9d48e1e Mon Sep 17 00:00:00 2001 From: sgasho Date: Thu, 4 Jun 2026 01:16:35 +0900 Subject: [PATCH 07/33] bump download-ci-llvm-stamp --- src/bootstrap/download-ci-llvm-stamp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index eb3f664e51b35..b61c7b18bad01 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/157557 +Last change is for: https://github.com/rust-lang/rust/pull/157385 From d8470753621c901d239bee25b0d642940c9b15b4 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Wed, 1 Jul 2026 16:35:43 +0700 Subject: [PATCH 08/33] Fix conditions of `&` API invalidating memory blocks. --- library/core/src/alloc/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index ec2f106e79364..806f67728efb8 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -123,9 +123,11 @@ impl fmt::Display for AllocError { /// * owning an allocator that memory block is allocated with, and /// * not publicly exposing `&mut` access to that allocator. /// -/// Also note that accessing an allocator with `&` access cannot invalidate -/// its memory blocks. Therefore, collections may safely expose `&` access -/// to its allocator. +/// Also note that safe public API of an allocator with `&` access is not +/// allowed to invalidate its memory blocks. Furthermore, unsafe public API +/// of an allocator with `&` access must document that they invalidate +/// memory blocks (e.g., by calling `deallocate`) if they do. Therefore, +/// collections may safely expose `&` access to its allocator. /// /// Also note that, even in cases where are other "alive" allocators known to be /// equivalent to a given collection's allocator, most collections still should From bf03fc384e14e557fd91eb77b4fbbb365d420d5b Mon Sep 17 00:00:00 2001 From: Piotr Kubaj Date: Wed, 1 Jul 2026 08:27:35 +0000 Subject: [PATCH 09/33] powerpc64le_unknown_freebsd.rs: link with -lgcc Starting with FreeBSD 16.0, powerpc64le switches to IEEE long double. 128 bit arithmetics are implemented in LLVM's compiler_rt, which is FreeBSD's libgcc. Link with it so that building on FreeBSD 16.0 succeeds - noop for earlier releases. --- .../src/spec/targets/powerpc64le_unknown_freebsd.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index 35c477d2bdaf8..1e6b9a7bdc267 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -1,12 +1,15 @@ use crate::spec::{ Arch, Cc, CfgAbi, LinkerFlavor, Lld, LlvmAbi, StackProbeType, Target, TargetMetadata, - TargetOptions, base, + TargetOptions, add_link_args, base, }; pub(crate) fn target() -> Target { let mut base = base::freebsd::opts(); base.cpu = "ppc64le".into(); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); + // long double is IEEE-128; f128 soft-float ops emit the PPC __*kf* helpers, + // which compiler_builtins lacks. Resolve them from base libgcc. + add_link_args(&mut base.late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-lgcc"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; base.cfg_abi = CfgAbi::ElfV2; From a00bdacb0a83c006f2a4b804cec2cf1bb16a9662 Mon Sep 17 00:00:00 2001 From: Rohan Singla Date: Fri, 3 Jul 2026 03:46:34 +0530 Subject: [PATCH 10/33] diagnostics: suggest type annotation for closure params on HRTB FnOnce mismatch --- .../nice_region_error/placeholder_error.rs | 49 ++++++++++++++++++- .../hrtb-closure-suggest-type-annotation.rs | 43 ++++++++++++++++ ...rtb-closure-suggest-type-annotation.stderr | 29 +++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 tests/ui/closures/hrtb-closure-suggest-type-annotation.rs create mode 100644 tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index e4a2aaff86aed..6b1af2314ed0a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -1,13 +1,14 @@ use std::fmt; use rustc_data_structures::intern::Interned; -use rustc_errors::{Diag, IntoDiagArg}; +use rustc_errors::{Applicability, Diag, IntoDiagArg}; +use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_middle::bug; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode}; -use rustc_middle::ty::{self, GenericArgsRef, RePlaceholder, Region, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, IsSuggestable, RePlaceholder, Region, TyCtxt}; use tracing::{debug, instrument}; use crate::diagnostics::{ @@ -379,6 +380,50 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { } } + // When the mismatched trait is an Fn-trait and the self type is a closure with + // unannotated parameters, suggest adding explicit type annotations. This turns + // the confusing lifetime-generality error into an actionable hint, e.g.: + // |buf| → |buf: &mut [u8]| + if self.tcx().is_fn_trait(trait_def_id) { + let actual_self_ty = self.cx.resolve_vars_if_possible( + ty::TraitRef::new_from_args(self.cx.tcx, trait_def_id, actual_args).self_ty(), + ); + if let ty::Closure(closure_def_id, _) = *actual_self_ty.kind() + && let Some(local_def_id) = closure_def_id.as_local() + && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = + self.tcx().hir_node_by_def_id(local_def_id) + { + let body = self.tcx().hir_body(closure.body); + // For Fn traits, args[1] is the tupled input types (e.g. `(&mut [u8],)`). + let expected_input_tys = expected_args.type_at(1); + if let ty::Tuple(input_tys) = *expected_input_tys.kind() { + let suggestions: Vec<_> = body + .params + .iter() + .zip(input_tys.iter()) + .filter_map(|(param, ty)| { + // ty_span == pat.span means no explicit type annotation was written. + if param.ty_span == param.pat.span + && ty.is_suggestable(self.tcx(), false) + { + Some((param.pat.span.shrink_to_hi(), format!(": {ty}"))) + } else { + None + } + }) + .collect(); + if !suggestions.is_empty() { + err.multipart_suggestion( + "consider adding an explicit type annotation to the closure \ + parameter to resolve the lifetime ambiguity", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + } + } + err } diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs b/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs new file mode 100644 index 0000000000000..0e3904d77517d --- /dev/null +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs @@ -0,0 +1,43 @@ +// When a closure is passed where a higher-ranked `FnOnce` is expected, but the closure +// parameter has no explicit type annotation, the compiler should suggest adding one. +// See . + +fn inner(buf: &mut [u8], func: F) -> usize +where + F: FnOnce(&mut [u8]) -> Result, +{ + match func(buf) { + Ok(n) => n, + Err(e) => e as usize, + } +} + +fn outer(buf: &mut [u8], func: F) -> usize +where + F: FnOnce(&mut [u8]) -> Result, +{ + let outer_closure = |buf| { + match func(buf) { + Ok(n) => { + println!("OK: {n}"); + Ok(n) + } + Err(e) => { + println!("ERR: {e}"); + Err(e) + } + } + }; + + inner(buf, outer_closure) + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough +} + +fn main() { + let mut x = [0u8; 16]; + let res = outer(&mut x, |buf| { + if buf.len() % 2 == 0 { Ok(buf.len()) } else { Err(buf.len() as isize) } + }); + println!("{res:?}"); +} diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr new file mode 100644 index 0000000000000..3e119f8379a4c --- /dev/null +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr @@ -0,0 +1,29 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/hrtb-closure-suggest-type-annotation.rs:32:5 + | +LL | inner(buf, outer_closure) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let outer_closure = |buf: &mut [u8]| { + | +++++++++++ + +error: implementation of `FnOnce` is not general enough + --> $DIR/hrtb-closure-suggest-type-annotation.rs:32:5 + | +LL | inner(buf, outer_closure) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let outer_closure = |buf: &mut [u8]| { + | +++++++++++ + +error: aborting due to 2 previous errors + From 155ead144d38968362b9effee52c12fac3bbbe43 Mon Sep 17 00:00:00 2001 From: Rohan Singla Date: Fri, 3 Jul 2026 03:46:37 +0530 Subject: [PATCH 11/33] test: bless existing UI tests affected by new closure type annotation suggestion --- ...ranked-auto-trait-15.no_assumptions.stderr | 8 +++++++ .../normalize-under-binder/issue-71955.stderr | 16 +++++++++++++ tests/ui/lifetimes/issue-105675.stderr | 24 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr index b4f3570d9f2da..ce58bee426b6b 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr @@ -6,6 +6,10 @@ LL | require_send(future); | = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | for _ in things.iter().map(|n: &Vec| n.iter()).flatten() { + | +++++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/higher-ranked-auto-trait-15.rs:20:5 @@ -16,6 +20,10 @@ LL | require_send(future); = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | for _ in things.iter().map(|n: &Vec| n.iter()).flatten() { + | +++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index b2bb417a8f01b..a85801fb1078f 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -6,6 +6,10 @@ LL | foo(bar, "string", |s| s.len() == 5); | = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | foo(bar, "string", |s: &&str| s.len() == 5); + | +++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:45:5 @@ -16,6 +20,10 @@ LL | foo(bar, "string", |s| s.len() == 5); = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | foo(bar, "string", |s: &&str| s.len() == 5); + | +++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 @@ -25,6 +33,10 @@ LL | foo(baz, "string", |s| s.0.len() == 5); | = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); + | ++++++++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-71955.rs:48:5 @@ -35,6 +47,10 @@ LL | foo(baz, "string", |s| s.0.len() == 5); = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); + | ++++++++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index 4b3d0e8ac5efc..a55eb267b104f 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -6,6 +6,10 @@ LL | thing(f); | = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let f = | _: &u32 , y: &u32 , z: u32 | (); + | ++++++ +++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:5:5 @@ -16,6 +20,10 @@ LL | thing(f); = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let f = | _: &u32 , y: &u32 , z: u32 | (); + | ++++++ +++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 @@ -25,6 +33,10 @@ LL | thing(f); | = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let f = | x: &u32, y: _ , z: u32 | (); + | ++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 @@ -34,6 +46,10 @@ LL | thing(f); | = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let f = | x: &u32, y: _ , z: u32 | (); + | ++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 @@ -44,6 +60,10 @@ LL | thing(f); = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let f = | x: &u32, y: _ , z: u32 | (); + | ++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-105675.rs:9:5 @@ -54,6 +74,10 @@ LL | thing(f); = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let f = | x: &u32, y: _ , z: u32 | (); + | ++++++ error: aborting due to 6 previous errors From 5817f14710392ebac8bee0ffa0a10c43c9535816 Mon Sep 17 00:00:00 2001 From: Rohan Singla Date: Fri, 3 Jul 2026 03:51:57 +0530 Subject: [PATCH 12/33] test: bless remaining UI tests affected by new closure type annotation suggestion --- tests/ui/lifetimes/issue-79187-2.stderr | 8 ++++++++ tests/ui/lifetimes/issue-79187.stderr | 8 ++++++++ .../closure-mismatch.current.stderr | 16 ++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index 78f6ce882dfab..a357332d5a2f0 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -24,6 +24,10 @@ LL | take_foo(|a| a); | = note: closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | take_foo(|a: &i32| a); + | ++++++ error: implementation of `Fn` is not general enough --> $DIR/issue-79187-2.rs:8:5 @@ -33,6 +37,10 @@ LL | take_foo(|a| a); | = note: closure with signature `fn(&'2 i32) -> &i32` must implement `Fn<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 i32,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | take_foo(|a: &i32| a); + | ++++++ error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:11:5 diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr index 8adde8d6dfbf3..59e45f13d6da9 100644 --- a/tests/ui/lifetimes/issue-79187.stderr +++ b/tests/ui/lifetimes/issue-79187.stderr @@ -6,6 +6,10 @@ LL | thing(f); | = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let f = |_: &u32| (); + | ++++++ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 @@ -16,6 +20,10 @@ LL | thing(f); = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | let f = |_: &u32| (); + | ++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/mismatched_types/closure-mismatch.current.stderr b/tests/ui/mismatched_types/closure-mismatch.current.stderr index 378fe83ea89bd..eaa4397c79d1c 100644 --- a/tests/ui/mismatched_types/closure-mismatch.current.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.current.stderr @@ -6,6 +6,10 @@ LL | baz(|_| ()); | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | baz(|_: &()| ()); + | +++++ error: implementation of `Fn` is not general enough --> $DIR/closure-mismatch.rs:12:5 @@ -15,6 +19,10 @@ LL | baz(|_| ()); | = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | baz(|_: &()| ()); + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/closure-mismatch.rs:16:5 @@ -24,6 +32,10 @@ LL | baz(|x| ()); | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | baz(|x: &()| ()); + | +++++ error: implementation of `Fn` is not general enough --> $DIR/closure-mismatch.rs:16:5 @@ -33,6 +45,10 @@ LL | baz(|x| ()); | = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity + | +LL | baz(|x: &()| ()); + | +++++ error: aborting due to 4 previous errors From b51d75e3a933cdce36627a0b531acb9521bef510 Mon Sep 17 00:00:00 2001 From: Sylvester Kpei Date: Fri, 3 Jul 2026 20:01:47 -0700 Subject: [PATCH 13/33] Clarify that LocalKey::try_with may return AccessError The docs stated that try_with will return an AccessError when the key has been destroyed. This is not guaranteed: on some platforms, TLS slots can be re-initialized during destruction, so the destroyed state cannot always be observed. Change 'will' to 'may' to accurately reflect the best-effort nature of the check. --- library/std/src/thread/local.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index ec0ba9970e479..8684bfab9da60 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -434,7 +434,7 @@ impl LocalKey { /// /// This will lazily initialize the value if this thread has not referenced /// this key yet. If the key has been destroyed (which may happen if this is called - /// in a destructor), this function will return an [`AccessError`]. + /// in a destructor), this function may return an [`AccessError`]. /// /// # Panics /// From 340e079cfe5fcd3a88ac6838e0a6570d432e1798 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sun, 5 Jul 2026 17:08:57 +0800 Subject: [PATCH 14/33] ci: use `ci-mirrors` in `armhf-gnu` for {busybox, ubuntu rootfs} artifacts --- src/ci/docker/host-x86_64/armhf-gnu/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile index a06331d88490b..f9a25a31c4930 100644 --- a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile @@ -47,7 +47,7 @@ RUN curl https://ci-mirrors.rust-lang.org/rustc/linux-4.14.336.tar.gz | \ # Compile an instance of busybox as this provides a lightweight system and init # binary which we will boot into. Only trick here is configuring busybox to # build static binaries. -RUN curl https://www.busybox.net/downloads/busybox-1.32.1.tar.bz2 | tar xjf - && \ +RUN curl https://ci-mirrors.rust-lang.org/rustc/busybox/busybox-1.32.1.tar.bz2 | tar xjf - && \ cd busybox-1.32.1 && \ make defconfig && \ sed -i 's/.*CONFIG_STATIC.*/CONFIG_STATIC=y/' .config && \ @@ -60,7 +60,7 @@ RUN curl https://www.busybox.net/downloads/busybox-1.32.1.tar.bz2 | tar xjf - && # Download the ubuntu rootfs, which we'll use as a chroot for all our tests. WORKDIR /tmp RUN mkdir rootfs/ubuntu -RUN curl https://cdimage.ubuntu.com/ubuntu-base/releases/22.04/release/ubuntu-base-22.04.2-base-armhf.tar.gz | \ +RUN curl https://ci-mirrors.rust-lang.org/rustc/ubuntu/ubuntu-base-22.04.2-base-armhf.tar.gz | \ tar xzf - -C rootfs/ubuntu && \ cd rootfs && mkdir proc sys dev etc etc/init.d From 0e0b98abb450465f196385b5c677b9e70d3e2ed6 Mon Sep 17 00:00:00 2001 From: Rohan Singla Date: Mon, 6 Jul 2026 02:30:55 +0530 Subject: [PATCH 15/33] diagnostics: improve suggestion message and add rustfix test for closure HRTB annotation --- .../nice_region_error/placeholder_error.rs | 12 ++--- ...ranked-auto-trait-15.no_assumptions.stderr | 4 +- ...hrtb-closure-suggest-type-annotation.fixed | 44 +++++++++++++++++++ .../hrtb-closure-suggest-type-annotation.rs | 1 + ...rtb-closure-suggest-type-annotation.stderr | 8 ++-- .../normalize-under-binder/issue-71955.stderr | 8 ++-- tests/ui/lifetimes/issue-105675.stderr | 12 ++--- tests/ui/lifetimes/issue-79187-2.stderr | 4 +- tests/ui/lifetimes/issue-79187.stderr | 4 +- .../closure-mismatch.current.stderr | 8 ++-- 10 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 tests/ui/closures/hrtb-closure-suggest-type-annotation.fixed diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 6b1af2314ed0a..f6887c18075a4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -413,12 +413,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { }) .collect(); if !suggestions.is_empty() { - err.multipart_suggestion( - "consider adding an explicit type annotation to the closure \ - parameter to resolve the lifetime ambiguity", - suggestions, - Applicability::MaybeIncorrect, - ); + let msg = if suggestions.len() == 1 { + "consider adding an explicit type annotation to the closure's argument" + } else { + "consider adding explicit type annotations to the closure's arguments" + }; + err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); } } } diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr index ce58bee426b6b..461b065d55ad3 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr @@ -6,7 +6,7 @@ LL | require_send(future); | = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | for _ in things.iter().map(|n: &Vec| n.iter()).flatten() { | +++++++++++ @@ -20,7 +20,7 @@ LL | require_send(future); = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | for _ in things.iter().map(|n: &Vec| n.iter()).flatten() { | +++++++++++ diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.fixed b/tests/ui/closures/hrtb-closure-suggest-type-annotation.fixed new file mode 100644 index 0000000000000..e4a948eb9f7bd --- /dev/null +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.fixed @@ -0,0 +1,44 @@ +//@ run-rustfix +// When a closure is passed where a higher-ranked `FnOnce` is expected, but the closure +// parameter has no explicit type annotation, the compiler should suggest adding one. +// See . + +fn inner(buf: &mut [u8], func: F) -> usize +where + F: FnOnce(&mut [u8]) -> Result, +{ + match func(buf) { + Ok(n) => n, + Err(e) => e as usize, + } +} + +fn outer(buf: &mut [u8], func: F) -> usize +where + F: FnOnce(&mut [u8]) -> Result, +{ + let outer_closure = |buf: &mut [u8]| { + match func(buf) { + Ok(n) => { + println!("OK: {n}"); + Ok(n) + } + Err(e) => { + println!("ERR: {e}"); + Err(e) + } + } + }; + + inner(buf, outer_closure) + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough +} + +fn main() { + let mut x = [0u8; 16]; + let res = outer(&mut x, |buf| { + if buf.len() % 2 == 0 { Ok(buf.len()) } else { Err(buf.len() as isize) } + }); + println!("{res:?}"); +} diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs b/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs index 0e3904d77517d..080874d8e236a 100644 --- a/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.rs @@ -1,3 +1,4 @@ +//@ run-rustfix // When a closure is passed where a higher-ranked `FnOnce` is expected, but the closure // parameter has no explicit type annotation, the compiler should suggest adding one. // See . diff --git a/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr index 3e119f8379a4c..51691c35f795b 100644 --- a/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr +++ b/tests/ui/closures/hrtb-closure-suggest-type-annotation.stderr @@ -1,18 +1,18 @@ error: implementation of `FnOnce` is not general enough - --> $DIR/hrtb-closure-suggest-type-annotation.rs:32:5 + --> $DIR/hrtb-closure-suggest-type-annotation.rs:33:5 | LL | inner(buf, outer_closure) | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough | = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | let outer_closure = |buf: &mut [u8]| { | +++++++++++ error: implementation of `FnOnce` is not general enough - --> $DIR/hrtb-closure-suggest-type-annotation.rs:32:5 + --> $DIR/hrtb-closure-suggest-type-annotation.rs:33:5 | LL | inner(buf, outer_closure) | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough @@ -20,7 +20,7 @@ LL | inner(buf, outer_closure) = note: closure with signature `fn(&'2 mut [u8]) -> Result` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | let outer_closure = |buf: &mut [u8]| { | +++++++++++ diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index a85801fb1078f..3c6aab12bf137 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -6,7 +6,7 @@ LL | foo(bar, "string", |s| s.len() == 5); | = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | foo(bar, "string", |s: &&str| s.len() == 5); | +++++++ @@ -20,7 +20,7 @@ LL | foo(bar, "string", |s| s.len() == 5); = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | foo(bar, "string", |s: &&str| s.len() == 5); | +++++++ @@ -33,7 +33,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5); | = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); | ++++++++++++++ @@ -47,7 +47,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5); = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | foo(baz, "string", |s: &Wrapper<'_>| s.0.len() == 5); | ++++++++++++++ diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index a55eb267b104f..db623761b268e 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -6,7 +6,7 @@ LL | thing(f); | = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding explicit type annotations to the closure's arguments | LL | let f = | _: &u32 , y: &u32 , z: u32 | (); | ++++++ +++++ @@ -20,7 +20,7 @@ LL | thing(f); = note: closure with signature `for<'a> fn(&'2 u32, &'a u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding explicit type annotations to the closure's arguments | LL | let f = | _: &u32 , y: &u32 , z: u32 | (); | ++++++ +++++ @@ -33,7 +33,7 @@ LL | thing(f); | = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | let f = | x: &u32, y: _ , z: u32 | (); | ++++++ @@ -46,7 +46,7 @@ LL | thing(f); | = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | let f = | x: &u32, y: _ , z: u32 | (); | ++++++ @@ -60,7 +60,7 @@ LL | thing(f); = note: closure with signature `fn(&'2 u32, &u32, u32)` must implement `FnOnce<(&'1 u32, &u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32, &u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | let f = | x: &u32, y: _ , z: u32 | (); | ++++++ @@ -74,7 +74,7 @@ LL | thing(f); = note: closure with signature `fn(&u32, &'2 u32, u32)` must implement `FnOnce<(&u32, &'1 u32, u32)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&u32, &'2 u32, u32)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | let f = | x: &u32, y: _ , z: u32 | (); | ++++++ diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index a357332d5a2f0..2731d0972d2bc 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -24,7 +24,7 @@ LL | take_foo(|a| a); | = note: closure with signature `fn(&'2 i32) -> &i32` must implement `FnOnce<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 i32,)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | take_foo(|a: &i32| a); | ++++++ @@ -37,7 +37,7 @@ LL | take_foo(|a| a); | = note: closure with signature `fn(&'2 i32) -> &i32` must implement `Fn<(&'1 i32,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 i32,)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | take_foo(|a: &i32| a); | ++++++ diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr index 59e45f13d6da9..e08400481e470 100644 --- a/tests/ui/lifetimes/issue-79187.stderr +++ b/tests/ui/lifetimes/issue-79187.stderr @@ -6,7 +6,7 @@ LL | thing(f); | = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | let f = |_: &u32| (); | ++++++ @@ -20,7 +20,7 @@ LL | thing(f); = note: closure with signature `fn(&'2 u32)` must implement `FnOnce<(&'1 u32,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 u32,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | let f = |_: &u32| (); | ++++++ diff --git a/tests/ui/mismatched_types/closure-mismatch.current.stderr b/tests/ui/mismatched_types/closure-mismatch.current.stderr index eaa4397c79d1c..82e3e4b0f78f2 100644 --- a/tests/ui/mismatched_types/closure-mismatch.current.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.current.stderr @@ -6,7 +6,7 @@ LL | baz(|_| ()); | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | baz(|_: &()| ()); | +++++ @@ -19,7 +19,7 @@ LL | baz(|_| ()); | = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | baz(|_: &()| ()); | +++++ @@ -32,7 +32,7 @@ LL | baz(|x| ()); | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | baz(|x: &()| ()); | +++++ @@ -45,7 +45,7 @@ LL | baz(|x| ()); | = note: closure with signature `fn(&'2 ())` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` -help: consider adding an explicit type annotation to the closure parameter to resolve the lifetime ambiguity +help: consider adding an explicit type annotation to the closure's argument | LL | baz(|x: &()| ()); | +++++ From 049b3a32ab90edb3bc1d6d299145d49f9f0adc26 Mon Sep 17 00:00:00 2001 From: Rohan Singla Date: Mon, 6 Jul 2026 03:40:43 +0530 Subject: [PATCH 16/33] test: bless nll UI tests affected by new closure type annotation suggestion --- tests/ui/nll/ice-106874.stderr | 32 +++++++++++++++++++ tests/ui/nll/issue-57843.stderr | 4 +++ ...missing-universe-cause-issue-114907.stderr | 16 ++++++++++ ...insensitive-scopes-issue-117146.nll.stderr | 8 +++++ ...sitive-scopes-issue-117146.polonius.stderr | 8 +++++ 5 files changed, 68 insertions(+) diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr index 629570b602ed6..45dd1557dd027 100644 --- a/tests/ui/nll/ice-106874.stderr +++ b/tests/ui/nll/ice-106874.stderr @@ -6,6 +6,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) | = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:5 @@ -16,6 +20,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: higher-ranked subtype error --> $DIR/ice-106874.rs:8:5 @@ -39,6 +47,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) | = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -48,6 +60,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) | = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -58,6 +74,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -68,6 +88,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -78,6 +102,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: implementation of `Fn` is not general enough --> $DIR/ice-106874.rs:8:7 @@ -88,6 +116,10 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | A(B(C::new(D::new(move |st: &mut V| f(st))))) + | ++++++++ error: aborting due to 10 previous errors diff --git a/tests/ui/nll/issue-57843.stderr b/tests/ui/nll/issue-57843.stderr index eed511460cac7..386f952c0541d 100644 --- a/tests/ui/nll/issue-57843.stderr +++ b/tests/ui/nll/issue-57843.stderr @@ -6,6 +6,10 @@ LL | Foo(Box::new(|_| ())); | = note: closure with signature `fn(&'2 bool)` must implement `FnOnce<(&'1 bool,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 bool,)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | Foo(Box::new(|_: &'a bool| ())); + | ++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr index c2e91edd13872..d8922ef80e813 100644 --- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -6,6 +6,10 @@ LL | accept(callback); | = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let callback = |_: &()| {}; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 @@ -16,6 +20,10 @@ LL | accept(callback); = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let callback = |_: &()| {}; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 @@ -26,6 +34,10 @@ LL | accept(callback); = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let callback = |_: &()| {}; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/missing-universe-cause-issue-114907.rs:33:5 @@ -36,6 +48,10 @@ LL | accept(callback); = note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let callback = |_: &()| {}; + | +++++ error: higher-ranked subtype error --> $DIR/missing-universe-cause-issue-114907.rs:33:5 diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 804b3f00a2642..0734eba1496d7 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -32,6 +32,10 @@ LL | bad(&b); | = note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let b = |_: &()| &a; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 @@ -41,6 +45,10 @@ LL | bad(&b); | = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let b = |_: &()| &a; + | +++++ error: aborting due to 3 previous errors diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 804b3f00a2642..0734eba1496d7 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -32,6 +32,10 @@ LL | bad(&b); | = note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let b = |_: &()| &a; + | +++++ error: implementation of `FnOnce` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 @@ -41,6 +45,10 @@ LL | bad(&b); | = note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` +help: consider adding an explicit type annotation to the closure's argument + | +LL | let b = |_: &()| &a; + | +++++ error: aborting due to 3 previous errors From b50b5b25c460a5acbb5fa101720452567adcbea8 Mon Sep 17 00:00:00 2001 From: Yukang Date: Sat, 4 Jul 2026 09:51:59 +0800 Subject: [PATCH 17/33] Avoid unused braces lint for macro-provided call arguments --- compiler/rustc_lint/src/unused.rs | 33 +++++++++++++-- ...unused-braces-macro-arg-issue-158747.fixed | 40 +++++++++++++++++++ .../unused-braces-macro-arg-issue-158747.rs | 40 +++++++++++++++++++ ...nused-braces-macro-arg-issue-158747.stderr | 19 +++++++++ 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 tests/ui/lint/unused-braces-macro-arg-issue-158747.fixed create mode 100644 tests/ui/lint/unused-braces-macro-arg-issue-158747.rs create mode 100644 tests/ui/lint/unused-braces-macro-arg-issue-158747.stderr diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 5d1b82b0bb48c..4c22310571f1a 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -417,13 +417,19 @@ trait UnusedDelimLint { } // either function/method call, or something this lint doesn't care about ref call_or_other => { - let (args_to_check, ctx) = match *call_or_other { - Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg), - MethodCall(ref call) => (&call.args[..], UnusedDelimsCtx::MethodArg), + let (args_to_check, ctx, callee_from_expansion) = match *call_or_other { + Call(ref callee, ref args) => { + (&args[..], UnusedDelimsCtx::FunctionArg, callee.span.from_expansion()) + } + MethodCall(ref call) => ( + &call.args[..], + UnusedDelimsCtx::MethodArg, + call.seg.ident.span.from_expansion(), + ), Closure(ref closure) if matches!(closure.fn_decl.output, FnRetTy::Default(_)) => { - (&[closure.body.clone()][..], UnusedDelimsCtx::ClosureBody) + (&[closure.body.clone()][..], UnusedDelimsCtx::ClosureBody, false) } // actual catch-all arm _ => { @@ -438,6 +444,11 @@ trait UnusedDelimLint { return; } for arg in args_to_check { + // Whether an expression is wrapped in a block can change which `macro_rules!` + // arm is taken. Don't report the braces as unused in that case. (Issue #158747) + if callee_from_expansion && Self::block_wraps_expanded_expr(arg) { + continue; + } self.check_unused_delims_expr(cx, arg, ctx, false, None, None, false); } return; @@ -516,6 +527,20 @@ trait UnusedDelimLint { false, ); } + + // Returns true for a user-written block whose only expression came from a macro expansion. + fn block_wraps_expanded_expr(value: &ast::Expr) -> bool { + if let ast::ExprKind::Block(ref block, None) = value.kind + && block.rules == ast::BlockCheckMode::Default + && !value.span.from_expansion() + && let [stmt] = block.stmts.as_slice() + && let ast::StmtKind::Expr(ref expr) = stmt.kind + { + expr.span.from_expansion() + } else { + false + } + } } declare_lint! { diff --git a/tests/ui/lint/unused-braces-macro-arg-issue-158747.fixed b/tests/ui/lint/unused-braces-macro-arg-issue-158747.fixed new file mode 100644 index 0000000000000..840b33352939c --- /dev/null +++ b/tests/ui/lint/unused-braces-macro-arg-issue-158747.fixed @@ -0,0 +1,40 @@ +//@ check-pass +//@ run-rustfix + +// Removing block braces can change how macro-generated calls match macro arguments. + +#![warn(unused_braces)] + +macro_rules! type_or_expr { + ($x:ty) => { + identity(stringify!($x)) + }; + ($x:expr) => { + identity($x) + }; +} + +macro_rules! call_expr { + ($e:expr) => { + identity($e) + }; +} + +macro_rules! call_block { + ($b:block) => { + identity($b) + }; +} + +fn identity(x: T) -> T { + x +} + +fn main() { + // should not warn + let _ = type_or_expr!({ format!("{}", 1) }); + // should not warn + let _ = call_expr!(1); + //~^ WARN unnecessary braces around function argument + let _ = call_block!({ 1 }); +} diff --git a/tests/ui/lint/unused-braces-macro-arg-issue-158747.rs b/tests/ui/lint/unused-braces-macro-arg-issue-158747.rs new file mode 100644 index 0000000000000..3d03ce38fddaa --- /dev/null +++ b/tests/ui/lint/unused-braces-macro-arg-issue-158747.rs @@ -0,0 +1,40 @@ +//@ check-pass +//@ run-rustfix + +// Removing block braces can change how macro-generated calls match macro arguments. + +#![warn(unused_braces)] + +macro_rules! type_or_expr { + ($x:ty) => { + identity(stringify!($x)) + }; + ($x:expr) => { + identity($x) + }; +} + +macro_rules! call_expr { + ($e:expr) => { + identity($e) + }; +} + +macro_rules! call_block { + ($b:block) => { + identity($b) + }; +} + +fn identity(x: T) -> T { + x +} + +fn main() { + // should not warn + let _ = type_or_expr!({ format!("{}", 1) }); + // should not warn + let _ = call_expr!({ 1 }); + //~^ WARN unnecessary braces around function argument + let _ = call_block!({ 1 }); +} diff --git a/tests/ui/lint/unused-braces-macro-arg-issue-158747.stderr b/tests/ui/lint/unused-braces-macro-arg-issue-158747.stderr new file mode 100644 index 0000000000000..4c6ed914cc6a4 --- /dev/null +++ b/tests/ui/lint/unused-braces-macro-arg-issue-158747.stderr @@ -0,0 +1,19 @@ +warning: unnecessary braces around function argument + --> $DIR/unused-braces-macro-arg-issue-158747.rs:37:24 + | +LL | let _ = call_expr!({ 1 }); + | ^^ ^^ + | +note: the lint level is defined here + --> $DIR/unused-braces-macro-arg-issue-158747.rs:6:9 + | +LL | #![warn(unused_braces)] + | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - let _ = call_expr!({ 1 }); +LL + let _ = call_expr!(1); + | + +warning: 1 warning emitted + From 448e0f865fdcbfbe5e45202f8cf568f7bb25a108 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 6 Jul 2026 15:05:28 +0900 Subject: [PATCH 18/33] add regression test for final RPITIT override panic --- tests/ui/traits/final/overriding-rpitit.rs | 18 ++++++++++++++++++ tests/ui/traits/final/overriding-rpitit.stderr | 14 ++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/ui/traits/final/overriding-rpitit.rs create mode 100644 tests/ui/traits/final/overriding-rpitit.stderr diff --git a/tests/ui/traits/final/overriding-rpitit.rs b/tests/ui/traits/final/overriding-rpitit.rs new file mode 100644 index 0000000000000..b44b470175ce4 --- /dev/null +++ b/tests/ui/traits/final/overriding-rpitit.rs @@ -0,0 +1,18 @@ +#![feature(final_associated_functions)] + +// Regression test for https://github.com/rust-lang/rust/issues/158824. + +trait Item { + final fn bar() -> impl Clone { + todo!() + } +} + +struct Foo; + +impl Item for Foo { + fn bar() -> impl Clone {} + //~^ ERROR cannot override `bar` because it already has a `final` definition in the trait +} + +fn main() {} diff --git a/tests/ui/traits/final/overriding-rpitit.stderr b/tests/ui/traits/final/overriding-rpitit.stderr new file mode 100644 index 0000000000000..b865171472bab --- /dev/null +++ b/tests/ui/traits/final/overriding-rpitit.stderr @@ -0,0 +1,14 @@ +error: cannot override `bar` because it already has a `final` definition in the trait + --> $DIR/overriding-rpitit.rs:14:5 + | +LL | fn bar() -> impl Clone {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: `bar` is marked final here + --> $DIR/overriding-rpitit.rs:6:5 + | +LL | final fn bar() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From 5a5f78dd6ab10e1e5ac75cc1ec11431d6ba14567 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 6 Jul 2026 15:05:43 +0900 Subject: [PATCH 19/33] avoid final override diagnostics for non-function associated items --- compiler/rustc_hir_analysis/src/check/check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index aa204a20e2d57..c3dff49be9927 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1254,7 +1254,7 @@ fn check_overriding_final_trait_item<'tcx>( trait_item: ty::AssocItem, impl_item: ty::AssocItem, ) { - if trait_item.defaultness(tcx).is_final() { + if trait_item.is_fn() && trait_item.defaultness(tcx).is_final() { tcx.dcx().emit_err(diagnostics::OverridingFinalTraitFunction { impl_span: tcx.def_span(impl_item.def_id), trait_span: tcx.def_span(trait_item.def_id), From de73ac0de32872979092ebc6397265de9930447c Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Wed, 24 Jun 2026 01:21:05 +0200 Subject: [PATCH 20/33] Fix typetree generation for arguments, like slices and re-enable their generation for memcpy. This moves a TA failure in the testcase from memcpy to a later location. --- compiler/rustc_ast/src/expand/typetree.rs | 6 + compiler/rustc_codegen_llvm/src/builder.rs | 2 +- .../src/builder/autodiff.rs | 27 ++- compiler/rustc_codegen_llvm/src/intrinsic.rs | 5 +- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 6 + compiler/rustc_codegen_llvm/src/llvm/mod.rs | 15 ++ compiler/rustc_codegen_llvm/src/typetree.rs | 169 ++++++++++++------ .../rustc_codegen_ssa/src/traits/builder.rs | 10 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 4 + compiler/rustc_middle/src/ty/typetree.rs | 78 +++++--- .../autodiff/type-trees/iter/rmake.rs | 25 +++ .../autodiff/type-trees/iter/window.rs | 53 ++++++ 12 files changed, 298 insertions(+), 102 deletions(-) create mode 100644 tests/run-make/autodiff/type-trees/iter/rmake.rs create mode 100644 tests/run-make/autodiff/type-trees/iter/window.rs diff --git a/compiler/rustc_ast/src/expand/typetree.rs b/compiler/rustc_ast/src/expand/typetree.rs index 9619c80904426..e9885165ae8f5 100644 --- a/compiler/rustc_ast/src/expand/typetree.rs +++ b/compiler/rustc_ast/src/expand/typetree.rs @@ -28,6 +28,9 @@ pub enum Kind { Anything, Integer, Pointer, + // We prefer to directly lower to things that our Enzyme backend supports. + // However, it's sometimes convenient to pass ptr+int as one type. + RustSlice, Half, Float, Double, @@ -57,6 +60,9 @@ impl TypeTree { } Self(ints) } + pub fn add_indirection(self) -> Self { + Self(vec![Type { offset: 0, size: 1, kind: Kind::Pointer, child: self }]) + } } #[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, StableHash)] diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 804547745c5d5..23cf01a84f7fd 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1180,7 +1180,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // vs. copying a struct with mixed types requires different derivative handling. // The TypeTree tells Enzyme exactly what memory layout to expect. if let Some(tt) = tt { - crate::typetree::add_tt(self.cx().llmod, self.cx().llcx, memcpy, tt); + crate::typetree::add_tt(self, memcpy, tt); } } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index ee17468ec0c03..10e152a7c8c63 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -143,7 +143,6 @@ pub(crate) fn adjust_activity_to_abi<'tcx>( // FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it // using iterators and peek()? fn match_args_from_caller_to_enzyme<'ll, 'tcx>( - cx: &SimpleCx<'ll>, builder: &mut Builder<'_, 'll, 'tcx>, width: u32, args: &mut Vec<&'ll Value>, @@ -157,6 +156,7 @@ fn match_args_from_caller_to_enzyme<'ll, 'tcx>( // need to match those. // FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it // using iterators and peek()? + let cx = &builder.scx; let mut outer_pos: usize = 0; let mut activity_pos = 0; @@ -292,8 +292,7 @@ fn match_args_from_caller_to_enzyme<'ll, 'tcx>( // FIXME(ZuseZ4): `outer_fn` should include upstream safety checks to // cover some assumptions of enzyme/autodiff, which could lead to UB otherwise. pub(crate) fn generate_enzyme_call<'ll, 'tcx>( - builder: &mut Builder<'_, 'll, 'tcx>, - cx: &SimpleCx<'ll>, + bx: &mut Builder<'_, 'll, 'tcx>, fn_to_diff: &'ll Value, outer_name: &str, ret_ty: &'ll Type, @@ -303,6 +302,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( dest_place: Option>, fnc_tree: FncTree, ) -> IntrinsicResult<'tcx, &'ll Value> { + let cx: &SimpleCx<'ll> = &bx.scx; // We have to pick the name depending on whether we want forward or reverse mode autodiff. let mut ad_name: String = match attrs.mode { DiffMode::Forward => "__enzyme_fwddiff", @@ -369,34 +369,27 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } - match_args_from_caller_to_enzyme( - &cx, - builder, - attrs.width, - &mut args, - &attrs.input_activity, - fn_args, - ); + match_args_from_caller_to_enzyme(bx, attrs.width, &mut args, &attrs.input_activity, fn_args); if !fnc_tree.args.is_empty() || !fnc_tree.ret.0.is_empty() { - crate::typetree::add_tt(cx.llmod, cx.llcx, fn_to_diff, fnc_tree); + crate::typetree::add_tt(&bx, fn_to_diff, fnc_tree); } - let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None); + let call = bx.call(enzyme_ty, None, None, ad_fn, &args, None, None); - let fn_ret_ty = builder.cx.val_ty(call); - if fn_ret_ty == builder.cx.type_void() || fn_ret_ty == builder.cx.type_struct(&[], false) { + let fn_ret_ty = bx.cx.val_ty(call); + if fn_ret_ty == bx.cx.type_void() || fn_ret_ty == bx.cx.type_struct(&[], false) { // If we return void or an empty struct, then our caller (due to how we generated it) // does not expect a return value. As such, we have no pointer (or place) into which // we could store our value, and would store into an undef, which would cause UB. // As such, we just ignore the return value in those cases. IntrinsicResult::Operand(OperandValue::ZeroSized) } else if let Some(dest_place) = dest_place { - builder.store_to_place(call, dest_place); + bx.store_to_place(call, dest_place); IntrinsicResult::WroteIntoPlace } else { IntrinsicResult::Operand( - OperandRef::from_immediate_or_packed_pair(builder, call, dest_layout).val, + OperandRef::from_immediate_or_packed_pair(bx, call, dest_layout).val, ) } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 7bd604bdbbd76..bd7a4cfe38d48 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -225,7 +225,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { ) } sym::autodiff => { - return codegen_autodiff(self, tcx, instance, args, result_layout, result_place); + return codegen_autodiff(self, instance, args, result_layout, result_place); } sym::offload => { if tcx.sess.opts.unstable_opts.offload.is_empty() { @@ -1743,12 +1743,12 @@ fn codegen_retag_inner<'ll, 'tcx>( fn codegen_autodiff<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, - tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>, args: &[OperandRef<'tcx, &'ll Value>], result_layout: ty::layout::TyAndLayout<'tcx>, result_place: Option>, ) -> IntrinsicResult<'tcx, &'ll Value> { + let tcx = bx.tcx; if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) { let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutEnable); } @@ -1815,7 +1815,6 @@ fn codegen_autodiff<'ll, 'tcx>( // Build body generate_enzyme_call( bx, - bx.cx, fn_to_diff, &diff_symbol, llret_ty, diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 195e050a9b651..68ec7870811d2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -66,6 +66,7 @@ unsafe extern "C" { NameLen: libc::size_t, ) -> Option<&Value>; + pub(crate) safe fn LLVMRustIsCall(V: &Value) -> bool; } unsafe extern "C" { @@ -292,6 +293,11 @@ pub(crate) mod Enzyme_AD { unsafe { (self.EnzymeTypeTreeToString)(tree) } } + pub(crate) fn tree_to_cstr(&self, tree: *mut EnzymeTypeTree) -> &std::ffi::CStr { + let c_str = self.tree_to_string(tree); + unsafe { std::ffi::CStr::from_ptr(c_str) } + } + pub(crate) fn tree_to_string_free(&self, ch: *const c_char) { unsafe { (self.EnzymeTypeTreeToStringFree)(ch) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index e9bc6ae0e80ef..a2d17e93b4996 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -76,6 +76,21 @@ pub(crate) fn CreateAttrStringValue<'ll>( ) } } +pub(crate) fn CreateAttrStringValueFromCStr<'ll>( + llcx: &'ll Context, + attr: &std::ffi::CStr, + value: &std::ffi::CStr, +) -> &'ll Attribute { + unsafe { + LLVMCreateStringAttribute( + llcx, + (*attr).as_ptr(), + (*attr).to_bytes().len() as c_uint, + (*value).as_ptr(), + (*value).to_bytes().len() as c_uint, + ) + } +} pub(crate) fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute { unsafe { diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs index 4f433f273c8cc..7c2e09227e46b 100644 --- a/compiler/rustc_codegen_llvm/src/typetree.rs +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -1,35 +1,47 @@ -use std::ffi::{CString, c_char, c_uint}; +use std::ffi::{CString, c_char}; -use rustc_ast::expand::typetree::{FncTree, TypeTree as RustTypeTree}; +use rustc_ast::expand::typetree::{FncTree, Kind, TypeTree as RustTypeTree}; use crate::attributes; +use crate::context::FullCx; use crate::llvm::{self, EnzymeWrapper, Value}; fn to_enzyme_typetree( - rust_typetree: RustTypeTree, + rust_typetree: &RustTypeTree, _data_layout: &str, llcx: &llvm::Context, -) -> llvm::TypeTree { +) -> (llvm::TypeTree, Vec) { let mut enzyme_tt = llvm::TypeTree::new(); - process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx); - enzyme_tt + let extra_ints = process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx); + + let mut int_vec = vec![]; + for _ in 0..extra_ints { + let mut int_tt = llvm::TypeTree::new(); + int_tt.insert(&[0], llvm::CConcreteType::DT_Integer, llcx); + int_vec.push(int_tt); + } + + (enzyme_tt, int_vec) } + fn process_typetree_recursive( enzyme_tt: &mut llvm::TypeTree, rust_typetree: &RustTypeTree, parent_indices: &[i64], llcx: &llvm::Context, -) { +) -> u32 { + let mut extra_ints = 0; for rust_type in &rust_typetree.0 { let concrete_type = match rust_type.kind { - rustc_ast::expand::typetree::Kind::Anything => llvm::CConcreteType::DT_Anything, - rustc_ast::expand::typetree::Kind::Integer => llvm::CConcreteType::DT_Integer, - rustc_ast::expand::typetree::Kind::Pointer => llvm::CConcreteType::DT_Pointer, - rustc_ast::expand::typetree::Kind::Half => llvm::CConcreteType::DT_Half, - rustc_ast::expand::typetree::Kind::Float => llvm::CConcreteType::DT_Float, - rustc_ast::expand::typetree::Kind::Double => llvm::CConcreteType::DT_Double, - rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_FP128, - rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown, + Kind::Anything => llvm::CConcreteType::DT_Anything, + Kind::Integer => llvm::CConcreteType::DT_Integer, + Kind::Pointer => llvm::CConcreteType::DT_Pointer, + Kind::RustSlice => llvm::CConcreteType::DT_Pointer, + Kind::Half => llvm::CConcreteType::DT_Half, + Kind::Float => llvm::CConcreteType::DT_Float, + Kind::Double => llvm::CConcreteType::DT_Double, + Kind::F128 => llvm::CConcreteType::DT_FP128, + Kind::Unknown => llvm::CConcreteType::DT_Unknown, }; let mut indices = parent_indices.to_vec(); @@ -43,21 +55,28 @@ fn process_typetree_recursive( enzyme_tt.insert(&indices, concrete_type, llcx); - if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer + if matches!(rust_type.kind, Kind::RustSlice) { + // We lower slices to `ptr,int`, so add the int here. + extra_ints += 1; + } + + if matches!(rust_type.kind, Kind::Pointer | Kind::RustSlice) && !rust_type.child.0.is_empty() { process_typetree_recursive(enzyme_tt, &rust_type.child, &indices, llcx); } } + extra_ints +} + +// Describes all the locations in which we know how to apply an Enzyme TypeTree. +enum TTLocation { + Definition, + Callsite, } #[cfg_attr(not(feature = "llvm_enzyme"), allow(unused))] -pub(crate) fn add_tt<'ll>( - llmod: &'ll llvm::Module, - llcx: &'ll llvm::Context, - fn_def: &'ll Value, - tt: FncTree, -) { +pub(crate) fn add_tt<'tcx, 'll>(cx: &FullCx<'ll, 'tcx>, fn_def: &'ll Value, tt: FncTree) { // TypeTree processing uses functions from Enzyme, which we might not have available if we did // not build this compiler with `llvm_enzyme`. This feature is not strictly necessary, but // skipping this function increases the chance that Enzyme fails to compile some code. @@ -66,6 +85,16 @@ pub(crate) fn add_tt<'ll>( #[cfg(not(feature = "llvm_enzyme"))] return; + let tcx = cx.tcx; + if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) { + return; + } + if tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::NoTT) { + return; + } + + let llmod = cx.llmod; + let llcx = cx.llcx; let inputs = tt.args; let ret_tt: RustTypeTree = tt.ret; @@ -77,41 +106,81 @@ pub(crate) fn add_tt<'ll>( let attr_name = "enzyme_type"; let c_attr_name = CString::new(attr_name).unwrap(); + let tt_location: TTLocation = + if llvm::LLVMRustIsCall(fn_def) { TTLocation::Callsite } else { TTLocation::Definition }; + + let mut offset = 0; for (i, input) in inputs.iter().enumerate() { - unsafe { - let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx); + let (enzyme_tt, extra_ints) = to_enzyme_typetree(&input, llvm_data_layout, llcx); + + // This scope is just a visual reminder that we *must* drop the enzyme_wrapper before + // we drop any typetrees (mainly enzyme_tt and extra_ints). Drop calls can not accept + // arguments like an enzyme_wrapper, so the typetree drop impl has to call get_instance + // on the static enzyme instance, which is behind a Mutex. Therefore we'd deadlock if we + // hold the enzyme_wrapper while dropping the typetrees. + { let enzyme_wrapper = EnzymeWrapper::get_instance(); - let c_str = enzyme_wrapper.tree_to_string(enzyme_tt.inner); - let c_str = std::ffi::CStr::from_ptr(c_str); - - let attr = llvm::LLVMCreateStringAttribute( - llcx, - c_attr_name.as_ptr(), - c_attr_name.as_bytes().len() as c_uint, - c_str.as_ptr(), - c_str.to_bytes().len() as c_uint, - ); - - attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]); + let c_str = enzyme_wrapper.tree_to_cstr(enzyme_tt.inner); + + let attr = llvm::CreateAttrStringValueFromCStr(llcx, &c_attr_name, &c_str); + let arg_pos = llvm::AttributePlace::Argument(i as u32 + offset); + // FIXME(autodiff): We currently know that this is correct for all the cases in which we + // call this function. But we should make it more robust for the future. + match tt_location { + TTLocation::Definition => { + attributes::apply_to_llfn(fn_def, arg_pos, &[attr]); + } + TTLocation::Callsite => { + attributes::apply_to_callsite(fn_def, arg_pos, &[attr]); + } + } enzyme_wrapper.tree_to_string_free(c_str.as_ptr()); + for v in &extra_ints { + offset += 1; + let c_str = enzyme_wrapper.tree_to_cstr(v.inner); + let int_attr = llvm::CreateAttrStringValueFromCStr(llcx, &c_attr_name, &c_str); + let arg_pos = llvm::AttributePlace::Argument(i as u32 + offset); + match tt_location { + TTLocation::Definition => { + attributes::apply_to_llfn(fn_def, arg_pos, &[int_attr]); + } + TTLocation::Callsite => { + attributes::apply_to_callsite(fn_def, arg_pos, &[int_attr]); + } + } + enzyme_wrapper.tree_to_string_free(c_str.as_ptr()); + } + } + } + // We will only fail this if Rust types got lowered to LLVM in a way that we didn't predict. + // Error, so we can learn from our mistakes. + if matches!(tt_location, TTLocation::Definition) { + let expected = offset as usize + inputs.len(); + let actual = llvm::count_params(fn_def) as usize; + if expected != actual { + tcx.dcx().warn(format!( + "autodiff type-tree failure. We expected {expected} LLVM argument(s), \ + but the generated LLVM function has {actual} parameter(s)" + )); } } - unsafe { - let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx); + // FIXME(autodiff): We should think more about what it means if a function returns a slice or + // other fat ptrs. + let (enzyme_tt, _extra_ints) = to_enzyme_typetree(&ret_tt, llvm_data_layout, llcx); + if ret_tt != RustTypeTree::new() { let enzyme_wrapper = EnzymeWrapper::get_instance(); - let c_str = enzyme_wrapper.tree_to_string(enzyme_tt.inner); - let c_str = std::ffi::CStr::from_ptr(c_str); - - let ret_attr = llvm::LLVMCreateStringAttribute( - llcx, - c_attr_name.as_ptr(), - c_attr_name.as_bytes().len() as c_uint, - c_str.as_ptr(), - c_str.to_bytes().len() as c_uint, - ); - - attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]); + let c_str = enzyme_wrapper.tree_to_cstr(enzyme_tt.inner); + let ret_attr = llvm::CreateAttrStringValueFromCStr(llcx, &c_attr_name, &c_str); + let arg_pos = llvm::AttributePlace::ReturnValue; + match tt_location { + TTLocation::Definition => { + attributes::apply_to_llfn(fn_def, arg_pos, &[ret_attr]); + } + TTLocation::Callsite => { + attributes::apply_to_callsite(fn_def, arg_pos, &[ret_attr]); + } + } enzyme_wrapper.tree_to_string_free(c_str.as_ptr()); } } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 39c2529152566..0d27ff90991b3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -2,10 +2,12 @@ use std::assert_matches; use std::ops::Deref; use rustc_abi::{Align, Scalar, Size, WrappingRange}; +use rustc_ast::expand::typetree::{FncTree, TypeTree}; use rustc_hir::attrs::AttributeKind; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; +use rustc_middle::ty::typetree::typetree_from_ty; use rustc_middle::ty::{AtomicOrdering, Instance, Ty}; use rustc_session::config::OptLevel; use rustc_span::Span; @@ -456,7 +458,7 @@ pub trait BuilderMethods<'a, 'tcx>: src_align: Align, size: Self::Value, flags: MemFlags, - tt: Option, + tt: Option, ); fn memmove( &mut self, @@ -517,6 +519,10 @@ pub trait BuilderMethods<'a, 'tcx>: let temp = self.load_operand(src.with_type(layout)); temp.val.store_with_flags(self, dst.with_type(layout), flags); } else if !layout.is_zst() { + let tt = typetree_from_ty(self.tcx(), layout.ty); + // We seem to pass all values to memcpy with one more indirection. + let tt = tt.add_indirection(); + let fnc_tree = FncTree { args: vec![tt.clone(), tt], ret: TypeTree::new() }; let bytes = self.const_usize(layout.size.bytes()); let bytes = if layout.peel_transparent_wrappers(self).ty.is_scalable_vector() { let vscale = self.vscale(self.type_i64()); @@ -524,7 +530,7 @@ pub trait BuilderMethods<'a, 'tcx>: } else { bytes }; - self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, None); + self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, Some(fnc_tree)); } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 3b8e6f6415365..f500041a12d8b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -160,6 +160,10 @@ extern "C" void LLVMRustPrintStatisticsJSON(RustStringRef OutBuf) { llvm::PrintStatisticsJSON(OS); } +extern "C" bool LLVMRustIsCall(LLVMValueRef V) { + return llvm::isa(llvm::unwrap(V)); +} + // Some of the functions here rely on LLVM modules that may not always be // available. As such, we only try to build it in the first place, if // llvm.offload is enabled. diff --git a/compiler/rustc_middle/src/ty/typetree.rs b/compiler/rustc_middle/src/ty/typetree.rs index 9e941bdb849ec..7e3f5b4ab3389 100644 --- a/compiler/rustc_middle/src/ty/typetree.rs +++ b/compiler/rustc_middle/src/ty/typetree.rs @@ -32,12 +32,19 @@ pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree { // Create TypeTree for return type let ret = typetree_from_ty(tcx, sig.output()); - FncTree { args, ret } + let f = FncTree { args, ret }; + f } /// Generate a TypeTree for a specific type. /// Mainly a convenience wrapper around the actual implementation. pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { + if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) { + return TypeTree::new(); + } + if tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::NoTT) { + return TypeTree::new(); + } let mut visited = Vec::new(); typetree_from_ty_impl_inner(tcx, ty, 0, &mut visited, false) } @@ -64,31 +71,29 @@ fn typetree_from_ty_impl_inner<'tcx>( } visited.push(ty); - if ty.is_scalar() { - let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { - (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) - } else if ty.is_floating_point() { - match ty { - x if x == tcx.types.f16 => (Kind::Half, 2), - x if x == tcx.types.f32 => (Kind::Float, 4), - x if x == tcx.types.f64 => (Kind::Double, 8), - x if x == tcx.types.f128 => (Kind::F128, 16), - _ => (Kind::Integer, 0), - } - } else { - (Kind::Integer, 0) - }; - - // Use offset 0 for scalars that are direct targets of references (like &f64) - // Use offset -1 for scalars used directly (like function return types) - let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 }; - return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]); + if ty.is_slice() { + bug!("incorrect autodiff typetree handling for slice: {}", ty); } if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { let Some(inner_ty) = ty.builtin_deref(true) else { - return TypeTree::new(); + bug!("incorrect autodiff typetree handling for type: {}", ty); }; + // slices are represented as `&'{erased} mut [f32]` + // This reads as a reference to a slice of f32. + // So we'd end up with ptr->RustSlice->f32 without this extra handling + if inner_ty.is_slice() { + if let ty::Slice(element_ty) = inner_ty.kind() { + let element_tree = + typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); + return TypeTree(vec![Type { + offset: -1, + size: tcx.data_layout.pointer_size().bytes_usize(), + kind: Kind::RustSlice, + child: element_tree, + }]); + } + } let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true); return TypeTree(vec![Type { @@ -121,14 +126,6 @@ fn typetree_from_ty_impl_inner<'tcx>( } } - if ty.is_slice() { - if let ty::Slice(element_ty) = ty.kind() { - let element_tree = - typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); - return element_tree; - } - } - if let ty::Tuple(tuple_types) = ty.kind() { if tuple_types.is_empty() { return TypeTree::new(); @@ -204,5 +201,28 @@ fn typetree_from_ty_impl_inner<'tcx>( } } + if ty.is_scalar() { + let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { + (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) + } else if ty.is_floating_point() { + match ty { + x if x == tcx.types.f16 => (Kind::Half, 2), + x if x == tcx.types.f32 => (Kind::Float, 4), + x if x == tcx.types.f64 => (Kind::Double, 8), + x if x == tcx.types.f128 => (Kind::F128, 16), + _ => bug!("Unexpected floating point type: {:?}", ty), + } + } else { + // is_scalar also accepts things like FnDef or FnPtr, for which we don't know how to + // generate a TypeTree, so return nothing. + return TypeTree::new(); + }; + + // Use offset 0 for scalars that are direct targets of references (like &f64) + // Use offset -1 for scalars used directly (like function return types) or slices. + let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 }; + return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]); + } + TypeTree::new() } diff --git a/tests/run-make/autodiff/type-trees/iter/rmake.rs b/tests/run-make/autodiff/type-trees/iter/rmake.rs new file mode 100644 index 0000000000000..4aca0771b7ee8 --- /dev/null +++ b/tests/run-make/autodiff/type-trees/iter/rmake.rs @@ -0,0 +1,25 @@ +//@ needs-enzyme +//@ ignore-cross-compile + +use run_make_support::{llvm_filecheck, rfs, rustc}; + +// This test passes in release mode. If we run it in Debug mode and don't lower any MIR info to +// LLVM TypeTrees, then it fails on deducing the type of a memcpy. If we lower info it still fails, +// but at a later location based on an extractvalue call. We will fix this in a future PR. + +fn main() { + rustc() + .input("window.rs") + .arg("-Zautodiff=Enable,NoTT") + .arg("-Clto=fat") + .run_fail() + .assert_stderr_contains("Enzyme: Cannot deduce type of copy"); + rustc() + .input("window.rs") + .arg("-Zautodiff=Enable") + .arg("-Clto=fat") + .emit("llvm-ir") + .run_fail() + .assert_stderr_contains("Enzyme: Cannot deduce type of extract"); + rustc().input("window.rs").arg("-Zautodiff=Enable,NoTT").arg("-Clto=fat").arg("-O").run(); +} diff --git a/tests/run-make/autodiff/type-trees/iter/window.rs b/tests/run-make/autodiff/type-trees/iter/window.rs new file mode 100644 index 0000000000000..7a6a6239fc23d --- /dev/null +++ b/tests/run-make/autodiff/type-trees/iter/window.rs @@ -0,0 +1,53 @@ +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +// This tests verifies that Enzyme can differentiate the iterator and window version of the for +// loops given below. Iterators (especially the windows use here) cause a lot of extra abstractions +// and indirections. Without extra typetree hints, Enzyme failed to differentiate them in debug +// mode. + +//@revisions: tt no_tt +//@[tt] compile-flags: -Z autodiff=Enable +//@[no_tt] compile-flags: -Z autodiff=Enable,NoTT +//@[no_tt] build-fail + +#[unsafe(no_mangle)] +#[inline(never)] +#[autodiff_reverse(f_rev, 2, Duplicated, Const, Duplicated)] +fn f(x: &[f64; 3], args: &[f64; 3], y: &mut [f64; 2]) { + y[0] = x.iter().map(|i| args[0] * i.powi(2)).sum(); + y[1] = x + .windows(2) + .map(|w| (args[1] - w[0]).powi(2) + args[2] * (w[1] - w[0].powi(2)).powi(2)) + .sum(); + // The iterators above are equivalent to the two following for loops. + // for i in 0..3 { + // y[0] += args[0] * x[i].powi(2); + // } + // for i in 0..2 { + // y[1] += (args[1] - x[i]).powi(2) + args[2] * (x[i + 1] - x[i].powi(2)).powi(2); + // } +} + +// Not generally recommended, but since we rewrite llvm-ir, it should be good enough. +fn assert_abs_diff_eq(x: &[f64; N], y: &[f64; N]) { + for i in 0..N { + assert_eq!(x[i], y[i]); + } +} + +fn main() { + let x = [3.0, 5.0, 7.0]; + let args = [2.0, 1.0, 100.0]; + + let mut vjp = ([0.0; 3], [0.0; 3]); + let mut y = [0.0; 2]; + let mut dy = ([1.0, 0.0], [0.0, 1.0]); + + f_rev(&x, &mut vjp.0, &mut vjp.1, &args, &mut y, &mut dy.0, &mut dy.1); + + assert_abs_diff_eq::<2>(&y, &[166.0, 34020.0]); + assert_abs_diff_eq::<3>(&vjp.0, &[12.0, 20.0, 28.0]); + assert_abs_diff_eq::<3>(&vjp.1, &[4804.0, 35208.0, -3600.0]); +} From 6bb1c076c8412e0c86c034682fb7f6f5a1b13cca Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 6 Jul 2026 23:09:23 +0200 Subject: [PATCH 21/33] Refactor the Type to TypeTree parser into a large match --- compiler/rustc_ast/src/expand/typetree.rs | 5 + compiler/rustc_middle/src/ty/typetree.rs | 191 ++++++++++------------ 2 files changed, 92 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_ast/src/expand/typetree.rs b/compiler/rustc_ast/src/expand/typetree.rs index e9885165ae8f5..00fea30ba94e5 100644 --- a/compiler/rustc_ast/src/expand/typetree.rs +++ b/compiler/rustc_ast/src/expand/typetree.rs @@ -78,6 +78,11 @@ pub struct Type { pub kind: Kind, pub child: TypeTree, } +impl Type { + pub fn from_ty(offset: isize, other: &Type) -> Self { + Self { offset, size: other.size, kind: other.kind, child: other.child.clone() } + } +} impl Type { pub fn add_offset(self, add: isize) -> Self { diff --git a/compiler/rustc_middle/src/ty/typetree.rs b/compiler/rustc_middle/src/ty/typetree.rs index 7e3f5b4ab3389..d4cda033a7e87 100644 --- a/compiler/rustc_middle/src/ty/typetree.rs +++ b/compiler/rustc_middle/src/ty/typetree.rs @@ -53,6 +53,40 @@ pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree { /// from pathological deeply nested types. Combined with cycle detection. const MAX_TYPETREE_DEPTH: usize = 6; +fn handle_indirection<'a>( + ty: Ty<'a>, + tcx: TyCtxt<'a>, + depth: usize, + visited: &mut Vec>, +) -> TypeTree { + let Some(inner_ty) = ty.builtin_deref(true) else { + bug!("incorrect autodiff typetree handling for type: {}", ty); + }; + // slices are represented as `&'{erased} mut [f32]` + // This reads as a reference to a slice of f32. + // So we'd end up with ptr->RustSlice->f32 without this extra handling + if inner_ty.is_slice() { + if let ty::Slice(element_ty) = inner_ty.kind() { + let element_tree = + typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); + return TypeTree(vec![Type { + offset: -1, + size: tcx.data_layout.pointer_size().bytes_usize(), + kind: Kind::RustSlice, + child: element_tree, + }]); + } + } + + let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true); + return TypeTree(vec![Type { + offset: -1, + size: tcx.data_layout.pointer_size().bytes_usize(), + kind: Kind::Pointer, + child, + }]); +} + /// Internal implementation with context about whether this is for a reference target. fn typetree_from_ty_impl_inner<'tcx>( tcx: TyCtxt<'tcx>, @@ -71,41 +105,12 @@ fn typetree_from_ty_impl_inner<'tcx>( } visited.push(ty); - if ty.is_slice() { - bug!("incorrect autodiff typetree handling for slice: {}", ty); - } - - if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() { - let Some(inner_ty) = ty.builtin_deref(true) else { - bug!("incorrect autodiff typetree handling for type: {}", ty); - }; - // slices are represented as `&'{erased} mut [f32]` - // This reads as a reference to a slice of f32. - // So we'd end up with ptr->RustSlice->f32 without this extra handling - if inner_ty.is_slice() { - if let ty::Slice(element_ty) = inner_ty.kind() { - let element_tree = - typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); - return TypeTree(vec![Type { - offset: -1, - size: tcx.data_layout.pointer_size().bytes_usize(), - kind: Kind::RustSlice, - child: element_tree, - }]); - } - } - - let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true); - return TypeTree(vec![Type { - offset: -1, - size: tcx.data_layout.pointer_size().bytes_usize(), - kind: Kind::Pointer, - child, - }]); - } - - if ty.is_array() { - if let ty::Array(element_ty, len_const) = ty.kind() { + match ty.kind() { + // See handle_indirection for an explanation on why we don't handle it here. + ty::Slice(..) => bug!("incorrect autodiff typetree handling for slice: {}", ty), + ty::Ref(..) | ty::RawPtr(..) => handle_indirection(ty, tcx, depth, visited), + ty::Adt(def, _) if def.is_box() => handle_indirection(ty, tcx, depth, visited), + ty::Array(element_ty, len_const) => { let len = len_const.try_to_target_usize(tcx).unwrap_or(0); if len == 0 { return TypeTree::new(); @@ -114,57 +119,44 @@ fn typetree_from_ty_impl_inner<'tcx>( typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false); let mut types = Vec::new(); for elem_type in &element_tree.0 { - types.push(Type { - offset: -1, - size: elem_type.size, - kind: elem_type.kind, - child: elem_type.child.clone(), - }); + types.push(Type::from_ty(-1, elem_type)); } - return TypeTree(types); - } - } - - if let ty::Tuple(tuple_types) = ty.kind() { - if tuple_types.is_empty() { - return TypeTree::new(); + TypeTree(types) } + ty::Tuple(tuple_types) => { + if tuple_types.is_empty() { + return TypeTree::new(); + } - let mut types = Vec::new(); - let mut current_offset = 0; + let mut types = Vec::new(); + let mut current_offset = 0; - for tuple_ty in tuple_types.iter() { - let element_tree = - typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false); + for tuple_ty in tuple_types.iter() { + let element_tree = + typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false); - let element_layout = tcx - .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty)) - .ok() - .map(|layout| layout.size.bytes_usize()) - .unwrap_or(0); + let element_layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty)) + .ok() + .map(|layout| layout.size.bytes_usize()) + .unwrap_or(0); - for elem_type in &element_tree.0 { - types.push(Type { - offset: if elem_type.offset == -1 { + for elem_type in &element_tree.0 { + let offset = if elem_type.offset == -1 { current_offset as isize } else { current_offset as isize + elem_type.offset - }, - size: elem_type.size, - kind: elem_type.kind, - child: elem_type.child.clone(), - }); + }; + types.push(Type::from_ty(offset, elem_type)); + } + + current_offset += element_layout; } - current_offset += element_layout; + TypeTree(types) } - - return TypeTree(types); - } - - if let ty::Adt(adt_def, args) = ty.kind() { - if adt_def.is_struct() { + ty::Adt(adt_def, args) if adt_def.is_struct() => { let struct_layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)); if let Ok(layout) = struct_layout { @@ -183,46 +175,37 @@ fn typetree_from_ty_impl_inner<'tcx>( let field_offset = layout.fields.offset(field_idx).bytes_usize(); for elem_type in &field_tree.0 { - types.push(Type { - offset: if elem_type.offset == -1 { - field_offset as isize - } else { - field_offset as isize + elem_type.offset - }, - size: elem_type.size, - kind: elem_type.kind, - child: elem_type.child.clone(), - }); + let offset = if elem_type.offset == -1 { + field_offset as isize + } else { + field_offset as isize + elem_type.offset + }; + types.push(Type::from_ty(offset, elem_type)); } } - return TypeTree(types); + TypeTree(types) + } else { + TypeTree::new() } } - } - - if ty.is_scalar() { - let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() { - (Kind::Integer, ty.primitive_size(tcx).bytes_usize()) - } else if ty.is_floating_point() { - match ty { + ty::Char | ty::Bool | ty::Infer(ty::IntVar(_)) | ty::Int(_) | ty::Uint(_) => { + let kind = Kind::Integer; + let size = ty.primitive_size(tcx).bytes_usize(); + let offset = if is_reference_target { 0 } else { -1 }; + TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]) + } + ty::Float(_) | ty::Infer(ty::FloatVar(_)) => { + let (enzyme_ty, size) = match ty { x if x == tcx.types.f16 => (Kind::Half, 2), x if x == tcx.types.f32 => (Kind::Float, 4), x if x == tcx.types.f64 => (Kind::Double, 8), x if x == tcx.types.f128 => (Kind::F128, 16), _ => bug!("Unexpected floating point type: {:?}", ty), - } - } else { - // is_scalar also accepts things like FnDef or FnPtr, for which we don't know how to - // generate a TypeTree, so return nothing. - return TypeTree::new(); - }; - - // Use offset 0 for scalars that are direct targets of references (like &f64) - // Use offset -1 for scalars used directly (like function return types) or slices. - let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 }; - return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]); + }; + let offset = if is_reference_target { 0 } else { -1 }; + TypeTree(vec![Type { offset, size, kind: enzyme_ty, child: TypeTree::new() }]) + } + _ => TypeTree::new(), } - - TypeTree::new() } From f13657cad6ee6ac53e8ab6035fc4e4f62b8f7cf6 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sun, 28 Jun 2026 15:04:48 -0500 Subject: [PATCH 22/33] Rename some body_id vars to body_def_id `body_id` is often used to mean "ID of a body-owning node", which is confusing since the obvious reading of "body ID" is wrong. `body_def_id` is easier to read as "body-owning definition ID". --- compiler/rustc_hir_analysis/src/autoderef.rs | 8 +- .../src/check/compare_impl_item.rs | 16 +-- compiler/rustc_hir_typeck/src/_match.rs | 4 +- compiler/rustc_hir_typeck/src/autoderef.rs | 2 +- compiler/rustc_hir_typeck/src/callee.rs | 8 +- compiler/rustc_hir_typeck/src/cast.rs | 13 ++- compiler/rustc_hir_typeck/src/coercion.rs | 18 +-- compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/expectation.rs | 4 +- compiler/rustc_hir_typeck/src/expr.rs | 26 +++-- .../rustc_hir_typeck/src/expr_use_visitor.rs | 2 +- compiler/rustc_hir_typeck/src/fallback.rs | 15 ++- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 10 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 10 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 10 +- .../src/fn_ctxt/suggestions.rs | 8 +- .../rustc_hir_typeck/src/gather_locals.rs | 2 +- compiler/rustc_hir_typeck/src/lib.rs | 2 +- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 5 +- .../rustc_hir_typeck/src/method/suggest.rs | 18 +-- compiler/rustc_hir_typeck/src/op.rs | 4 +- compiler/rustc_hir_typeck/src/opaque_types.rs | 13 ++- compiler/rustc_hir_typeck/src/writeback.rs | 4 +- .../rustc_infer/src/infer/opaque_types/mod.rs | 4 +- compiler/rustc_infer/src/traits/mod.rs | 4 +- compiler/rustc_middle/src/traits/mod.rs | 16 +-- .../src/error_reporting/infer/mod.rs | 5 +- .../src/error_reporting/infer/suggest.rs | 4 +- .../src/error_reporting/traits/ambiguity.rs | 27 ++--- .../traits/fulfillment_errors.rs | 20 ++-- .../src/error_reporting/traits/mod.rs | 2 +- .../traits/on_unimplemented.rs | 2 +- .../src/error_reporting/traits/overflow.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 103 ++++++++++-------- compiler/rustc_trait_selection/src/regions.rs | 14 +-- .../src/solve/fulfill/derive_errors.rs | 7 +- .../src/traits/effects.rs | 2 +- .../src/traits/engine.rs | 10 +- .../src/traits/fulfill.rs | 2 +- .../rustc_trait_selection/src/traits/misc.rs | 4 +- .../rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/outlives_bounds.rs | 14 +-- .../src/traits/project.rs | 6 +- .../src/traits/select/mod.rs | 4 +- .../rustc_trait_selection/src/traits/wf.rs | 26 ++--- compiler/rustc_ty_utils/src/ty.rs | 5 +- .../ice-generics-of-crate-root-152335.rs | 2 +- 48 files changed, 262 insertions(+), 231 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 20223b66405cd..a1a466e82c95e 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -34,7 +34,7 @@ pub struct Autoderef<'a, 'tcx> { // Meta infos: infcx: &'a InferCtxt<'tcx>, span: Span, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, // Current state: @@ -119,7 +119,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { Autoderef { infcx, span, - body_id: body_def_id, + body_def_id, param_env, state: AutoderefSnapshot { steps: vec![], @@ -149,7 +149,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { (tcx.lang_items().deref_trait()?, tcx.lang_items().deref_target()?) }; let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]); - let cause = traits::ObligationCause::misc(self.span, self.body_id); + let cause = traits::ObligationCause::misc(self.span, self.body_def_id); let obligation = traits::Obligation::new( tcx, cause.clone(), @@ -181,7 +181,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> { let ocx = ObligationCtxt::new(self.infcx); let normalized_ty = ocx.normalize( - &traits::ObligationCause::misc(self.span, self.body_id), + &traits::ObligationCause::misc(self.span, self.body_def_id), self.param_env, ty, ); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index af779152ed675..1379ac2175e0b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -177,10 +177,10 @@ fn compare_method_predicate_entailment<'tcx>( trait_m: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - // This node-id should be used for the `body_id` field on each + // This node-id should be used for the `body_def_id` field on each // `ObligationCause` (and the `FnCtxt`). // - // FIXME(@lcnr): remove that after removing `cause.body_id` from + // FIXME(@lcnr): remove that after removing `cause.body_def_id` from // obligations. let impl_m_def_id = impl_m.def_id.expect_local(); let impl_m_span = tcx.def_span(impl_m_def_id); @@ -798,7 +798,7 @@ struct ImplTraitInTraitCollector<'a, 'tcx, E> { types: FxIndexMap, ty::GenericArgsRef<'tcx>)>, span: Span, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + impl_m_id: LocalDefId, } impl<'a, 'tcx, E> ImplTraitInTraitCollector<'a, 'tcx, E> @@ -809,9 +809,9 @@ where ocx: &'a ObligationCtxt<'a, 'tcx, E>, span: Span, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + impl_m_id: LocalDefId, ) -> Self { - ImplTraitInTraitCollector { ocx, types: FxIndexMap::default(), span, param_env, body_id } + ImplTraitInTraitCollector { ocx, types: FxIndexMap::default(), span, param_env, impl_m_id } } } @@ -847,7 +847,7 @@ where { let pred = pred.fold_with(self); let pred = self.ocx.normalize( - &ObligationCause::misc(self.span, self.body_id), + &ObligationCause::misc(self.span, self.impl_m_id), self.param_env, Unnormalized::new_wip(pred), ); @@ -856,7 +856,7 @@ where self.cx(), ObligationCause::new( self.span, - self.body_id, + self.impl_m_id, ObligationCauseCode::WhereClause(def_id, pred_span), ), self.param_env, @@ -2346,7 +2346,7 @@ fn compare_type_predicate_entailment<'tcx>( return Ok(()); } - // This `DefId` should be used for the `body_id` field on each + // This `DefId` should be used for the `body_def_id` field on each // `ObligationCause` (and the `FnCtxt`). This is what // `regionck_item` expects. let impl_ty_def_id = impl_ty.def_id.expect_local(); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 3f3373d372ddd..ebf9907e64e64 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -216,7 +216,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm: Option<(Option, Ty<'tcx>, Span)>, ) { // First, check that we're actually in the tail of a function. - let Some(body) = self.tcx.hir_maybe_body_owned_by(self.body_id) else { + let Some(body) = self.tcx.hir_maybe_body_owned_by(self.body_def_id) else { return; }; let hir::ExprKind::Block(block, _) = body.value.kind else { @@ -233,7 +233,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Next, make sure that we have no type expectation. let Some(ret) = - self.tcx.hir_node_by_def_id(self.body_id).fn_decl().map(|decl| decl.output.span()) + self.tcx.hir_node_by_def_id(self.body_def_id).fn_decl().map(|decl| decl.output.span()) else { return; }; diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs index f7700179d2a3a..6b0707c901393 100644 --- a/compiler/rustc_hir_typeck/src/autoderef.rs +++ b/compiler/rustc_hir_typeck/src/autoderef.rs @@ -15,7 +15,7 @@ use super::{FnCtxt, PlaceOp}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { - Autoderef::new(self, self.param_env, self.body_id, span, base_ty) + Autoderef::new(self, self.param_env, self.body_def_id, span, base_ty) } pub(crate) fn try_overloaded_deref( diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index bb822f8d0f68d..e7c4c8c55304c 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -39,11 +39,11 @@ pub(crate) fn check_legal_trait_for_method_call( receiver: Option, expr_span: Span, trait_id: DefId, - body_id: DefId, + body_def_id: DefId, ) -> Result<(), ErrorGuaranteed> { if tcx.is_lang_item(trait_id, LangItem::Drop) // Allow calling `Drop::pin_drop` in `Drop::drop` - && !tcx.is_lang_item(tcx.parent(body_id), LangItem::Drop) + && !tcx.is_lang_item(tcx.parent(body_def_id), LangItem::Drop) { let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { diagnostics::ExplicitDestructorCallSugg::Snippet { @@ -1042,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_did: DefId, callee_args: GenericArgsRef<'tcx>, ) { - let const_context = self.tcx.hir_body_const_context(self.body_id); + let const_context = self.tcx.hir_body_const_context(self.body_def_id); if let hir::Constness::Const { always: true } = self.tcx.constness(callee_did) { match const_context { @@ -1062,7 +1062,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If we have `rustc_do_not_const_check`, do not check `[const]` bounds. - if self.has_rustc_attrs && find_attr!(self.tcx, self.body_id, RustcDoNotConstCheck) { + if self.has_rustc_attrs && find_attr!(self.tcx, self.body_def_id, RustcDoNotConstCheck) { return; } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index f7f0b69873e1e..a28ab5887de2b 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -64,7 +64,7 @@ pub(crate) struct CastCheck<'tcx> { cast_ty: Ty<'tcx>, cast_span: Span, span: Span, - pub body_id: LocalDefId, + pub body_def_id: LocalDefId, } /// The kind of pointer and associated metadata (thin, length or vtable) - we @@ -247,8 +247,15 @@ impl<'a, 'tcx> CastCheck<'tcx> { span: Span, ) -> Result, ErrorGuaranteed> { let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span); - let check = - CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, body_id: fcx.body_id }; + let check = CastCheck { + expr, + expr_ty, + expr_span, + cast_ty, + cast_span, + span, + body_def_id: fcx.body_def_id, + }; // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 2ecbb8863bf91..986e127ac6b8b 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1258,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sig = if fn_attrs.safe_target_features { // Allow the coercion if the current function has all the features that would be // needed to call the coercee safely. - match tcx.adjust_target_feature_sig(def_id, sig, self.body_id.into()) { + match tcx.adjust_target_feature_sig(def_id, sig, self.body_def_id.into()) { Some(adjusted_sig) => adjusted_sig, None if matches!(expected_safety, Some(hir::Safety::Safe)) => { return Err(TypeError::TargetFeatureCast(def_id)); @@ -1477,12 +1477,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn can_coerce<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, ty: Ty<'tcx>, output_ty: Ty<'tcx>, ) -> bool { - let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id); - let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id); + let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_def_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_def_id); fn_ctxt.may_coerce(ty, output_ty) } @@ -2057,7 +2057,7 @@ impl<'tcx> CoerceMany<'tcx> { if due_to_block && let Some(expr) = expression && let Some(parent_fn_decl) = - fcx.tcx.hir_fn_decl_by_hir_id(fcx.tcx.local_def_id_to_hir_id(fcx.body_id)) + fcx.tcx.hir_fn_decl_by_hir_id(fcx.tcx.local_def_id_to_hir_id(fcx.body_def_id)) { fcx.suggest_missing_break_or_return_expr( &mut err, @@ -2066,14 +2066,14 @@ impl<'tcx> CoerceMany<'tcx> { expected, found, block_or_return_id, - fcx.body_id, + fcx.body_def_id, ); } let is_return_position = fcx .tcx .hir_get_fn_id_for_return_block(block_or_return_id) - .is_some_and(|fn_id| fn_id == fcx.tcx.local_def_id_to_hir_id(fcx.body_id)); + .is_some_and(|fn_id| fn_id == fcx.tcx.local_def_id_to_hir_id(fcx.body_def_id)); if is_return_position && let Some(sp) = fcx.ret_coercion_span.get() @@ -2083,7 +2083,7 @@ impl<'tcx> CoerceMany<'tcx> { // may occur at the first return expression we see in the closure // (if it conflicts with the declared return type). Skip adding a // note in this case, since it would be incorrect. - && let Some(fn_sig) = fcx.body_fn_sig() + && let Some(fn_sig) = fcx.fn_sig() && fn_sig.output().is_ty_var() { err.span_note(sp, format!("return type inferred to be `{expected}` here")); @@ -2096,7 +2096,7 @@ impl<'tcx> CoerceMany<'tcx> { /// sure we consider `dyn Trait: Sized` where clauses, which are trivially /// false but technically valid for typeck. fn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool { - if let Some(sig) = fcx.body_fn_sig() { + if let Some(sig) = fcx.fn_sig() { !fcx.predicate_may_hold(&Obligation::new( fcx.tcx, ObligationCause::dummy(), diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index bd8295ba3a328..66c214a1be98a 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -332,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() }; - let body = self.tcx.hir_body_owned_by(self.body_id); + let body = self.tcx.hir_body_owned_by(self.body_def_id); expr_finder.visit_expr(body.value); // Replaces all of the variables in the given type with a fresh inference variable. diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index ab66e44032f93..37c8d7b2ae24e 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -76,9 +76,9 @@ impl<'a, 'tcx> Expectation<'tcx> { pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { let span = match ty.kind() { ty::Adt(adt_def, _) => fcx.tcx.def_span(adt_def.did()), - _ => fcx.tcx.def_span(fcx.body_id), + _ => fcx.tcx.def_span(fcx.body_def_id), }; - let cause = ObligationCause::misc(span, fcx.body_id); + let cause = ObligationCause::misc(span, fcx.body_def_id); // FIXME(#155345): Missing normalization call match fcx.tcx.struct_tail_raw(ty, &cause, |ty| ty.skip_normalization(), || {}).kind() { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 0cd80a6a83c87..5a30f0fb56c66 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -965,7 +965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return_expr_ty, ); - if let Some(fn_sig) = self.body_fn_sig() + if let Some(fn_sig) = self.fn_sig() && fn_sig.output().has_opaque_types() { // Point any obligations that were registered due to opaque type @@ -2764,8 +2764,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(self.tcx(), guar); } - let (ident, def_scope) = - self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.body_id); + let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope( + field, + base_def.did(), + self.body_def_id, + ); if let Some((idx, field)) = self.find_adt_field(*base_def, ident) { self.write_field_index(expr.hir_id, idx); @@ -2938,7 +2941,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_ident.span, "field not available in `impl Future`, but it is available in its `Output`", ); - match self.tcx.coroutine_kind(self.body_id) { + match self.tcx.coroutine_kind(self.body_def_id) { Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { err.span_suggestion_verbose( base.span.shrink_to_hi(), @@ -2949,7 +2952,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => { let mut span: MultiSpan = base.span.into(); - span.push_span_label(self.tcx.def_span(self.body_id), "this is not `async`"); + span.push_span_label(self.tcx.def_span(self.body_def_id), "this is not `async`"); err.span_note( span, "this implements `Future` and its output type has the field, \ @@ -3119,7 +3122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn point_at_param_definition(&self, err: &mut Diag<'_>, param: ty::ParamTy) { - let generics = self.tcx.generics_of(self.body_id); + let generics = self.tcx.generics_of(self.body_def_id); let generic_param = generics.type_param(param, self.tcx); if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind { return; @@ -3703,7 +3706,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 !find_attr!(self.tcx, self.body_id, Naked(..)) { + if !find_attr!(self.tcx, self.body_def_id, Naked(..)) { self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span }); } } @@ -3802,8 +3805,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit(); break; }; - let (subident, sub_def_scope) = - self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, self.body_id); + let (subident, sub_def_scope) = self.tcx.adjust_ident_and_get_scope( + subfield, + variant.def_id, + self.body_def_id, + ); let Some((subindex, field)) = variant .fields @@ -3854,7 +3860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope( field, container_def.did(), - self.body_id, + self.body_def_id, ); let fields = &container_def.non_enum_variant().fields; diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 7b39b953e3be0..96ede89664fea 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -217,7 +217,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { } fn body_owner_def_id(&self) -> LocalDefId { - self.body_id + self.body_def_id } fn tcx(&self) -> TyCtxt<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 9af35b55f40b1..0e34a6120b609 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -293,7 +293,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { root_vid: ty::TyVid, ) { let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| { - let unsafe_infer_vars = compute_unsafe_infer_vars(self, self.body_id); + let unsafe_infer_vars = compute_unsafe_infer_vars(self, self.body_def_id); debug!(?unsafe_infer_vars); unsafe_infer_vars }); @@ -378,8 +378,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let sugg = self.try_to_suggest_annotations(diverging_vids, coercions); self.tcx.emit_node_span_lint( lint::builtin::DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, - self.tcx.local_def_id_to_hir_id(self.body_id), - self.tcx.def_span(self.body_id), + self.tcx.local_def_id_to_hir_id(self.body_def_id), + self.tcx.def_span(self.body_def_id), diagnostics::DependencyOnUnitNeverTypeFallback { obligation_span: never_error.obligation.cause.span, obligation: never_error.obligation.predicate, @@ -446,8 +446,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { diverging_vids: &[ty::TyVid], coercions: &VecGraph, ) -> diagnostics::SuggestAnnotations { - let body = - self.tcx.hir_maybe_body_owned_by(self.body_id).expect("body id must have an owner"); + let body = self.tcx.hir_body_owned_by(self.body_def_id); // For each diverging var, look through the HIR for a place to give it // a type annotation. We do this per var because we only really need one // suggestion to influence a var to be `()`. @@ -633,9 +632,9 @@ pub(crate) enum UnsafeUseReason { /// `compute_unsafe_infer_vars` will return `{ id(?X) -> (hir_id, span, Call) }` fn compute_unsafe_infer_vars<'a, 'tcx>( fcx: &'a FnCtxt<'a, 'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, ) -> UnordMap { - let body = fcx.tcx.hir_maybe_body_owned_by(body_id).expect("body id must have an owner"); + let body = fcx.tcx.hir_body_owned_by(body_def_id); let mut res = UnordMap::default(); struct UnsafeInferVarsVisitor<'a, 'tcx> { @@ -763,7 +762,7 @@ fn compute_unsafe_infer_vars<'a, 'tcx>( UnsafeInferVarsVisitor { fcx, res: &mut res }.visit_expr(&body.value); - debug!(?res, "collected the following unsafe vars for {body_id:?}"); + debug!(?res, "collected the following unsafe vars for {body_def_id:?}"); res } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 37e198d51a831..9a1b1f8300957 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -213,7 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // let it keep doing that and just ensure that compilation won't succeed. self.dcx().span_delayed_bug( self.tcx.hir_span(id), - format!("`{prev}` overridden by `{ty}` for {id:?} in {:?}", self.body_id), + format!("`{prev}` overridden by `{ty}` for {id:?} in {:?}", self.body_def_id), ); } } @@ -1070,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_span, span, container_id, - self.body_id.to_def_id(), + self.body_def_id.to_def_id(), ) { self.set_tainted_by_errors(e); } @@ -1192,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // error in `validate_res_from_ribs` -- it's just difficult to tell whether the // self type has any generic types during rustc_resolve, which is what we use // to determine if this is a hard error or warning. - if std::iter::successors(Some(self.body_id.to_def_id()), |&def_id| { + if std::iter::successors(Some(self.body_def_id.to_def_id()), |&def_id| { self.tcx.generics_of(def_id).parent }) .all(|def_id| def_id != impl_def_id) @@ -1534,7 +1534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let guar = self.tainted_by_errors().unwrap_or_else(|| { self.err_ctxt() .emit_inference_failure_err( - self.body_id, + self.body_def_id, sp, ty.into(), TypeAnnotationNeeded::E0282, @@ -1560,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let e = self.tainted_by_errors().unwrap_or_else(|| { self.err_ctxt() .emit_inference_failure_err( - self.body_id, + self.body_def_id, sp, ct.into(), TypeAnnotationNeeded::E0282, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7d85a5a4ded63..1b6f366b9d133 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -68,9 +68,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut deferred_cast_checks = self.root_ctxt.deferred_cast_checks.borrow_mut(); debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len()); for cast in deferred_cast_checks.drain(..) { - let body_id = std::mem::replace(&mut self.body_id, cast.body_id); + let body_def_id = std::mem::replace(&mut self.body_def_id, cast.body_def_id); cast.check(self); - self.body_id = body_id; + self.body_def_id = body_def_id; } } @@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in `execute_delegation_aware_arguments_check`. let checked_ty = self .tcx - .hir_opt_delegation_info(self.body_id) + .hir_opt_delegation_info(self.body_def_id) .and_then(|_| self.typeck_results.borrow().node_type_opt(provided_arg.hir_id)) .unwrap_or_else(|| self.check_expr_with_expectation(provided_arg, expectation)); @@ -1627,7 +1627,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let callee_ty = callee_ty.peel_refs(); match *callee_ty.kind() { ty::Param(param) => { - let param = self.tcx.generics_of(self.body_id).type_param(param, self.tcx); + let param = self.tcx.generics_of(self.body_def_id).type_param(param, self.tcx); if param.kind.is_synthetic() { // if it's `impl Fn() -> ..` then just fall down to the def-id based logic def_id = param.def_id; @@ -1636,7 +1636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // and point at that. let instantiated = self .tcx - .explicit_predicates_of(self.body_id) + .explicit_predicates_of(self.body_def_id) .instantiate_identity(self.tcx); // FIXME(compiler-errors): This could be problematic if something has two // fn-like predicates with different args, but callable types really never diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 6d2e36e081a5e..e9f935ba73cf9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -43,7 +43,7 @@ use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt}; /// /// [`InferCtxt`]: infer::InferCtxt pub(crate) struct FnCtxt<'a, 'tcx> { - pub(super) body_id: LocalDefId, + pub(super) body_def_id: LocalDefId, /// The parameter environment used for proving trait obligations /// in this function. This can change when we descend into @@ -138,12 +138,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn new( root_ctxt: &'a TypeckRootCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, ) -> FnCtxt<'a, 'tcx> { let (diverging_fallback_behavior, diverging_block_behavior) = never_type_behavior(root_ctxt.tcx); FnCtxt { - body_id, + body_def_id, param_env, ret_coercion: None, ret_coercion_span: Cell::new(None), @@ -179,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, code: ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { - ObligationCause::new(span, self.body_id, code) + ObligationCause::new(span, self.body_def_id, code) } pub(crate) fn misc(&self, span: Span) -> ObligationCause<'tcx> { @@ -230,7 +230,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { } fn item_def_id(&self) -> LocalDefId { - self.body_id + self.body_def_id } fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index b3fec86229fae..6fb72f414a049 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -40,11 +40,11 @@ use crate::method::probe; use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub(crate) fn body_fn_sig(&self) -> Option> { + pub(crate) fn fn_sig(&self) -> Option> { self.typeck_results .borrow() .liberated_fn_sigs() - .get(self.tcx.local_def_id_to_hir_id(self.body_id)) + .get(self.tcx.local_def_id_to_hir_id(self.body_def_id)) .copied() } @@ -170,7 +170,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec>)> { - self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty) + self.err_ctxt().extract_callable_info(self.body_def_id, self.param_env, ty) } pub(crate) fn suggest_two_fn_call( @@ -2292,7 +2292,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; }; let ret_ty_matches = |diagnostic_item| { - let Some(sig) = self.body_fn_sig() else { + let Some(sig) = self.fn_sig() else { return false; }; let ty::Adt(kind, _) = sig.output().kind() else { diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 85c8400f227bd..21954203a705a 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -193,7 +193,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // ascription, or if it's an implicit `self` parameter ObligationCauseCode::SizedArgumentType( if ty_span == ident.span - && self.fcx.tcx.is_closure_like(self.fcx.body_id.into()) + && self.fcx.tcx.is_closure_like(self.fcx.body_def_id.into()) { None } else { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 335caf571aa6f..6b5f084fc3dbe 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -378,7 +378,7 @@ fn extend_err_with_const_context( fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Option> { let tcx = fcx.tcx; - let def_id = fcx.body_id; + let def_id = fcx.body_def_id; let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty() { if let Some(item) = tcx.opt_associated_item(def_id.into()) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index d5169cd30aa9a..d5dc17837f1ed 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -702,7 +702,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { Some(self.self_expr.span), self.call_expr.span, trait_def_id, - self.body_id.to_def_id(), + self.body_def_id.to_def_id(), ) { self.set_tainted_by_errors(e); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index ce22ab937391e..811f0eafec16b 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -511,7 +511,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !self.tcx.features().arbitrary_self_types(); let mut err = self.err_ctxt().emit_inference_failure_err( - self.body_id, + self.body_def_id, err_span, ty.into(), TypeAnnotationNeeded::E0282, @@ -811,7 +811,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let is_accessible = if let Some(name) = self.method_name { let item = candidate.item; let container_id = item.container_id(self.tcx); - let def_scope = self.tcx.adjust_ident_and_get_scope(name, container_id, self.body_id).1; + let def_scope = + self.tcx.adjust_ident_and_get_scope(name, container_id, self.body_def_id).1; item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx) } else { true diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0a72f1d47b8b8..42c08f6409e8a 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -160,7 +160,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *ty.peel_refs().kind() { ty::Param(param) => { - let generics = self.tcx.generics_of(self.body_id); + let generics = self.tcx.generics_of(self.body_def_id); let generic_param = generics.type_param(param, self.tcx); for unsatisfied in unsatisfied_predicates.iter() { // The parameter implements `IntoIterator` @@ -634,7 +634,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> LetVisitor<'a, 'tcx> { // Check scope of binding. fn is_sub_scope(&self, sub_id: hir::ItemLocalId, super_id: hir::ItemLocalId) -> bool { - let scope_tree = self.fcx.tcx.region_scope_tree(self.fcx.body_id); + let scope_tree = self.fcx.tcx.region_scope_tree(self.fcx.body_def_id); if let Some(sub_var_scope) = scope_tree.var_scope(sub_id) && let Some(super_var_scope) = scope_tree.var_scope(super_id) && scope_tree.is_subscope_of(sub_var_scope, super_var_scope) @@ -742,7 +742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::def::Res::Local(recv_id) = path.res && let Some(segment) = path.segments.first() { - let body = self.tcx.hir_body_owned_by(self.body_id); + let body = self.tcx.hir_body_owned_by(self.body_def_id); if let Node::Expr(call_expr) = self.tcx.parent_hir_node(rcvr.hir_id) { let mut let_visitor = LetVisitor { @@ -1148,7 +1148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let mut ty_span = match rcvr_ty.kind() { ty::Param(param_type) => { - Some(param_type.span_from_generics(self.tcx, self.body_id.to_def_id())) + Some(param_type.span_from_generics(self.tcx, self.body_def_id.to_def_id())) } ty::Adt(def, _) if def.did().is_local() => Some(self.tcx.def_span(def.did())), _ => None, @@ -1779,7 +1779,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Param(_) => { // Account for `fn` items like in `issue-35677.rs` to // suggest restricting its type params. - Some(self.tcx.hir_node_by_def_id(self.body_id)) + Some(self.tcx.hir_node_by_def_id(self.body_def_id)) } ty::Adt(def, _) => { def.did().as_local().map(|def_id| self.tcx.hir_node_by_def_id(def_id)) @@ -2842,7 +2842,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }); if let Some((field, field_ty)) = field_receiver { - let scope = tcx.parent_module_from_def_id(self.body_id); + let scope = tcx.parent_module_from_def_id(self.body_def_id); let is_accessible = field.vis.is_accessible_from(scope, tcx); if is_accessible { @@ -3147,7 +3147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { seg1.ident.span, StashKey::CallAssocMethod, |err| { - let body = self.tcx.hir_body_owned_by(self.body_id); + let body = self.tcx.hir_body_owned_by(self.body_def_id); struct LetVisitor { ident_name: Symbol, } @@ -3997,7 +3997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let parent_map = self.tcx.visible_parent_map(()); - let scope = self.tcx.parent_module_from_def_id(self.body_id); + let scope = self.tcx.parent_module_from_def_id(self.body_def_id); let (accessible_candidates, inaccessible_candidates): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|id| { let vis = self.tcx.visibility(*id); @@ -4555,7 +4555,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Obtain the span for `param` and use it for a structured suggestion. if let Some(param) = param_type { - let generics = self.tcx.generics_of(self.body_id.to_def_id()); + let generics = self.tcx.generics_of(self.body_def_id.to_def_id()); let type_param = generics.type_param(param, self.tcx); let tcx = self.tcx; if let Some(def_id) = type_param.def_id.as_local() { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index fd52c7f4b4d26..682ae998b411d 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -517,7 +517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, trait_pred, output_associated_item, - self.body_id, + self.body_def_id, ); } } @@ -1004,7 +1004,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, pred, None, - self.body_id, + self.body_def_id, ); } } diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 6c55251bdef5a..797077d97c133 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -163,13 +163,18 @@ impl<'tcx> FnCtxt<'_, 'tcx> { if let Some(guar) = self.tainted_by_errors() { guar } else { - report_item_does_not_constrain_error(self.tcx, self.body_id, def_id, None) + report_item_does_not_constrain_error( + self.tcx, + self.body_def_id, + def_id, + None, + ) } } UsageKind::NonDefiningUse(opaque_type_key, hidden_type) => { report_item_does_not_constrain_error( self.tcx, - self.body_id, + self.body_def_id, def_id, Some((opaque_type_key, hidden_type.span)), ) @@ -186,7 +191,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .unwrap_or_else(|| hidden_type.ty.into()); self.err_ctxt() .emit_inference_failure_err( - self.body_id, + self.body_def_id, hidden_type.span, infer_var, TypeAnnotationNeeded::E0282, @@ -235,7 +240,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return UsageKind::UnconstrainedHiddenType(hidden_type); } - let cause = ObligationCause::misc(hidden_type.span, self.body_id); + let cause = ObligationCause::misc(hidden_type.span, self.body_def_id); let at = self.at(&cause, self.param_env); let hidden_type = match solve::deeply_normalize(at, Unnormalized::new_wip(hidden_type)) { Ok(hidden_type) => hidden_type, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 3d50befe042f1..4161975d88ea9 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -948,8 +948,8 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { // We must deeply normalize in the new solver, since later lints expect // that types that show up in the typeck are fully normalized. let mut value = if self.should_normalize && self.fcx.next_trait_solver() { - let body_id = tcx.hir_body_owner_def_id(self.body.id()); - let cause = ObligationCause::misc(self.span.to_span(tcx), body_id); + let body_def_id = tcx.hir_body_owner_def_id(self.body.id()); + let cause = ObligationCause::misc(self.span.to_span(tcx), body_def_id); let at = self.fcx.at(&cause, self.fcx.param_env); let universes = vec![None; outer_exclusive_binder(&value).as_usize()]; match solve::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index f381146726734..2d05e33e44891 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn replace_opaque_types_with_inference_vars>>( &self, value: T, - body_id: LocalDefId, + body_def_id: LocalDefId, span: Span, param_env: ty::ParamEnv<'tcx>, ) -> InferOk<'tcx, T> { @@ -60,7 +60,7 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx, ObligationCause::new( span, - body_id, + body_def_id, traits::ObligationCauseCode::OpaqueReturnType(None), ), goal.param_env, diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 0536a6c909507..219d7efa391e3 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -158,11 +158,11 @@ impl<'tcx, O> Obligation<'tcx, O> { pub fn misc( tcx: TyCtxt<'tcx>, span: Span, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, trait_ref: impl Upcast, O>, ) -> Obligation<'tcx, O> { - Obligation::new(tcx, ObligationCause::misc(span, body_id), param_env, trait_ref) + Obligation::new(tcx, ObligationCause::misc(span, body_def_id), param_env, trait_ref) } pub fn with

( diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 4cd124248e093..58a8eeeb242c0 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -44,13 +44,13 @@ use crate::ty::{self, AdtKind, GenericArgsRef, Ty}; pub struct ObligationCause<'tcx> { pub span: Span, - /// The ID of the fn body that triggered this obligation. This is + /// The ID of the fn that triggered this obligation. This is /// used for region obligations to determine the precise /// environment in which the region obligation should be evaluated /// (in particular, closures can add new assumptions). See the /// field `region_obligations` of the `FulfillmentContext` for more /// information. - pub body_id: LocalDefId, + pub body_def_id: LocalDefId, code: ObligationCauseCodeHandle<'tcx>, } @@ -62,7 +62,7 @@ pub struct ObligationCause<'tcx> { // which is hashed as an interned pointer. See #90996. impl Hash for ObligationCause<'_> { fn hash(&self, state: &mut H) { - self.body_id.hash(state); + self.body_def_id.hash(state); self.span.hash(state); } } @@ -71,14 +71,14 @@ impl<'tcx> ObligationCause<'tcx> { #[inline] pub fn new( span: Span, - body_id: LocalDefId, + body_def_id: LocalDefId, code: ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { - ObligationCause { span, body_id, code: code.into() } + ObligationCause { span, body_def_id, code: code.into() } } - pub fn misc(span: Span, body_id: LocalDefId) -> ObligationCause<'tcx> { - ObligationCause::new(span, body_id, ObligationCauseCode::Misc) + pub fn misc(span: Span, body_def_id: LocalDefId) -> ObligationCause<'tcx> { + ObligationCause::new(span, body_def_id, ObligationCauseCode::Misc) } #[inline(always)] @@ -88,7 +88,7 @@ impl<'tcx> ObligationCause<'tcx> { #[inline(always)] pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> { - ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() } + ObligationCause { span, body_def_id: CRATE_DEF_ID, code: Default::default() } } #[inline] diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9822e8cdef8b2..63a55c32b54ce 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1813,7 +1813,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let body_owner_def_id = (cause.body_id != CRATE_DEF_ID).then(|| cause.body_id.to_def_id()); + let body_owner_def_id = + (cause.body_def_id != CRATE_DEF_ID).then(|| cause.body_def_id.to_def_id()); self.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id); if let Some(exp_found) = exp_found && let exp_found = TypeError::Sorts(exp_found) @@ -1945,7 +1946,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let TypeError::ArraySize(sz) = terr else { return None; }; - let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) { + let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_def_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { body: body_id, .. }, .. }) => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index aa10b4ee6d39c..71f81bb633ba6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -173,7 +173,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { exp_span, exp_found.expected, exp_found.found, ); - match self.tcx.coroutine_kind(cause.body_id) { + match self.tcx.coroutine_kind(cause.body_def_id) { Some(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen, _, @@ -636,7 +636,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - self.tcx.hir_maybe_body_owned_by(cause.body_id).and_then(|body| { + self.tcx.hir_maybe_body_owned_by(cause.body_def_id).and_then(|body| { IfVisitor { err_span: span, found_if: false } .visit_body(&body) .is_break() diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 622c0b619431e..40bae03a649db 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -144,14 +144,14 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( }, ); - // If our `body_id` has been set (and isn't just from a dummy obligation cause), + // If our `body_def_id` has been set (and isn't just from a dummy obligation cause), // then try to look for a param-env clause that would apply. The way we compute // this is somewhat manual, since we need the spans, so we elaborate this directly // from `predicates_of` rather than actually looking at the param-env which // otherwise would be more appropriate. - let body_id = obligation.cause.body_id; - if body_id != CRATE_DEF_ID { - let predicates = tcx.predicates_of(body_id.to_def_id()).instantiate_identity(tcx); + let body_def_id = obligation.cause.body_def_id; + if body_def_id != CRATE_DEF_ID { + let predicates = tcx.predicates_of(body_def_id.to_def_id()).instantiate_identity(tcx); for (pred, span) in elaborate(tcx, predicates.into_iter().map(|(c, s)| (c.skip_norm_wip(), s))) { @@ -231,7 +231,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return match self.tainted_by_errors() { None => self .emit_inference_failure_err( - obligation.cause.body_id, + obligation.cause.body_def_id, span, trait_pred.self_ty().skip_binder().into(), TypeAnnotationNeeded::E0282, @@ -285,7 +285,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) .collect(); self.emit_inference_failure_err_with_type_hint( - obligation.cause.body_id, + obligation.cause.body_def_id, span, term, TypeAnnotationNeeded::E0283, @@ -369,7 +369,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { impl_candidates.as_slice(), obligation, trait_pred, - obligation.cause.body_id, + obligation.cause.body_def_id, &mut err, false, obligation.param_env, @@ -384,7 +384,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if term.is_some_and(|term| term.as_type().is_some()) - && let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) + && let Some(body) = + self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id) { let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(&body.value); @@ -546,7 +547,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } self.emit_inference_failure_err( - obligation.cause.body_id, + obligation.cause.body_def_id, span, term, TypeAnnotationNeeded::E0282, @@ -565,7 +566,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); self.emit_inference_failure_err( - obligation.cause.body_id, + obligation.cause.body_def_id, span, a.into(), TypeAnnotationNeeded::E0282, @@ -599,7 +600,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let predicate = self.tcx.short_string(predicate, &mut long_ty_path); if let Some(term) = term { self.emit_inference_failure_err( - obligation.cause.body_id, + obligation.cause.body_def_id, span, term, TypeAnnotationNeeded::E0284, @@ -631,7 +632,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { data.walk().filter_map(ty::GenericArg::as_term).find(|term| term.is_infer()); if let Some(term) = term { self.emit_inference_failure_err( - obligation.cause.body_id, + obligation.cause.body_def_id, span, term, TypeAnnotationNeeded::E0284, @@ -653,7 +654,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self .emit_inference_failure_err( - obligation.cause.body_id, + obligation.cause.body_def_id, span, ct.into(), TypeAnnotationNeeded::E0284, 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 e1b1a41f37a74..617ec6c4ac229 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 @@ -468,7 +468,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } if let Some(s) = parent_label { - let body = obligation.cause.body_id; + let body = obligation.cause.body_def_id; err.span_label(tcx.def_span(body), s); } @@ -689,7 +689,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { violations, ); if let hir::Node::Item(item) = - self.tcx.hir_node_by_def_id(obligation.cause.body_id) + self.tcx.hir_node_by_def_id(obligation.cause.body_def_id) && let hir::ItemKind::Impl(impl_) = item.kind && let None = impl_.of_trait && let hir::TyKind::TraitObject(_, tagged_ptr) = impl_.self_ty.kind @@ -949,7 +949,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } else if let ty::Param(param) = trait_ref.self_ty().skip_binder().kind() && let Some(generics) = - self.tcx.hir_node_by_def_id(main_obligation.cause.body_id).generics() + self.tcx.hir_node_by_def_id(main_obligation.cause.body_def_id).generics() { let constraint = ty::print::with_no_trimmed_paths!(format!( "[const] {}", @@ -1144,7 +1144,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } } - let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); + let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_def_id); let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return (false, false) }; let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir_body(body_id)) @@ -1382,7 +1382,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty: Ty<'tcx>, obligation: &PredicateObligation<'tcx>, ) -> Diag<'a> { - let def_id = obligation.cause.body_id; + let def_id = obligation.cause.body_def_id; let span = self.tcx.ty_span(def_id); let mut file = None; @@ -2869,7 +2869,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { self.note_obligation_cause_code( - obligation.cause.body_id, + obligation.cause.body_def_id, err, obligation.predicate, obligation.param_env, @@ -2884,7 +2884,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), ); self.suggest_borrow_for_unsized_closure_return( - obligation.cause.body_id, + obligation.cause.body_def_id, err, obligation.predicate, ); @@ -3211,7 +3211,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { is_fn_trait: bool, suggested: bool, ) { - let body_def_id = obligation.cause.body_id; + let body_def_id = obligation.cause.body_def_id; let span = if let ObligationCauseCode::BinOp { rhs_span, .. } = obligation.cause.code() { *rhs_span } else { @@ -3242,7 +3242,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err, trait_predicate, None, - obligation.cause.body_id, + obligation.cause.body_def_id, ); } else if trait_def_id.is_local() && self.tcx.trait_impls_of(trait_def_id).is_empty() @@ -3798,7 +3798,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { trait_item_def_id.as_local() } else { - Some(obligation.cause.body_id) + Some(obligation.cause.body_def_id) }; if let Some(suggestion_def_id) = suggestion_def_id && let Some(generics) = self.tcx.hir_get_generics(suggestion_def_id) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index e38ac4c447fcc..b50ace11bbd75 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -340,7 +340,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::WhereClauseInExpr(..) = code { self.note_obligation_cause_code( - error.obligation.cause.body_id, + error.obligation.cause.body_def_id, &mut diag, error.obligation.predicate, error.obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 53eebfd377171..138c53d013ebc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -72,7 +72,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, // but I guess we could synthesize one here. We don't see any errors that rely on // that yet, though. - let item_context = self.describe_enclosure(obligation.cause.body_id).unwrap_or(""); + let item_context = self.describe_enclosure(obligation.cause.body_def_id).unwrap_or(""); let direct = match obligation.cause.code() { ObligationCauseCode::BuiltinDerived(..) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index df7f89266012e..a5377fc04acef 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -150,7 +150,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { suggest_increasing_limit, |err| { self.note_obligation_cause_code( - obligation.cause.body_id, + obligation.cause.body_def_id, err, predicate, obligation.param_env, 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 9f5cfb39b9718..6872df04354c8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -285,7 +285,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if !cause.span.is_dummy() - && let Some(body) = self.tcx.hir_maybe_body_owned_by(cause.body_id) + && let Some(body) = self.tcx.hir_maybe_body_owned_by(cause.body_def_id) { let mut expr_finder = FindExprBySpan::new(cause.span, self.tcx); expr_finder.visit_body(body); @@ -467,7 +467,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, associated_ty: Option<(&'static str, Ty<'tcx>)>, - mut body_id: LocalDefId, + mut body_def_id: LocalDefId, ) { if trait_pred.skip_binder().polarity != ty::PredicatePolarity::Positive { return; @@ -494,7 +494,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. loop { - let node = self.tcx.hir_node_by_def_id(body_id); + let node = self.tcx.hir_node_by_def_id(body_def_id); match node { hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait { ident, generics, bounds, .. }, @@ -504,7 +504,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Restricting `Self` for a single method. suggest_restriction( self.tcx, - body_id, + body_def_id, generics, "`Self`", err, @@ -524,7 +524,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( - self.tcx, body_id, generics, "`Self`", err, None, projection, trait_pred, + self.tcx, + body_def_id, + generics, + "`Self`", + err, + None, + projection, + trait_pred, None, ); return; @@ -547,7 +554,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, - body_id, + body_def_id, generics, "the associated type", err, @@ -567,7 +574,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, - body_id, + body_def_id, generics, "the associated type", err, @@ -687,7 +694,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => {} } - body_id = self.tcx.local_parent(body_id); + body_def_id = self.tcx.local_parent(body_def_id); } } @@ -1024,7 +1031,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let Some((def_id_or_name, output, inputs)) = - self.extract_callable_info(obligation.cause.body_id, obligation.param_env, self_ty) + self.extract_callable_info(obligation.cause.body_def_id, obligation.param_env, self_ty) else { return false; }; @@ -1232,7 +1239,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Wrap method receivers and `&`-references in parens. let suggestion = if self.tcx.sess.source_map().span_followed_by(span, ".").is_some() { parenthesized_cast(span) - } else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) { + } else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id) { let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(body.value); if let Some(expr) = expr_finder.result @@ -1271,7 +1278,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span.remove_mark(); } let mut expr_finder = FindExprBySpan::new(span, self.tcx); - let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else { + let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id) else { return; }; expr_finder.visit_expr(body.value); @@ -1350,7 +1357,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> bool { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); self.enter_forall(self_ty, |ty: Ty<'_>| { - let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_id) else { + let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_def_id) else { return false; }; let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; @@ -1444,7 +1451,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// because the callable type must also be well-formed to be called. pub fn extract_callable_info( &self, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, found: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec>)> { @@ -1526,7 +1533,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } }), ty::Param(param) => { - let generics = self.tcx.generics_of(body_id); + let generics = self.tcx.generics_of(body_def_id); let name = if generics.count() > param.index as usize && let def = generics.param_at(param.index as usize, self.tcx) && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) @@ -1597,7 +1604,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let (Some(typeck_results), Some(body)) = ( self.typeck_results.as_ref(), - self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id), + self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id), ) else { return true; }; @@ -1859,7 +1866,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Issue #104961, we need to add parentheses properly for compound expressions // for example, `x.starts_with("hi".to_string() + "you")` // should be `x.starts_with(&("hi".to_string() + "you"))` - let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else { + let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id) else { return false; }; let mut expr_finder = FindExprBySpan::new(span, self.tcx); @@ -2085,7 +2092,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span.remove_mark(); } let mut expr_finder = super::FindExprBySpan::new(span, self.tcx); - let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else { + let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id) else { return false; }; expr_finder.visit_expr(body.value); @@ -2413,7 +2420,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span: Span, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { - let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id); + let node = self.tcx.hir_node_by_def_id(obligation.cause.body_def_id); if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn {sig, body: body_id, .. }, .. }) = node && let hir::ExprKind::Block(blk, _) = &self.tcx.hir_body(*body_id).value.kind && sig.decl.output.span().overlaps(span) @@ -2449,7 +2456,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn suggest_borrow_for_unsized_closure_return( &self, - body_id: LocalDefId, + body_def_id: LocalDefId, err: &mut Diag<'_, G>, predicate: ty::Predicate<'tcx>, ) { @@ -2463,10 +2470,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let Some(span) = err.span.primary_span() else { return; }; - let Some(node_body_id) = self.tcx.hir_node_by_def_id(body_id).body_id() else { + let Some(body_id) = self.tcx.hir_node_by_def_id(body_def_id).body_id() else { return; }; - let body = self.tcx.hir_body(node_body_id); + let body = self.tcx.hir_body(body_id); let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(body.value); let Some(expr) = expr_finder.result else { @@ -2503,7 +2510,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option { let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig, .. }, .. }) = - self.tcx.hir_node_by_def_id(obligation.cause.body_id) + self.tcx.hir_node_by_def_id(obligation.cause.body_def_id) else { return None; }; @@ -2529,7 +2536,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(fn_sig, _), .. }) | Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(fn_sig, _), .. }) = - self.tcx.hir_node_by_def_id(obligation.cause.body_id) + self.tcx.hir_node_by_def_id(obligation.cause.body_def_id) && let hir::FnRetTy::Return(ty) = fn_sig.decl.output && let hir::TyKind::Path(qpath) = ty.kind && let hir::QPath::Resolved(None, path) = qpath @@ -2559,8 +2566,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut span = obligation.cause.span; let mut is_async_fn_return = false; - if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id) - && let parent = self.tcx.local_parent(obligation.cause.body_id) + if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_def_id) + && let parent = self.tcx.local_parent(obligation.cause.body_def_id) && let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent) && self.tcx.asyncness(parent).is_async() && let Node::Item(hir::Item { kind: hir::ItemKind::Fn { sig: fn_sig, .. }, .. }) @@ -2577,11 +2584,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { is_async_fn_return = true; err.span(span); } - let body = self.tcx.hir_body_owned_by(obligation.cause.body_id); + let body = self.tcx.hir_body_owned_by(obligation.cause.body_def_id); if !is_async_fn_return && let Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = - self.tcx.hir_node_by_def_id(obligation.cause.body_id) + self.tcx.hir_node_by_def_id(obligation.cause.body_def_id) && matches!(closure.fn_decl.output, hir::FnRetTy::DefaultReturn(_)) { return true; @@ -3447,7 +3454,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // bound that introduced the obligation (e.g. `T: Send`). debug!(?next_code); self.note_obligation_cause_code( - obligation.cause.body_id, + obligation.cause.body_def_id, err, obligation.predicate, obligation.param_env, @@ -3459,7 +3466,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn note_obligation_cause_code( &self, - body_id: LocalDefId, + body_def_id: LocalDefId, err: &mut Diag<'_, G>, predicate: T, param_env: ty::ParamEnv<'tcx>, @@ -4125,7 +4132,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // #74711: avoid a stack overflow ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, parent_predicate, param_env, @@ -4137,7 +4144,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else { ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, parent_predicate, param_env, @@ -4167,7 +4174,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Skip PinDerefMutHelper in suggestions, but still show downstream suggestions. ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, parent_predicate, param_env, @@ -4321,7 +4328,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // #74711: avoid a stack overflow ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, parent_predicate, param_env, @@ -4364,7 +4371,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, data.derived.parent_host_pred, param_env, @@ -4377,7 +4384,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ObligationCauseCode::BuiltinDerivedHost(ref data) => { ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, data.parent_host_pred, param_env, @@ -4393,7 +4400,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // #74711: avoid a stack overflow ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, parent_predicate, param_env, @@ -4407,7 +4414,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // #74711: avoid a stack overflow ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, predicate, param_env, @@ -4427,7 +4434,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { arg_hir_id, call_hir_id, ref parent_code, .. } => { self.note_function_argument_obligation( - body_id, + body_def_id, err, arg_hir_id, parent_code, @@ -4437,7 +4444,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); ensure_sufficient_stack(|| { self.note_obligation_cause_code( - body_id, + body_def_id, err, predicate, param_env, @@ -4481,7 +4488,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info { let expr = tcx.hir_expect_expr(hir_id); (expr_ty, expr) - } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id() + } else if let Some(body_id) = tcx.hir_node_by_def_id(body_def_id).body_id() && let body = tcx.hir_body(body_id) && let hir::ExprKind::Block(block, _) = body.value.kind && let Some(expr) = block.expr @@ -4579,7 +4586,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) && snippet.ends_with('?') { - match self.tcx.coroutine_kind(obligation.cause.body_id) { + match self.tcx.coroutine_kind(obligation.cause.body_def_id) { Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { err.span_suggestion_verbose( span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), @@ -4591,7 +4598,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => { let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into(); span.push_span_label( - self.tcx.def_span(obligation.cause.body_id), + self.tcx.def_span(obligation.cause.body_def_id), "this is not `async`", ); err.span_note( @@ -4732,7 +4739,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn note_function_argument_obligation( &self, - body_id: LocalDefId, + body_def_id: LocalDefId, err: &mut Diag<'_, G>, arg_hir_id: HirId, parent_code: &ObligationCauseCode<'tcx>, @@ -4749,7 +4756,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some(failed_pred) = failed_pred.as_trait_clause() && let pred = failed_pred.map_bound(|pred| pred.with_replaced_self_ty(tcx, ty)) && self.predicate_must_hold_modulo_regions(&Obligation::misc( - tcx, expr.span, body_id, param_env, pred, + tcx, + expr.span, + body_def_id, + param_env, + pred, )) && expr.span.hi() != rcvr.span.hi() { @@ -4882,7 +4893,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { for (expected, actual) in zipped { self.probe(|_| { match self - .at(&ObligationCause::misc(expr.span, body_id), param_env) + .at(&ObligationCause::misc(expr.span, body_def_id), param_env) // Doesn't actually matter if we define opaque types here, this is just used for // diagnostics, and the result is never kept around. .eq(DefineOpaqueTypes::Yes, expected, actual) @@ -5870,7 +5881,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id); + let node = self.tcx.hir_node_by_def_id(obligation.cause.body_def_id); if let Some((fn_decl, body_id)) = choose_suggest_items(self.tcx, node) && let hir::FnRetTy::DefaultReturn(ret_span) = fn_decl.output && self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id()) diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 866be1e532661..cff2e64a0d1e3 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -14,16 +14,16 @@ use crate::traits::outlives_bounds::InferCtxtExt; impl<'tcx> OutlivesEnvironment<'tcx> { fn new( infcx: &InferCtxt<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, assumed_wf_tys: impl IntoIterator>, ) -> Self { - Self::new_with_implied_bounds_compat(infcx, body_id, param_env, assumed_wf_tys, false) + Self::new_with_implied_bounds_compat(infcx, body_def_id, param_env, assumed_wf_tys, false) } fn new_with_implied_bounds_compat( infcx: &InferCtxt<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, assumed_wf_tys: impl IntoIterator>, disable_implied_bounds_hack: bool, @@ -60,7 +60,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { param_env, bounds, infcx.implied_bounds_tys( - body_id, + body_def_id, param_env, assumed_wf_tys, disable_implied_bounds_hack, @@ -82,13 +82,13 @@ impl<'tcx> InferCtxt<'tcx> { /// This function assumes that all infer variables are already constrained. fn resolve_regions( &self, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, assumed_wf_tys: impl IntoIterator>, ) -> Vec> { self.resolve_regions_with_outlives_env( - &OutlivesEnvironment::new(self, body_id, param_env, assumed_wf_tys), - self.tcx.def_span(body_id), + &OutlivesEnvironment::new(self, body_def_id, param_env, assumed_wf_tys), + self.tcx.def_span(body_def_id), ) } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 816bf7248f3bf..0c365e9dea707 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -258,10 +258,11 @@ impl<'tcx> BestObligation<'tcx> { ) -> ControlFlow> { let infcx = candidate.goal().infcx(); let param_env = candidate.goal().goal().param_env; - let body_id = self.obligation.cause.body_id; + let body_def_id = self.obligation.cause.body_def_id; - for obligation in wf::unnormalized_obligations(infcx, param_env, term, self.span(), body_id) - .into_flat_iter() + for obligation in + wf::unnormalized_obligations(infcx, param_env, term, self.span(), body_def_id) + .into_flat_iter() { let nested_goal = candidate.instantiate_proof_tree_for_nested_goal( GoalSource::Misc, diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index f6a7bbdc686ec..449fdbaca9abc 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -574,7 +574,7 @@ fn evaluate_host_effect_for_fn_goal<'tcx>( .map(|(c, span)| { let code = ObligationCauseCode::WhereClause(def, span); let cause = - ObligationCause::new(obligation.cause.span, obligation.cause.body_id, code); + ObligationCause::new(obligation.cause.span, obligation.cause.body_def_id, code); Obligation::new( tcx, cause, diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 6cddd79544906..1990ebd913eca 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -246,15 +246,15 @@ where /// will result in region constraints getting ignored. pub fn resolve_regions_and_report_errors( self, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, assumed_wf_tys: impl IntoIterator>, ) -> Result<(), ErrorGuaranteed> { - let errors = self.infcx.resolve_regions(body_id, param_env, assumed_wf_tys); + let errors = self.infcx.resolve_regions(body_def_id, param_env, assumed_wf_tys); if errors.is_empty() { Ok(()) } else { - Err(self.infcx.err_ctxt().report_region_errors(body_id, &errors)) + Err(self.infcx.err_ctxt().report_region_errors(body_def_id, &errors)) } } @@ -265,11 +265,11 @@ where #[must_use] pub fn resolve_regions( self, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, assumed_wf_tys: impl IntoIterator>, ) -> Vec> { - self.infcx.resolve_regions(body_id, param_env, assumed_wf_tys) + self.infcx.resolve_regions(body_def_id, param_env, assumed_wf_tys) } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 00ad863f38346..aa963b1bca749 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -611,7 +611,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { match wf::obligations( self.selcx.infcx, obligation.param_env, - obligation.cause.body_id, + obligation.cause.body_def_id, obligation.recursion_depth + 1, term, obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 79f1a59d9884f..46616c84578cc 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -190,7 +190,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( } // Check regions assuming the self type of the impl is WF - let errors = infcx.resolve_regions(parent_cause.body_id, param_env, [self_type]); + let errors = infcx.resolve_regions(parent_cause.body_def_id, param_env, [self_type]); if !errors.is_empty() { infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Regions(errors))); continue; @@ -279,7 +279,7 @@ pub fn all_fields_implement_trait<'tcx>( } // Check regions assuming the self type of the impl is WF - let errors = infcx.resolve_regions(parent_cause.body_id, param_env, [self_type]); + let errors = infcx.resolve_regions(parent_cause.body_def_id, param_env, [self_type]); if !errors.is_empty() { infringing.push((field, ty, InfringingFieldsReason::Regions(errors))); } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 3abc79bd21304..92be8fdfaa20b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -300,7 +300,7 @@ fn do_normalize_predicates<'tcx>( // // This is required by trait-system-refactor-initiative#166. The new solver encounters // this more frequently as we entirely ignore outlives predicates with the old solver. - let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []); + let _errors = infcx.resolve_regions(cause.body_def_id, elaborated_env, []); match infcx.fully_resolve(predicates) { Ok(predicates) => Ok(predicates), Err(fixup_err) => { diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index a171a0de9dd79..84cae1e7bfa0a 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -27,15 +27,15 @@ use crate::traits::ObligationCause; /// # Parameters /// /// - `param_env`, the where-clauses in scope -/// - `body_id`, the body-id to use when normalizing assoc types. +/// - `body_def_id`, the body_def_id to use when normalizing assoc types. /// Note that this may cause outlives obligations to be injected /// into the inference context with this body-id. /// - `ty`, the type that we are supposed to assume is WF. -#[instrument(level = "debug", skip(infcx, param_env, body_id), ret)] +#[instrument(level = "debug", skip(infcx, param_env, body_def_id), ret)] fn implied_outlives_bounds<'a, 'tcx>( infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, ty: Ty<'tcx>, disable_implied_bounds_hack: bool, ) -> Vec> { @@ -60,7 +60,7 @@ fn implied_outlives_bounds<'a, 'tcx>( }; let mut constraints = QueryRegionConstraints::default(); - let span = infcx.tcx.def_span(body_id); + let span = infcx.tcx.def_span(body_def_id); let Ok(InferOk { value: mut bounds, obligations }) = infcx .instantiate_nll_query_response_and_region_obligations( &ObligationCause::dummy_with_span(span), @@ -83,7 +83,7 @@ fn implied_outlives_bounds<'a, 'tcx>( // We otherwise would get spurious errors if normalizing an implied // outlives bound required proving some higher-ranked coroutine obl. let QueryRegionConstraints { constraints, assumptions: _ } = constraints; - let cause = ObligationCause::misc(span, body_id); + let cause = ObligationCause::misc(span, body_def_id); for &QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in &constraints { match constraint { ty::RegionConstraint::Outlives(predicate) => { @@ -105,13 +105,13 @@ impl<'tcx> InferCtxt<'tcx> { /// instead if you're interested in the implied bounds for a given signature. fn implied_bounds_tys>>( &self, - body_id: LocalDefId, + body_def_id: LocalDefId, param_env: ParamEnv<'tcx>, tys: Tys, disable_implied_bounds_hack: bool, ) -> impl Iterator> { tys.into_iter().flat_map(move |ty| { - implied_outlives_bounds(self, param_env, body_id, ty, disable_implied_bounds_hack) + implied_outlives_bounds(self, param_env, body_def_id, ty, disable_implied_bounds_hack) }) } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index e2257703f5775..cc418ede7f5ed 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -230,7 +230,7 @@ fn project_and_unify_term<'cx, 'tcx>( let InferOk { value: actual, obligations: new } = selcx.infcx.replace_opaque_types_with_inference_vars( actual, - obligation.cause.body_id, + obligation.cause.body_def_id, obligation.cause.span, obligation.param_env, ); @@ -557,7 +557,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( let nested_cause = ObligationCause::new( cause.span, - cause.body_id, + cause.body_def_id, // FIXME(inherent_associated_types): Since we can't pass along the self type to the // cause code, inherent projections will be printed with identity instantiation in // diagnostics which is not ideal. @@ -2149,7 +2149,7 @@ fn assoc_term_own_obligations<'cx, 'tcx>( } else { ObligationCause::new( obligation.cause.span, - obligation.cause.body_id, + obligation.cause.body_def_id, ObligationCauseCode::WhereClause(def_id, span), ) }; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f0a6ff9a58b51..440ed2b46320b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -727,7 +727,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match wf::obligations( self.infcx, obligation.param_env, - obligation.cause.body_id, + obligation.cause.body_def_id, obligation.recursion_depth + 1, term, obligation.cause.span, @@ -2557,7 +2557,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let cause = ObligationCause::new( obligation.cause.span, - obligation.cause.body_id, + obligation.cause.body_def_id, ObligationCauseCode::MatchImpl(obligation.cause.clone(), impl_def_id), ); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index a47f933f5c25e..8ecea8279aac1 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -30,7 +30,7 @@ use crate::traits; pub fn obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, recursion_depth: usize, term: Term<'tcx>, span: Span, @@ -72,17 +72,17 @@ pub fn obligations<'tcx>( let mut wf = WfPredicates { infcx, param_env, - body_id, + body_def_id, span, out: PredicateObligations::new(), recursion_depth, item: None, }; wf.add_wf_preds_for_term(term); - debug!("wf::obligations({:?}, body_id={:?}) = {:?}", term, body_id, wf.out); + debug!("wf::obligations({:?}, body_def_id={:?}) = {:?}", term, body_def_id, wf.out); let result = wf.normalize(infcx); - debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", term, body_id, result); + debug!("wf::obligations({:?}, body_def_id={:?}) ~~> {:?}", term, body_def_id, result); Some(result) } @@ -95,7 +95,7 @@ pub fn unnormalized_obligations<'tcx>( param_env: ty::ParamEnv<'tcx>, term: Term<'tcx>, span: Span, - body_id: LocalDefId, + body_def_id: LocalDefId, ) -> Option> { debug_assert_eq!(term, infcx.resolve_vars_if_possible(term)); @@ -109,7 +109,7 @@ pub fn unnormalized_obligations<'tcx>( let mut wf = WfPredicates { infcx, param_env, - body_id, + body_def_id, span, out: PredicateObligations::new(), recursion_depth: 0, @@ -126,7 +126,7 @@ pub fn unnormalized_obligations<'tcx>( pub fn trait_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, trait_pred: ty::TraitPredicate<'tcx>, span: Span, item: &'tcx hir::Item<'tcx>, @@ -134,7 +134,7 @@ pub fn trait_obligations<'tcx>( let mut wf = WfPredicates { infcx, param_env, - body_id, + body_def_id, span, out: PredicateObligations::new(), recursion_depth: 0, @@ -154,14 +154,14 @@ pub fn trait_obligations<'tcx>( pub fn clause_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, clause: ty::Clause<'tcx>, span: Span, ) -> PredicateObligations<'tcx> { let mut wf = WfPredicates { infcx, param_env, - body_id, + body_def_id, span, out: PredicateObligations::new(), recursion_depth: 0, @@ -205,7 +205,7 @@ pub fn clause_obligations<'tcx>( struct WfPredicates<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: LocalDefId, + body_def_id: LocalDefId, span: Span, out: PredicateObligations<'tcx>, recursion_depth: usize, @@ -334,7 +334,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { - traits::ObligationCause::new(self.span, self.body_id, code) + traits::ObligationCause::new(self.span, self.body_def_id, code) } fn normalize(self, infcx: &InferCtxt<'tcx>) -> PredicateObligations<'tcx> { @@ -423,7 +423,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { .filter_map(|(i, arg)| arg.as_term().map(|t| (i, t))) .filter(|(_, term)| !term.has_escaping_bound_vars()) .map(|(i, term)| { - let mut cause = traits::ObligationCause::misc(self.span, self.body_id); + let mut cause = traits::ObligationCause::misc(self.span, self.body_def_id); // The first arg is the self ty - use the correct span for it. if i == 0 { if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) = diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 29bda55bbbaab..95bb37f20fa00 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -196,12 +196,11 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { )); } - let local_did = def_id.as_local(); + let local_did = def_id.as_local().unwrap_or(CRATE_DEF_ID); let unnormalized_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates)); - let body_id = local_did.unwrap_or(CRATE_DEF_ID); - let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); + let cause = traits::ObligationCause::misc(tcx.def_span(def_id), local_did); traits::normalize_param_env_or_error(tcx, unnormalized_env, cause) } diff --git a/tests/ui/dyn-compatibility/ice-generics-of-crate-root-152335.rs b/tests/ui/dyn-compatibility/ice-generics-of-crate-root-152335.rs index a1d0e540b398d..bc7efac9dfccd 100644 --- a/tests/ui/dyn-compatibility/ice-generics-of-crate-root-152335.rs +++ b/tests/ui/dyn-compatibility/ice-generics-of-crate-root-152335.rs @@ -1,7 +1,7 @@ // Regression test for #152335. // The compiler used to ICE in `generics_of` when `note_and_explain_type_err` // was called with `CRATE_DEF_ID` as the body owner during dyn-compatibility -// checking. This happened because `ObligationCause::dummy()` sets `body_id` +// checking. This happened because `ObligationCause::dummy()` sets `body_def_id` // to `CRATE_DEF_ID`, and error reporting tried to look up generics on it. struct ActuallySuper; From f05ac1dcb998e870466a5dba2dce9cac3eb7cee9 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Mon, 6 Jul 2026 21:01:44 -0400 Subject: [PATCH 23/33] tests: catch up with LLVM returning f128 on the stack In LLVM 22 the x64 MSVC ABI wasn't matched and f128 was being directly returned in %xmm0, but now it correctly returns the value via a pointer. --- tests/assembly-llvm/x86_64-windows-float-abi.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/assembly-llvm/x86_64-windows-float-abi.rs b/tests/assembly-llvm/x86_64-windows-float-abi.rs index 51daff56789e6..b6ab9995fdb3e 100644 --- a/tests/assembly-llvm/x86_64-windows-float-abi.rs +++ b/tests/assembly-llvm/x86_64-windows-float-abi.rs @@ -3,6 +3,9 @@ //@ compile-flags: --target x86_64-pc-windows-msvc //@ needs-llvm-components: x86 //@ add-minicore +//@ revisions: LLVM22 LLVM23 +//@ [LLVM22] max-llvm-major-version: 22 +//@ [LLVM23] min-llvm-version: 23 #![feature(f16, f128)] #![feature(no_core)] @@ -37,8 +40,12 @@ pub extern "C" fn second_f64(_: f64, x: f64) -> f64 { } // CHECK-LABEL: second_f128 -// CHECK: movaps (%rdx), %xmm0 -// CHECK-NEXT: retq +// LLVM22: movaps (%rdx), %xmm0 +// LLVM22-NEXT: retq +// LLVM23: movq %rcx, %rax +// LLVM23-NEXT: movaps (%r8), %xmm0 +// LLVM23-NEXT: movaps %xmm0, (%rcx) +// LLVM23-NEXT: retq #[no_mangle] pub extern "C" fn second_f128(_: f128, x: f128) -> f128 { x From 3ed5f56b7d381af42cd7a460a777cd5ea500af85 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Tue, 7 Jul 2026 10:10:53 +0200 Subject: [PATCH 24/33] pattern-types: fix formatting in rustfmt --- src/tools/rustfmt/src/types.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index cdba2ddc36e22..9e7bbcc243ccf 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1015,11 +1015,6 @@ impl Rewrite for ast::Ty { } ast::TyKind::CVarArgs => Ok("...".to_owned()), ast::TyKind::Dummy | ast::TyKind::Err(_) => Ok(context.snippet(self.span).to_owned()), - ast::TyKind::Pat(ref ty, ref pat) => { - let ty = ty.rewrite_result(context, shape)?; - let pat = pat.rewrite_result(context, shape)?; - Ok(format!("{ty} is {pat}")) - } ast::TyKind::FieldOf(ref ty, ref variant, ref field) => { let ty = ty.rewrite_result(context, shape)?; if let Some(variant) = variant { @@ -1055,10 +1050,10 @@ impl Rewrite for ast::Ty { Ok(result) } - ast::TyKind::View(..) => { - // This doesn't normally occur in the AST because macros aren't expanded. However, + ast::TyKind::Pat(..) | ast::TyKind::View(..) => { + // These don't normally occur in the AST because macros aren't expanded. However, // rustfmt tries to parse macro arguments when formatting macros, so it's not - // totally impossible for rustfmt to come across this node when formatting a file. + // totally impossible for rustfmt to come across these nodes when formatting a file. // Also, rustfmt might get passed the output from `-Zunpretty=expanded`. Err(RewriteError::Unknown) } From 66beceb52082bf2a32f9bfcb0b8613058dd6e3bd Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 7 Jul 2026 13:42:44 +0300 Subject: [PATCH 25/33] Add constraints to new delegation's generic args --- compiler/rustc_ast_lowering/src/delegation/mod.rs | 7 +++++-- .../constraints-in-generic-args-ice-158812.rs | 13 +++++++++++++ .../constraints-in-generic-args-ice-158812.stderr | 9 +++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 tests/ui/delegation/constraints-in-generic-args-ice-158812.rs create mode 100644 tests/ui/delegation/constraints-in-generic-args-ice-158812.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation/mod.rs b/compiler/rustc_ast_lowering/src/delegation/mod.rs index cd742a6c30671..b1edd2ab60c2e 100644 --- a/compiler/rustc_ast_lowering/src/delegation/mod.rs +++ b/compiler/rustc_ast_lowering/src/delegation/mod.rs @@ -453,11 +453,14 @@ impl<'hir> LoweringContext<'_, 'hir> { }) .unwrap_or_else(|| self.arena.alloc_from_iter(args_iter.consume_all(self))); + // Do not omit constraints as there might be some and they must be present in HIR (#158812). + let has_constraints = segment.args.is_some_and(|a| !a.constraints.is_empty()); + // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). - segment.args = (!new_args.is_empty()).then(|| { + segment.args = (has_constraints || !new_args.is_empty()).then(|| { &*self.arena.alloc(hir::GenericArgs { args: new_args, - constraints: &[], + constraints: segment.args.map(|a| a.constraints).unwrap_or(&[]), parenthesized: hir::GenericArgsParentheses::No, span_ext: segment.args.map_or(span, |args| args.span_ext), }) diff --git a/tests/ui/delegation/constraints-in-generic-args-ice-158812.rs b/tests/ui/delegation/constraints-in-generic-args-ice-158812.rs new file mode 100644 index 0000000000000..1764a9d979992 --- /dev/null +++ b/tests/ui/delegation/constraints-in-generic-args-ice-158812.rs @@ -0,0 +1,13 @@ +#![feature(fn_delegation)] + +pub trait Trait<'a> { + fn foo(&self); +} + +pub struct S<'a, A>(&'a A); +impl<'a, A> Trait<'a> for S<'a, A> { + reuse Trait::::foo; + //~^ ERROR: associated item constraints are not allowed here +} + +fn main() {} diff --git a/tests/ui/delegation/constraints-in-generic-args-ice-158812.stderr b/tests/ui/delegation/constraints-in-generic-args-ice-158812.stderr new file mode 100644 index 0000000000000..1d4b02ef87a6c --- /dev/null +++ b/tests/ui/delegation/constraints-in-generic-args-ice-158812.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated item constraints are not allowed here + --> $DIR/constraints-in-generic-args-ice-158812.rs:9:19 + | +LL | reuse Trait::::foo; + | ^^^^^^ associated item constraint not allowed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0229`. From 831a2e85ab1c323e94e1bde969b1fc0b81bb31fb Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 7 Jul 2026 11:01:21 +0000 Subject: [PATCH 26/33] delegation: support mapping of all arguments with `Self` type * Support mapping of all arguments with Self type * Address some review comments * Review: use #[cfg(debug_assertions)] on the whole module * Review: emit error when trying to map non-receiver argument when block contains definitions * Use `cfg_select` * Fix tidy * Unify mapping with `should_generate_block` * Better naming and message for error * loop -> `extend` --- .../src/delegation/generics.rs | 23 ++-- .../rustc_ast_lowering/src/delegation/mod.rs | 123 +++++++++++------ .../src/delegation/resolution.rs | 126 ++++++++++++------ .../rustc_ast_lowering/src/diagnostics.rs | 9 ++ compiler/rustc_ast_lowering/src/lib.rs | 63 +++++++-- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir_typeck/src/callee.rs | 6 +- tests/ui/delegation/bad-resolve.rs | 1 + tests/ui/delegation/bad-resolve.stderr | 23 +++- .../self-mapping-arguments-errors.rs | 47 +++++++ .../self-mapping-arguments-errors.stderr | 98 ++++++++++++++ tests/ui/delegation/self-mapping-arguments.rs | 59 ++++++++ .../self-mapping-arguments.run.stdout | 5 + 13 files changed, 471 insertions(+), 114 deletions(-) create mode 100644 tests/ui/delegation/self-mapping-arguments-errors.rs create mode 100644 tests/ui/delegation/self-mapping-arguments-errors.stderr create mode 100644 tests/ui/delegation/self-mapping-arguments.rs create mode 100644 tests/ui/delegation/self-mapping-arguments.run.stdout diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index cd7b23c18971d..4d9bc09faeecb 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_middle::{bug, ty}; use rustc_span::symbol::kw; -use rustc_span::{Ident, Span, sym}; +use rustc_span::{ErrorGuaranteed, Ident, Span, sym}; use crate::LoweringContext; use crate::delegation::resolution::resolver::DelegationResolver; @@ -281,7 +281,7 @@ impl<'hir> DelegationResolver<'_, 'hir> { &self, delegation: &'a Delegation, sig_id: DefId, - ) -> GenericsResolution<'a, 'hir> { + ) -> Result, ErrorGuaranteed> { let tcx = self.tcx(); let delegation_parent_kind = tcx.def_kind(tcx.local_parent(self.owner_id())); @@ -300,9 +300,8 @@ impl<'hir> DelegationResolver<'_, 'hir> { let qself_is_none = delegation.qself.is_none(); let parent_args = if let [.., parent_segment, _] = &delegation.path.segments[..] { - if let Some(res) = self.get_resolution_id(parent_segment.id) - && matches!(tcx.def_kind(res), DefKind::Trait | DefKind::TraitAlias) - { + let res = self.get_resolution_id(parent_segment.id)?; + if matches!(tcx.def_kind(res), DefKind::Trait | DefKind::TraitAlias) { sig_parent_params = &tcx.generics_of(sig_parent).own_params; self.get_user_args(parent_segment) .map(|args| ParentSegmentArgs::Specified(args)) @@ -314,7 +313,7 @@ impl<'hir> DelegationResolver<'_, 'hir> { ParentSegmentArgs::Invalid }; - GenericsResolution { + Ok(GenericsResolution { parent_args, sig_parent_params, qself_is_none, @@ -326,7 +325,7 @@ impl<'hir> DelegationResolver<'_, 'hir> { child_args: self.get_user_args( delegation.path.segments.last().expect("must be at least one segment"), ), - } + }) } fn get_user_args<'a>(&self, segment: &'a PathSegment) -> Option<&'a AngleBracketedArgs> { @@ -350,14 +349,14 @@ impl<'hir> DelegationResolver<'_, 'hir> { &self, delegation: &Delegation, sig_id: DefId, - ) -> GenericsGenerationResults<'hir> { + ) -> Result, ErrorGuaranteed> { let res @ GenericsResolution { trait_impl, generate_self, sig_child_params, sig_parent_params, .. - } = self.resolve_generics(delegation, sig_id); + } = self.resolve_generics(delegation, sig_id)?; // If we are in trait impl always generate function whose generics matches // those that are defined in trait. @@ -374,7 +373,7 @@ impl<'hir> DelegationResolver<'_, 'hir> { let child = GenericsGenerationResult::new(child); - return GenericsGenerationResults { parent, child, self_ty_propagation_kind: None }; + return Ok(GenericsGenerationResults { parent, child, self_ty_propagation_kind: None }); } let tcx = self.tcx(); @@ -421,7 +420,7 @@ impl<'hir> DelegationResolver<'_, 'hir> { DelegationGenerics::generate_all(sig_child_params, GenericsPosition::Child, trait_impl) }; - GenericsGenerationResults { + Ok(GenericsGenerationResults { parent: GenericsGenerationResult::new(parent_generics), child: GenericsGenerationResult::new(child_generics), self_ty_propagation_kind: match res.free_to_trait_delegation { @@ -435,7 +434,7 @@ impl<'hir> DelegationResolver<'_, 'hir> { }), false => None, }, - } + }) } /// Generates generic argument slots for user-specified `args` and diff --git a/compiler/rustc_ast_lowering/src/delegation/mod.rs b/compiler/rustc_ast_lowering/src/delegation/mod.rs index cd742a6c30671..3b85dd85985d2 100644 --- a/compiler/rustc_ast_lowering/src/delegation/mod.rs +++ b/compiler/rustc_ast_lowering/src/delegation/mod.rs @@ -45,6 +45,7 @@ use hir::def::Res; use rustc_abi::ExternAbi; use rustc_ast as ast; use rustc_ast::*; +use rustc_hir::def::DefKind; use rustc_hir::{self as hir, FnDeclFlags}; use rustc_middle::ty::Asyncness; use rustc_span::def_id::DefId; @@ -249,20 +250,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut unused_target_expr = false; let block_id = self.lower_body(|this| { - let &DelegationResolution { - param_info, span, should_generate_block, is_method, .. - } = res; - + let &DelegationResolution { param_info, span, is_method, .. } = res; let ParamInfo { param_count, .. } = param_info; + let arguments_to_map = &res.sig_mapping.arguments_to_map; let mut parameters: Vec> = Vec::with_capacity(param_count); let mut args: Vec> = Vec::with_capacity(param_count); - let mut stmts: &[hir::Stmt<'hir>] = &[]; + let mut stmts = vec![]; // Consider non-specified target expression as generated, // as we do not want to emit error when target expression is // not specified. - unused_target_expr = block.is_some() && (param_count == 0 || !should_generate_block); + unused_target_expr = + block.is_some() && (param_count == 0 || arguments_to_map.is_empty()); for idx in 0..param_count { let (param, pat_node_id) = this.generate_param(is_method, idx, span); @@ -271,41 +271,38 @@ impl<'hir> LoweringContext<'_, 'hir> { let generate_arg = |this: &mut Self| this.generate_arg(is_method, idx, param.pat.hir_id, span); - let arg = if let Some(block) = block - && idx == 0 - && should_generate_block - { - let mut self_resolver = SelfResolver { - ctxt: this, - path_id: delegation.id, - self_param_id: pat_node_id, - }; - self_resolver.visit_block(block); - // Target expr needs to lower `self` path. - this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id); - - // Lower with `HirId::INVALID` as we will use only expr and stmts. - // FIXME(fn_delegation): Alternatives for target expression lowering: - // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600. - let block = this.lower_block_noalloc(HirId::INVALID, block, false); - - stmts = block.stmts; - - // The behavior of the delegation's target expression differs from the - // behavior of the usual block, where if there is no final expression - // the `()` is returned. In case of the similar situation in delegation - // (no final expression) we propagate first argument instead of replacing - // it with `()`. - if let Some(&expr) = block.expr { expr } else { generate_arg(this) } - } else { - generate_arg(this) - }; + let arg = block + .filter(|_| arguments_to_map.contains(&idx)) + .and_then(|block| { + let block = this.lower_block_maybe_more_than_once( + block, + pat_node_id, + param.pat.hir_id.local_id, + delegation.id, + ); + + stmts.push(block.stmts); + + // The behavior of the delegation's target expression differs from the + // behavior of the usual block, where if there is no final expression + // the `()` is returned. In case of the similar situation in delegation + // (no final expression) we propagate first argument instead of replacing + // it with `()`. + block.expr.copied() + }) + .unwrap_or_else(|| generate_arg(this)); args.push(arg); } - let (final_expr, hir_id) = - this.finalize_body_lowering(delegation, stmts, args, res, generics, span); + let (final_expr, hir_id) = this.finalize_body_lowering( + delegation, + this.arena.alloc_from_iter(stmts.into_iter().flatten().copied()), + args, + res, + generics, + span, + ); call_expr_id = hir_id; @@ -317,6 +314,48 @@ impl<'hir> LoweringContext<'_, 'hir> { (block_id, call_expr_id, unused_target_expr) } + fn lower_block_maybe_more_than_once( + &mut self, + block: &Block, + pat_node_id: NodeId, + param_local_id: hir::ItemLocalId, + delegation_id: NodeId, + ) -> hir::Block<'hir> { + let mut self_resolver = SelfResolver { + ctxt: self, + path_id: delegation_id, + self_param_id: pat_node_id, + overwrites: vec![], + }; + + self_resolver.visit_block(block); + + let overwrites = self_resolver.overwrites; + + // Target expr needs to lower `self` path. + self.ident_and_label_to_local_id.insert(pat_node_id, param_local_id); + + let block = cfg_select! { + debug_assertions => { + crate::re_lowering::ReloweringChecker::allow_relowering(self, |this| { + this.lower_block_noalloc(HirId::INVALID, block, false) + }) + }, + _ => self.lower_block_noalloc(HirId::INVALID, block, false) + }; + + // Remove node ids for which we overwrote resolution to generated param + // before block lowering as block can be relowered. We need to do it because + // check in `SelfResolver` uses `get_partial_res` to decide whether to overwrite + // resolution, and if it is already overwritten from previous block lowering this + // check will not pass. + for id in overwrites { + self.partial_res_overrides.remove(&id); + } + + block + } + fn finalize_body_lowering( &mut self, delegation: &Delegation, @@ -392,8 +431,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let args = self.arena.alloc_from_iter(args); let call = self.mk_expr(hir::ExprKind::Call(callee_path, args), span); - let expr = if let Some((parent, of_trait)) = res.output_self_mapping { - let res = Res::SelfTyAlias { alias_to: parent.to_def_id(), is_trait_impl: of_trait }; + let expr = if res.sig_mapping.map_return { + let res = Res::SelfTyAlias { + alias_to: res.parent.to_def_id(), + is_trait_impl: self.tcx.def_kind(res.parent) == DefKind::Impl { of_trait: true }, + }; + let ident = Ident::new(kw::SelfUpper, span); let path = self.create_resolved_path(res, ident, span); @@ -538,6 +581,7 @@ struct SelfResolver<'a, 'b, 'hir> { ctxt: &'a mut LoweringContext<'b, 'hir>, path_id: NodeId, self_param_id: NodeId, + overwrites: Vec, } impl SelfResolver<'_, '_, '_> { @@ -546,6 +590,7 @@ impl SelfResolver<'_, '_, '_> { && let Some(Res::Local(sig_id)) = res.full_res() && sig_id == self.path_id { + self.overwrites.push(id); self.ctxt.partial_res_overrides.insert(id, self.self_param_id); } } diff --git a/compiler/rustc_ast_lowering/src/delegation/resolution.rs b/compiler/rustc_ast_lowering/src/delegation/resolution.rs index 3cb40d256ba8b..21fbed81b3e0b 100644 --- a/compiler/rustc_ast_lowering/src/delegation/resolution.rs +++ b/compiler/rustc_ast_lowering/src/delegation/resolution.rs @@ -6,7 +6,7 @@ use rustc_ast as ast; use rustc_ast::*; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; -use rustc_middle::span_bug; +use rustc_middle::{span_bug, ty}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{ErrorGuaranteed, Span}; @@ -14,7 +14,8 @@ use crate::delegation::generics::GenericsGenerationResults; use crate::delegation::resolution::resolver::DelegationResolver; use crate::diagnostics::{ CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion, - DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee, + DelegationAttemptedBlockWithDefsRelowering, DelegationBlockSpecifiedWhenNoParams, + UnresolvedDelegationCallee, }; /// Summary info about function parameters. @@ -30,21 +31,28 @@ pub(super) struct ParamInfo { pub splatted: Option, } +#[derive(Default)] +pub(super) struct SigMapping { + pub map_return: bool, + pub arguments_to_map: FxHashSet, +} + pub(super) struct DelegationResolution { pub sig_id: DefId, pub is_method: bool, pub param_info: ParamInfo, pub span: Span, - pub should_generate_block: bool, - pub call_path_res: Option, + pub call_path_res: DefId, pub source: DelegationSource, - pub output_self_mapping: Option<(LocalDefId, bool)>, + pub parent: LocalDefId, + pub sig_mapping: SigMapping, } pub(super) mod resolver { use rustc_ast::NodeId; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::TyCtxt; + use rustc_span::ErrorGuaranteed; use crate::LoweringContext; @@ -87,8 +95,10 @@ pub(super) mod resolver { } #[inline] - pub(crate) fn get_resolution_id(&self, id: NodeId) -> Option { - self.0.get_partial_res(id).and_then(|r| r.expect_full_res().opt_def_id()) + pub(crate) fn get_resolution_id(&self, id: NodeId) -> Result { + self.0.get_partial_res(id).and_then(|r| r.expect_full_res().opt_def_id()).ok_or_else( + || self.tcx().dcx().delayed_bug(format!("failed to resolve node {id:?}")), + ) } } } @@ -126,25 +136,31 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { let sig = tcx.fn_sig(sig_id).skip_binder().skip_binder(); let param_count = sig.inputs().len() + usize::from(sig.c_variadic()); + let parent = tcx.local_parent(def_id); + + let (should_generate_block, contains_defs) = + self.check_block_soundness(delegation, sig_id, is_method, param_count)?; let res = DelegationResolution { is_method, span, sig_id, + parent, // FIXME(splat): use `sig.splatted()` once FnSig has it param_info: ParamInfo { param_count, c_variadic: sig.c_variadic(), splatted: None }, - should_generate_block: self.check_block_soundness( + source: delegation.source, + call_path_res: self.get_resolution_id(delegation.id)?, + sig_mapping: self.create_self_mapping( delegation, - sig_id, - is_method, - param_count, + span, + should_generate_block, + parent, + sig, + contains_defs, )?, - source: delegation.source, - call_path_res: self.get_resolution_id(delegation.id), - output_self_mapping: self.should_map_return_value(delegation), }; - Ok((res, self.resolve_and_generate_generics(delegation, sig_id))) + Ok((res, self.resolve_and_generate_generics(delegation, sig_id)?)) } fn check_for_cycles(&self, mut def_id: DefId, span: Span) -> Result<(), ErrorGuaranteed> { @@ -180,13 +196,13 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { sig_id: DefId, is_method: bool, param_count: usize, - ) -> Result { + ) -> Result<(/* should generate block */ bool, /* contains defs */ bool), ErrorGuaranteed> { let tcx = self.tcx(); let should_generate_block = is_method || matches!(tcx.def_kind(sig_id), DefKind::Fn) || matches!(delegation.source, DelegationSource::Single); - let Some(block) = &delegation.body else { return Ok(should_generate_block) }; + let Some(block) = &delegation.body else { return Ok((should_generate_block, false)) }; // Report an error if user has explicitly specified delegation's target expression // in a single delegation when reused function has no params. @@ -194,44 +210,84 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { let err = DelegationBlockSpecifiedWhenNoParams { span: block.span }; return Err(tcx.dcx().emit_err(err)); } - struct DefinitionsFinder<'a, 'hir> { - ctx: &'a DelegationResolver<'a, 'hir>, + resolver: &'a DelegationResolver<'a, 'hir>, } impl<'a> Visitor<'a> for DefinitionsFinder<'a, '_> { type Result = ControlFlow<()>; fn visit_id(&mut self, id: NodeId) -> Self::Result { - match self.ctx.is_definition(id) { + match self.resolver.is_definition(id) { true => ControlFlow::Break(()), false => ControlFlow::Continue(()), } } } - let mut collector = DefinitionsFinder { ctx: self }; + let mut collector = DefinitionsFinder { resolver: self }; let contains_defs = collector.visit_block(block).is_break(); // If there are definitions inside and we can't delete target expression, then report an error. // FIXME(fn_delegation): support deletion of target expression with defs inside. if should_generate_block || !contains_defs { - Ok(should_generate_block) + Ok((should_generate_block, contains_defs)) } else { Err(tcx.dcx().emit_err(DelegationAttemptedBlockWithDefsDeletion { span: block.span })) } } - fn should_map_return_value(&self, delegation: &Delegation) -> Option<(LocalDefId, bool)> { + fn create_self_mapping( + &self, + delegation: &Delegation, + span: Span, + should_generate_block: bool, + parent: LocalDefId, + sig: ty::FnSig<'tcx>, + contains_defs: bool, + ) -> Result { + let mut mapping = SigMapping::default(); + if should_generate_block { + mapping.arguments_to_map.insert(0); + } + + if self.can_perform_self_mapping(delegation, parent)? { + mapping.map_return = sig.output().is_param(0); + + let arguments_to_map = sig + .inputs() + .iter() + .enumerate() + .skip(1) // Already checked above. + .filter_map(|(idx, param)| param.is_param(0).then_some(idx)); + + mapping.arguments_to_map.extend(arguments_to_map); + } + + // We can't yet map more than one argument if there are definitions inside. + // FIXME(fn_delegation): support relowering with defs inside + if contains_defs && mapping.arguments_to_map.len() > 1 { + return Err(self + .tcx() + .dcx() + .emit_err(DelegationAttemptedBlockWithDefsRelowering { span })); + } + + Ok(mapping) + } + + fn can_perform_self_mapping( + &self, + delegation: &Delegation, + parent: LocalDefId, + ) -> Result { // Heuristic: don't do wrapping if there is no target expression. if delegation.body.is_none() { - return None; + return Ok(false); } let tcx = self.tcx(); - let parent = tcx.local_parent(self.owner_id()); - let parent_kind = tcx.def_kind(parent); // Apply wrapping for delegations inside // 1) Trait impls, as the return type of both signature function @@ -244,21 +300,13 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { // 2) Inherent methods when delegating to trait, as we change the type of // `Self` to type of struct or enum we delegate from. if !matches!(tcx.def_kind(parent), DefKind::Impl { .. }) { - return None; + return Ok(false); } - let is_trait_impl = parent_kind == DefKind::Impl { of_trait: true }; - // Check that delegation path resolves to a trait AssocFn, not to a free method. - Some((parent, is_trait_impl)).filter(|_| { - self.get_resolution_id(delegation.id).is_some_and(|id| { - tcx.def_kind(id) == DefKind::AssocFn - // Check that the return type of the callee is `Self` param. - // After previous check we are sure that `sig_id` and `delegation.id` - // point to the same function. - && tcx.def_kind(tcx.parent(id)) == DefKind::Trait - && tcx.fn_sig(id).skip_binder().output().skip_binder().is_param(0) - }) - }) + // After previous check we are sure that `sig_id` and `delegation.id` + // point to the same function. + let id = self.get_resolution_id(delegation.id)?; + Ok(tcx.def_kind(id) == DefKind::AssocFn && tcx.def_kind(tcx.parent(id)) == DefKind::Trait) } } diff --git a/compiler/rustc_ast_lowering/src/diagnostics.rs b/compiler/rustc_ast_lowering/src/diagnostics.rs index 238a16d9b859d..2d559f97ae1e8 100644 --- a/compiler/rustc_ast_lowering/src/diagnostics.rs +++ b/compiler/rustc_ast_lowering/src/diagnostics.rs @@ -569,3 +569,12 @@ pub(crate) struct DelegationInfersMismatch { pub expected: Symbol, pub actual: Symbol, } + +#[derive(Diagnostic)] +#[diag( + "attempted to lower target expression with definitions more than once while mapping argument" +)] +pub(crate) struct DelegationAttemptedBlockWithDefsRelowering { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 35e16ce78a8a8..33ccf6db6ea7e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -100,6 +100,49 @@ pub fn provide(providers: &mut Providers) { providers.lower_to_hir = lower_to_hir; } +#[cfg(debug_assertions)] +pub(crate) mod re_lowering { + use rustc_ast::NodeId; + use rustc_ast::node_id::NodeMap; + use rustc_hir::{self as hir}; + + use crate::LoweringContext; + + #[derive(Debug, Default)] + pub(crate) struct ReloweringChecker { + node_id_to_local_id: NodeMap, + can_relower: bool, + } + + impl ReloweringChecker { + pub(crate) fn assert_node_is_not_relowered( + &mut self, + ast_node_id: NodeId, + local_id: hir::ItemLocalId, + ) { + if !self.can_relower { + let old = self.node_id_to_local_id.insert(ast_node_id, local_id); + assert_eq!(old, None); + } + } + + pub(crate) fn allow_relowering<'a, 'hir, TRes>( + ctx: &mut LoweringContext<'a, 'hir>, + op: impl FnOnce(&mut LoweringContext<'a, 'hir>) -> TRes, + ) -> TRes { + assert!(!ctx.relowering_checker.can_relower, "reentrant relowering is not supported"); + + ctx.relowering_checker.can_relower = true; + + let res = op(ctx); + + ctx.relowering_checker.can_relower = false; + + res + } + } +} + struct LoweringContext<'a, 'hir> { tcx: TyCtxt<'hir>, resolver: &'a ResolverAstLowering<'hir>, @@ -146,7 +189,7 @@ struct LoweringContext<'a, 'hir> { ident_and_label_to_local_id: NodeMap, /// NodeIds that are lowered inside the current HIR owner. Only used for duplicate lowering check. #[cfg(debug_assertions)] - node_id_to_local_id: NodeMap, + relowering_checker: re_lowering::ReloweringChecker, /// The `NodeId` space is split in two. /// `0..resolver.next_node_id` are created by the resolver on the AST. /// The higher part `resolver.next_node_id..next_node_id` are created during lowering. @@ -205,8 +248,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // and we never call `lower_node_id(owner)`. item_local_id_counter: hir::ItemLocalId::new(1), ident_and_label_to_local_id: Default::default(), + #[cfg(debug_assertions)] - node_id_to_local_id: Default::default(), + relowering_checker: Default::default(), + trait_map: Default::default(), next_node_id: resolver.next_node_id, node_id_to_def_id: NodeMap::default(), @@ -808,7 +853,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let current_ident_and_label_to_local_id = mem::take(&mut self.ident_and_label_to_local_id); #[cfg(debug_assertions)] - let current_node_id_to_local_id = mem::take(&mut self.node_id_to_local_id); + let current_relowering_checker = mem::take(&mut self.relowering_checker); let current_trait_map = mem::take(&mut self.trait_map); let current_owner = mem::replace(&mut self.current_hir_id_owner, owner_id); let current_local_counter = @@ -824,10 +869,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Always allocate the first `HirId` for the owner itself. #[cfg(debug_assertions)] - { - let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); - debug_assert_eq!(_old, None); - } + self.relowering_checker.assert_node_is_not_relowered(owner, hir::ItemLocalId::ZERO); let item = f(self); assert_eq!(owner_id, item.def_id()); @@ -845,7 +887,7 @@ impl<'hir> LoweringContext<'_, 'hir> { #[cfg(debug_assertions)] { - self.node_id_to_local_id = current_node_id_to_local_id; + self.relowering_checker = current_relowering_checker; } self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; @@ -936,10 +978,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Check whether the same `NodeId` is lowered more than once. #[cfg(debug_assertions)] - { - let old = self.node_id_to_local_id.insert(ast_node_id, local_id); - assert_eq!(old, None); - } + self.relowering_checker.assert_node_is_not_relowered(ast_node_id, local_id); hir_id } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 254d5fdd5f80c..153212def0731 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3877,7 +3877,7 @@ pub enum DelegationSelfTyPropagationKind { #[derive(Debug, Clone, Copy, PartialEq, Eq, StableHash)] pub struct DelegationInfo { pub call_expr_id: HirId, - pub call_path_res: Option, + pub call_path_res: DefId, /// Id of the child segment in delegation: `reuse Trait::foo`, /// `child_seg_id` points to `foo`. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index bb822f8d0f68d..c8e54aed87661 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -724,17 +724,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - let Some(path_res_id) = info.call_path_res else { return None }; - // Check that delegation has first provided arg and that the call path // resolves to a trait method (inherent methods are not yet supported). if arg_exprs.is_empty() - || !self.tcx.opt_associated_item(path_res_id).is_some_and(|i| i.is_method()) + || !self.tcx.opt_associated_item(info.call_path_res).is_some_and(|i| i.is_method()) { return None; } - Some(ProbeScope::Single(path_res_id)) + Some(ProbeScope::Single(info.call_path_res)) } /// Attempts to reinterpret `method(rcvr, args...)` as `rcvr.method(args...)` diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index 2c2c622e09006..3700b04160292 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -33,6 +33,7 @@ impl Trait for S { reuse foo { &self.0 } //~^ ERROR cannot find function `foo` in this scope + //~| ERROR: method `foo` has a `&self` declaration in the trait, but not in the impl reuse Trait::foo2 { self.0 } //~^ ERROR cannot find function `foo2` in trait `Trait` //~| ERROR method `foo2` is not a member of trait `Trait` diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index d1b3974e77081..29460e0ce982f 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -26,7 +26,7 @@ LL | reuse ::baz; | not a member of trait `Trait` error[E0407]: method `foo2` is not a member of trait `Trait` - --> $DIR/bad-resolve.rs:36:5 + --> $DIR/bad-resolve.rs:37:5 | LL | reuse Trait::foo2 { self.0 } | ^^^^^^^^^^^^^----^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | reuse foo { &self.0 } | ^^^ not found in this scope error[E0425]: cannot find function `foo2` in trait `Trait` - --> $DIR/bad-resolve.rs:36:18 + --> $DIR/bad-resolve.rs:37:18 | LL | fn foo(&self, x: i32) -> i32 { x } | ---------------------------- similarly named associated function `foo` defined here @@ -83,11 +83,20 @@ LL + reuse Trait::foo { self.0 } | error[E0423]: expected function, found module `prefix::self` - --> $DIR/bad-resolve.rs:43:7 + --> $DIR/bad-resolve.rs:44:7 | LL | reuse prefix::{self, super, crate}; | ^^^^^^ not a function +error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl + --> $DIR/bad-resolve.rs:34:11 + | +LL | fn foo(&self, x: i32) -> i32 { x } + | ---------------------------- `&self` used in trait +... +LL | reuse foo { &self.0 } + | ^^^ expected `&self` in impl + error[E0046]: not all trait items implemented, missing: `Type` --> $DIR/bad-resolve.rs:21:1 | @@ -98,7 +107,7 @@ LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ missing `Type` in implementation error[E0433]: cannot find module or crate `unresolved_prefix` in this scope - --> $DIR/bad-resolve.rs:42:7 + --> $DIR/bad-resolve.rs:43:7 | LL | reuse unresolved_prefix::{a, b, c}; | ^^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `unresolved_prefix` @@ -106,12 +115,12 @@ LL | reuse unresolved_prefix::{a, b, c}; = help: you might be missing a crate named `unresolved_prefix` error[E0433]: `crate` in paths can only be used in start position - --> $DIR/bad-resolve.rs:43:29 + --> $DIR/bad-resolve.rs:44:29 | LL | reuse prefix::{self, super, crate}; | ^^^^^ can only be used in path start position -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors -Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0433, E0575, E0576. +Some errors have detailed explanations: E0046, E0186, E0324, E0407, E0423, E0425, E0433, E0575, E0576. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/self-mapping-arguments-errors.rs b/tests/ui/delegation/self-mapping-arguments-errors.rs new file mode 100644 index 0000000000000..c7789c69be805 --- /dev/null +++ b/tests/ui/delegation/self-mapping-arguments-errors.rs @@ -0,0 +1,47 @@ +#![feature(fn_delegation)] + +mod target_expr_doesnt_relower_when_defs_inside { + trait MyAdd { + fn add(self, other: Self) -> Self; + } + + impl MyAdd for usize { + fn add(self, other: usize) -> usize { self + other } + } + + #[derive(Eq, PartialEq, Debug)] + struct W(usize); + reuse impl MyAdd for W { + //~^ ERROR: attempted to lower target expression with definitions more than once while mapping argument + //~| ERROR: method `add` has a `self` declaration in the trait, but not in the impl + //~| ERROR: the trait bound `(): target_expr_doesnt_relower_when_defs_inside::MyAdd` is not satisfied + //~| ERROR: this function takes 2 arguments but 1 argument was supplied + println!("{self:?}"); + fn foo() { + println!("hello"); + } + + reuse foo as bar; + bar(); + bar(); + + self.0 + } +} + +mod complex_Self_doesnt_map { + trait MyAdd { + fn add(self, other: Box) -> Self; + } + + impl MyAdd for usize { + fn add(self, other: Box) -> usize { self + *other.as_ref() } + } + + #[derive(Eq, PartialEq, Debug)] + struct W(usize); + reuse impl MyAdd for W { self.0 } + //~^ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/delegation/self-mapping-arguments-errors.stderr b/tests/ui/delegation/self-mapping-arguments-errors.stderr new file mode 100644 index 0000000000000..6208a1463c443 --- /dev/null +++ b/tests/ui/delegation/self-mapping-arguments-errors.stderr @@ -0,0 +1,98 @@ +error: attempted to lower target expression with definitions more than once while mapping argument + --> $DIR/self-mapping-arguments-errors.rs:14:5 + | +LL | / reuse impl MyAdd for W { +... | +LL | | self.0 +LL | | } + | |_____^ + +error[E0186]: method `add` has a `self` declaration in the trait, but not in the impl + --> $DIR/self-mapping-arguments-errors.rs:14:5 + | +LL | fn add(self, other: Self) -> Self; + | ---------------------------------- `self` used in trait +... +LL | / reuse impl MyAdd for W { +... | +LL | | self.0 +LL | | } + | |_____^ expected `self` in impl + +error[E0277]: the trait bound `(): target_expr_doesnt_relower_when_defs_inside::MyAdd` is not satisfied + --> $DIR/self-mapping-arguments-errors.rs:14:5 + | +LL | / reuse impl MyAdd for W { +... | +LL | | self.0 +LL | | } + | |_____^ the trait `target_expr_doesnt_relower_when_defs_inside::MyAdd` is not implemented for `()` + | +help: the following other types implement trait `target_expr_doesnt_relower_when_defs_inside::MyAdd` + --> $DIR/self-mapping-arguments-errors.rs:8:5 + | +LL | impl MyAdd for usize { + | ^^^^^^^^^^^^^^^^^^^^ `usize` +... +LL | reuse impl MyAdd for W { + | ^^^^^^^^^^^^^^^^^^^^^^ `target_expr_doesnt_relower_when_defs_inside::W` + +error[E0061]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/self-mapping-arguments-errors.rs:14:5 + | +LL | / reuse impl MyAdd for W { +... | +LL | | self.0 +LL | | } + | | ^ + | | | + | |_____argument #2 of type `()` is missing + | this implicit `()` return type influences the call expression's return type + | +note: method defined here + --> $DIR/self-mapping-arguments-errors.rs:5:12 + | +LL | fn add(self, other: Self) -> Self; + | ^^^ ----- +help: provide the argument + | +LL ~ }({ +LL + +LL + +LL + +LL + +LL + println!("{self:?}"); +LL + fn foo() { +LL + println!("hello"); +LL + } +LL + +LL + reuse foo as bar; +LL + bar(); +LL + bar(); +LL + +LL + self.0 +LL + }, ()) + | + +error[E0308]: mismatched types + --> $DIR/self-mapping-arguments-errors.rs:43:5 + | +LL | reuse impl MyAdd for W { self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected `Box`, found `Box` + | arguments to this function are incorrect + | this return type influences the call expression's return type + | + = note: expected struct `Box` + found struct `Box` +note: method defined here + --> $DIR/self-mapping-arguments-errors.rs:34:12 + | +LL | fn add(self, other: Box) -> Self; + | ^^^ ----- + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0061, E0186, E0277, E0308. +For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/delegation/self-mapping-arguments.rs b/tests/ui/delegation/self-mapping-arguments.rs new file mode 100644 index 0000000000000..f1b5279927af7 --- /dev/null +++ b/tests/ui/delegation/self-mapping-arguments.rs @@ -0,0 +1,59 @@ +//@ run-pass +//@ check-run-results + +#![feature(fn_delegation)] + + +mod default_test { + trait MyAdd { + fn add(self, other: Self) -> Self; + } + + impl MyAdd for usize { + fn add(self, other: usize) -> usize { self + other } + } + + #[derive(Eq, PartialEq, Debug)] + struct W(usize); + reuse impl MyAdd for W { + println!("{self:?}"); + let _x = 213; + + self.0 + } + + pub fn check() { + assert_eq!(W(1).add(W(2)), W(3)) + } +} + +mod arguments_mapping_works_without_return_self { + trait MyAdd { + fn add(self, other: Self); + } + + impl MyAdd for usize { + fn add(self, other: usize) { + let result = self + other; + println!("{result}"); + } + } + + #[derive(Eq, PartialEq, Debug)] + struct W(usize); + reuse impl MyAdd for W { + println!("{self:?}"); + let _x = 213; + + self.0 + } + + pub fn check() { + W(2).add(W(10)); + } +} + +fn main() { + default_test::check(); + arguments_mapping_works_without_return_self::check(); +} diff --git a/tests/ui/delegation/self-mapping-arguments.run.stdout b/tests/ui/delegation/self-mapping-arguments.run.stdout new file mode 100644 index 0000000000000..d8177420647a8 --- /dev/null +++ b/tests/ui/delegation/self-mapping-arguments.run.stdout @@ -0,0 +1,5 @@ +W(1) +W(2) +W(2) +W(10) +12 From 4b909171f5dddd7c6d9ef278e5075675d4d2edc2 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 30 Jun 2026 18:01:45 +0200 Subject: [PATCH 27/33] add wasm targets to unsupported abi test --- tests/ui/abi/unsupported.aarch64.stderr | 58 ++++++++++++------------- tests/ui/abi/unsupported.arm.stderr | 52 +++++++++++----------- tests/ui/abi/unsupported.i686.stderr | 28 ++++++------ tests/ui/abi/unsupported.riscv32.stderr | 56 ++++++++++++------------ tests/ui/abi/unsupported.riscv64.stderr | 56 ++++++++++++------------ tests/ui/abi/unsupported.rs | 58 +++++++++++++------------ tests/ui/abi/unsupported.x64.stderr | 50 ++++++++++----------- tests/ui/abi/unsupported.x64_win.stderr | 52 +++++++++++----------- 8 files changed, 207 insertions(+), 203 deletions(-) diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 6add008aa60fa..ed9cde8658159 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -1,89 +1,89 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:37:8 + --> $DIR/unsupported.rs:41:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:22 + --> $DIR/unsupported.rs:43: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:43:8 + --> $DIR/unsupported.rs:47:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:8 + --> $DIR/unsupported.rs:49:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:8 + --> $DIR/unsupported.rs:52:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:24 + --> $DIR/unsupported.rs:54:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:8 + --> $DIR/unsupported.rs:58:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:57:8 + --> $DIR/unsupported.rs:61:8 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:60:8 + --> $DIR/unsupported.rs:64:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:63:8 + --> $DIR/unsupported.rs:67:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:66:8 + --> $DIR/unsupported.rs:70:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:69:8 + --> $DIR/unsupported.rs:73:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:27 + --> $DIR/unsupported.rs:75:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:8 + --> $DIR/unsupported.rs:79:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:8 + --> $DIR/unsupported.rs:82:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -91,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:82:26 + --> $DIR/unsupported.rs:86:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -99,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:88:8 + --> $DIR/unsupported.rs:92:8 | 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:92:8 + --> $DIR/unsupported.rs:96:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -115,49 +115,49 @@ 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:112:8 + --> $DIR/unsupported.rs:116:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:114:29 + --> $DIR/unsupported.rs:118:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:118:8 + --> $DIR/unsupported.rs:122:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:28 + --> $DIR/unsupported.rs:125:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:126:8 + --> $DIR/unsupported.rs:130:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:128:29 + --> $DIR/unsupported.rs:132:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:8 + --> $DIR/unsupported.rs:136:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:17 + --> $DIR/unsupported.rs:104:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -168,7 +168,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:109:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -178,7 +178,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:112:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,7 +188,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 + --> $DIR/unsupported.rs:101:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index ab345f9e42e96..63b27f428543e 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -1,71 +1,71 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:37:8 + --> $DIR/unsupported.rs:41:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:22 + --> $DIR/unsupported.rs:43: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:43:8 + --> $DIR/unsupported.rs:47:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:8 + --> $DIR/unsupported.rs:49:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:57:8 + --> $DIR/unsupported.rs:61:8 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:60:8 + --> $DIR/unsupported.rs:64:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:63:8 + --> $DIR/unsupported.rs:67:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:66:8 + --> $DIR/unsupported.rs:70:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:69:8 + --> $DIR/unsupported.rs:73:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:27 + --> $DIR/unsupported.rs:75:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:8 + --> $DIR/unsupported.rs:79:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:8 + --> $DIR/unsupported.rs:82:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -73,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:82:26 + --> $DIR/unsupported.rs:86:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -81,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:88:8 + --> $DIR/unsupported.rs:92:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -89,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:92:8 + --> $DIR/unsupported.rs:96:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -97,49 +97,49 @@ 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:112:8 + --> $DIR/unsupported.rs:116:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:114:29 + --> $DIR/unsupported.rs:118:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:118:8 + --> $DIR/unsupported.rs:122:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:28 + --> $DIR/unsupported.rs:125:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:126:8 + --> $DIR/unsupported.rs:130:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:128:29 + --> $DIR/unsupported.rs:132:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:8 + --> $DIR/unsupported.rs:136:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:17 + --> $DIR/unsupported.rs:104:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:109:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:112:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 + --> $DIR/unsupported.rs:101:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 0b29b557c6d48..11084099308c8 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -1,83 +1,83 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:37:8 + --> $DIR/unsupported.rs:41:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:22 + --> $DIR/unsupported.rs:43: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:43:8 + --> $DIR/unsupported.rs:47:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:8 + --> $DIR/unsupported.rs:49:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:8 + --> $DIR/unsupported.rs:52:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:24 + --> $DIR/unsupported.rs:54:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:8 + --> $DIR/unsupported.rs:58:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:57:8 + --> $DIR/unsupported.rs:61:8 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:60:8 + --> $DIR/unsupported.rs:64:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:63:8 + --> $DIR/unsupported.rs:67:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:28 + --> $DIR/unsupported.rs:125:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:126:8 + --> $DIR/unsupported.rs:130:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:128:29 + --> $DIR/unsupported.rs:132:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:8 + --> $DIR/unsupported.rs:136:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index e2ca35d6a50e2..584a7769fd4a2 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -1,83 +1,83 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:37:8 + --> $DIR/unsupported.rs:41:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:22 + --> $DIR/unsupported.rs:43: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:43:8 + --> $DIR/unsupported.rs:47:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:8 + --> $DIR/unsupported.rs:49:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:8 + --> $DIR/unsupported.rs:52:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:24 + --> $DIR/unsupported.rs:54:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:8 + --> $DIR/unsupported.rs:58:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:57:8 + --> $DIR/unsupported.rs:61:8 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:60:8 + --> $DIR/unsupported.rs:64:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:66:8 + --> $DIR/unsupported.rs:70:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:69:8 + --> $DIR/unsupported.rs:73:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:27 + --> $DIR/unsupported.rs:75:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:8 + --> $DIR/unsupported.rs:79:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:8 + --> $DIR/unsupported.rs:82:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -85,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:82:26 + --> $DIR/unsupported.rs:86:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -93,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:88:8 + --> $DIR/unsupported.rs:92:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -101,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:92:8 + --> $DIR/unsupported.rs:96:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -109,49 +109,49 @@ 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:112:8 + --> $DIR/unsupported.rs:116:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:114:29 + --> $DIR/unsupported.rs:118:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:118:8 + --> $DIR/unsupported.rs:122:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:28 + --> $DIR/unsupported.rs:125:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:126:8 + --> $DIR/unsupported.rs:130:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:128:29 + --> $DIR/unsupported.rs:132:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:8 + --> $DIR/unsupported.rs:136:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:17 + --> $DIR/unsupported.rs:104:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:109:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:112:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -182,7 +182,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 + --> $DIR/unsupported.rs:101:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index e2ca35d6a50e2..584a7769fd4a2 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -1,83 +1,83 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:37:8 + --> $DIR/unsupported.rs:41:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:22 + --> $DIR/unsupported.rs:43: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:43:8 + --> $DIR/unsupported.rs:47:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:8 + --> $DIR/unsupported.rs:49:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:8 + --> $DIR/unsupported.rs:52:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:24 + --> $DIR/unsupported.rs:54:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:8 + --> $DIR/unsupported.rs:58:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:57:8 + --> $DIR/unsupported.rs:61:8 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:60:8 + --> $DIR/unsupported.rs:64:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:66:8 + --> $DIR/unsupported.rs:70:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:69:8 + --> $DIR/unsupported.rs:73:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:27 + --> $DIR/unsupported.rs:75:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:8 + --> $DIR/unsupported.rs:79:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:8 + --> $DIR/unsupported.rs:82:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -85,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:82:26 + --> $DIR/unsupported.rs:86:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -93,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:88:8 + --> $DIR/unsupported.rs:92:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -101,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:92:8 + --> $DIR/unsupported.rs:96:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -109,49 +109,49 @@ 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:112:8 + --> $DIR/unsupported.rs:116:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:114:29 + --> $DIR/unsupported.rs:118:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:118:8 + --> $DIR/unsupported.rs:122:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:28 + --> $DIR/unsupported.rs:125:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:126:8 + --> $DIR/unsupported.rs:130:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:128:29 + --> $DIR/unsupported.rs:132:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:8 + --> $DIR/unsupported.rs:136:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:17 + --> $DIR/unsupported.rs:104:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:109:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:112:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -182,7 +182,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 + --> $DIR/unsupported.rs:101:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 7f7963ea51e18..0abc25a6114bd 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -1,5 +1,5 @@ //@ add-minicore -//@ revisions: x64 x64_win i686 aarch64 arm riscv32 riscv64 +//@ revisions: x64 x64_win i686 aarch64 arm riscv32 riscv64 wasm32 wasm64 // //@ [x64] needs-llvm-components: x86 //@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib @@ -15,6 +15,10 @@ //@ [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 +//@ [wasm32] needs-llvm-components: webassembly +//@ [wasm32] compile-flags: --target wasm32-unknown-unknown --crate-type=rlib +//@ [wasm64] needs-llvm-components: webassembly +//@ [wasm64] compile-flags: --target wasm64-unknown-unknown --crate-type=rlib //@ ignore-backends: gcc #![no_core] #![feature( @@ -37,7 +41,7 @@ use minicore::*; extern "ptx-kernel" fn ptx() {} //~^ ERROR is not a supported ABI fn ptx_ptr(f: extern "ptx-kernel" fn()) { -//~^ ERROR is not a supported ABI + //~^ ERROR is not a supported ABI f() } extern "ptx-kernel" {} @@ -46,13 +50,13 @@ extern "gpu-kernel" fn gpu() {} //~^ ERROR is not a supported ABI extern "aapcs" fn aapcs() {} -//[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[x64,x64_win,i686,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI fn aapcs_ptr(f: extern "aapcs" fn()) { - //[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI + //[x64,x64_win,i686,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI f() } extern "aapcs" {} -//[x64,x64_win,i686,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[x64,x64_win,i686,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI extern "msp430-interrupt" {} //~^ ERROR is not a supported ABI @@ -61,72 +65,72 @@ extern "avr-interrupt" {} //~^ ERROR is not a supported ABI extern "riscv-interrupt-m" {} -//[x64,x64_win,i686,arm,aarch64]~^ ERROR is not a supported ABI +//[x64,x64_win,i686,arm,aarch64,wasm32,wasm64]~^ ERROR is not a supported ABI extern "x86-interrupt" {} -//[aarch64,arm,riscv32,riscv64]~^ ERROR is not a supported ABI +//[aarch64,arm,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI extern "thiscall" fn thiscall() {} -//[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[x64,x64_win,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI fn thiscall_ptr(f: extern "thiscall" fn()) { - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI + //[x64,x64_win,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI f() } extern "thiscall" {} -//[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[x64,x64_win,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI extern "stdcall" fn stdcall() {} -//[x64,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[x64,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI //[x64_win]~^^ WARN unsupported_calling_conventions //[x64_win]~^^^ WARN this was previously accepted fn stdcall_ptr(f: extern "stdcall" fn()) { - //[x64,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI + //[x64,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI //[x64_win]~^^ WARN unsupported_calling_conventions //[x64_win]~| WARN this was previously accepted f() } extern "stdcall" {} -//[x64,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[x64,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI //[x64_win]~^^ WARN unsupported_calling_conventions //[x64_win]~^^^ WARN this was previously accepted extern "stdcall-unwind" {} -//[x64,arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[x64,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI //[x64_win]~^^ WARN unsupported_calling_conventions //[x64_win]~^^^ WARN this was previously accepted extern "cdecl" fn cdecl() {} -//[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,wasm32,wasm64]~^ WARN unsupported_calling_conventions +//[x64,x64_win,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^^ 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,wasm32,wasm64]~^ WARN unsupported_calling_conventions + //[x64,x64_win,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~| WARN this was previously accepted f() } extern "cdecl" {} -//[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,wasm32,wasm64]~^ WARN unsupported_calling_conventions +//[x64,x64_win,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^^ WARN this was previously accepted extern "cdecl-unwind" {} -//[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,wasm32,wasm64]~^ WARN unsupported_calling_conventions +//[x64,x64_win,arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^^ WARN this was previously accepted extern "vectorcall" fn vectorcall() {} -//[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI fn vectorcall_ptr(f: extern "vectorcall" fn()) { - //[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI + //[arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI f() } extern "vectorcall" {} -//[arm,aarch64,riscv32,riscv64]~^ ERROR is not a supported ABI +//[arm,aarch64,riscv32,riscv64,wasm32,wasm64]~^ ERROR is not a supported ABI fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { -//~^ ERROR is not a supported ABI + //~^ ERROR is not a supported ABI f() } extern "cmse-nonsecure-entry" fn cmse_entry() {} //~^ ERROR is not a supported ABI fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { -//~^ ERROR is not a supported ABI + //~^ ERROR is not a supported ABI f() } extern "cmse-nonsecure-entry" {} diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 41842eecbd020..a664651a80867 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -1,83 +1,83 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:37:8 + --> $DIR/unsupported.rs:41:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:22 + --> $DIR/unsupported.rs:43: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:43:8 + --> $DIR/unsupported.rs:47:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:8 + --> $DIR/unsupported.rs:49:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:8 + --> $DIR/unsupported.rs:52:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:24 + --> $DIR/unsupported.rs:54:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:8 + --> $DIR/unsupported.rs:58:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:57:8 + --> $DIR/unsupported.rs:61:8 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:60:8 + --> $DIR/unsupported.rs:64:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:63:8 + --> $DIR/unsupported.rs:67:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:69:8 + --> $DIR/unsupported.rs:73:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:27 + --> $DIR/unsupported.rs:75:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:8 + --> $DIR/unsupported.rs:79:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:8 + --> $DIR/unsupported.rs:82:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -85,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:82:26 + --> $DIR/unsupported.rs:86:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -93,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:88:8 + --> $DIR/unsupported.rs:92:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -101,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:92:8 + --> $DIR/unsupported.rs:96:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -109,31 +109,31 @@ 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]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:28 + --> $DIR/unsupported.rs:125:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:126:8 + --> $DIR/unsupported.rs:130:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:128:29 + --> $DIR/unsupported.rs:132:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:8 + --> $DIR/unsupported.rs:136:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:17 + --> $DIR/unsupported.rs:104:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:109:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:112:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +164,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 + --> $DIR/unsupported.rs:101:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 79938f04c5996..5a6d2f148d470 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -1,107 +1,107 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:37:8 + --> $DIR/unsupported.rs:41:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:39:22 + --> $DIR/unsupported.rs:43: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:43:8 + --> $DIR/unsupported.rs:47:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:45:8 + --> $DIR/unsupported.rs:49:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:48:8 + --> $DIR/unsupported.rs:52:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:50:24 + --> $DIR/unsupported.rs:54:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:8 + --> $DIR/unsupported.rs:58:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:57:8 + --> $DIR/unsupported.rs:61:8 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^ error[E0570]: "avr-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:60:8 + --> $DIR/unsupported.rs:64:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:63:8 + --> $DIR/unsupported.rs:67:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:69:8 + --> $DIR/unsupported.rs:73:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:71:27 + --> $DIR/unsupported.rs:75:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:8 + --> $DIR/unsupported.rs:79:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:28 + --> $DIR/unsupported.rs:125:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:126:8 + --> $DIR/unsupported.rs:130:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:128:29 + --> $DIR/unsupported.rs:132:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:8 + --> $DIR/unsupported.rs:136:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:82:19 + --> $DIR/unsupported.rs:86:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:88:1 + --> $DIR/unsupported.rs:92:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | extern "stdcall" {} = note: for more information, see issue #137018 warning: "stdcall-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:92:1 + --> $DIR/unsupported.rs:96:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | extern "stdcall-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:100:17 + --> $DIR/unsupported.rs:104:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:105:1 + --> $DIR/unsupported.rs:109:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -152,7 +152,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:108:1 + --> $DIR/unsupported.rs:112:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:137:1 + --> $DIR/unsupported.rs:141:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:78:1 + --> $DIR/unsupported.rs:82:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -182,7 +182,7 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:97:1 + --> $DIR/unsupported.rs:101:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ From 3decf25956a0e34505e1b237a5f306d8659502aa Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 30 Jun 2026 18:14:11 +0200 Subject: [PATCH 28/33] disallow `extern "custom"` on wasm --- compiler/rustc_target/src/spec/abi_map.rs | 7 +- tests/ui/abi/unsupported.aarch64.stderr | 58 +++--- tests/ui/abi/unsupported.arm.stderr | 52 +++--- tests/ui/abi/unsupported.i686.stderr | 28 +-- tests/ui/abi/unsupported.riscv32.stderr | 56 +++--- tests/ui/abi/unsupported.riscv64.stderr | 56 +++--- tests/ui/abi/unsupported.rs | 10 +- tests/ui/abi/unsupported.wasm32.stderr | 214 ++++++++++++++++++++++ tests/ui/abi/unsupported.wasm64.stderr | 214 ++++++++++++++++++++++ tests/ui/abi/unsupported.x64.stderr | 50 ++--- tests/ui/abi/unsupported.x64_win.stderr | 52 +++--- 11 files changed, 618 insertions(+), 179 deletions(-) create mode 100644 tests/ui/abi/unsupported.wasm32.stderr create mode 100644 tests/ui/abi/unsupported.wasm64.stderr diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index f7a7ae1eb7555..607ca691c3afd 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -62,6 +62,7 @@ impl AbiMap { Arch::RiscV32 | Arch::RiscV64 => ArchKind::Riscv, Arch::X86 => ArchKind::X86, Arch::X86_64 => ArchKind::X86_64, + Arch::Wasm32 | Arch::Wasm64 => ArchKind::Wasm, _ => ArchKind::Other, }; @@ -102,8 +103,6 @@ impl AbiMap { (ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone, (ExternAbi::RustTail, _) => CanonAbi::RustTail, - (ExternAbi::Custom, _) => CanonAbi::Custom, - (ExternAbi::Swift, _) => CanonAbi::Swift, (ExternAbi::System { .. }, ArchKind::X86) @@ -122,6 +121,9 @@ impl AbiMap { // always and forever (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid, + (ExternAbi::Custom, ArchKind::Wasm) => return AbiMapping::Invalid, + (ExternAbi::Custom, _) => CanonAbi::Custom, + (ExternAbi::EfiApi, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), (ExternAbi::EfiApi, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64), ( @@ -221,6 +223,7 @@ enum ArchKind { Riscv, X86, X86_64, + Wasm, /// Architectures which don't need other considerations for ABI lowering Other, } diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index ed9cde8658159..f0768b8953c5b 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -1,89 +1,89 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:8 + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:22 + --> $DIR/unsupported.rs:44: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:47:8 + --> $DIR/unsupported.rs:48:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:49:8 + --> $DIR/unsupported.rs:50:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:52:8 + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:24 + --> $DIR/unsupported.rs:55:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:61:8 + --> $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:64:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:70:8 + --> $DIR/unsupported.rs:71:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:73:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:27 + --> $DIR/unsupported.rs:76:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:79:8 + --> $DIR/unsupported.rs:80:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:82:8 + --> $DIR/unsupported.rs:83:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -91,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:86:26 + --> $DIR/unsupported.rs:87:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -99,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:92:8 + --> $DIR/unsupported.rs:93:8 | 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:96:8 + --> $DIR/unsupported.rs:97:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -115,49 +115,49 @@ 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:116:8 + --> $DIR/unsupported.rs:117:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:118:29 + --> $DIR/unsupported.rs:119:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:8 + --> $DIR/unsupported.rs:123:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:28 + --> $DIR/unsupported.rs:126:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:29 + --> $DIR/unsupported.rs:133:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:136:8 + --> $DIR/unsupported.rs:137:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:104:17 + --> $DIR/unsupported.rs:105:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -168,7 +168,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:109:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -178,7 +178,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:112:1 + --> $DIR/unsupported.rs:113:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,7 +188,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:101:1 + --> $DIR/unsupported.rs:102:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 63b27f428543e..dc50397601690 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -1,71 +1,71 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:8 + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:22 + --> $DIR/unsupported.rs:44: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:47:8 + --> $DIR/unsupported.rs:48:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:49:8 + --> $DIR/unsupported.rs:50:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:61:8 + --> $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:64:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:70:8 + --> $DIR/unsupported.rs:71:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:73:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:27 + --> $DIR/unsupported.rs:76:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:79:8 + --> $DIR/unsupported.rs:80:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:82:8 + --> $DIR/unsupported.rs:83:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -73,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:86:26 + --> $DIR/unsupported.rs:87:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -81,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:92:8 + --> $DIR/unsupported.rs:93:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -89,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:96:8 + --> $DIR/unsupported.rs:97:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -97,49 +97,49 @@ 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:116:8 + --> $DIR/unsupported.rs:117:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:118:29 + --> $DIR/unsupported.rs:119:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:8 + --> $DIR/unsupported.rs:123:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:28 + --> $DIR/unsupported.rs:126:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:29 + --> $DIR/unsupported.rs:133:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:136:8 + --> $DIR/unsupported.rs:137:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:104:17 + --> $DIR/unsupported.rs:105:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:109:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:112:1 + --> $DIR/unsupported.rs:113:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:101:1 + --> $DIR/unsupported.rs:102:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 11084099308c8..65a8e44d06b4b 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -1,83 +1,83 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:8 + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:22 + --> $DIR/unsupported.rs:44: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:47:8 + --> $DIR/unsupported.rs:48:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:49:8 + --> $DIR/unsupported.rs:50:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:52:8 + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:24 + --> $DIR/unsupported.rs:55:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:61:8 + --> $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:64:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:28 + --> $DIR/unsupported.rs:126:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:29 + --> $DIR/unsupported.rs:133:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:136:8 + --> $DIR/unsupported.rs:137:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index 584a7769fd4a2..de7f5e436154e 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -1,83 +1,83 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:8 + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:22 + --> $DIR/unsupported.rs:44: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:47:8 + --> $DIR/unsupported.rs:48:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:49:8 + --> $DIR/unsupported.rs:50:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:52:8 + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:24 + --> $DIR/unsupported.rs:55:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:61:8 + --> $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:64:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:70:8 + --> $DIR/unsupported.rs:71:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:73:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:27 + --> $DIR/unsupported.rs:76:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:79:8 + --> $DIR/unsupported.rs:80:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:82:8 + --> $DIR/unsupported.rs:83:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -85,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:86:26 + --> $DIR/unsupported.rs:87:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -93,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:92:8 + --> $DIR/unsupported.rs:93:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -101,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:96:8 + --> $DIR/unsupported.rs:97:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -109,49 +109,49 @@ 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:116:8 + --> $DIR/unsupported.rs:117:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:118:29 + --> $DIR/unsupported.rs:119:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:8 + --> $DIR/unsupported.rs:123:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:28 + --> $DIR/unsupported.rs:126:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:29 + --> $DIR/unsupported.rs:133:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:136:8 + --> $DIR/unsupported.rs:137:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:104:17 + --> $DIR/unsupported.rs:105:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:109:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:112:1 + --> $DIR/unsupported.rs:113:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -182,7 +182,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:101:1 + --> $DIR/unsupported.rs:102:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index 584a7769fd4a2..de7f5e436154e 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -1,83 +1,83 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:8 + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:22 + --> $DIR/unsupported.rs:44: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:47:8 + --> $DIR/unsupported.rs:48:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:49:8 + --> $DIR/unsupported.rs:50:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:52:8 + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:24 + --> $DIR/unsupported.rs:55:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:61:8 + --> $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:64:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "x86-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:70:8 + --> $DIR/unsupported.rs:71:8 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:73:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:27 + --> $DIR/unsupported.rs:76:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:79:8 + --> $DIR/unsupported.rs:80:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:82:8 + --> $DIR/unsupported.rs:83:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -85,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:86:26 + --> $DIR/unsupported.rs:87:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -93,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:92:8 + --> $DIR/unsupported.rs:93:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -101,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:96:8 + --> $DIR/unsupported.rs:97:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -109,49 +109,49 @@ 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:116:8 + --> $DIR/unsupported.rs:117:8 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:118:29 + --> $DIR/unsupported.rs:119:29 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^ error[E0570]: "vectorcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:122:8 + --> $DIR/unsupported.rs:123:8 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:28 + --> $DIR/unsupported.rs:126:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:29 + --> $DIR/unsupported.rs:133:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:136:8 + --> $DIR/unsupported.rs:137:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:104:17 + --> $DIR/unsupported.rs:105:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:109:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:112:1 + --> $DIR/unsupported.rs:113:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -182,7 +182,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:101:1 + --> $DIR/unsupported.rs:102:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 0abc25a6114bd..661691956cb5d 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -32,7 +32,8 @@ abi_riscv_interrupt, abi_cmse_nonsecure_call, abi_vectorcall, - cmse_nonsecure_entry + cmse_nonsecure_entry, + abi_custom )] extern crate minicore; @@ -141,3 +142,10 @@ extern "cmse-nonsecure-entry" {} extern "cdecl" {} //[x64_win]~^ WARN unsupported_calling_conventions //[x64_win]~^^ WARN this was previously accepted + +fn custom_ptr(f: extern "custom" fn()) { + //[wasm32,wasm64]~^ ERROR is not a supported ABI + let _ = f; +} +extern "custom" {} +//[wasm32,wasm64]~^ ERROR is not a supported ABI diff --git a/tests/ui/abi/unsupported.wasm32.stderr b/tests/ui/abi/unsupported.wasm32.stderr new file mode 100644 index 0000000000000..9314c287b8591 --- /dev/null +++ b/tests/ui/abi/unsupported.wasm32.stderr @@ -0,0 +1,214 @@ +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44: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:48:8 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^ + +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:50:8 + | +LL | extern "gpu-kernel" fn gpu() {} + | ^^^^^^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:53:8 + | +LL | extern "aapcs" fn aapcs() {} + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:55:24 + | +LL | fn aapcs_ptr(f: extern "aapcs" fn()) { + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:59:8 + | +LL | extern "aapcs" {} + | ^^^^^^^ + +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" {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:68:8 + | +LL | extern "riscv-interrupt-m" {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 + | +LL | extern "x86-interrupt" {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:74:8 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:27 + | +LL | fn thiscall_ptr(f: extern "thiscall" fn()) { + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:80:8 + | +LL | extern "thiscall" {} + | ^^^^^^^^^^ + +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:83:8 + | +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:87: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:93: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:97:8 + | +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:117:8 + | +LL | extern "vectorcall" fn vectorcall() {} + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:119:29 + | +LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:123:8 + | +LL | extern "vectorcall" {} + | ^^^^^^^^^^^^ + +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:126:28 + | +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:131:8 + | +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:133:29 + | +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:137:8 + | +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "custom" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:25 + | +LL | fn custom_ptr(f: extern "custom" fn()) { + | ^^^^^^^^ + +error[E0570]: "custom" is not a supported ABI for the current target + --> $DIR/unsupported.rs:150:8 + | +LL | extern "custom" {} + | ^^^^^^^^ + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:105:17 + | +LL | fn cdecl_ptr(f: extern "cdecl" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + | + = help: use `extern "C"` instead + = 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 #137018 + = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:110:1 + | +LL | extern "cdecl" {} + | ^^^^^^^^^^^^^^^^^ + | + = help: use `extern "C"` instead + = 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 #137018 + +warning: "cdecl-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:113:1 + | +LL | extern "cdecl-unwind" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `extern "C-unwind"` instead + = 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 #137018 + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:102:1 + | +LL | extern "cdecl" fn cdecl() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `extern "C"` instead + = 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 #137018 + +error: aborting due to 27 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.wasm64.stderr b/tests/ui/abi/unsupported.wasm64.stderr new file mode 100644 index 0000000000000..9314c287b8591 --- /dev/null +++ b/tests/ui/abi/unsupported.wasm64.stderr @@ -0,0 +1,214 @@ +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:42:8 + | +LL | extern "ptx-kernel" fn ptx() {} + | ^^^^^^^^^^^^ + +error[E0570]: "ptx-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:44: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:48:8 + | +LL | extern "ptx-kernel" {} + | ^^^^^^^^^^^^ + +error[E0570]: "gpu-kernel" is not a supported ABI for the current target + --> $DIR/unsupported.rs:50:8 + | +LL | extern "gpu-kernel" fn gpu() {} + | ^^^^^^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:53:8 + | +LL | extern "aapcs" fn aapcs() {} + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:55:24 + | +LL | fn aapcs_ptr(f: extern "aapcs" fn()) { + | ^^^^^^^ + +error[E0570]: "aapcs" is not a supported ABI for the current target + --> $DIR/unsupported.rs:59:8 + | +LL | extern "aapcs" {} + | ^^^^^^^ + +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" {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target + --> $DIR/unsupported.rs:68:8 + | +LL | extern "riscv-interrupt-m" {} + | ^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "x86-interrupt" is not a supported ABI for the current target + --> $DIR/unsupported.rs:71:8 + | +LL | extern "x86-interrupt" {} + | ^^^^^^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:74:8 + | +LL | extern "thiscall" fn thiscall() {} + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:76:27 + | +LL | fn thiscall_ptr(f: extern "thiscall" fn()) { + | ^^^^^^^^^^ + +error[E0570]: "thiscall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:80:8 + | +LL | extern "thiscall" {} + | ^^^^^^^^^^ + +error[E0570]: "stdcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:83:8 + | +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:87: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:93: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:97:8 + | +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:117:8 + | +LL | extern "vectorcall" fn vectorcall() {} + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:119:29 + | +LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { + | ^^^^^^^^^^^^ + +error[E0570]: "vectorcall" is not a supported ABI for the current target + --> $DIR/unsupported.rs:123:8 + | +LL | extern "vectorcall" {} + | ^^^^^^^^^^^^ + +error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target + --> $DIR/unsupported.rs:126:28 + | +LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:131:8 + | +LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:133:29 + | +LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target + --> $DIR/unsupported.rs:137:8 + | +LL | extern "cmse-nonsecure-entry" {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0570]: "custom" is not a supported ABI for the current target + --> $DIR/unsupported.rs:146:25 + | +LL | fn custom_ptr(f: extern "custom" fn()) { + | ^^^^^^^^ + +error[E0570]: "custom" is not a supported ABI for the current target + --> $DIR/unsupported.rs:150:8 + | +LL | extern "custom" {} + | ^^^^^^^^ + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:105:17 + | +LL | fn cdecl_ptr(f: extern "cdecl" fn()) { + | ^^^^^^^^^^^^^^^^^^^ + | + = help: use `extern "C"` instead + = 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 #137018 + = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:110:1 + | +LL | extern "cdecl" {} + | ^^^^^^^^^^^^^^^^^ + | + = help: use `extern "C"` instead + = 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 #137018 + +warning: "cdecl-unwind" is not a supported ABI for the current target + --> $DIR/unsupported.rs:113:1 + | +LL | extern "cdecl-unwind" {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `extern "C-unwind"` instead + = 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 #137018 + +warning: "cdecl" is not a supported ABI for the current target + --> $DIR/unsupported.rs:102:1 + | +LL | extern "cdecl" fn cdecl() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `extern "C"` instead + = 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 #137018 + +error: aborting due to 27 previous errors; 4 warnings emitted + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index a664651a80867..a1233e2c13cf3 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -1,83 +1,83 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:8 + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:22 + --> $DIR/unsupported.rs:44: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:47:8 + --> $DIR/unsupported.rs:48:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:49:8 + --> $DIR/unsupported.rs:50:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:52:8 + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:24 + --> $DIR/unsupported.rs:55:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:61:8 + --> $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:64:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:73:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:27 + --> $DIR/unsupported.rs:76:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:79:8 + --> $DIR/unsupported.rs:80:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:82:8 + --> $DIR/unsupported.rs:83:8 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^ @@ -85,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:86:26 + --> $DIR/unsupported.rs:87:26 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^ @@ -93,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:92:8 + --> $DIR/unsupported.rs:93:8 | LL | extern "stdcall" {} | ^^^^^^^^^ @@ -101,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:96:8 + --> $DIR/unsupported.rs:97:8 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^ @@ -109,31 +109,31 @@ 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]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:28 + --> $DIR/unsupported.rs:126:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:29 + --> $DIR/unsupported.rs:133:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:136:8 + --> $DIR/unsupported.rs:137:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:104:17 + --> $DIR/unsupported.rs:105:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:109:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:112:1 + --> $DIR/unsupported.rs:113:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +164,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:101:1 + --> $DIR/unsupported.rs:102:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 5a6d2f148d470..a011fcf4a06fb 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -1,107 +1,107 @@ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:41:8 + --> $DIR/unsupported.rs:42:8 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^ error[E0570]: "ptx-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:22 + --> $DIR/unsupported.rs:44: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:47:8 + --> $DIR/unsupported.rs:48:8 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^ error[E0570]: "gpu-kernel" is not a supported ABI for the current target - --> $DIR/unsupported.rs:49:8 + --> $DIR/unsupported.rs:50:8 | LL | extern "gpu-kernel" fn gpu() {} | ^^^^^^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:52:8 + --> $DIR/unsupported.rs:53:8 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:54:24 + --> $DIR/unsupported.rs:55:24 | LL | fn aapcs_ptr(f: extern "aapcs" fn()) { | ^^^^^^^ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported.rs:58:8 + --> $DIR/unsupported.rs:59:8 | LL | extern "aapcs" {} | ^^^^^^^ error[E0570]: "msp430-interrupt" is not a supported ABI for the current target - --> $DIR/unsupported.rs:61:8 + --> $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:64:8 + --> $DIR/unsupported.rs:65:8 | LL | extern "avr-interrupt" {} | ^^^^^^^^^^^^^^^ error[E0570]: "riscv-interrupt-m" is not a supported ABI for the current target - --> $DIR/unsupported.rs:67:8 + --> $DIR/unsupported.rs:68:8 | LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:73:8 + --> $DIR/unsupported.rs:74:8 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:75:27 + --> $DIR/unsupported.rs:76:27 | LL | fn thiscall_ptr(f: extern "thiscall" fn()) { | ^^^^^^^^^^ error[E0570]: "thiscall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:79:8 + --> $DIR/unsupported.rs:80:8 | LL | extern "thiscall" {} | ^^^^^^^^^^ error[E0570]: "cmse-nonsecure-call" is not a supported ABI for the current target - --> $DIR/unsupported.rs:125:28 + --> $DIR/unsupported.rs:126:28 | LL | fn cmse_call_ptr(f: extern "cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:130:8 + --> $DIR/unsupported.rs:131:8 | LL | extern "cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:132:29 + --> $DIR/unsupported.rs:133:29 | LL | fn cmse_entry_ptr(f: extern "cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: "cmse-nonsecure-entry" is not a supported ABI for the current target - --> $DIR/unsupported.rs:136:8 + --> $DIR/unsupported.rs:137:8 | LL | extern "cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:86:19 + --> $DIR/unsupported.rs:87:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:92:1 + --> $DIR/unsupported.rs:93:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | extern "stdcall" {} = note: for more information, see issue #137018 warning: "stdcall-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:96:1 + --> $DIR/unsupported.rs:97:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | extern "stdcall-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:104:17 + --> $DIR/unsupported.rs:105:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | fn cdecl_ptr(f: extern "cdecl" fn()) { = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:109:1 + --> $DIR/unsupported.rs:110:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -152,7 +152,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "cdecl-unwind" is not a supported ABI for the current target - --> $DIR/unsupported.rs:112:1 + --> $DIR/unsupported.rs:113:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | extern "cdecl-unwind" {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:1 + --> $DIR/unsupported.rs:142:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | extern "cdecl" {} = note: for more information, see issue #137018 warning: "stdcall" is not a supported ABI for the current target - --> $DIR/unsupported.rs:82:1 + --> $DIR/unsupported.rs:83:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -182,7 +182,7 @@ LL | extern "stdcall" fn stdcall() {} = note: for more information, see issue #137018 warning: "cdecl" is not a supported ABI for the current target - --> $DIR/unsupported.rs:101:1 + --> $DIR/unsupported.rs:102:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ From b10bdc4db4500035aab90a49ca908268fe997a71 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 30 Jun 2026 18:21:23 +0200 Subject: [PATCH 29/33] add `extern "custom"` test to the naked functions tests --- tests/ui/asm/naked-functions.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 55f2f552ad31c..a6ed7d69a0866 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -3,7 +3,7 @@ //@ ignore-spirv //@ reference: attributes.codegen.naked.body -#![feature(asm_unwind, linkage, rustc_attrs, cfg_target_object_format)] +#![feature(asm_unwind, linkage, rustc_attrs, cfg_target_object_format, abi_custom)] #![crate_type = "lib"] use std::arch::{asm, naked_asm}; @@ -241,3 +241,10 @@ pub extern "C" fn rustc_std_internal_symbol() { pub extern "C" fn rustfmt_skip() { naked_asm!("", options(raw)); } + +/// This is here to ensure that for any new target that adds assembly support, we +/// check whether it can/does support `extern "custom"`. +#[unsafe(naked)] +unsafe extern "custom" fn abi_custom() { + naked_asm!("") +} From 5d925d753c8b50a1448c18b8e36247433e570585 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 30 Jun 2026 20:05:59 +0200 Subject: [PATCH 30/33] disallow `extern "custom"` on spirv --- compiler/rustc_target/src/spec/abi_map.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index 607ca691c3afd..dd69afec47975 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -60,9 +60,10 @@ impl AbiMap { Arch::Msp430 => ArchKind::Msp430, Arch::Nvptx64 => ArchKind::Nvptx, Arch::RiscV32 | Arch::RiscV64 => ArchKind::Riscv, + Arch::SpirV => ArchKind::Spirv, + Arch::Wasm32 | Arch::Wasm64 => ArchKind::Wasm, Arch::X86 => ArchKind::X86, Arch::X86_64 => ArchKind::X86_64, - Arch::Wasm32 | Arch::Wasm64 => ArchKind::Wasm, _ => ArchKind::Other, }; @@ -121,7 +122,7 @@ impl AbiMap { // always and forever (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid, - (ExternAbi::Custom, ArchKind::Wasm) => return AbiMapping::Invalid, + (ExternAbi::Custom, ArchKind::Wasm | ArchKind::Spirv) => return AbiMapping::Invalid, (ExternAbi::Custom, _) => CanonAbi::Custom, (ExternAbi::EfiApi, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), @@ -224,6 +225,7 @@ enum ArchKind { X86, X86_64, Wasm, + Spirv, /// Architectures which don't need other considerations for ABI lowering Other, } From 4674b5d223f722d6002dec449c1767b07aa82b81 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 7 Jul 2026 15:06:51 +0200 Subject: [PATCH 31/33] std: unconditionally use `preadv`/`pwritev` on AArch64 macOS --- library/std/src/sys/fd/unix.rs | 37 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index edb2ffc49995e..1a6e882177ae1 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -38,7 +38,10 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[cfg(all(target_os = "android", target_pointer_width = "64"))] use crate::sys::pal::weak::syscall; -#[cfg(any(all(target_os = "android", target_pointer_width = "32"), target_vendor = "apple"))] +#[cfg(any( + all(target_os = "android", target_pointer_width = "32"), + all(target_vendor = "apple", not(all(target_os = "macos", target_arch = "aarch64"))) +))] use crate::sys::pal::weak::weak; use crate::sys::{AsInner, FromInner, IntoInner, cvt}; @@ -219,6 +222,7 @@ impl FileDesc { target_os = "linux", target_os = "netbsd", target_os = "openbsd", // OpenBSD 2.7 + all(target_os = "macos", target_arch = "aarch64"), ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { let ret = cvt(unsafe { @@ -307,14 +311,15 @@ impl FileDesc { // We support old MacOS, iOS, watchOS, tvOS and visionOS. `preadv` was added in the following // Apple OS versions: - // ios 14.0 - // tvos 14.0 - // macos 11.0 - // watchos 7.0 + // iOS 14.0 + // tvOS 14.0 + // macOS 11.0 + // watchOS 7.0 // - // These versions may be newer than the minimum supported versions of OS's we support so we must - // use "weak" linking. - #[cfg(target_vendor = "apple")] + // Since macOS 11.0 is also the first version with AArch64 support, we can + // `preadv` unconditionally there. But on all other targets we must use + // "weak" linking. + #[cfg(all(target_vendor = "apple", not(all(target_os = "macos", target_arch = "aarch64"))))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { weak!( fn preadv( @@ -426,6 +431,7 @@ impl FileDesc { target_os = "linux", target_os = "netbsd", target_os = "openbsd", // OpenBSD 2.7 + all(target_os = "macos", target_arch = "aarch64"), ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { let ret = cvt(unsafe { @@ -514,14 +520,15 @@ impl FileDesc { // We support old MacOS, iOS, watchOS, tvOS and visionOS. `pwritev` was added in the following // Apple OS versions: - // ios 14.0 - // tvos 14.0 - // macos 11.0 - // watchos 7.0 + // iOS 14.0 + // tvOS 14.0 + // macOS 11.0 + // watchOS 7.0 // - // These versions may be newer than the minimum supported versions of OS's we support so we must - // use "weak" linking. - #[cfg(target_vendor = "apple")] + // Since macOS 11.0 is also the first version with AArch64 support, we can + // `pwritev` unconditionally there. But on all other targets we must use + // "weak" linking. + #[cfg(all(target_vendor = "apple", not(all(target_os = "macos", target_arch = "aarch64")),))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { weak!( fn pwritev( From 49769afe4b36702a816eb8bde0230d3b0e194e0c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 8 May 2026 16:07:42 +0200 Subject: [PATCH 32/33] QNX SDP 8 fixes. 1) setsid/setpgrp: check child's group process ID Linux [1], FreeBSD [2] and the Open Group [3] manuals for both setsid and setpgrp state that the calling process will be assigned a process group ID that matches its process ID so check that's the case in the test by calling getpgid on the child process ID. on QNX8 (as of GA8.0.2) libc::kill(pgid) appears unable to terminate the child process so skip that check on that target as it's behavior that libstd provides no API for [1]: https://man7.org/linux/man-pages/man2/setsid.2.html [2]: https://man.freebsd.org/cgi/man.cgi?query=setsid&sektion=2 [3]: https://pubs.opengroup.org/onlinepubs/000095399/functions/setsid.html 2) fix handling of sockaddr_un.len on QNX also extend the existing tests to exercise the getsockname(2) and getpeername(2) paths with both named and unnamed Unix sockets 3) Additional fixes library/std after earlier PR renamed some targets 4) Replace more instances of "QNX Neutrino / QNX OS" with "QNX SDP" and fix up some documentation URLs 5) Tests ignored on target_os = "nto" should also be ignored on target_os = "qnx". 6) Simplify nto-qnx.md documentation cc-rs now knows about QNX so the environment isn't required --- library/std/src/os/unix/net/addr.rs | 18 +++++- library/std/src/os/unix/net/stream.rs | 1 + library/std/src/os/unix/net/tests.rs | 10 +++ library/std/src/os/unix/process.rs | 4 +- library/std/src/sys/pal/unix/time.rs | 4 +- library/std/src/sys/paths/unix.rs | 2 +- .../std/src/sys/process/unix/common/tests.rs | 43 +++++++++++-- library/std/src/sys/process/unix/unix.rs | 10 +-- library/std/src/sys/thread/unix.rs | 9 +-- library/std/src/sys/thread_local/key/racy.rs | 8 +-- src/doc/rustc/src/platform-support.md | 12 ++-- src/doc/rustc/src/platform-support/nto-qnx.md | 61 ++++++------------- .../src/directives/directive_names.rs | 1 + tests/codegen-llvm/thread-local.rs | 1 + tests/ui/abi/stack-probes-lto.rs | 3 +- tests/ui/abi/stack-probes.rs | 3 +- tests/ui/command/command-setgroups.rs | 1 + tests/ui/process/process-spawn-failure.rs | 1 + tests/ui/runtime/out-of-stack.rs | 1 + .../runtime/signal-alternate-stack-cleanup.rs | 1 + .../suggestions/missing-lifetime-specifier.rs | 1 + .../missing-lifetime-specifier.stderr | 18 +++--- 22 files changed, 128 insertions(+), 85 deletions(-) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 304f2f23828de..e13f44d6fc9bd 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -53,7 +53,15 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s let mut len = SUN_PATH_OFFSET + bytes.len(); match bytes.get(0) { Some(&0) | None => {} - Some(_) => len += 1, + Some(_) => { + // on QNX7.1 and QNX8 the `len` value returned by the SUN_LEN + // macro in its libc does not include the null byte in the count so + // don't add it here to match what a C program passes to bind(2) and + // similar functions + if cfg!(not(any(target_os = "qnx", target_env = "nto71"))) { + len += 1 + } + } } Ok((addr, len as libc::socklen_t)) } @@ -247,7 +255,13 @@ impl SocketAddr { } else if self.addr.sun_path[0] == 0 { AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + // the value returned by getsockname(2) and similar on QNX7.1 and + // QNX8 does not count the NUL byte terminator of the path string, + // which matches the behavior of the SUN_LEN macro in libc, but + // other OSes do count the NUL byte so adjust accordingly + let end = + if cfg!(any(target_os = "qnx", target_env = "nto71")) { len } else { len - 1 }; + AddressKind::Pathname(OsStr::from_bytes(&path[..end]).as_ref()) } } } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 4dfa06d74ce7e..a50b10539ebf5 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -256,6 +256,7 @@ impl UnixStream { target_os = "netbsd", target_os = "openbsd", target_os = "nto", + target_os = "qnx", target_vendor = "apple", target_os = "cygwin" ))] diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index f703fc6d54c02..3ba4b44d2f1ef 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -9,6 +9,7 @@ use crate::os::cygwin::net::{SocketAddrExt, UnixSocketExt}; use crate::os::linux::net::{SocketAddrExt, UnixSocketExt}; #[cfg(any(target_os = "android", target_os = "linux"))] use crate::os::unix::io::AsRawFd; +use crate::path::Path; use crate::test_helpers::tmpdir; use crate::thread; use crate::time::Duration; @@ -22,6 +23,12 @@ macro_rules! or_panic { }; } +#[test] +fn sock_addr_from_pathname() { + let address = or_panic!(SocketAddr::from_pathname("/path/to/socket")); + assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); +} + #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")] @@ -32,6 +39,7 @@ fn basic() { let msg2 = b"world!"; let listener = or_panic!(UnixListener::bind(&socket_path)); + assert_eq!(Some(&*socket_path), listener.local_addr().unwrap().as_pathname()); let thread = thread::spawn(move || { let mut stream = or_panic!(listener.accept()).0; let mut buf = [0; 5]; @@ -79,6 +87,8 @@ fn pair() { let msg2 = b"world!"; let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + assert!(s1.local_addr().unwrap().is_unnamed()); + assert!(s2.peer_addr().unwrap().is_unnamed()); let thread = thread::spawn(move || { // s1 must be moved in or the test will hang! let mut buf = [0; 5]; diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index dcec7b2a1077c..d1b0114604080 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -19,9 +19,9 @@ cfg_select! { type GroupId = u16; } any(target_os = "nto", target_os = "qnx") => { - // Both IDs are signed, see `sys/target_nto.h` of the QNX Neutrino SDP. + // Both IDs are signed, see `sys/target_nto.h` of the QNX SDP. // Only positive values should be used, see e.g. - // https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html + // https://www.qnx.com/developers/docs/7.1/com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html type UserId = i32; type GroupId = i32; } diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 26296b5d169a1..9c4ba9f5f388a 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -177,9 +177,9 @@ impl Timespec { }) } - // On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait + // On QNX, the maximum timespec for e.g. pthread_cond_timedwait // is 2^64 nanoseconds - #[cfg(target_os = "nto")] + #[cfg(any(target_os = "nto", target_os = "qnx"))] pub(in crate::sys) fn to_timespec_capped(&self) -> Option { // Check if timeout in nanoseconds would fit into an u64 if (self.tv_nsec.as_inner() as u64) diff --git a/library/std/src/sys/paths/unix.rs b/library/std/src/sys/paths/unix.rs index 36879b7b9bce3..a2b4f34e54b39 100644 --- a/library/std/src/sys/paths/unix.rs +++ b/library/std/src/sys/paths/unix.rs @@ -272,7 +272,7 @@ pub fn current_exe() -> io::Result { #[cfg(any(target_os = "nto", target_os = "qnx"))] pub fn current_exe() -> io::Result { let mut e = crate::fs::read("/proc/self/exefile")?; - // Current versions of QNX Neutrino provide a null-terminated path. + // Current versions of QNX SDP provide a null-terminated path. // Ensure the trailing null byte is not returned here. if let Some(0) = e.last() { e.pop(); diff --git a/library/std/src/sys/process/unix/common/tests.rs b/library/std/src/sys/process/unix/common/tests.rs index 5f71bf051f8a8..bc1d158b74861 100644 --- a/library/std/src/sys/process/unix/common/tests.rs +++ b/library/std/src/sys/process/unix/common/tests.rs @@ -99,8 +99,13 @@ fn test_process_group_posix_spawn() { cmd.stdout(Stdio::MakePipe); let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); + let pid = cat.id() as libc::pid_t; + let pgid = libc::getpgid(pid); + assert_ne!(-1, pgid, "getpgid failed"); + assert_eq!(pid, pgid, "child process ID does not match its process group ID"); + // Check that we can kill its process group, which means there *is* one. - t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + t!(cvt(libc::kill(-pgid, libc::SIGINT))); t!(cat.wait()); } @@ -127,8 +132,18 @@ fn test_process_group_no_posix_spawn() { cmd.stdout(Stdio::MakePipe); let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); + let pid = cat.id() as libc::pid_t; + let pgid = libc::getpgid(pid); + assert_ne!(-1, pgid, "getpgid failed"); + assert_eq!(pid, pgid, "child process ID does not match its process group ID"); + + if cfg!(target_os = "qnx") { + // kill(-pgid) appears to be unable to terminate the child process on QNX8 + return; + } + // Check that we can kill its process group, which means there *is* one. - t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + t!(cvt(libc::kill(-pgid, libc::SIGINT))); t!(cat.wait()); } @@ -154,9 +169,19 @@ fn test_setsid_posix_spawn() { let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); unsafe { + let pid = cat.id() as libc::pid_t; + let pgid = libc::getpgid(pid); + assert_ne!(-1, pgid, "getpgid failed"); + assert_eq!(pid, pgid, "child process ID does not match its process group ID"); + + if cfg!(target_os = "qnx") { + // kill(-pgid) appears to be unable to terminate the child process on QNX8 + return; + } + // Setsid will create a new session and process group, so check that // we can kill the process group, which means there *is* one. - t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + t!(cvt(libc::kill(-pgid, libc::SIGINT))); t!(cat.wait()); } @@ -184,9 +209,19 @@ fn test_setsid_no_posix_spawn() { cmd.pre_exec(Box::new(|| Ok(()))); // pre_exec forces fork + exec rather than posix spawn. let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); + let pid = cat.id() as libc::pid_t; + let pgid = libc::getpgid(pid); + assert_ne!(-1, pgid, "getpgid failed"); + assert_eq!(pid, pgid, "child process ID does not match its process group ID"); + + if cfg!(target_os = "qnx") { + // kill(-pgid) appears to be unable to terminate the child process on QNX8 + return; + } + // Setsid will create a new session and process group, so check that // we can kill the process group, which means there *is* one. - t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + t!(cvt(libc::kill(-pgid, libc::SIGINT))); t!(cat.wait()); } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 55906ed2854f2..51f6d21127f4f 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -193,10 +193,10 @@ impl Command { cvt(libc::fork()) } - // On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened + // On QNX SDP, fork can fail with EBADF in case "another thread might have opened // or closed a file descriptor while the fork() was occurring". // Documentation says "... or try calling fork() again". This is what we do here. - // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html + // See also https://www.qnx.com/developers/docs/7.1/com.qnx.doc.neutrino.lib_ref/topic/f/fork.html #[cfg(any(target_os = "nto", target_os = "qnx"))] unsafe fn do_fork(&mut self) -> Result { use crate::sys::io::errno; @@ -553,10 +553,10 @@ impl Command { } } - // On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened + // On QNX SDP, posix_spawnp can fail with EBADF in case "another thread might have opened // or closed a file descriptor while the posix_spawn() was occurring". // Documentation says "... or try calling posix_spawn() again". This is what we do here. - // See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html + // See also https://www.qnx.com/developers/docs/7.1/com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html #[cfg(any(target_os = "nto", target_os = "qnx"))] unsafe fn retrying_libc_posix_spawnp( pid: *mut pid_t, @@ -756,7 +756,7 @@ impl Command { if self.get_setsid() { cfg_select! { all(target_os = "linux", target_env = "gnu") => { - flags |= libc::POSIX_SPAWN_SETSID; + flags |= libc::POSIX_SPAWN_SETSID as i32; } _ => { return Ok(None); diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index e52ffff165beb..2dbb0314cb271 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -278,7 +278,7 @@ pub fn available_parallelism() -> io::Result> { Ok(unsafe { NonZero::new_unchecked(cpus as usize) }) } - target_os = "nto" => { + any(target_os = "nto", target_os = "qnx") => { unsafe { use libc::_syspage_ptr; if _syspage_ptr.is_null() { @@ -347,7 +347,7 @@ pub fn current_os_id() -> Option { let id: libc::pid_t = unsafe { gettid() }; Some(id as u64) } - target_os = "nto" => { + any(target_os = "nto", target_os = "qnx") => { // SAFETY: FFI call with no preconditions. let id: libc::pid_t = unsafe { libc::gettid() }; Some(id as u64) @@ -392,6 +392,7 @@ pub fn current_os_id() -> Option { #[cfg(any( target_os = "linux", target_os = "nto", + target_os = "qnx", target_os = "solaris", target_os = "illumos", target_os = "vxworks", @@ -484,14 +485,14 @@ pub fn set_name(name: &CStr) { } } -#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] +#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto", target_os = "qnx"))] pub fn set_name(name: &CStr) { weak!( fn pthread_setname_np(thread: libc::pthread_t, name: *const libc::c_char) -> libc::c_int; ); if let Some(f) = pthread_setname_np.get() { - #[cfg(target_os = "nto")] + #[cfg(any(target_os = "nto", target_os = "qnx"))] const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize; #[cfg(any(target_os = "solaris", target_os = "illumos"))] const THREAD_NAME_MAX: usize = 32; diff --git a/library/std/src/sys/thread_local/key/racy.rs b/library/std/src/sys/thread_local/key/racy.rs index 0a10925ae6499..37ccb10337cf9 100644 --- a/library/std/src/sys/thread_local/key/racy.rs +++ b/library/std/src/sys/thread_local/key/racy.rs @@ -21,12 +21,12 @@ pub struct LazyKey { // Define a sentinel value that is likely not to be returned // as a TLS key. -#[cfg(not(target_os = "nto"))] +#[cfg(not(any(target_os = "nto", target_os = "qnx")))] const KEY_SENTVAL: usize = 0; -// On QNX Neutrino, 0 is always returned when currently not in use. -// Using 0 would mean to always create two keys and remote the first +// On QNX SDP, 0 is always returned when currently not in use. +// Using 0 would mean to always create two keys and remove the first // one (with value of 0) immediately afterwards. -#[cfg(target_os = "nto")] +#[cfg(any(target_os = "nto", target_os = "qnx"))] const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1; impl LazyKey { diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 1bdbae13bdaec..3a1e12aad6c73 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -275,9 +275,9 @@ target | std | host | notes [`aarch64-unknown-linux-pauthtest`](platform-support/aarch64-unknown-linux-pauthtest.md) | ✓ | ✓ | ARM64 PAC ELF ABI [`aarch64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | ARM64 Managarm [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD -[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | -[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | -[`aarch64-unknown-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS with new network stack (io-sock) | +[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX SDP 7.0 | +[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX SDP 7.1 with default network stack (io-pkt) | +[`aarch64-unknown-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX SDP 7.1 with new network stack (io-sock) | [`aarch64-unknown-qnx`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX SDP 8.0+ | [`aarch64-unknown-nuttx`](platform-support/nuttx.md) | ✓ | | ARM64 with NuttX [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD @@ -340,7 +340,7 @@ target | std | host | notes [`i586-unknown-redox`](platform-support/redox.md) | ✓ | | 32-bit x86 Redox OS (PentiumPro) [^x86_32-floats-x87] [`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+, Penryn) [^x86_32-floats-return-ABI] [`i686-oe-linux-gnu`](platform-support/oe-linux-gnu.md) | ✓ | | 32-bit x86 OpenEmbedded/Yocto Linux (GNU) -[`i686-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS (Pentium 4) [^x86_32-floats-return-ABI] +[`i686-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX SDP 7.0 (Pentium 4) [^x86_32-floats-return-ABI] `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku (Pentium 4) [^x86_32-floats-return-ABI] [`i686-unknown-helenos`](platform-support/helenos.md) | ✓ | | HelenOS IA-32 (see docs for pending issues) [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (Pentium 4) [^x86_32-floats-return-ABI] @@ -449,8 +449,8 @@ target | std | host | notes [`x86_64-lynx-lynxos178`](platform-support/lynxos178.md) | | | x86_64 LynxOS-178 [`x86_64-oe-linux-gnu`](platform-support/oe-linux-gnu.md) | ✓ | | x86 64-bit OpenEmbedded/Yocto Linux (GNU) [`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ✓ | | 64-bit x86 Cygwin | -[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) | -[`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) | +[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX SDP 7.1 with default network stack (io-pkt) | +[`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX SDP 7.1 with new network stack (io-sock) | [`x86_64-pc-qnx`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX SDP 8.0+ | [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl 1.2.5 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index b3ab1c7c4485b..899b550e3f603 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -83,49 +83,23 @@ For conditional compilation, the following QNX specific attributes are defined: ```toml profile = "compiler" change-id = 999999 - ``` - -2. Compile the Rust toolchain for an `x86_64-unknown-linux-gnu` host - - Compiling the Rust toolchain requires the same environment variables used for compiling C binaries. - Refer to the [QNX developer manual](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.prog/topic/devel_OS_version.html). - - To compile for QNX, environment variables must be set to use the correct tools and compiler switches: - - `CC_=qcc` - - `CFLAGS_=` - - `CXX_=qcc` - - `AR_=` - - With: - - - `` target triplet using underscores instead of hyphens, e.g. `aarch64_unknown_nto_qnx710` - - `` - - - `-Vgcc_ntox86_cxx` for x86 (32 bit) - - `-Vgcc_ntox86_64_cxx` for x86_64 (64 bit) - - `-Vgcc_ntoaarch64le_cxx` for Aarch64 (64 bit) + [build] + host = ["x86_64-unknown-linux-gnu"] + target = ["x86_64-unknown-linux-gnu", "aarch64-unknown-nto-qnx710"] + ``` - - `` +2. Compile the Rust toolchain with the QNX SDP environment loaded - - `ntox86-ar` for x86 (32 bit) - - `ntox86_64-ar` for x86_64 (64 bit) - - `ntoaarch64-ar` for Aarch64 (64 bit) + As noted above, we need the right environment variables for QNX SDP to work, + and for `qcc` to be in your system PATH. Typically this is done by sourcing + the `qnxsdp-env.sh` file (or equivalent for your host platform). - Example to build the Rust toolchain including a standard library for x86_64-linux-gnu and Aarch64-QNX-7.1: + To build on Linux, you would run: ```bash - export build_env=' - CC_aarch64_unknown_nto_qnx710=qcc - CFLAGS_aarch64_unknown_nto_qnx710=-Vgcc_ntoaarch64le_cxx - CXX_aarch64_unknown_nto_qnx710=qcc - AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar - ' - - env $build_env \ - ./x.py build \ - --target x86_64-unknown-linux-gnu,aarch64-unknown-nto-qnx710 \ - rustc library/core library/alloc library/std + source ~/qnx710/qnxsdp-env.sh + ./x.py build rustc library/core library/alloc library/std ``` ## Building Rust programs @@ -147,7 +121,7 @@ change calling conventions or memory layout. The test suites of the Rust compiler and standard library can be executed much like other Rust targets. The environment for testing should match the one used -during compiler compilation (refer to `build_env` and `qcc`/`PATH` above) with +during compiler compilation (refer to notes on `qnxsdp-env.sh` above) with the addition of the `TEST_DEVICE_ADDR` environment variable. The `TEST_DEVICE_ADDR` variable controls the remote runner and should point to a target running the `remote-test-server` executable. @@ -158,8 +132,8 @@ target maintainers which can be seen in the following example. To run all tests on a x86_64 QNX Neutrino 7.1 target: ```bash +source ~/qnx710/qnxsdp-env.sh export TEST_DEVICE_ADDR="1.2.3.4:12345" # must address the test target, can be a SSH tunnel -export build_env= # Disable tests that only work on the host or don't make sense for this target. # See also: @@ -174,11 +148,10 @@ export exclude_tests=' --exclude rustc --exclude rustdoc' -env $build_env \ - ./x.py test \ - $exclude_tests \ - --stage 1 \ - --target x86_64-pc-nto-qnx710 +./x.py test \ + $exclude_tests \ + --stage 1 \ + --target x86_64-pc-nto-qnx710 ``` ### Rust std library test suite diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 7c4469afda282..70901f5b84c56 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -109,6 +109,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-pauthtest", "ignore-powerpc", "ignore-powerpc64", + "ignore-qnx", "ignore-remote", "ignore-riscv32", "ignore-riscv64", diff --git a/tests/codegen-llvm/thread-local.rs b/tests/codegen-llvm/thread-local.rs index 41df8c9be1b9d..8eb0443ebb9b5 100644 --- a/tests/codegen-llvm/thread-local.rs +++ b/tests/codegen-llvm/thread-local.rs @@ -5,6 +5,7 @@ //@ ignore-emscripten globals are used instead of thread locals //@ ignore-android does not use #[thread_local] //@ ignore-nto does not use #[thread_local] +//@ ignore-qnx does not use #[thread_local] #![crate_type = "lib"] diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs index 6203be90590d3..94ba5a79aa725 100644 --- a/tests/ui/abi/stack-probes-lto.rs +++ b/tests/ui/abi/stack-probes-lto.rs @@ -8,7 +8,8 @@ //@ ignore-fuchsia no exception handler registered for segfault //@ compile-flags: -C lto //@ no-prefer-dynamic -//@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino +//@ ignore-nto Crash analysis impossible at SIGSEGV in QNX SDP 7.x +//@ ignore-qnx Crash analysis impossible at SIGSEGV in QNX SDP 8.0+ //@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't //@ ignore-tvos Stack probes are enabled, but the SIGSEGV handler isn't //@ ignore-watchos Stack probes are enabled, but the SIGSEGV handler isn't diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs index 4d0301411e0fd..be36eeefc31ea 100644 --- a/tests/ui/abi/stack-probes.rs +++ b/tests/ui/abi/stack-probes.rs @@ -5,7 +5,8 @@ //@[x64] only-x86_64 //@ needs-subprocess //@ ignore-fuchsia no exception handler registered for segfault -//@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino +//@ ignore-nto Crash analysis impossible at SIGSEGV in QNX SDP 7.x +//@ ignore-qnx Crash analysis impossible at SIGSEGV in QNX SDP 8.0+ //@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't //@ ignore-tvos Stack probes are enabled, but the SIGSEGV handler isn't //@ ignore-watchos Stack probes are enabled, but the SIGSEGV handler isn't diff --git a/tests/ui/command/command-setgroups.rs b/tests/ui/command/command-setgroups.rs index 047f06729af98..6e369c9b56c04 100644 --- a/tests/ui/command/command-setgroups.rs +++ b/tests/ui/command/command-setgroups.rs @@ -2,6 +2,7 @@ //@ only-unix (this is a unix-specific test) //@ ignore-musl - returns dummy result for _SC_NGROUPS_MAX //@ ignore-nto - does not have `/bin/id`, expects groups to be i32 (not u32) +//@ ignore-qnx - does not have `/bin/id`, expects groups to be i32 (not u32) //@ needs-subprocess #![feature(rustc_private)] diff --git a/tests/ui/process/process-spawn-failure.rs b/tests/ui/process/process-spawn-failure.rs index ac2c34bc7836d..7f2dfa2aaa652 100644 --- a/tests/ui/process/process-spawn-failure.rs +++ b/tests/ui/process/process-spawn-failure.rs @@ -9,6 +9,7 @@ //@ ignore-vxworks no 'ps' //@ ignore-fuchsia no 'ps' //@ ignore-nto no 'ps' +//@ ignore-qnx no 'ps' //@ ignore-ios no 'ps' //@ ignore-tvos no 'ps' //@ ignore-watchos no 'ps' diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs index 3e092728f2929..9b3878229417c 100644 --- a/tests/ui/runtime/out-of-stack.rs +++ b/tests/ui/runtime/out-of-stack.rs @@ -6,6 +6,7 @@ //@ needs-subprocess //@ ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590) //@ ignore-nto no stack overflow handler used (no alternate stack available) +//@ ignore-qnx no stack overflow handler used (no alternate stack available) //@ ignore-ios stack overflow handlers aren't enabled //@ ignore-tvos stack overflow handlers aren't enabled //@ ignore-watchos stack overflow handlers aren't enabled diff --git a/tests/ui/runtime/signal-alternate-stack-cleanup.rs b/tests/ui/runtime/signal-alternate-stack-cleanup.rs index 8d52e9e26a29c..73bf741a73f1c 100644 --- a/tests/ui/runtime/signal-alternate-stack-cleanup.rs +++ b/tests/ui/runtime/signal-alternate-stack-cleanup.rs @@ -8,6 +8,7 @@ //@ ignore-sgx no libc //@ ignore-vxworks no SIGWINCH in user space //@ ignore-nto no SA_ONSTACK +//@ ignore-qnx no SA_ONSTACK #![allow(function_casts_as_integer)] #![feature(rustc_private)] diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs index 88d9736a071de..93416a9bc2ac7 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.rs +++ b/tests/ui/suggestions/missing-lifetime-specifier.rs @@ -4,6 +4,7 @@ //@ ignore-emscripten globals are used instead of thread locals //@ ignore-android does not use #[thread_local] //@ ignore-nto does not use #[thread_local] +//@ ignore-qnx does not use #[thread_local] // Different number of duplicated diagnostics on different targets //@ compile-flags: -Zdeduplicate-diagnostics=yes diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr index b8c58155e636d..4c50f2a43e270 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.stderr +++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:26:44 + --> $DIR/missing-lifetime-specifier.rs:27:44 | LL | static a: RefCell>>> = RefCell::new(HashMap::new()); | ^^^ expected 2 lifetime parameters @@ -11,7 +11,7 @@ LL | static a: RefCell>>>> = RefC | ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:30:44 + --> $DIR/missing-lifetime-specifier.rs:31:44 | LL | static b: RefCell>>> = RefCell::new(HashMap::new()); | ^ ^^^ expected 2 lifetime parameters @@ -25,7 +25,7 @@ LL | static b: RefCell $DIR/missing-lifetime-specifier.rs:34:47 + --> $DIR/missing-lifetime-specifier.rs:35:47 | LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); | ^ expected 2 lifetime parameters @@ -37,7 +37,7 @@ LL | static c: RefCell>>>> = | +++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:38:44 + --> $DIR/missing-lifetime-specifier.rs:39:44 | LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); | ^ ^ expected 2 lifetime parameters @@ -51,7 +51,7 @@ LL | static d: RefCell $DIR/missing-lifetime-specifier.rs:47:44 + --> $DIR/missing-lifetime-specifier.rs:48:44 | LL | static f: RefCell>>>> = | ^ expected named lifetime parameter @@ -68,7 +68,7 @@ LL + static f: RefCell>>>> = | error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:43:44 + --> $DIR/missing-lifetime-specifier.rs:44:44 | LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -76,7 +76,7 @@ LL | static e: RefCell>>>> = RefCell: | expected 2 lifetime arguments | note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:19:11 + --> $DIR/missing-lifetime-specifier.rs:20:11 | LL | pub union Qux<'t, 'k, I> { | ^^^ -- -- @@ -86,7 +86,7 @@ LL | static e: RefCell>>>> = | +++++++++ error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:47:49 + --> $DIR/missing-lifetime-specifier.rs:48:49 | LL | static f: RefCell>>>> = | ^^^ ------- supplied 1 lifetime argument @@ -94,7 +94,7 @@ LL | static f: RefCell>>>> = | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:23:7 + --> $DIR/missing-lifetime-specifier.rs:24:7 | LL | trait Tar<'t, 'k, I> {} | ^^^ -- -- From 0a81c75ed04159cc45768a2c0a0521374de0619f Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Tue, 7 Jul 2026 13:40:23 -0400 Subject: [PATCH 33/33] tests: clean up over-constraint on LLVM feature count Upstream dropped a feature, resulting in the invalid-attribute test failing because it was expecting "and 76 more" but now it's "and 75 more". Adjust the test to do a replacement with a placeholder on that text so the test is less brittle. --- tests/ui/target-feature/invalid-attribute.rs | 1 + .../target-feature/invalid-attribute.stderr | 60 +++++++++---------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index 968fbdc1dc7f1..cd367fb722621 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -1,6 +1,7 @@ //@ add-minicore //@ compile-flags: --target=x86_64-unknown-linux-gnu //@ needs-llvm-components: x86 +//@ normalize-stderr: "and \d+ more" -> "and X more" #![warn(unused_attributes)] #![feature(no_core)] diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index 702ea3bb3ba5f..abe3ab431635f 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -1,5 +1,5 @@ error: `#[target_feature]` attribute cannot be used on extern crates - --> $DIR/invalid-attribute.rs:11:1 + --> $DIR/invalid-attribute.rs:12:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on use statements - --> $DIR/invalid-attribute.rs:15:1 + --> $DIR/invalid-attribute.rs:16:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on foreign modules - --> $DIR/invalid-attribute.rs:19:1 + --> $DIR/invalid-attribute.rs:20:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error[E0539]: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:23:1 + --> $DIR/invalid-attribute.rs:24:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^---------^ @@ -37,7 +37,7 @@ LL + #[target_feature(enable = "feat1, feat2")] | error[E0539]: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:29:1 + --> $DIR/invalid-attribute.rs:30:1 | LL | #[target_feature(bar)] | ^^^^^^^^^^^^^^^^^---^^ @@ -51,7 +51,7 @@ LL + #[target_feature(enable = "feat1, feat2")] | error[E0539]: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:32:1 + --> $DIR/invalid-attribute.rs:33:1 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^^^-------^^^^^^^^^^ @@ -65,7 +65,7 @@ LL + #[target_feature(enable = "feat1, feat2")] | error: `#[target_feature]` attribute cannot be used on modules - --> $DIR/invalid-attribute.rs:37:1 + --> $DIR/invalid-attribute.rs:38:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on constants - --> $DIR/invalid-attribute.rs:41:1 + --> $DIR/invalid-attribute.rs:42:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on structs - --> $DIR/invalid-attribute.rs:45:1 + --> $DIR/invalid-attribute.rs:46:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on enums - --> $DIR/invalid-attribute.rs:49:1 + --> $DIR/invalid-attribute.rs:50:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on unions - --> $DIR/invalid-attribute.rs:53:1 + --> $DIR/invalid-attribute.rs:54:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on type aliases - --> $DIR/invalid-attribute.rs:60:1 + --> $DIR/invalid-attribute.rs:61:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on traits - --> $DIR/invalid-attribute.rs:64:1 + --> $DIR/invalid-attribute.rs:65:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on statics - --> $DIR/invalid-attribute.rs:74:1 + --> $DIR/invalid-attribute.rs:75:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on trait impl blocks - --> $DIR/invalid-attribute.rs:78:1 + --> $DIR/invalid-attribute.rs:79:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on inherent impl blocks - --> $DIR/invalid-attribute.rs:84:1 + --> $DIR/invalid-attribute.rs:85:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on expressions - --> $DIR/invalid-attribute.rs:105:5 + --> $DIR/invalid-attribute.rs:106:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can only be applied to functions error: `#[target_feature]` attribute cannot be used on closures - --> $DIR/invalid-attribute.rs:111:5 + --> $DIR/invalid-attribute.rs:112:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -161,7 +161,7 @@ LL | #[target_feature(enable = "sse2")] = help: `#[target_feature]` can be applied to functions and methods error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:68:1 + --> $DIR/invalid-attribute.rs:69:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ @@ -169,15 +169,15 @@ LL | #[inline(always)] = note: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574 error: the feature named `foo` is not valid for this target - --> $DIR/invalid-attribute.rs:26:18 + --> $DIR/invalid-attribute.rs:27:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target | - = help: valid names are: `fma`, `xop`, `adx`, `aes`, and `avx` and 76 more + = help: valid names are: `fma`, `xop`, `adx`, `aes`, and `avx` and X more error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/invalid-attribute.rs:80:1 + --> $DIR/invalid-attribute.rs:81:1 | LL | impl Quux for u8 {} | ^^^^^^^^^^^^^^^^ missing `foo` in implementation @@ -186,7 +186,7 @@ LL | fn foo(); | --------- `foo` from trait error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/invalid-attribute.rs:94:5 + --> $DIR/invalid-attribute.rs:95:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method @@ -195,13 +195,13 @@ LL | fn foo() {} | -------- not an `unsafe` function error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/invalid-attribute.rs:97:5 + --> $DIR/invalid-attribute.rs:98:5 | LL | fn foo() {} | ^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait - --> $DIR/invalid-attribute.rs:89:5 + --> $DIR/invalid-attribute.rs:90:5 | LL | fn foo(); | ^^^^^^^^^ @@ -209,7 +209,7 @@ LL | fn foo(); found signature `#[target_features] fn()` error: the feature named `+sse2` is not valid for this target - --> $DIR/invalid-attribute.rs:116:18 + --> $DIR/invalid-attribute.rs:117:18 | LL | #[target_feature(enable = "+sse2")] | ^^^^^^^^^^^^^^^^ `+sse2` is not valid for this target @@ -221,20 +221,20 @@ LL + #[target_feature(enable = "sse2")] | error: the feature named `sse5` is not valid for this target - --> $DIR/invalid-attribute.rs:121:18 + --> $DIR/invalid-attribute.rs:122:18 | LL | #[target_feature(enable = "sse5")] | ^^^^^^^^^^^^^^^ `sse5` is not valid for this target | - = help: valid names are: `sse`, `sse2`, `sse3`, `sse4a`, and `ssse3` and 76 more + = help: valid names are: `sse`, `sse2`, `sse3`, `sse4a`, and `ssse3` and X more error: the feature named `avx512` is not valid for this target - --> $DIR/invalid-attribute.rs:126:18 + --> $DIR/invalid-attribute.rs:127:18 | LL | #[target_feature(enable = "avx512")] | ^^^^^^^^^^^^^^^^^ `avx512` is not valid for this target | - = help: valid names are: `avx512f`, `avx2`, `avx512bw`, `avx512cd`, and `avx512dq` and 76 more + = help: valid names are: `avx512f`, `avx2`, `avx512bw`, `avx512cd`, and `avx512dq` and X more error: aborting due to 26 previous errors