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/43] 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/43] 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 84f289674c391d8a049373a3c1ea46759be2cdaf Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 6 Jun 2026 22:19:12 -0700 Subject: [PATCH 03/43] rustdoc: do not include extra stuff in span This change prevents our lints from returning a span with stuff in it that isn't actually part of the doc comment. When that happens, it returns `None` instead. --- compiler/rustc_resolve/src/rustdoc.rs | 67 ++++++++++++------- .../lints/invalid-html-tags-ice-146890.rs | 8 +-- .../lints/invalid-html-tags-ice-146890.stderr | 2 - tests/rustdoc-ui/lints/invalid-html-tags.rs | 2 +- .../rustdoc-ui/lints/invalid-html-tags.stderr | 1 - .../lints/redundant_explicit_links_split.rs | 43 ++++++++++++ .../redundant_explicit_links_split.stderr | 45 +++++++++++++ 7 files changed, 137 insertions(+), 31 deletions(-) create mode 100644 tests/rustdoc-ui/lints/redundant_explicit_links_split.rs create mode 100644 tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 92bc577f59201..fdfe5afb7d7ec 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::mem; use std::ops::Range; @@ -641,41 +642,61 @@ pub fn source_span_for_markdown_range_inner( let mut start_bytes = 0; let mut end_bytes = 0; + let span = span_of_fragments(fragments)?; + + let mut line_bytes = 0; + let mut sorted_fragments = fragments.to_vec(); + sorted_fragments.sort_by_key(|fragment| fragment.span.lo().0); 'outer: for (line_no, md_line) in md_lines.enumerate() { loop { let source_line = src_lines.next()?; - match source_line.find(md_line) { - Some(offset) => { - if line_no == starting_line { - start_bytes += offset; + // Since we're counting bytes, `source_line_len` includes the "\n". + let source_line_len = u32::try_from(source_line.len() + 1).unwrap(); + let has_fragment = sorted_fragments + .binary_search_by(|fragment| { + if fragment.span.hi().0 < span.lo().0 + line_bytes { + Ordering::Less + } else if fragment.span.lo().0 > span.lo().0 + line_bytes + source_line_len { + Ordering::Greater + } else { + Ordering::Equal + } + }) + .is_ok(); + line_bytes += source_line_len; + if has_fragment && let Some(offset) = source_line.find(md_line) { + if line_no == starting_line { + start_bytes += offset; - if starting_line == ending_line { - break 'outer; - } - } else if line_no == ending_line { - end_bytes += offset; + if starting_line == ending_line { break 'outer; - } else if line_no < starting_line { - start_bytes += source_line.len() - md_line.len(); - } else { - end_bytes += source_line.len() - md_line.len(); } - break; + } else if line_no == ending_line { + end_bytes += offset; + break 'outer; + } else if line_no < starting_line { + start_bytes += source_line.len() - md_line.len(); + } else { + end_bytes += source_line.len() - md_line.len(); } - None => { - // Since this is a source line that doesn't include a markdown line, - // we have to count the newline that we split from earlier. - if line_no <= starting_line { - start_bytes += source_line.len() + 1; - } else { - end_bytes += source_line.len() + 1; - } + break; + } else { + // Since this is a source line that doesn't include a markdown line, + // we have to count the newline that we split from earlier. + if line_no <= starting_line { + start_bytes += source_line.len() + 1; + } else if source_line.chars().any(|c| !c.is_whitespace()) { + // If we're past the first line, but haven't found the last line, + // we can only return a contiguous span if every line is either + // part of the doc comment or blank. + return None; + } else { + end_bytes += source_line.len() + 1; } } } } - let span = span_of_fragments(fragments)?; let src_span = span.from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, diff --git a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs index d7efc201e7e39..53df3e9eb5a80 100644 --- a/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs +++ b/tests/rustdoc-ui/lints/invalid-html-tags-ice-146890.rs @@ -7,17 +7,17 @@ /// /// key +//~^^ ERROR: unclosed HTML tag `TH` /// +//~^^ ERROR: unopened HTML tag `TD` /// value +//~^^ ERROR: unclosed HTML tag `TH` /// +//~^^ ERROR: unopened HTML tag `TD` /// /// | |_____^ | @@ -18,7 +17,6 @@ error: unopened HTML tag `TD` | LL | /// | |_____^ diff --git a/tests/rustdoc-ui/lints/invalid-html-tags.rs b/tests/rustdoc-ui/lints/invalid-html-tags.rs index 8003e5efdd582..f5700e5846e51 100644 --- a/tests/rustdoc-ui/lints/invalid-html-tags.rs +++ b/tests/rustdoc-ui/lints/invalid-html-tags.rs @@ -164,8 +164,8 @@ pub fn r() {} /// >
/// > href="#broken" +//~^^ ERROR incomplete HTML tag `img` pub fn s() {} ///
diff --git a/tests/rustdoc-ui/lints/invalid-html-tags.stderr b/tests/rustdoc-ui/lints/invalid-html-tags.stderr index b6ec22c247901..3256004ddb6ab 100644 --- a/tests/rustdoc-ui/lints/invalid-html-tags.stderr +++ b/tests/rustdoc-ui/lints/invalid-html-tags.stderr @@ -123,7 +123,6 @@ error: incomplete HTML tag `img` | LL | /// > href="#broken" | |____________________^ diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs b/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs new file mode 100644 index 0000000000000..9de8bbe3b8c98 --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs @@ -0,0 +1,43 @@ +#![deny(rustdoc::redundant_explicit_links)] + +// Right now, redundant_explicit_links won't produce a warning at all if +// rustdoc isn't able to calculate an accurate span for the link. +// +// If that changes and this test starts to fail, you should add the +// appropriate annotations, and, also, make sure that it doesn't +// suggest a correction that wipes out the `fn` formal signature +// or the `#[inline]` attribute. + +/// [std::clone::Clone]( +pub fn split_outer_inner() { + //! std::clone::Clone) +} + +/// [std::clone::Clone](std::clone::Clone +pub fn split_outer_inner_b() { + //! ) +} + +/// [std::clone::Clone]( +#[inline] +/// std::clone::Clone) +pub fn split_attr() { +} + +/// [std::clone::Clone](std::clone::Clone +#[inline] +/// ) +pub fn split_attr_b() { +} + +/// [std::clone::Clone]( +/// std::clone::Clone) +//~^^ ERROR redundant_explicit_links +pub fn not_split() { +} + +/// [std::clone::Clone](std::clone::Clone +/// ) +//~^^ ERROR redundant_explicit_links +pub fn not_split_b() { +} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr new file mode 100644 index 0000000000000..3e2e99f10d9f7 --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr @@ -0,0 +1,45 @@ +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:33:25 + | +LL | /// [std::clone::Clone]( + | ______-----------------__^ + | | | + | | because label contains path that resolves to same destination +LL | | /// std::clone::Clone) + | |_____________________^ explicit target is redundant + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +note: the lint level is defined here + --> $DIR/redundant_explicit_links_split.rs:1:9 + | +LL | #![deny(rustdoc::redundant_explicit_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: remove explicit link target + | +LL - /// [std::clone::Clone]( +LL - /// std::clone::Clone) +LL + /// [std::clone::Clone] + | + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:39:25 + | +LL | /// [std::clone::Clone](std::clone::Clone + | ______-----------------__^ + | | | + | | because label contains path that resolves to same destination +LL | | /// ) + | |____^ explicit target is redundant + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL - /// [std::clone::Clone](std::clone::Clone +LL - /// ) +LL + /// [std::clone::Clone] + | + +error: aborting due to 2 previous errors + From 2001b88a962332f3799d3719867812900561d5bb Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 7 Jun 2026 17:41:40 -0700 Subject: [PATCH 04/43] Fix `unbalanced_ticks` when doc isn't contiguous --- src/tools/clippy/clippy_lints/src/doc/mod.rs | 13 +++---------- .../clippy/tests/ui/doc/unbalanced_ticks.stderr | 5 ++--- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index c5816cb8b2d63..013fb32bdaf3c 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -1242,7 +1242,8 @@ fn check_doc<'a, Events: Iterator, Range, Range tests/ui/doc/unbalanced_ticks.rs:6:5 + --> tests/ui/doc/unbalanced_ticks.rs:6:1 | -LL | /// This is a doc comment with `unbalanced_tick marks and several words that - | _____^ +LL | / /// This is a doc comment with `unbalanced_tick marks and several words that LL | | LL | | /// should be `encompassed_by` tick marks because they `contain_underscores`. LL | | /// Because of the initial `unbalanced_tick` pair, the error message is From e66a50496cf5e996bb354f61508db540d62eb51a Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 7 Jun 2026 17:46:08 -0700 Subject: [PATCH 05/43] Add test case for split missing punctuation --- ...doc_paragraph_missing_punctuation_split_16169.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/tools/clippy/tests/ui/doc/doc_paragraph_missing_punctuation_split_16169.rs diff --git a/src/tools/clippy/tests/ui/doc/doc_paragraph_missing_punctuation_split_16169.rs b/src/tools/clippy/tests/ui/doc/doc_paragraph_missing_punctuation_split_16169.rs new file mode 100644 index 0000000000000..c01b0c90b120e --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_paragraph_missing_punctuation_split_16169.rs @@ -0,0 +1,13 @@ +//@ check-pass +// https://github.com/rust-lang/rust-clippy/issues/16169 +#![allow(clippy::mixed_attributes_style)] + +/// +pub fn dont_warn_inner_outer() { + //!w +} +/// +#[inline] +///w +pub fn dont_warn_split_by_attr() { +} From f7302b9723082a9310e901b58eae530363571d96 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 13 Jun 2026 09:47:29 -0700 Subject: [PATCH 06/43] Skip the unhelpful binary search It requires an allocation, and doesn't seem to help in practice. Fixes a nit found during review. --- compiler/rustc_resolve/src/rustdoc.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index fdfe5afb7d7ec..8efad0a343ac5 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -1,4 +1,3 @@ -use std::cmp::Ordering; use std::mem; use std::ops::Range; @@ -645,24 +644,15 @@ pub fn source_span_for_markdown_range_inner( let span = span_of_fragments(fragments)?; let mut line_bytes = 0; - let mut sorted_fragments = fragments.to_vec(); - sorted_fragments.sort_by_key(|fragment| fragment.span.lo().0); 'outer: for (line_no, md_line) in md_lines.enumerate() { loop { let source_line = src_lines.next()?; // Since we're counting bytes, `source_line_len` includes the "\n". let source_line_len = u32::try_from(source_line.len() + 1).unwrap(); - let has_fragment = sorted_fragments - .binary_search_by(|fragment| { - if fragment.span.hi().0 < span.lo().0 + line_bytes { - Ordering::Less - } else if fragment.span.lo().0 > span.lo().0 + line_bytes + source_line_len { - Ordering::Greater - } else { - Ordering::Equal - } - }) - .is_ok(); + let has_fragment = fragments.iter().any(|fragment| { + fragment.span.hi().0 >= span.lo().0 + line_bytes + && fragment.span.lo().0 <= span.lo().0 + line_bytes + source_line_len + }); line_bytes += source_line_len; if has_fragment && let Some(offset) = source_line.find(md_line) { if line_no == starting_line { From b66a23fb4b2f9cff20ea6f8b34d223e4073a99d8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 17 Jun 2026 17:58:10 -0700 Subject: [PATCH 07/43] Rename `span` and `line_bytes` to more specific Co-authored-by: binarycat --- compiler/rustc_resolve/src/rustdoc.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 8efad0a343ac5..9abb79d5ca02f 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -641,19 +641,20 @@ pub fn source_span_for_markdown_range_inner( let mut start_bytes = 0; let mut end_bytes = 0; - let span = span_of_fragments(fragments)?; + let span_of_all_fragments = span_of_fragments(fragments)?; - let mut line_bytes = 0; + let mut prev_lines_bytes = 0; 'outer: for (line_no, md_line) in md_lines.enumerate() { loop { let source_line = src_lines.next()?; // Since we're counting bytes, `source_line_len` includes the "\n". let source_line_len = u32::try_from(source_line.len() + 1).unwrap(); let has_fragment = fragments.iter().any(|fragment| { - fragment.span.hi().0 >= span.lo().0 + line_bytes - && fragment.span.lo().0 <= span.lo().0 + line_bytes + source_line_len + fragment.span.hi().0 >= span_of_all_fragments.lo().0 + prev_lines_bytes + && fragment.span.lo().0 + <= span_of_all_fragments.lo().0 + prev_lines_bytes + source_line_len }); - line_bytes += source_line_len; + prev_lines_bytes += source_line_len; if has_fragment && let Some(offset) = source_line.find(md_line) { if line_no == starting_line { start_bytes += offset; @@ -687,7 +688,7 @@ pub fn source_span_for_markdown_range_inner( } } - let src_span = span.from_inner(InnerSpan::new( + let src_span = span_of_all_fragments.from_inner(InnerSpan::new( md_range.start + start_bytes, md_range.end + start_bytes + end_bytes, )); From f93f2e446b457c871510340c22a4a68192ae48d1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 17 Jun 2026 18:07:20 -0700 Subject: [PATCH 08/43] Use an intermediate variable for readability Co-authored-by: binarycat --- compiler/rustc_resolve/src/rustdoc.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 9abb79d5ca02f..4cae23ed7e12a 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -641,20 +641,20 @@ pub fn source_span_for_markdown_range_inner( let mut start_bytes = 0; let mut end_bytes = 0; - let span_of_all_fragments = span_of_fragments(fragments)?; + let span_of_all_fragments: Span = span_of_fragments(fragments)?; let mut prev_lines_bytes = 0; 'outer: for (line_no, md_line) in md_lines.enumerate() { loop { let source_line = src_lines.next()?; - // Since we're counting bytes, `source_line_len` includes the "\n". - let source_line_len = u32::try_from(source_line.len() + 1).unwrap(); - let has_fragment = fragments.iter().any(|fragment| { - fragment.span.hi().0 >= span_of_all_fragments.lo().0 + prev_lines_bytes - && fragment.span.lo().0 - <= span_of_all_fragments.lo().0 + prev_lines_bytes + source_line_len - }); - prev_lines_bytes += source_line_len; + let source_line_len = u32::try_from(source_line.len()).unwrap(); + let source_line_span = + span_of_all_fragments.split_at(prev_lines_bytes).1.split_at(source_line_len).0; + let has_fragment = fragments + .iter() + .any(|fragment| fragment.span.contains(source_line_span.shrink_to_hi())); + // Since we're counting bytes, `prev_line_bytes` includes the "\n". + prev_lines_bytes += source_line_len + 1; if has_fragment && let Some(offset) = source_line.find(md_line) { if line_no == starting_line { start_bytes += offset; From 7975dc779706cb384101867ffa9008816ed01d7e Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 17 Jun 2026 19:19:02 -0700 Subject: [PATCH 09/43] Add clarifying comment Co-authored-by: binarycat --- compiler/rustc_resolve/src/rustdoc.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 4cae23ed7e12a..42a5005552825 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -673,13 +673,14 @@ pub fn source_span_for_markdown_range_inner( break; } else { // Since this is a source line that doesn't include a markdown line, - // we have to count the newline that we split from earlier. + // we have to count it and its newline as non-markdown bytes. if line_no <= starting_line { start_bytes += source_line.len() + 1; } else if source_line.chars().any(|c| !c.is_whitespace()) { - // If we're past the first line, but haven't found the last line, - // we can only return a contiguous span if every line is either - // part of the doc comment or blank. + // We're past the first line, but haven't found the last line, + // but we found a non-empty non-markdown line. + // This could be an attribute, and we don't want a diagnostic + // suggesting to delete that attribute, so we return None to be safe. return None; } else { end_bytes += source_line.len() + 1; From 4d83004499d40452cef97b9cd103f53cb98fccd2 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 17 Jun 2026 19:34:27 -0700 Subject: [PATCH 10/43] Remove unused `Option` return --- src/librustdoc/passes/lint/redundant_explicit_links.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 8da21f100c6a3..8ccf819fff987 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -80,7 +80,7 @@ fn check_redundant_explicit_link<'md>( hir_id: HirId, doc: &'md str, resolutions: &DocLinkResMap, -) -> Option<()> { +) { let mut broken_line_callback = |link: BrokenLink<'md>| Some((link.reference, "".into())); let mut offset_iter = Parser::new_with_broken_link_callback( doc, @@ -146,8 +146,6 @@ fn check_redundant_explicit_link<'md>( } } } - - None } /// FIXME(ChAoSUnItY): Too many arguments. From 9438aac0c297bbc8804c0e6796c24637df1f6e99 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 17 Jun 2026 20:15:28 -0700 Subject: [PATCH 11/43] Handle span failure in redundant_explicit_links --- .../passes/lint/redundant_explicit_links.rs | 182 +++++++++++++----- .../lints/redundant_explicit_links_split.rs | 27 ++- .../redundant_explicit_links_split.stderr | 74 +++++-- 3 files changed, 205 insertions(+), 78 deletions(-) diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 8ccf819fff987..ad45b6e1d1c5b 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -115,7 +115,7 @@ fn check_redundant_explicit_link<'md>( } if dest_url.ends_with(resolvable_link) || resolvable_link.ends_with(&*dest_url) { - match link_type { + let check_result = match link_type { LinkType::Inline | LinkType::ReferenceUnknown => { check_inline_or_reference_unknown_redundancy( cx, @@ -127,27 +127,54 @@ fn check_redundant_explicit_link<'md>( dest_url.to_string(), link_data, if link_type == LinkType::Inline { (b'(', b')') } else { (b'[', b']') }, - ); + ) } - LinkType::Reference => { - check_reference_redundancy( - cx, - item, - hir_id, - doc, - resolutions, - link_range, - &dest_url, - link_data, - ); - } - _ => {} + LinkType::Reference => check_reference_redundancy( + cx, + item, + hir_id, + doc, + resolutions, + link_range, + &dest_url, + link_data, + ), + _ => Ok(()), + }; + if let Err(lint) = check_result { + cx.tcx.emit_node_span_lint( + crate::lint::REDUNDANT_EXPLICIT_LINKS, + hir_id, + item.attr_span(cx.tcx), + lint, + ); } } } } } +struct RedundantExplicitLinksCannotSuggest { + attr_span: Span, + display_link: String, + dest_link: String, +} + +impl<'a> Diagnostic<'a, ()> for RedundantExplicitLinksCannotSuggest { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { attr_span, display_link, dest_link } = self; + + Diag::new(dcx, level, "redundant explicit link target") + .with_span_label( + attr_span, + format!("explicit target `{dest_link}` is redundant because label `{display_link}` resolves to same destination") + ) + .with_note( + "when a link's destination is not specified,\nthe label is used to resolve intra-doc links" + ) + } +} + /// FIXME(ChAoSUnItY): Too many arguments. fn check_inline_or_reference_unknown_redundancy( cx: &DocContext<'_>, @@ -159,7 +186,7 @@ fn check_inline_or_reference_unknown_redundancy( dest: String, link_data: LinkData, (open, close): (u8, u8), -) -> Option<()> { +) -> Result<(), RedundantExplicitLinksCannotSuggest> { struct RedundantExplicitLinks { explicit_span: Span, display_span: Span, @@ -194,42 +221,65 @@ fn check_inline_or_reference_unknown_redundancy( } } - let (resolvable_link, resolvable_link_range) = - (&link_data.resolvable_link?, &link_data.resolvable_link_range?); - let (dest_res, display_res) = - (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?); + let (Some(resolvable_link), Some(resolvable_link_range)) = + (&link_data.resolvable_link, &link_data.resolvable_link_range) + else { + return Ok(()); + }; + let (Some(dest_res), Some(display_res)) = + (find_resolution(resolutions, &dest), find_resolution(resolutions, resolvable_link)) + else { + return Ok(()); + }; if dest_res == display_res { + let attr_span = item.attr_span(cx.tcx); let link_span = match source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings) { Some((sp, from_expansion)) => { if from_expansion { - return None; + return Ok(()); } sp } - None => item.attr_span(cx.tcx), + None => attr_span, }; - let (explicit_span, false) = source_span_for_markdown_range( + let explicit_span = match source_span_for_markdown_range( cx.tcx, doc, &offset_explicit_range(doc, link_range, open, close), &item.attrs.doc_strings, - )? - else { + ) { + Some((explicit_span, false)) => explicit_span, // This `span` comes from macro expansion so skipping it. - return None; + Some((_, true)) => return Ok(()), + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksCannotSuggest { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } }; - let (display_span, false) = source_span_for_markdown_range( + let display_span = match source_span_for_markdown_range( cx.tcx, doc, resolvable_link_range, &item.attrs.doc_strings, - )? - else { + ) { + Some((display_span, false)) => display_span, // This `span` comes from macro expansion so skipping it. - return None; + Some((_, true)) => return Ok(()), + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksCannotSuggest { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } }; cx.tcx.emit_node_span_lint( @@ -245,7 +295,7 @@ fn check_inline_or_reference_unknown_redundancy( ); } - None + Ok(()) } /// FIXME(ChAoSUnItY): Too many arguments. @@ -258,7 +308,7 @@ fn check_reference_redundancy( link_range: Range, dest: &CowStr<'_>, link_data: LinkData, -) -> Option<()> { +) -> Result<(), RedundantExplicitLinksCannotSuggest> { struct RedundantExplicitLinkTarget { explicit_span: Span, display_span: Span, @@ -292,49 +342,83 @@ fn check_reference_redundancy( } } - let (resolvable_link, resolvable_link_range) = - (&link_data.resolvable_link?, &link_data.resolvable_link_range?); - let (dest_res, display_res) = - (find_resolution(resolutions, dest)?, find_resolution(resolutions, resolvable_link)?); + let (Some(resolvable_link), Some(resolvable_link_range)) = + (&link_data.resolvable_link, &link_data.resolvable_link_range) + else { + return Ok(()); + }; + let (Some(dest_res), Some(display_res)) = + (find_resolution(resolutions, dest), find_resolution(resolutions, resolvable_link)) + else { + return Ok(()); + }; if dest_res == display_res { + let attr_span = item.attr_span(cx.tcx); let link_span = match source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings) { Some((sp, from_expansion)) => { if from_expansion { - return None; + // This `span` comes from macro expansion so skipping it. + return Ok(()); } sp } - None => item.attr_span(cx.tcx), + None => attr_span, }; - let (explicit_span, false) = source_span_for_markdown_range( + let explicit_span = match source_span_for_markdown_range( cx.tcx, doc, &offset_explicit_range(doc, link_range.clone(), b'[', b']'), &item.attrs.doc_strings, - )? - else { + ) { + Some((explicit_span, false)) => explicit_span, // This `span` comes from macro expansion so skipping it. - return None; + Some((_, true)) => return Ok(()), + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksCannotSuggest { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } }; - let (display_span, false) = source_span_for_markdown_range( + let display_span = match source_span_for_markdown_range( cx.tcx, doc, resolvable_link_range, &item.attrs.doc_strings, - )? - else { + ) { + Some((display_span, false)) => display_span, // This `span` comes from macro expansion so skipping it. - return None; + Some((_, true)) => return Ok(()), + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksCannotSuggest { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } }; - let (def_span, _) = source_span_for_markdown_range( + let def_span = match source_span_for_markdown_range( cx.tcx, doc, &offset_reference_def_range(doc, dest, link_range), &item.attrs.doc_strings, - )?; + ) { + Some((def_span, _)) => def_span, + // Cannot give a contiguous span for this link. + None => { + return Err(RedundantExplicitLinksCannotSuggest { + display_link: resolvable_link.clone(), + dest_link: dest.to_string(), + attr_span, + }); + } + }; cx.tcx.emit_node_span_lint( crate::lint::REDUNDANT_EXPLICIT_LINKS, @@ -350,7 +434,7 @@ fn check_reference_redundancy( ); } - None + Ok(()) } fn find_resolution(resolutions: &DocLinkResMap, path: &str) -> Option> { diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs b/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs index 9de8bbe3b8c98..2975ddfcc68bb 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs @@ -1,43 +1,42 @@ #![deny(rustdoc::redundant_explicit_links)] +use std::clone::Clone; -// Right now, redundant_explicit_links won't produce a warning at all if -// rustdoc isn't able to calculate an accurate span for the link. -// -// If that changes and this test starts to fail, you should add the -// appropriate annotations, and, also, make sure that it doesn't -// suggest a correction that wipes out the `fn` formal signature -// or the `#[inline]` attribute. - -/// [std::clone::Clone]( +/// [Clone]( pub fn split_outer_inner() { //! std::clone::Clone) +//~^^^ ERROR redundant_explicit_links } -/// [std::clone::Clone](std::clone::Clone +/// [Clone](std::clone::Clone pub fn split_outer_inner_b() { //! ) +//~^^^ ERROR redundant_explicit_links } -/// [std::clone::Clone]( +/// [Clone]( #[inline] /// std::clone::Clone) +//~^^^ ERROR redundant_explicit_links pub fn split_attr() { } -/// [std::clone::Clone](std::clone::Clone +/// [Clone](std::clone::Clone #[inline] /// ) +//~^^^ ERROR redundant_explicit_links pub fn split_attr_b() { } -/// [std::clone::Clone]( +/// [Clone]( /// std::clone::Clone) //~^^ ERROR redundant_explicit_links +//~| SUGGESTION [Clone] pub fn not_split() { } -/// [std::clone::Clone](std::clone::Clone +/// [Clone](std::clone::Clone /// ) //~^^ ERROR redundant_explicit_links +//~| SUGGESTION [Clone] pub fn not_split_b() { } diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr index 3e2e99f10d9f7..ff9bdfb48fc49 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr +++ b/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr @@ -1,12 +1,10 @@ error: redundant explicit link target - --> $DIR/redundant_explicit_links_split.rs:33:25 + --> $DIR/redundant_explicit_links_split.rs:4:1 | -LL | /// [std::clone::Clone]( - | ______-----------------__^ - | | | - | | because label contains path that resolves to same destination -LL | | /// std::clone::Clone) - | |_____________________^ explicit target is redundant +LL | / /// [Clone]( +LL | | pub fn split_outer_inner() { +LL | | //! std::clone::Clone) + | |__________________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination | = note: when a link's destination is not specified, the label is used to resolve intra-doc links @@ -15,18 +13,64 @@ note: the lint level is defined here | LL | #![deny(rustdoc::redundant_explicit_links)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:10:1 + | +LL | / /// [Clone](std::clone::Clone +LL | | pub fn split_outer_inner_b() { +LL | | //! ) + | |_________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:16:1 + | +LL | / /// [Clone]( +LL | | #[inline] +LL | | /// std::clone::Clone) + | |______________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:23:1 + | +LL | / /// [Clone](std::clone::Clone +LL | | #[inline] +LL | | /// ) + | |_____^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:30:13 + | +LL | /// [Clone]( + | ______-----__^ + | | | + | | because label contains path that resolves to same destination +LL | | /// std::clone::Clone) + | |_____________________^ explicit target is redundant + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links help: remove explicit link target | -LL - /// [std::clone::Clone]( +LL - /// [Clone]( LL - /// std::clone::Clone) -LL + /// [std::clone::Clone] +LL + /// [Clone] | error: redundant explicit link target - --> $DIR/redundant_explicit_links_split.rs:39:25 + --> $DIR/redundant_explicit_links_split.rs:37:13 | -LL | /// [std::clone::Clone](std::clone::Clone - | ______-----------------__^ +LL | /// [Clone](std::clone::Clone + | ______-----__^ | | | | | because label contains path that resolves to same destination LL | | /// ) @@ -36,10 +80,10 @@ LL | | /// ) the label is used to resolve intra-doc links help: remove explicit link target | -LL - /// [std::clone::Clone](std::clone::Clone +LL - /// [Clone](std::clone::Clone LL - /// ) -LL + /// [std::clone::Clone] +LL + /// [Clone] | -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors From 74c203dfbdccbc169eea104bf09778c2b8912bc7 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 17 Jun 2026 20:35:58 -0700 Subject: [PATCH 12/43] Add clarifying comment for shrink_to_hi --- compiler/rustc_resolve/src/rustdoc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 42a5005552825..7ee5f04ef7243 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -652,6 +652,8 @@ pub fn source_span_for_markdown_range_inner( span_of_all_fragments.split_at(prev_lines_bytes).1.split_at(source_line_len).0; let has_fragment = fragments .iter() + // `source_line_span` might contain indentation that `fragment.span` doesn't contain, + // so `shrink_to_hi()` removes it .any(|fragment| fragment.span.contains(source_line_span.shrink_to_hi())); // Since we're counting bytes, `prev_line_bytes` includes the "\n". prev_lines_bytes += source_line_len + 1; From 162a90c2455223e6fab5d3b540c07851e8818a92 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 18 Jun 2026 12:12:03 -0700 Subject: [PATCH 13/43] Handle block doc comments better --- compiler/rustc_resolve/src/rustdoc.rs | 46 ++++++- .../lints/redundant_explicit_links_split.rs | 58 +++++++++ .../redundant_explicit_links_split.stderr | 118 +++++++++++++++++- 3 files changed, 214 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 7ee5f04ef7243..f1e94b415787b 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -650,14 +650,50 @@ pub fn source_span_for_markdown_range_inner( let source_line_len = u32::try_from(source_line.len()).unwrap(); let source_line_span = span_of_all_fragments.split_at(prev_lines_bytes).1.split_at(source_line_len).0; - let has_fragment = fragments + let fragment = fragments .iter() - // `source_line_span` might contain indentation that `fragment.span` doesn't contain, - // so `shrink_to_hi()` removes it - .any(|fragment| fragment.span.contains(source_line_span.shrink_to_hi())); + // `source_line_span` might contain indentation that `fragment.span` doesn't contain + .find(|fragment| fragment.span.overlaps(source_line_span)); // Since we're counting bytes, `prev_line_bytes` includes the "\n". prev_lines_bytes += source_line_len + 1; - if has_fragment && let Some(offset) = source_line.find(md_line) { + if let Some(fragment) = fragment + && let Some(offset) = source_line.find(md_line) + { + if fragment.span.lo() > source_line_span.lo() + && source_line + [..usize::try_from(fragment.span.lo().0 - source_line_span.lo().0).unwrap()] + .chars() + .any(|c| !c.is_whitespace()) + { + // Make sure anything between the start of this line and the fragment itself is just indentation. + // Because source_line is built by splitting the span that covers all fragments, this only finds + // characters *between* doc comments, not characters before or after doc comments. + // + // 1| /** doc */ + // 2| #[inline] /** doc2 */ + // ^^^^^^^^^ + // | this + // + // 3| fn foo() {} + return None; + } + if fragment.span.hi() < source_line_span.hi() + && source_line + [usize::try_from(fragment.span.hi().0 - source_line_span.lo().0).unwrap()..] + .chars() + .any(|c| !c.is_whitespace()) + { + // Make sure anything between the start of this line and the fragment itself is just indentation. + // Because source_line is built by splitting the span that covers all fragments, this only finds + // characters *between* doc comments, not characters before or after doc comments. + // 1| /** doc */ #[inline] + // ^^^^^^^^^ + // | this + // + // 2| /** doc2 */ fn foo() {} + // 3| fn foo() {} + return None; + } if line_no == starting_line { start_bytes += offset; diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs b/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs index 2975ddfcc68bb..eebc6a0aa023c 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links_split.rs @@ -27,6 +27,64 @@ pub fn split_attr() { pub fn split_attr_b() { } +/** [Clone]( */ #[inline] /** std::clone::Clone) */ +//~^ ERROR redundant_explicit_links +pub fn split_blockcomment_attr() { +} + +/** [Clone](std::clone::Clone */ #[inline] /** ) */ +//~^ ERROR redundant_explicit_links +pub fn split_blockcomment_attr_b() { +} + +/** [Clone]( */ +#[inline] +/** std::clone::Clone) */ +//~^^^ ERROR redundant_explicit_links +pub fn split_blockcomment_multiline_attr() { +} + +/** [Clone](std::clone::Clone */ +#[inline] +/** ) */ +//~^^^ ERROR redundant_explicit_links +pub fn split_blockcomment_multiline_attr_b() { +} + +/** [Clone]( */ #[inline] +/** std::clone::Clone) */ +//~^^ ERROR redundant_explicit_links +pub fn split_blockcomment_twoline_attr() { +} + +/** [Clone](std::clone::Clone */ #[inline] +/** ) */ +//~^^ ERROR redundant_explicit_links +pub fn split_blockcomment_twoline_attr_b() { +} + +/** [Clone]( */ +#[inline] /** std::clone::Clone) */ +//~^^ ERROR redundant_explicit_links +pub fn split_blockcomment_secondline_attr() { +} + +/** [Clone](std::clone::Clone */ +#[inline] /** ) */ +//~^^ ERROR redundant_explicit_links +pub fn split_blockcomment_secondline_attr_b() { +} + +/** [Clone](std::clone::Clone) */ #[inline] +//~^ ERROR redundant_explicit_links +//~| SUGGESTION [Clone] +pub fn split_blockcomment_singleline_attr() { +} + +/** [Clone](std::clone::Clone) */ #[inline] pub fn split_blockcomment_singleline_attr_b() { } +//~^ ERROR redundant_explicit_links +//~| SUGGESTION [Clone] + /// [Clone]( /// std::clone::Clone) //~^^ ERROR redundant_explicit_links diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr index ff9bdfb48fc49..bfab5b751eedf 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr +++ b/tests/rustdoc-ui/lints/redundant_explicit_links_split.stderr @@ -48,7 +48,119 @@ LL | | /// ) the label is used to resolve intra-doc links error: redundant explicit link target - --> $DIR/redundant_explicit_links_split.rs:30:13 + --> $DIR/redundant_explicit_links_split.rs:30:1 + | +LL | /** [Clone]( */ #[inline] /** std::clone::Clone) */ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:35:1 + | +LL | /** [Clone](std::clone::Clone */ #[inline] /** ) */ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:40:1 + | +LL | / /** [Clone]( */ +LL | | #[inline] +LL | | /** std::clone::Clone) */ + | |_________________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:47:1 + | +LL | / /** [Clone](std::clone::Clone */ +LL | | #[inline] +LL | | /** ) */ + | |________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:54:1 + | +LL | / /** [Clone]( */ #[inline] +LL | | /** std::clone::Clone) */ + | |_________________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:60:1 + | +LL | / /** [Clone](std::clone::Clone */ #[inline] +LL | | /** ) */ + | |________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:66:1 + | +LL | / /** [Clone]( */ +LL | | #[inline] /** std::clone::Clone) */ + | |___________________________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:72:1 + | +LL | / /** [Clone](std::clone::Clone */ +LL | | #[inline] /** ) */ + | |__________________^ explicit target `std::clone::Clone` is redundant because label `Clone` resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:78:13 + | +LL | /** [Clone](std::clone::Clone) */ #[inline] + | ----- ^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL - /** [Clone](std::clone::Clone) */ #[inline] +LL + /** [Clone] */ #[inline] + | + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:84:13 + | +LL | /** [Clone](std::clone::Clone) */ #[inline] pub fn split_blockcomment_singleline_attr_b() { } + | ----- ^^^^^^^^^^^^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL - /** [Clone](std::clone::Clone) */ #[inline] pub fn split_blockcomment_singleline_attr_b() { } +LL + /** [Clone] */ #[inline] pub fn split_blockcomment_singleline_attr_b() { } + | + +error: redundant explicit link target + --> $DIR/redundant_explicit_links_split.rs:88:13 | LL | /// [Clone]( | ______-----__^ @@ -67,7 +179,7 @@ LL + /// [Clone] | error: redundant explicit link target - --> $DIR/redundant_explicit_links_split.rs:37:13 + --> $DIR/redundant_explicit_links_split.rs:95:13 | LL | /// [Clone](std::clone::Clone | ______-----__^ @@ -85,5 +197,5 @@ LL - /// ) LL + /// [Clone] | -error: aborting due to 6 previous errors +error: aborting due to 16 previous errors From 310bfad291cc0ff04a86fa1510a46f7ebdbe3644 Mon Sep 17 00:00:00 2001 From: sgasho Date: Thu, 4 Jun 2026 00:40:11 +0900 Subject: [PATCH 14/43] 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 15/43] 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 16/43] 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 17/43] 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 18/43] 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 19/43] 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 20/43] 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 21/43] 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 22/43] 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 23/43] 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 24/43] 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 25/43] 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 26/43] 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 27/43] 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 7f39e9fdd91dca202b41b59d5b0b356b3c5e33e9 Mon Sep 17 00:00:00 2001 From: khyperia <953151+khyperia@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:25:01 +0200 Subject: [PATCH 28/43] allow mGCA const arguments to fall back to anon consts --- compiler/rustc_ast/src/ast.rs | 16 +- compiler/rustc_ast/src/util/classify.rs | 3 + compiler/rustc_ast/src/visit.rs | 3 +- compiler/rustc_ast_lowering/src/expr.rs | 18 +- compiler/rustc_ast_lowering/src/lib.rs | 293 ++++++++++++------ compiler/rustc_ast_pretty/src/pprust/state.rs | 6 + .../rustc_ast_pretty/src/pprust/state/expr.rs | 6 + .../src/assert/context.rs | 1 + compiler/rustc_builtin_macros/src/autodiff.rs | 10 +- .../src/direct_const_arg.rs | 39 +++ compiler/rustc_builtin_macros/src/lib.rs | 2 + .../rustc_builtin_macros/src/pattern_type.rs | 18 +- compiler/rustc_expand/src/build.rs | 5 +- .../src/collect/generics_of.rs | 11 + compiler/rustc_metadata/src/rmeta/encoder.rs | 24 +- compiler/rustc_parse/src/parser/asm.rs | 4 +- .../rustc_parse/src/parser/diagnostics.rs | 20 +- compiler/rustc_parse/src/parser/expr.rs | 18 +- compiler/rustc_parse/src/parser/item.rs | 17 +- compiler/rustc_parse/src/parser/mod.rs | 5 +- compiler/rustc_parse/src/parser/path.rs | 23 +- compiler/rustc_parse/src/parser/ty.rs | 12 +- compiler/rustc_passes/src/input_stats.rs | 5 +- compiler/rustc_resolve/src/def_collector.rs | 23 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/marker.rs | 14 + .../clippy_utils/src/check_proc_macro.rs | 1 + src/tools/clippy/clippy_utils/src/sugg.rs | 1 + src/tools/rustfmt/src/expr.rs | 3 +- src/tools/rustfmt/src/types.rs | 9 +- src/tools/rustfmt/src/utils.rs | 5 +- .../rustfmt/tests/source/direct_const_arg.rs | 14 + .../rustfmt/tests/target/direct_const_arg.rs | 14 + tests/pretty/direct-const-arg.pp | 15 + tests/pretty/direct-const-arg.rs | 10 + .../doesnt_unify_evaluatable.stderr | 4 +- .../mgca/adt_expr_arg_simple.rs | 3 +- .../mgca/adt_expr_arg_simple.stderr | 8 +- .../mgca/array-expr-complex.r1.stderr | 6 +- .../mgca/array-expr-complex.r2.stderr | 6 +- .../mgca/array-expr-complex.r3.stderr | 6 +- .../const-generics/mgca/array-expr-complex.rs | 6 +- .../mgca/array_expr_arg_complex.rs | 4 +- .../mgca/array_expr_arg_complex.stderr | 12 +- ...non-const-def-id-on-const-arg-with-anon.rs | 11 + .../mgca/bad-const-arg-fn-154539.rs | 5 +- .../mgca/bad-const-arg-fn-154539.stderr | 8 +- .../mgca/bad-direct-const-arg.rs | 8 + .../mgca/bad-direct-const-arg.stderr | 14 + .../mgca/direct-const-arg-feature-gate.rs | 5 + .../mgca/direct-const-arg-feature-gate.stderr | 28 ++ .../mgca/direct-const-arg-multiple-exprs.rs | 5 + .../direct-const-arg-multiple-exprs.stderr | 8 + ...rapped-path-not-accidentally-stabilized.rs | 15 + ...ed-path-not-accidentally-stabilized.stderr | 11 + .../mgca/explicit_anon_consts.rs | 16 +- .../mgca/explicit_anon_consts.stderr | 36 +-- ...ixed-direct-anon-expression-diagnostics.rs | 17 + ...-direct-anon-expression-diagnostics.stderr | 16 + ...lized-direct-const-with-anon-const-body.rs | 16 + .../mgca/tuple_ctor_complex_args.rs | 2 +- .../mgca/tuple_ctor_complex_args.stderr | 6 +- .../mgca/tuple_expr_arg_complex.rs | 8 +- .../mgca/tuple_expr_arg_complex.stderr | 24 +- ...type-const-free-anon-const-mismatch.stderr | 2 +- ...const-free-value-type-mismatch.next.stderr | 2 +- ...t-inherent-value-type-mismatch.next.stderr | 2 +- ...type-const-value-type-mismatch.next.stderr | 2 +- ...ems-before-lowering-ices.ice_155125.stderr | 7 +- ...ems-before-lowering-ices.ice_155164.stderr | 7 +- .../hir-crate-items-before-lowering-ices.rs | 8 +- .../inside-const-body-ice-155300.rs | 5 +- .../inside-const-body-ice-155300.stderr | 13 +- 73 files changed, 676 insertions(+), 355 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/direct_const_arg.rs create mode 100644 src/tools/rustfmt/tests/source/direct_const_arg.rs create mode 100644 src/tools/rustfmt/tests/target/direct_const_arg.rs create mode 100644 tests/pretty/direct-const-arg.pp create mode 100644 tests/pretty/direct-const-arg.rs create mode 100644 tests/ui/const-generics/mgca/auxiliary/anon-const-def-id-on-const-arg-with-anon.rs create mode 100644 tests/ui/const-generics/mgca/bad-direct-const-arg.rs create mode 100644 tests/ui/const-generics/mgca/bad-direct-const-arg.stderr create mode 100644 tests/ui/const-generics/mgca/direct-const-arg-feature-gate.rs create mode 100644 tests/ui/const-generics/mgca/direct-const-arg-feature-gate.stderr create mode 100644 tests/ui/const-generics/mgca/direct-const-arg-multiple-exprs.rs create mode 100644 tests/ui/const-generics/mgca/direct-const-arg-multiple-exprs.stderr create mode 100644 tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.rs create mode 100644 tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.stderr create mode 100644 tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.rs create mode 100644 tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.stderr create mode 100644 tests/ui/const-generics/mgca/serialized-direct-const-with-anon-const-body.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index bd5ce5d18b839..10633f71a6a2c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1378,15 +1378,6 @@ pub enum UnsafeSource { UserProvided, } -/// Track whether under `feature(min_generic_const_args)` this anon const -/// was explicitly disambiguated as an anon const or not through the use of -/// `const { ... }` syntax. -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Walkable)] -pub enum MgcaDisambiguation { - AnonConst, - Direct, -} - /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) @@ -1396,7 +1387,6 @@ pub enum MgcaDisambiguation { pub struct AnonConst { pub id: NodeId, pub value: Box, - pub mgca_disambiguation: MgcaDisambiguation, } /// An expression. @@ -1627,6 +1617,7 @@ impl Expr { | ExprKind::UnsafeBinderCast(..) | ExprKind::While(..) | ExprKind::Yield(YieldKind::Postfix(..)) + | ExprKind::DirectConstArg(..) | ExprKind::Err(_) | ExprKind::Dummy => prefix_attrs_precedence(&self.attrs), } @@ -1920,6 +1911,9 @@ pub enum ExprKind { UnsafeBinderCast(UnsafeBinderCastKind, Box, Option>), + /// An mGCA `direct_const_arg!()` expression. + DirectConstArg(Box), + /// Placeholder for an expression that wasn't syntactically well formed in some way. Err(ErrorGuaranteed), @@ -2564,6 +2558,8 @@ pub enum TyKind { /// Usually not written directly in user code but indirectly via the macro /// `core::field::field_of!(...)`. FieldOf(Box, Option, Ident), + /// An mGCA `direct_const_arg!()` expression. + DirectConstArg(Box), /// 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..e68ba52a0730b 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -155,6 +155,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool { | Yeet(..) | Yield(..) | UnsafeBinderCast(..) + | DirectConstArg(..) | Err(..) | Dummy => return false, } @@ -240,6 +241,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { | Try(_) | Yeet(None) | UnsafeBinderCast(..) + | DirectConstArg(..) | Err(_) | Dummy => { break None; @@ -301,6 +303,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { | ast::TyKind::CVarArgs | ast::TyKind::Pat(..) | ast::TyKind::FieldOf(..) + | ast::TyKind::DirectConstArg(..) | ast::TyKind::Dummy | ast::TyKind::Err(..) => break None, } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1e96d1d52f7eb..7bc6675902bfc 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -416,7 +416,6 @@ macro_rules! common_visitor_and_walkers { UnsafeBinderCastKind, BinOpKind, BlockCheckMode, - MgcaDisambiguation, BorrowKind, BoundAsyncness, BoundConstness, @@ -1072,6 +1071,8 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, bytes), ExprKind::UnsafeBinderCast(kind, expr, ty) => visit_visitable!($($mut)? vis, kind, expr, ty), + ExprKind::DirectConstArg(expr) => + visit_visitable!($($mut)? vis, expr), ExprKind::Err(_guar) => {} ExprKind::Dummy => {} } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index f66d1ac16c907..4ed23e032d234 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -498,6 +498,18 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), + + ExprKind::DirectConstArg(_) => { + let e = self + .tcx + .dcx() + .struct_span_err( + e.span, + "expected expression, found `direct_const_arg!()` constant", + ) + .emit(); + hir::ExprKind::Err(e) + } }; hir::Expr { hir_id: expr_hir_id, kind, span } @@ -599,11 +611,7 @@ impl<'hir> LoweringContext<'_, 'hir> { arg }; - let anon_const = AnonConst { - id: node_id, - value: const_value, - mgca_disambiguation: MgcaDisambiguation::AnonConst, - }; + let anon_const = AnonConst { id: node_id, value: const_value }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); } else { real_args.push(arg); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 35e16ce78a8a8..1c67ee1264283 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1439,6 +1439,16 @@ impl<'hir> LoweringContext<'_, 'hir> { } } } + TyKind::DirectConstArg(expr) + if self.tcx.features().min_generic_const_args() => + { + let ct = match self.can_lower_expr_to_const_arg_direct(expr) { + Ok(()) => self.lower_expr_to_const_arg_direct(expr, None), + Err(e) => e.emit(self), + }; + let ct = self.arena.alloc(ct); + return GenericArg::Const(ct.try_as_ambig_ct().unwrap()); + } _ => {} } GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap()) @@ -1711,6 +1721,14 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::TyKind::Err(guar) } + TyKind::DirectConstArg(_) => { + let e = self + .tcx + .dcx() + .struct_span_err(t.span, "expected type, found `direct_const_arg!()` constant") + .emit(); + hir::TyKind::Err(e) + } TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"), }; @@ -2629,23 +2647,86 @@ impl<'hir> LoweringContext<'_, 'hir> { } #[instrument(level = "debug", skip(self), ret)] - fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> { - let span = self.lower_span(expr.span); - - let overly_complex_const = |this: &mut Self| { - let msg = "complex const arguments must be placed inside of a `const` block"; - let e = if expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break() { - // FIXME(mgca): make this non-fatal once we have a better way to handle - // nested items in const args - // Issue: https://github.com/rust-lang/rust/issues/154539 - this.dcx().struct_span_fatal(expr.span, msg).emit() - } else { - this.dcx().struct_span_err(expr.span, msg).emit() - }; + fn can_lower_expr_to_const_arg_direct( + &mut self, + expr: &Expr, + ) -> Result<(), UnrepresentableConstArgError> { + let is_mgca = self.tcx.features().min_generic_const_args(); + // Note the only stable case is currently ExprKind::Path. All others have an is_mgca guard. + match &expr.kind { + ExprKind::Call(func, args) + if is_mgca && let ExprKind::Path(_qself, _path) = &func.kind => + { + for arg in args { + self.can_lower_expr_to_const_arg_direct(arg)?; + } + Ok(()) + } + ExprKind::Tup(exprs) if is_mgca => { + for expr in exprs { + self.can_lower_expr_to_const_arg_direct(expr)?; + } + Ok(()) + } + ExprKind::Path(qself, path) + if is_mgca + || path.is_potential_trivial_const_arg() + && matches!( + self.get_partial_res(expr.id) + .and_then(|partial_res| partial_res.full_res()), + Some(Res::Def(DefKind::ConstParam, _)) + ) => + { + Ok(()) + } + ExprKind::Struct(se) if is_mgca => { + for f in &se.fields { + self.can_lower_expr_to_const_arg_direct(&f.expr)?; + } + Ok(()) + } + ExprKind::Array(elements) if is_mgca => { + for element in elements { + self.can_lower_expr_to_const_arg_direct(element)?; + } + Ok(()) + } + ExprKind::Underscore if is_mgca => Ok(()), + ExprKind::Block(block, _) + if is_mgca + && let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind => + { + self.can_lower_expr_to_const_arg_direct(expr) + } + ExprKind::Lit(literal) if is_mgca => Ok(()), + ExprKind::Unary(UnOp::Neg, inner_expr) + if is_mgca && let ExprKind::Lit(_) = &inner_expr.kind => + { + Ok(()) + } + ExprKind::ConstBlock(anon) if is_mgca => Ok(()), + ExprKind::DirectConstArg(expr) if is_mgca => { + // Always report this as able to be represented directly. If it turns out not to be, + // `lower_expr_to_const_arg_direct` will report an error. + Ok(()) + } + _ => Err(UnrepresentableConstArgError::new(expr)), + } + } - ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e), span } - }; + /// It is not allowed to call this function without checking can_lower_expr_to_const_arg_direct + /// first, as we assume all feature gates/etc. have been checked already. + #[instrument(level = "debug", skip(self), ret)] + fn lower_expr_to_const_arg_direct( + &mut self, + expr: &Expr, + id_override: Option, + ) -> hir::ConstArg<'hir> { + debug_assert!(self.can_lower_expr_to_const_arg_direct(expr).is_ok()); + let span = self.lower_span(expr.span); + let node_id = id_override.unwrap_or(expr.id); match &expr.kind { ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => { let qpath = self.lower_qpath( @@ -2659,23 +2740,27 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| { - let const_arg = self.lower_expr_to_const_arg_direct(arg); + let const_arg = self.lower_expr_to_const_arg_direct(arg, None); &*self.arena.alloc(const_arg) })); ConstArg { - hir_id: self.next_id(), + hir_id: self.lower_node_id(node_id), kind: hir::ConstArgKind::TupleCall(qpath, lowered_args), span, } } ExprKind::Tup(exprs) => { let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| { - let expr = self.lower_expr_to_const_arg_direct(&expr); + let expr = self.lower_expr_to_const_arg_direct(expr, None); &*self.arena.alloc(expr) })); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(exprs), span } + ConstArg { + hir_id: self.lower_node_id(node_id), + kind: hir::ConstArgKind::Tup(exprs), + span, + } } ExprKind::Path(qself, path) => { let qpath = self.lower_qpath( @@ -2689,7 +2774,11 @@ impl<'hir> LoweringContext<'_, 'hir> { None, ); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span } + ConstArg { + hir_id: self.lower_node_id(node_id), + kind: hir::ConstArgKind::Path(qpath), + span, + } } ExprKind::Struct(se) => { let path = self.lower_qpath( @@ -2711,7 +2800,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // then go unused as the `Target::ExprField` is not actually // corresponding to `Node::ExprField`. self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); - let expr = self.lower_expr_to_const_arg_direct(&f.expr); + let expr = self.lower_expr_to_const_arg_direct(&f.expr, None); &*self.arena.alloc(hir::ConstArgExprField { hir_id, @@ -2722,14 +2811,14 @@ impl<'hir> LoweringContext<'_, 'hir> { })); ConstArg { - hir_id: self.next_id(), + hir_id: self.lower_node_id(node_id), kind: hir::ConstArgKind::Struct(path, fields), span, } } ExprKind::Array(elements) => { let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| { - let const_arg = self.lower_expr_to_const_arg_direct(element); + let const_arg = self.lower_expr_to_const_arg_direct(element, None); &*self.arena.alloc(const_arg) })); let array_expr = self.arena.alloc(hir::ConstArgArrayExpr { @@ -2738,31 +2827,28 @@ impl<'hir> LoweringContext<'_, 'hir> { }); ConstArg { - hir_id: self.next_id(), + hir_id: self.lower_node_id(node_id), kind: hir::ConstArgKind::Array(array_expr), span, } } ExprKind::Underscore => ConstArg { - hir_id: self.lower_node_id(expr.id), + hir_id: self.lower_node_id(node_id), kind: hir::ConstArgKind::Infer(()), span, }, - ExprKind::Block(block, _) => { + ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() - && let StmtKind::Expr(expr) = &stmt.kind - { - return self.lower_expr_to_const_arg_direct(expr); - } - - overly_complex_const(self) + && let StmtKind::Expr(expr) = &stmt.kind => + { + return self.lower_expr_to_const_arg_direct(expr, id_override); } ExprKind::Lit(literal) => { let span = self.lower_span(expr.span); let literal = self.lower_lit(literal, span); ConstArg { - hir_id: self.lower_node_id(expr.id), + hir_id: self.lower_node_id(node_id), kind: hir::ConstArgKind::Literal { lit: literal.node, negated: false }, span, } @@ -2773,29 +2859,45 @@ impl<'hir> LoweringContext<'_, 'hir> { let span = self.lower_span(expr.span); let literal = self.lower_lit(literal, span); - if !matches!(literal.node, LitKind::Int(..)) { + let kind = if !matches!(literal.node, LitKind::Int(..)) { let err = self.dcx().struct_span_err(expr.span, "negated literal must be an integer"); - - return ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Error(err.emit()), - span, - }; - } - - ConstArg { - hir_id: self.lower_node_id(expr.id), - kind: hir::ConstArgKind::Literal { lit: literal.node, negated: true }, - span, - } + hir::ConstArgKind::Error(err.emit()) + } else { + hir::ConstArgKind::Literal { lit: literal.node, negated: true } + }; + ConstArg { hir_id: self.lower_node_id(node_id), kind, span } } ExprKind::ConstBlock(anon_const) => { + // Do not use lower_anon_const_to_const_arg, as that attempts to represent the body + // directly. Instead, force an anon const. let def_id = self.local_def_id(anon_const.id); assert_eq!(DefKind::InlineConst, self.tcx.def_kind(def_id)); - self.lower_anon_const_to_const_arg(anon_const, span) + let lowered_anon = self.lower_anon_const_to_anon_const(anon_const, span); + ConstArg { + hir_id: self.lower_node_id(node_id), + kind: hir::ConstArgKind::Anon(lowered_anon), + span, + } + } + ExprKind::DirectConstArg(expr) => { + // `can_lower_expr_to_const_arg_direct` always returns success upon encountering a + // ExprKind::DirectConstArg, which effectively forces the expression to be lowered + // as a direct arg. If it actually turns out to not be possible, emit an error + // instead. + match self.can_lower_expr_to_const_arg_direct(expr) { + Ok(()) => self.lower_expr_to_const_arg_direct(expr, id_override), + Err(err) => err.emit(self), + } + } + _ => { + span_bug!( + expr.span, + "lower_expr_to_const_arg_direct encountered an unlowerable expression, either \ + can_lower_expr_to_const_arg_direct returned Ok() on something it shouldn't \ + have, or you forgot to check can_lower_expr_to_const_arg_direct first" + ); } - _ => overly_complex_const(self), } } @@ -2814,67 +2916,23 @@ impl<'hir> LoweringContext<'_, 'hir> { anon: &AnonConst, span: Span, ) -> hir::ConstArg<'hir> { - let tcx = self.tcx; - - // We cannot change parsing depending on feature gates available, - // we can only require feature gates to be active as a delayed check. - // Thus we just parse anon consts generally and make the real decision - // making in ast lowering. - // FIXME(min_generic_const_args): revisit once stable - if tcx.features().min_generic_const_args() { - return match anon.mgca_disambiguation { - MgcaDisambiguation::AnonConst => { - let lowered_anon = self.lower_anon_const_to_anon_const(anon, span); - ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Anon(lowered_anon), - span: lowered_anon.span, - } - } - MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value), - }; - } - - // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments - // currently have to be wrapped in curly brackets, so it's necessary to special-case. - let expr = if let ExprKind::Block(block, _) = &anon.value.kind - && let [stmt] = block.stmts.as_slice() - && let StmtKind::Expr(expr) = &stmt.kind - && let ExprKind::Path(..) = &expr.kind - { - expr - } else { + // Stable only allows one nesting of blocks for directly represented paths. mGCA allows + // arbitrarily many, and are handled inside lower_expr_to_const_arg_direct for consistency. + let expr = if self.tcx.features().min_generic_const_args() { &anon.value + } else { + anon.value.maybe_unwrap_block() }; - let maybe_res = - self.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); - if let ExprKind::Path(qself, path) = &expr.kind - && path.is_potential_trivial_const_arg() - && matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))) - { - let qpath = self.lower_qpath( - expr.id, - qself, - path, - ParamMode::Explicit, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - - return ConstArg { - hir_id: self.lower_node_id(anon.id), - kind: hir::ConstArgKind::Path(qpath), - span: self.lower_span(expr.span), - }; + if self.can_lower_expr_to_const_arg_direct(expr).is_ok() { + return self.lower_expr_to_const_arg_direct(expr, Some(anon.id)); } let lowered_anon = self.lower_anon_const_to_anon_const(anon, anon.value.span); ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon), - span: self.lower_span(expr.span), + span: self.lower_span(anon.value.span), } } @@ -3170,3 +3228,36 @@ impl<'hir> GenericArgsCtor<'hir> { this.arena.alloc(ga) } } + +#[derive(Debug)] +struct UnrepresentableConstArgError { + span: Span, + will_create_def_ids: bool, +} + +impl UnrepresentableConstArgError { + fn new(expr: &Expr) -> Self { + Self { + span: expr.span, + will_create_def_ids: expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break(), + } + } + + fn emit<'hir>(self, lowering_context: &mut LoweringContext<'_, 'hir>) -> ConstArg<'hir> { + let msg = "complex const arguments must be placed inside of a `const` block"; + let e = if self.will_create_def_ids { + // FIXME(mgca): make this non-fatal once we have a better way to handle + // nested items in const args + // Issue: https://github.com/rust-lang/rust/issues/154539 + lowering_context.dcx().struct_span_fatal(self.span, msg).emit() + } else { + lowering_context.dcx().struct_span_err(self.span, msg).emit() + }; + + ConstArg { + hir_id: lowering_context.next_id(), + kind: hir::ConstArgKind::Error(e), + span: self.span, + } + } +} diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 8b2da2acaa520..e6e9ad7f3ef8c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1441,6 +1441,12 @@ impl<'a> State<'a> { self.end(ib); self.pclose(); } + ast::TyKind::DirectConstArg(expr) => { + self.word_nbsp("core::direct_const_arg!"); + self.popen(); + self.print_expr(expr, FixupContext::default()); + self.pclose() + } } self.end(ib); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 176e91e544ec5..4f3281641359d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -883,6 +883,12 @@ impl<'a> State<'a> { self.word("/*DUMMY*/"); self.pclose(); } + ast::ExprKind::DirectConstArg(expr) => { + self.word_nbsp("core::direct_const_arg!"); + self.popen(); + self.print_expr(expr, FixupContext::default()); + self.pclose() + } } self.ann.post(self, AnnNode::Expr(expr)); diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index f15acc154baf3..1bc2bc8342559 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -323,6 +323,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Yeet(_) | ExprKind::Become(_) | ExprKind::Yield(_) + | ExprKind::DirectConstArg(_) | ExprKind::UnsafeBinderCast(..) => {} } } diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 311a24280cfb7..bd5bf3a687d92 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -16,7 +16,7 @@ mod llvm_enzyme { use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode, FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind, - MetaItemInner, MgcaDisambiguation, PatKind, Path, PathSegment, TyKind, Visibility, + MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility, }; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_hir::attrs::RustcAutodiff; @@ -602,11 +602,7 @@ mod llvm_enzyme { } GenericParamKind::Const { .. } => { let expr = ecx.expr_path(ast::Path::from_ident(p.ident)); - let anon_const = AnonConst { - id: ast::DUMMY_NODE_ID, - value: expr, - mgca_disambiguation: MgcaDisambiguation::Direct, - }; + let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr }; Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const))) } GenericParamKind::Lifetime { .. } => None, @@ -861,7 +857,6 @@ mod llvm_enzyme { let anon_const = rustc_ast::AnonConst { id: ast::DUMMY_NODE_ID, value: ecx.expr_usize(span, 1 + x.width as usize), - mgca_disambiguation: MgcaDisambiguation::Direct, }; TyKind::Array(ty.clone(), anon_const) }; @@ -876,7 +871,6 @@ mod llvm_enzyme { let anon_const = rustc_ast::AnonConst { id: ast::DUMMY_NODE_ID, value: ecx.expr_usize(span, x.width as usize), - mgca_disambiguation: MgcaDisambiguation::Direct, }; let kind = TyKind::Array(ty.clone(), anon_const); let ty = diff --git a/compiler/rustc_builtin_macros/src/direct_const_arg.rs b/compiler/rustc_builtin_macros/src/direct_const_arg.rs new file mode 100644 index 0000000000000..51c169134e03f --- /dev/null +++ b/compiler/rustc_builtin_macros/src/direct_const_arg.rs @@ -0,0 +1,39 @@ +use rustc_ast::ast; +use rustc_ast::tokenstream::TokenStream; +use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_span::Span; + +use crate::util::get_single_expr_from_tts; + +pub(crate) fn expand<'cx>( + cx: &'cx mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + let ExpandResult::Ready(expr) = get_single_expr_from_tts(cx, span, tts, "direct_const_arg!") + else { + return ExpandResult::Retry(()); + }; + let expr = match expr { + Ok(expr) => expr, + Err(err) => return ExpandResult::Ready(DummyResult::any(span, err)), + }; + + let id = ast::DUMMY_NODE_ID; + ExpandResult::Ready(Box::new(base::MacEager { + expr: Some(Box::new(ast::Expr { + id, + kind: ast::ExprKind::DirectConstArg(expr.clone()), + span, + attrs: Default::default(), + tokens: None, + })), + ty: Some(Box::new(ast::Ty { + id, + kind: ast::TyKind::DirectConstArg(expr), + span, + tokens: None, + })), + ..Default::default() + })) +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4a5ff44c402ab..991f773df55f4 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -34,6 +34,7 @@ mod define_opaque; mod derive; mod deriving; mod diagnostics; +mod direct_const_arg; mod edition_panic; mod eii; mod env; @@ -80,6 +81,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { concat_bytes: concat_bytes::expand_concat_bytes, const_format_args: format::expand_format_args, core_panic: edition_panic::expand_panic, + direct_const_arg: direct_const_arg::expand, env: env::expand_env, file: source_util::expand_file, format_args: format::expand_format_args, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 53ab3fcd9b34b..065ba9f6a2096 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,5 +1,5 @@ use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AnonConst, DUMMY_NODE_ID, MgcaDisambiguation, Ty, TyPat, TyPatKind, ast, token}; +use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token}; use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_parse::exp; @@ -60,20 +60,8 @@ fn ty_pat(kind: TyPatKind, span: Span) -> TyPat { fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat { let kind = match pat.kind { ast::PatKind::Range(start, end, include_end) => TyPatKind::Range( - start.map(|value| { - Box::new(AnonConst { - id: DUMMY_NODE_ID, - value, - mgca_disambiguation: MgcaDisambiguation::Direct, - }) - }), - end.map(|value| { - Box::new(AnonConst { - id: DUMMY_NODE_ID, - value, - mgca_disambiguation: MgcaDisambiguation::Direct, - }) - }), + start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), + end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), include_end, ), ast::PatKind::Or(variants) => { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 01886a97f55a2..f3792d4d45235 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -2,8 +2,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, - MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream, + self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, + UnOp, attr, token, tokenstream, }; use rustc_span::{DUMMY_SP, Ident, Span, Spanned, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -100,7 +100,6 @@ impl<'a> ExtCtxt<'a> { attrs: AttrVec::new(), tokens: None, }), - mgca_disambiguation: MgcaDisambiguation::Direct, } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 811ed83e0bf48..d6a5db4c22f24 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -214,6 +214,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { "synthetic HIR should have its `generics_of` explicitly fed" ), + Node::ConstArg(..) => { + // These can show up in mGCA when representing "direct" const arguments. The + // DefCollector cannot know whether an anon const will be represented by an actual HIR + // Node::AnonConst, or whether it will be represented directly, so it must generate a + // DefId. If it ends up being direct, this DefId is then attached to the top-level + // ConstArg, which is what we are seeing here. + debug_assert!(tcx.features().min_generic_const_args()); + // Forward to the real parent. + Some(tcx.local_parent(def_id)) + } + _ => span_bug!(tcx.def_span(def_id), "generics_of: unexpected node kind {node:?}"), }; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 16a5a6c8877a5..6a7942a2bad29 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1108,7 +1108,7 @@ fn should_encode_mir( // instance_mir uses mir_for_ctfe rather than optimized_mir for constructors DefKind::Ctor(_, _) => (true, false), // Constants - DefKind::AnonConst { .. } + DefKind::AnonConst | DefKind::InlineConst | DefKind::AssocConst { .. } | DefKind::Const { .. } => (true, false), @@ -1438,27 +1438,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // for trivial const arguments which are directly lowered to // `ConstArgKind::Path`. We never actually access this `DefId` // anywhere so we don't need to encode it for other crates. + // FIXME(mgca): This probably isn't true, they probably are accessed, but, test case? if def_kind == DefKind::AnonConst - && match tcx.hir_node_by_def_id(local_id) { - hir::Node::ConstArg(hir::ConstArg { kind, .. }) => match kind { - // Skip encoding defs for these as they should not have had a `DefId` created - hir::ConstArgKind::Error(..) - | hir::ConstArgKind::Struct(..) - | hir::ConstArgKind::Array(..) - | hir::ConstArgKind::TupleCall(..) - | hir::ConstArgKind::Tup(..) - | hir::ConstArgKind::Path(..) - | hir::ConstArgKind::Literal { .. } - | hir::ConstArgKind::Infer(..) => true, - hir::ConstArgKind::Anon(..) => false, - }, - _ => false, - } + && matches!(tcx.hir_node_by_def_id(local_id), hir::Node::ConstArg(_)) { - // MGCA doesn't have unnecessary DefIds - if !tcx.features().min_generic_const_args() { - continue; - } + continue; } if def_kind == DefKind::Field diff --git a/compiler/rustc_parse/src/parser/asm.rs b/compiler/rustc_parse/src/parser/asm.rs index 3fab234adaad4..11460e775d36d 100644 --- a/compiler/rustc_parse/src/parser/asm.rs +++ b/compiler/rustc_parse/src/parser/asm.rs @@ -1,4 +1,4 @@ -use rustc_ast::{self as ast, AsmMacro, MgcaDisambiguation}; +use rustc_ast::{self as ast, AsmMacro}; use rustc_span::{Span, Symbol, kw}; use super::{ExpKeywordPair, ForceCollect, IdentIsRaw, Trailing, UsePreAttrPos}; @@ -149,7 +149,7 @@ fn parse_asm_operand<'a>( let block = p.parse_block()?; ast::InlineAsmOperand::Label { block } } else if p.eat_keyword(exp!(Const)) { - let anon_const = p.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; + let anon_const = p.parse_expr_anon_const()?; ast::InlineAsmOperand::Const { anon_const } } else if p.eat_keyword(exp!(Sym)) { let expr = p.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 28e2841b9f1fe..a91ee634f3d47 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -7,7 +7,7 @@ use rustc_ast::util::parser::AssocOp; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, GenericArgs, Generics, Item, ItemKind, - MgcaDisambiguation, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, + Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -2585,11 +2585,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg }); let value = self.mk_expr_err(param.span(), guar); - Some(GenericArg::Const(AnonConst { - id: ast::DUMMY_NODE_ID, - value, - mgca_disambiguation: MgcaDisambiguation::Direct, - })) + Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) } pub(super) fn recover_const_param_declaration( @@ -2673,11 +2669,7 @@ impl<'a> Parser<'a> { ); let guar = err.emit(); let value = self.mk_expr_err(start.to(expr.span), guar); - return Ok(GenericArg::Const(AnonConst { - id: ast::DUMMY_NODE_ID, - value, - mgca_disambiguation: MgcaDisambiguation::Direct, - })); + return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); } else if snapshot.token == token::Colon && expr.span.lo() == snapshot.token.span.hi() && matches!(expr.kind, ExprKind::Path(..)) @@ -2746,11 +2738,7 @@ impl<'a> Parser<'a> { ); let guar = err.emit(); let value = self.mk_expr_err(span, guar); - GenericArg::Const(AnonConst { - id: ast::DUMMY_NODE_ID, - value, - mgca_disambiguation: MgcaDisambiguation::Direct, - }) + GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }) } /// Some special error handling for the "top-level" patterns in a match arm, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 60a94345c5325..794ad760aab4c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,8 +15,8 @@ use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{ self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, - FnRetTy, Guard, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, - RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, + FnRetTy, Guard, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, + TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -83,15 +83,8 @@ impl<'a> Parser<'a> { ) } - pub fn parse_expr_anon_const( - &mut self, - mgca_disambiguation: impl FnOnce(&Self, &Expr) -> MgcaDisambiguation, - ) -> PResult<'a, AnonConst> { - self.parse_expr().map(|value| AnonConst { - id: DUMMY_NODE_ID, - mgca_disambiguation: mgca_disambiguation(self, &value), - value, - }) + pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> { + self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) } fn parse_expr_catch_underscore( @@ -1672,7 +1665,7 @@ impl<'a> Parser<'a> { let first_expr = self.parse_expr()?; if self.eat(exp!(Semi)) { // Repeating array syntax: `[ 0; 512 ]` - let count = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?; + let count = self.parse_expr_anon_const()?; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(exp!(Comma)) { @@ -4508,6 +4501,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::IncludedBytes(_) | ExprKind::FormatArgs(_) | ExprKind::Err(_) + | ExprKind::DirectConstArg(_) | ExprKind::Dummy => { // These would forbid any let expressions they contain already. } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 627711cb2f822..a5f828c09d12b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1695,9 +1695,9 @@ impl<'a> Parser<'a> { if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() }; let rhs = match (self.eat(exp!(Eq)), const_arg) { - (true, true) => ConstItemRhsKind::TypeConst { - rhs: Some(self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?), - }, + (true, true) => { + ConstItemRhsKind::TypeConst { rhs: Some(self.parse_expr_anon_const()?) } + } (true, false) => ConstItemRhsKind::Body { rhs: Some(self.parse_expr()?) }, (false, true) => ConstItemRhsKind::TypeConst { rhs: None }, (false, false) => ConstItemRhsKind::Body { rhs: None }, @@ -1917,11 +1917,8 @@ impl<'a> Parser<'a> { VariantData::Unit(DUMMY_NODE_ID) }; - let disr_expr = if this.eat(exp!(Eq)) { - Some(this.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?) - } else { - None - }; + let disr_expr = + if this.eat(exp!(Eq)) { Some(this.parse_expr_anon_const()?) } else { None }; let span = vlo.to(this.prev_token.span); if ident.name == kw::Underscore { @@ -2142,7 +2139,7 @@ impl<'a> Parser<'a> { if p.token == token::Eq { let mut snapshot = p.create_snapshot_for_diagnostic(); snapshot.bump(); - match snapshot.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst) { + match snapshot.parse_expr_anon_const() { Ok(const_expr) => { let sp = ty.span.shrink_to_hi().to(const_expr.value.span); p.psess.gated_spans.gate(sym::default_field_values, sp); @@ -2371,7 +2368,7 @@ impl<'a> Parser<'a> { } let default = if self.token == token::Eq { self.bump(); - let const_expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; + let const_expr = self.parse_expr_anon_const()?; let sp = ty.span.shrink_to_hi().to(const_expr.value.span); self.psess.gated_spans.gate(sym::default_field_values, sp); Some(const_expr) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 64255d51a7c69..d25caa2456f85 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -36,8 +36,8 @@ use rustc_ast::util::classify; use rustc_ast::{ self as ast, AnonConst, AttrArgs, AttrId, BinOpKind, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, ImplRestriction, - MgcaDisambiguation, MutRestriction, Mutability, Recovered, RestrictionKind, Safety, StrLit, - Visibility, VisibilityKind, + MutRestriction, Mutability, Recovered, RestrictionKind, Safety, StrLit, Visibility, + VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -1298,7 +1298,6 @@ impl<'a> Parser<'a> { let anon_const = AnonConst { id: DUMMY_NODE_ID, value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), - mgca_disambiguation: MgcaDisambiguation::AnonConst, }; let blk_span = anon_const.value.span; let kind = if pat { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index ea86c08915b31..d3839579d1311 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -4,8 +4,8 @@ use ast::token::IdentIsRaw; use rustc_ast::token::{self, MetaVarKind, Token, TokenKind}; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint, - AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, MgcaDisambiguation, - ParenthesizedArgs, Path, PathSegment, QSelf, + AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, + Path, PathSegment, QSelf, }; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{BytePos, Ident, Span, kw, sym}; @@ -876,13 +876,12 @@ impl<'a> Parser<'a> { /// the caller. pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> { // Parse const argument. - let (value, mgca_disambiguation) = if self.token.kind == token::OpenBrace { - let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; - (value, MgcaDisambiguation::Direct) + let value = if self.token.kind == token::OpenBrace { + self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)? } else { self.parse_unambiguous_unbraced_const_arg()? }; - Ok(AnonConst { id: ast::DUMMY_NODE_ID, value, mgca_disambiguation }) + Ok(AnonConst { id: ast::DUMMY_NODE_ID, value }) } /// Attempt to parse a const argument that has not been enclosed in braces. @@ -892,9 +891,7 @@ impl<'a> Parser<'a> { /// - Single-segment paths (i.e. standalone generic const parameters). /// All other expressions that can be parsed will emit an error suggesting the expression be /// wrapped in braces. - pub(super) fn parse_unambiguous_unbraced_const_arg( - &mut self, - ) -> PResult<'a, (Box, MgcaDisambiguation)> { + pub(super) fn parse_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, Box> { let start = self.token.span; let attrs = self.parse_outer_attributes()?; let (expr, _) = @@ -915,7 +912,7 @@ impl<'a> Parser<'a> { }); } - Ok((expr, MgcaDisambiguation::Direct)) + Ok(expr) } /// Parse a generic argument in a path segment. @@ -1019,11 +1016,7 @@ impl<'a> Parser<'a> { GenericArg::Type(_) => GenericArg::Type(self.mk_ty(attr_span, TyKind::Err(guar))), GenericArg::Const(_) => { let error_expr = self.mk_expr(attr_span, ExprKind::Err(guar)); - GenericArg::Const(AnonConst { - id: ast::DUMMY_NODE_ID, - value: error_expr, - mgca_disambiguation: MgcaDisambiguation::Direct, - }) + GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: error_expr }) } GenericArg::Lifetime(lt) => GenericArg::Lifetime(lt), })); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8a881c6f8b568..ea4cc9799156d 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -2,9 +2,9 @@ use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy, - GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MgcaDisambiguation, - MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, - TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, + GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, + Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, + TyKind, UnsafeBinderTy, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, E0516, PResult}; @@ -660,7 +660,7 @@ impl<'a> Parser<'a> { }; let ty = if self.eat(exp!(Semi)) { - let mut length = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?; + let mut length = self.parse_expr_anon_const()?; if let Err(e) = self.expect(exp!(CloseBracket)) { // Try to recover from `X` when `X::` works @@ -704,7 +704,7 @@ impl<'a> Parser<'a> { // FIXME(mgca): recovery is broken for `const {` args // we first try to parse pattern like `[u8 5]` - let length = match self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct) { + let length = match self.parse_expr_anon_const() { Ok(length) => length, Err(e) => { e.cancel(); @@ -813,7 +813,7 @@ impl<'a> Parser<'a> { /// an error type. fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> { self.expect(exp!(OpenParen))?; - let _expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; + let _expr = self.parse_expr_anon_const()?; self.expect(exp!(CloseParen))?; let span = lo.to(self.prev_token.span); let guar = self diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 2f3fbc28ad49d..57d1b12e8a178 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -660,7 +660,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { If, While, ForLoop, Loop, Match, Closure, Block, Await, Move, Use, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, - Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy + Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy, DirectConstArg ] ); ast_visit::walk_expr(self, e) @@ -688,8 +688,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ImplicitSelf, MacCall, CVarArgs, - Dummy, FieldOf, + DirectConstArg, + Dummy, Err ] ); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index de3f8c380fc44..81c6db6a9d6d7 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -425,26 +425,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { fn visit_anon_const(&mut self, constant: &'a AnonConst) { // Note that `visit_anon_const` is skipped for AnonConst nodes wrapped in an // ExprKind::ConstBlock - these are handled in visit_expr, and are DefKind::InlineConst. - - // `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so - // to avoid affecting stable we have to feature gate the not creating - // anon consts - if !self.r.features.min_generic_const_args() { - let parent = self - .create_def(constant.id, None, DefKind::AnonConst, constant.value.span) - .def_id(); - return self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); - } - - match constant.mgca_disambiguation { - MgcaDisambiguation::Direct => visit::walk_anon_const(self, constant), - MgcaDisambiguation::AnonConst => { - let parent = self - .create_def(constant.id, None, DefKind::AnonConst, constant.value.span) - .def_id(); - self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); - } - }; + let parent = + self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span).def_id(); + self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 71eae246ebaff..a65ebe3663929 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -821,6 +821,7 @@ symbols! { diagnostic_on_unmatched_args, dialect, direct, + direct_const_arg, discriminant_kind, discriminant_type, discriminant_value, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 45b8b266a2671..e3785c92c8d0d 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1073,6 +1073,20 @@ pub const trait Destruct: PointeeSized {} #[rustc_dyn_incompatible_trait] pub trait Tuple {} +/// Creates a new style directly represented const argument. +/// ```ignore (cannot test this from within core yet) +/// type const BAR: usize = N; +/// type const FOO: usize = direct!(BAR::); +/// ``` +#[rustc_builtin_macro(direct_const_arg)] +#[unstable(feature = "min_generic_const_args", issue = "132980")] +#[macro_export] +macro_rules! direct_const_arg { + ($($arg:tt)*) => { + /* compiler built-in */ + }; +} + /// A marker for types which can be used as types of `const` generic parameters. /// /// These types must have a proper equivalence relation (`Eq`) and it must be automatically 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..24ccb99a7c6ee 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::DirectConstArg(..) // unused | TyKind::CVarArgs diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index f194103ae2e88..cb0db1ed014fc 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -248,6 +248,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) + | ast::ExprKind::DirectConstArg(..) | ast::ExprKind::Err(_) | ast::ExprKind::Dummy | ast::ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(snippet(expr.span)), diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 8a3674bff1ca6..cc7fdaefc8fee 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -486,7 +486,8 @@ pub(crate) fn format_expr( | ast::ExprKind::Type(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::OffsetOf(..) - | ast::ExprKind::UnsafeBinderCast(..) => { + | ast::ExprKind::UnsafeBinderCast(..) + | ast::ExprKind::DirectConstArg(..) => { // 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 one of these nodes when formatting a file. diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 2dfb5e5b28f61..1a3e1f53c1504 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1014,7 +1014,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)?; @@ -1054,6 +1053,14 @@ impl Rewrite for ast::Ty { result.push_str(&rewrite); Ok(result) } + ast::TyKind::DirectConstArg(..) => { + // 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 one of these nodes when formatting + // a file. Also, rustfmt might get passed the output from `-Zunpretty=expanded`. + Ok(context.snippet(self.span).to_owned()) + } + ast::TyKind::Dummy | ast::TyKind::Err(_) => Ok(context.snippet(self.span).to_owned()), } } } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 1fcc59f2a1ea4..3e06f3899d1b3 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -532,9 +532,8 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Index(_, ref expr, _) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Try(ref expr) - | ast::ExprKind::Yield(YieldKind::Prefix(Some(ref expr))) => { - is_block_expr(context, expr, repr) - } + | ast::ExprKind::Yield(YieldKind::Prefix(Some(ref expr))) + | ast::ExprKind::DirectConstArg(ref expr) => is_block_expr(context, expr, repr), ast::ExprKind::Closure(ref closure) => is_block_expr(context, &closure.body, repr), // This can only be a string lit ast::ExprKind::Lit(_) => { diff --git a/src/tools/rustfmt/tests/source/direct_const_arg.rs b/src/tools/rustfmt/tests/source/direct_const_arg.rs new file mode 100644 index 0000000000000..f6f9c25d9a0d8 --- /dev/null +++ b/src/tools/rustfmt/tests/source/direct_const_arg.rs @@ -0,0 +1,14 @@ +// direct_const_arg! is a built-in macro relevant to min_generic_const_args; its contents should be +// formatted as if its contents were passed through unchanged (the macro changes the semantics of +// the contained expression, the syntax is unchanged) + +#![feature(min_generic_const_args)] + +trait Trait { + type const TYPE_CONST: usize; +} + +struct S; + +fn parsed_as_expr_kind(_: S<{ core::direct_const_arg!( T :: TYPE_CONST ) }>) {} +fn parsed_as_ty_kind(_: S< core::direct_const_arg!( T :: TYPE_CONST ) >) {} diff --git a/src/tools/rustfmt/tests/target/direct_const_arg.rs b/src/tools/rustfmt/tests/target/direct_const_arg.rs new file mode 100644 index 0000000000000..1ebadae00ff05 --- /dev/null +++ b/src/tools/rustfmt/tests/target/direct_const_arg.rs @@ -0,0 +1,14 @@ +// direct_const_arg! is a built-in macro relevant to min_generic_const_args; its contents should be +// formatted as if its contents were passed through unchanged (the macro changes the semantics of +// the contained expression, the syntax is unchanged) + +#![feature(min_generic_const_args)] + +trait Trait { + type const TYPE_CONST: usize; +} + +struct S; + +fn parsed_as_expr_kind(_: S<{ core::direct_const_arg!(T::TYPE_CONST) }>) {} +fn parsed_as_ty_kind(_: S) {} diff --git a/tests/pretty/direct-const-arg.pp b/tests/pretty/direct-const-arg.pp new file mode 100644 index 0000000000000..a76ed9a480e71 --- /dev/null +++ b/tests/pretty/direct-const-arg.pp @@ -0,0 +1,15 @@ +#![feature(prelude_import)] +#![no_std] +//@ pretty-mode:expanded +//@ pp-exact:direct-const-arg.pp +#![feature(min_generic_const_args)] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +fn f() {} + +fn main() { + f::(); + f::<{ core::direct_const_arg! (2) }>(); +} diff --git a/tests/pretty/direct-const-arg.rs b/tests/pretty/direct-const-arg.rs new file mode 100644 index 0000000000000..330c1cac024de --- /dev/null +++ b/tests/pretty/direct-const-arg.rs @@ -0,0 +1,10 @@ +//@ pretty-mode:expanded +//@ pp-exact:direct-const-arg.pp +#![feature(min_generic_const_args)] + +fn f() {} + +fn main() { + f::(); + f::<{ core::direct_const_arg!(2) }>(); +} diff --git a/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr b/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr index 62bebd53b14a6..6cf4e881adae8 100644 --- a/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr +++ b/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr @@ -1,8 +1,8 @@ error: unconstrained generic constant - --> $DIR/doesnt_unify_evaluatable.rs:9:13 + --> $DIR/doesnt_unify_evaluatable.rs:9:11 | LL | bar::<{ T::ASSOC }>(); - | ^^^^^^^^ + | ^^^^^^^^^^^^ | help: try adding a `where` bound | diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs b/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs index 8470b933cadd2..b09d17fb11262 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs +++ b/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs @@ -10,7 +10,6 @@ use Option::Some; fn foo>() {} - trait Trait { type const ASSOC: u32; } @@ -26,7 +25,7 @@ fn bar() { // this on the other hand is not allowed as `N + 1` is not a legal // const argument - foo::<{ Some:: { 0: N + 1 } }>(); + foo::<{ core::direct_const_arg!(Some:: { 0: N + 1 }) }>(); //~^ ERROR: complex const arguments must be placed inside of a `const` block // this also is not allowed as generic parameters cannot be used diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr b/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr index 0060c94875b5c..8f02ce0f82315 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr +++ b/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr @@ -1,11 +1,11 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/adt_expr_arg_simple.rs:29:30 + --> $DIR/adt_expr_arg_simple.rs:28:54 | -LL | foo::<{ Some:: { 0: N + 1 } }>(); - | ^^^^^ +LL | foo::<{ core::direct_const_arg!(Some:: { 0: N + 1 }) }>(); + | ^^^^^ error: generic parameters may not be used in const operations - --> $DIR/adt_expr_arg_simple.rs:34:38 + --> $DIR/adt_expr_arg_simple.rs:33:38 | LL | foo::<{ Some:: { 0: const { N + 1 } } }>(); | ^ diff --git a/tests/ui/const-generics/mgca/array-expr-complex.r1.stderr b/tests/ui/const-generics/mgca/array-expr-complex.r1.stderr index 0c931af8d8b1c..a226d7ff0c225 100644 --- a/tests/ui/const-generics/mgca/array-expr-complex.r1.stderr +++ b/tests/ui/const-generics/mgca/array-expr-complex.r1.stderr @@ -1,8 +1,8 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/array-expr-complex.rs:11:28 + --> $DIR/array-expr-complex.rs:11:52 | -LL | takes_array::<{ [1, 2, 1 + 2] }>(); - | ^^^^^ +LL | takes_array::<{ core::direct_const_arg!([1, 2, 1 + 2]) }>(); + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/array-expr-complex.r2.stderr b/tests/ui/const-generics/mgca/array-expr-complex.r2.stderr index 335af9235e0c9..cc1e70c1d9a7a 100644 --- a/tests/ui/const-generics/mgca/array-expr-complex.r2.stderr +++ b/tests/ui/const-generics/mgca/array-expr-complex.r2.stderr @@ -1,8 +1,8 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/array-expr-complex.rs:14:21 + --> $DIR/array-expr-complex.rs:14:45 | -LL | takes_array::<{ [X; 3] }>(); - | ^^^^^^ +LL | takes_array::<{ core::direct_const_arg!([X; 3]) }>(); + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/array-expr-complex.r3.stderr b/tests/ui/const-generics/mgca/array-expr-complex.r3.stderr index 02d74c1b5d0c5..cc52abe0e8fb8 100644 --- a/tests/ui/const-generics/mgca/array-expr-complex.r3.stderr +++ b/tests/ui/const-generics/mgca/array-expr-complex.r3.stderr @@ -1,8 +1,8 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/array-expr-complex.rs:17:21 + --> $DIR/array-expr-complex.rs:17:45 | -LL | takes_array::<{ [0; Y] }>(); - | ^^^^^^ +LL | takes_array::<{ core::direct_const_arg!([0; Y]) }>(); + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/array-expr-complex.rs b/tests/ui/const-generics/mgca/array-expr-complex.rs index 26f4700b5885c..7f5a77fdff3df 100644 --- a/tests/ui/const-generics/mgca/array-expr-complex.rs +++ b/tests/ui/const-generics/mgca/array-expr-complex.rs @@ -8,13 +8,13 @@ fn takes_array() {} fn generic_caller() { // not supported yet #[cfg(r1)] - takes_array::<{ [1, 2, 1 + 2] }>(); + takes_array::<{ core::direct_const_arg!([1, 2, 1 + 2]) }>(); //[r1]~^ ERROR: complex const arguments must be placed inside of a `const` block #[cfg(r2)] - takes_array::<{ [X; 3] }>(); + takes_array::<{ core::direct_const_arg!([X; 3]) }>(); //[r2]~^ ERROR: complex const arguments must be placed inside of a `const` block #[cfg(r3)] - takes_array::<{ [0; Y] }>(); + takes_array::<{ core::direct_const_arg!([0; Y]) }>(); //[r3]~^ ERROR: complex const arguments must be placed inside of a `const` block } diff --git a/tests/ui/const-generics/mgca/array_expr_arg_complex.rs b/tests/ui/const-generics/mgca/array_expr_arg_complex.rs index 6d57e4f4b9686..4adb2bf6e429d 100644 --- a/tests/ui/const-generics/mgca/array_expr_arg_complex.rs +++ b/tests/ui/const-generics/mgca/array_expr_arg_complex.rs @@ -9,8 +9,8 @@ fn takes_array() {} fn takes_tuple_with_array() {} fn generic_caller() { - takes_array::<{ [N, N + 1] }>(); //~ ERROR complex const arguments must be placed inside of a `const` block - takes_tuple_with_array::<{ ([N, N + 1], N) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_array::<{ core::direct_const_arg!([N, N + 1]) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_tuple_with_array::<{ core::direct_const_arg!(([N, N + 1], N)) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block } fn main() {} diff --git a/tests/ui/const-generics/mgca/array_expr_arg_complex.stderr b/tests/ui/const-generics/mgca/array_expr_arg_complex.stderr index f40d4b5035d86..c7b13351d453c 100644 --- a/tests/ui/const-generics/mgca/array_expr_arg_complex.stderr +++ b/tests/ui/const-generics/mgca/array_expr_arg_complex.stderr @@ -1,14 +1,14 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/array_expr_arg_complex.rs:12:25 + --> $DIR/array_expr_arg_complex.rs:12:49 | -LL | takes_array::<{ [N, N + 1] }>(); - | ^^^^^ +LL | takes_array::<{ core::direct_const_arg!([N, N + 1]) }>(); + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/array_expr_arg_complex.rs:13:37 + --> $DIR/array_expr_arg_complex.rs:13:61 | -LL | takes_tuple_with_array::<{ ([N, N + 1], N) }>(); - | ^^^^^ +LL | takes_tuple_with_array::<{ core::direct_const_arg!(([N, N + 1], N)) }>(); + | ^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/auxiliary/anon-const-def-id-on-const-arg-with-anon.rs b/tests/ui/const-generics/mgca/auxiliary/anon-const-def-id-on-const-arg-with-anon.rs new file mode 100644 index 0000000000000..c1ebfc18e0816 --- /dev/null +++ b/tests/ui/const-generics/mgca/auxiliary/anon-const-def-id-on-const-arg-with-anon.rs @@ -0,0 +1,11 @@ +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] +pub struct S; +// this is a directly represented anon const... it's a bit weird. +// imagine `S<{ (2, const { 1 + 1 }) }>`. a directly represented tuple, containing an anon const. +// now, replace `(2, _)` with `_`. it's a directly represented anon const. +// this is different from const argument lowering failing to represent an argument directly and +// falling back to representing it as an anon const instead. +pub fn f() -> S<{ const { 1 + 1 } }> { + S +} diff --git a/tests/ui/const-generics/mgca/bad-const-arg-fn-154539.rs b/tests/ui/const-generics/mgca/bad-const-arg-fn-154539.rs index 7c7ffd9a9bd5f..e3d1f577d4f60 100644 --- a/tests/ui/const-generics/mgca/bad-const-arg-fn-154539.rs +++ b/tests/ui/const-generics/mgca/bad-const-arg-fn-154539.rs @@ -2,10 +2,11 @@ trait Iter< const FN: fn() = { - || { //~ ERROR complex const arguments must be placed inside of a `const` block + core::direct_const_arg!(|| { + //~^ ERROR complex const arguments must be placed inside of a `const` block use std::io::*; write!(_, "") - } + }) }, > { diff --git a/tests/ui/const-generics/mgca/bad-const-arg-fn-154539.stderr b/tests/ui/const-generics/mgca/bad-const-arg-fn-154539.stderr index 60774c4a3efea..96fcea9e906cf 100644 --- a/tests/ui/const-generics/mgca/bad-const-arg-fn-154539.stderr +++ b/tests/ui/const-generics/mgca/bad-const-arg-fn-154539.stderr @@ -1,10 +1,12 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/bad-const-arg-fn-154539.rs:5:9 + --> $DIR/bad-const-arg-fn-154539.rs:5:33 | -LL | / || { +LL | core::direct_const_arg!(|| { + | _________________________________^ +LL | | LL | | use std::io::*; LL | | write!(_, "") -LL | | } +LL | | }) | |_________^ error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/mgca/bad-direct-const-arg.rs b/tests/ui/const-generics/mgca/bad-direct-const-arg.rs new file mode 100644 index 0000000000000..451806ca6e1db --- /dev/null +++ b/tests/ui/const-generics/mgca/bad-direct-const-arg.rs @@ -0,0 +1,8 @@ +//! Simple error message test, nothing special here +#![feature(min_generic_const_args)] + +fn main(x: core::direct_const_arg!(2)) { + //~^ ERROR expected type, found `direct_const_arg!()` constant + let _ = core::direct_const_arg!(2); + //~^ ERROR expected expression, found `direct_const_arg!()` constant +} diff --git a/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr b/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr new file mode 100644 index 0000000000000..b77791ad5b3ee --- /dev/null +++ b/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr @@ -0,0 +1,14 @@ +error: expected expression, found `direct_const_arg!()` constant + --> $DIR/bad-direct-const-arg.rs:6:13 + | +LL | let _ = core::direct_const_arg!(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected type, found `direct_const_arg!()` constant + --> $DIR/bad-direct-const-arg.rs:4:12 + | +LL | fn main(x: core::direct_const_arg!(2)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/direct-const-arg-feature-gate.rs b/tests/ui/const-generics/mgca/direct-const-arg-feature-gate.rs new file mode 100644 index 0000000000000..16ba349a29be6 --- /dev/null +++ b/tests/ui/const-generics/mgca/direct-const-arg-feature-gate.rs @@ -0,0 +1,5 @@ +fn foo(_: [(); core::direct_const_arg!(N)]) {} +//~^ ERROR use of unstable library feature `min_generic_const_args` +//~| ERROR expected expression, found `direct_const_arg!()` constant +//~| ERROR generic parameters may not be used in const operations +fn main() {} diff --git a/tests/ui/const-generics/mgca/direct-const-arg-feature-gate.stderr b/tests/ui/const-generics/mgca/direct-const-arg-feature-gate.stderr new file mode 100644 index 0000000000000..f5dc211c2f71a --- /dev/null +++ b/tests/ui/const-generics/mgca/direct-const-arg-feature-gate.stderr @@ -0,0 +1,28 @@ +error[E0658]: use of unstable library feature `min_generic_const_args` + --> $DIR/direct-const-arg-feature-gate.rs:1:32 + | +LL | fn foo(_: [(); core::direct_const_arg!(N)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` 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: generic parameters may not be used in const operations + --> $DIR/direct-const-arg-feature-gate.rs:1:56 + | +LL | fn foo(_: [(); core::direct_const_arg!(N)]) {} + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: expected expression, found `direct_const_arg!()` constant + --> $DIR/direct-const-arg-feature-gate.rs:1:32 + | +LL | fn foo(_: [(); core::direct_const_arg!(N)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/mgca/direct-const-arg-multiple-exprs.rs b/tests/ui/const-generics/mgca/direct-const-arg-multiple-exprs.rs new file mode 100644 index 0000000000000..8c802e563db7c --- /dev/null +++ b/tests/ui/const-generics/mgca/direct-const-arg-multiple-exprs.rs @@ -0,0 +1,5 @@ +#![feature(min_generic_const_args)] +struct S; +fn foo(_: S) {} +//~^ ERROR direct_const_arg! takes 1 argument +fn main() {} diff --git a/tests/ui/const-generics/mgca/direct-const-arg-multiple-exprs.stderr b/tests/ui/const-generics/mgca/direct-const-arg-multiple-exprs.stderr new file mode 100644 index 0000000000000..6f54a563ffbfc --- /dev/null +++ b/tests/ui/const-generics/mgca/direct-const-arg-multiple-exprs.stderr @@ -0,0 +1,8 @@ +error: direct_const_arg! takes 1 argument + --> $DIR/direct-const-arg-multiple-exprs.rs:3:45 + | +LL | fn foo(_: S) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.rs b/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.rs new file mode 100644 index 0000000000000..09bce5c7f9aa2 --- /dev/null +++ b/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.rs @@ -0,0 +1,15 @@ +//! When doing some refactorings in mGCA, it was easy to accidentally stabilize doubly-brace-wrapped +//! paths. Check to make sure we don't accidentally do so. +//! +//! Feel free to delete this test if/when mGCA is stabilized and we support this syntax on stable, +//! it's testing nothing useful beyond that point. + +fn f() {} + +fn g() { + f::<{ N }>(); // ok + f::<{ { N } }>(); + //~^ ERROR: generic parameters may not be used in const operations +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.stderr b/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.stderr new file mode 100644 index 0000000000000..6168ec242a38c --- /dev/null +++ b/tests/ui/const-generics/mgca/double-wrapped-path-not-accidentally-stabilized.stderr @@ -0,0 +1,11 @@ +error: generic parameters may not be used in const operations + --> $DIR/double-wrapped-path-not-accidentally-stabilized.rs:11:13 + | +LL | f::<{ { N } }>(); + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs index 2b9909b43dfbb..9b642b286fa3e 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -10,7 +10,7 @@ type Adt1 = Foo; type Adt2 = Foo<{ N }>; type Adt3 = Foo; //~^ ERROR: generic parameters may not be used in const operations -type Adt4 = Foo<{ 1 + 1 }>; +type Adt4 = Foo; //~^ ERROR: complex const arguments must be placed inside of a `const` block type Adt5 = Foo; @@ -18,7 +18,7 @@ type Arr = [(); N]; type Arr2 = [(); { N }]; type Arr3 = [(); const { N }]; //~^ ERROR: generic parameters may not be used in const operations -type Arr4 = [(); 1 + 1]; +type Arr4 = [(); core::direct_const_arg!(1 + 1)]; //~^ ERROR: complex const arguments must be placed inside of a `const` block type Arr5 = [(); const { 1 + 1 }]; @@ -27,7 +27,7 @@ fn repeats() -> [(); N] { let _2 = [(); { N }]; let _3 = [(); const { N }]; //~^ ERROR: generic parameters may not be used in const operations - let _4 = [(); 1 + 1]; + let _4 = [(); core::direct_const_arg!(1 + 1)]; //~^ ERROR: complex const arguments must be placed inside of a `const` block let _5 = [(); const { 1 + 1 }]; let _6: [(); const { N }] = todo!(); @@ -42,10 +42,10 @@ type const ITEM2: usize = { N }; type const ITEM3: usize = const { N }; //~^ ERROR: generic parameters may not be used in const operations -type const ITEM4: usize = { 1 + 1 }; +type const ITEM4: usize = core::direct_const_arg!(1 + 1); //~^ ERROR: complex const arguments must be placed inside of a `const` block -type const ITEM5: usize = const { 1 + 1}; +type const ITEM5: usize = const { 1 + 1 }; trait Trait { @@ -59,7 +59,7 @@ fn ace_bounds< T2: Trait, T3: Trait, //~^ ERROR: generic parameters may not be used in const operations - T4: Trait, + T4: Trait, //~^ ERROR: complex const arguments must be placed inside of a `const` block T5: Trait, >() {} @@ -68,6 +68,6 @@ struct Default1; struct Default2; struct Default3; //~^ ERROR: generic parameters may not be used in const operations -struct Default4; +struct Default4; //~^ ERROR: complex const arguments must be placed inside of a `const` block -struct Default5; +struct Default5; diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index f634ec1cf12e4..9ab6af010bf21 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -1,38 +1,38 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:13:35 + --> $DIR/explicit_anon_consts.rs:13:57 | -LL | type Adt4 = Foo<{ 1 + 1 }>; - | ^^^^^ +LL | type Adt4 = Foo; + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:21:34 + --> $DIR/explicit_anon_consts.rs:21:58 | -LL | type Arr4 = [(); 1 + 1]; - | ^^^^^ +LL | type Arr4 = [(); core::direct_const_arg!(1 + 1)]; + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:30:19 + --> $DIR/explicit_anon_consts.rs:30:43 | -LL | let _4 = [(); 1 + 1]; - | ^^^^^ +LL | let _4 = [(); core::direct_const_arg!(1 + 1)]; + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:45:45 + --> $DIR/explicit_anon_consts.rs:45:67 | -LL | type const ITEM4: usize = { 1 + 1 }; - | ^^^^^ +LL | type const ITEM4: usize = core::direct_const_arg!(1 + 1); + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:62:25 + --> $DIR/explicit_anon_consts.rs:62:49 | -LL | T4: Trait, - | ^^^^^ +LL | T4: Trait, + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:71:52 + --> $DIR/explicit_anon_consts.rs:71:76 | -LL | struct Default4; - | ^^^^^ +LL | struct Default4; + | ^^^^^ error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:42:51 diff --git a/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.rs b/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.rs new file mode 100644 index 0000000000000..1653fd63ed3f8 --- /dev/null +++ b/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.rs @@ -0,0 +1,17 @@ +//! Diagnostics for expressions that contain things that must be a mGCA direct expression, *and* +//! things that must be an anon const, are currently less than ideal. This test merely asserts the +//! current (bad) state of diagnostics, so we can track improvements over time. + +#![feature(min_generic_const_args, min_adt_const_params)] +#![allow(incomplete_features)] + +fn f() {} + +fn g() { + f::<{ (N, 1 + 1) }>(); + //~^ ERROR: generic parameters may not be used in const operations + f::<{ core::direct_const_arg!((N, 1 + 1)) }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.stderr b/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.stderr new file mode 100644 index 0000000000000..ae297de108493 --- /dev/null +++ b/tests/ui/const-generics/mgca/mixed-direct-anon-expression-diagnostics.stderr @@ -0,0 +1,16 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/mixed-direct-anon-expression-diagnostics.rs:13:39 + | +LL | f::<{ core::direct_const_arg!((N, 1 + 1)) }>(); + | ^^^^^ + +error: generic parameters may not be used in const operations + --> $DIR/mixed-direct-anon-expression-diagnostics.rs:11:12 + | +LL | f::<{ (N, 1 + 1) }>(); + | ^ + | + = help: add `#![feature(generic_const_args)]` to allow generic expressions as the RHS of const items + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/serialized-direct-const-with-anon-const-body.rs b/tests/ui/const-generics/mgca/serialized-direct-const-with-anon-const-body.rs new file mode 100644 index 0000000000000..985e14fddb676 --- /dev/null +++ b/tests/ui/const-generics/mgca/serialized-direct-const-with-anon-const-body.rs @@ -0,0 +1,16 @@ +//@ check-pass +//@ aux-build:anon-const-def-id-on-const-arg-with-anon.rs +//! The DefCollector sometimes generates "fake" DefKind::AnonConst DefIds for AST AnonConsts that +//! are not actually lowered to HIR AnonConsts, and so the DefId is placed on a hir::Node::ConstArg +//! (just to place it *somewhere*). These "fake" DefIds should not be serialized. Previously, the +//! logic to skip serializing them was incorrect (we were still serializing fake DefIds for +//! `ConstArg(ConstArgKind::Anon)` if the directly represented expression contained within it +//! *another*, unrelated, anon const). This test checks that case, a directly-represented +//! fake-anon-const directly containing another anon const. + +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] +extern crate anon_const_def_id_on_const_arg_with_anon; +fn main() { + anon_const_def_id_on_const_arg_with_anon::f(); +} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs index 2e39f8952b11d..460c8af840a1c 100644 --- a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs +++ b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs @@ -9,7 +9,7 @@ struct Point(u32, u32); fn with_point() {} fn test() { - with_point::<{ Point(N + 1, N) }>(); + with_point::<{ core::direct_const_arg!(Point(N + 1, N)) }>(); //~^ ERROR complex const arguments must be placed inside of a `const` block with_point::<{ Point(const { N + 1 }, N) }>(); diff --git a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr index 3a873ec33fb19..a4e7cb94c57c3 100644 --- a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr +++ b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr @@ -1,8 +1,8 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/tuple_ctor_complex_args.rs:12:26 + --> $DIR/tuple_ctor_complex_args.rs:12:50 | -LL | with_point::<{ Point(N + 1, N) }>(); - | ^^^^^ +LL | with_point::<{ core::direct_const_arg!(Point(N + 1, N)) }>(); + | ^^^^^ error: generic parameters may not be used in const operations --> $DIR/tuple_ctor_complex_args.rs:15:34 diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_complex.rs b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.rs index d7cab17bad124..0d99b8ae345d6 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_complex.rs +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.rs @@ -9,11 +9,11 @@ fn takes_tuple() {} fn takes_nested_tuple() {} fn generic_caller() { - takes_tuple::<{ (N, N + 1) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block - takes_tuple::<{ (N, T::ASSOC + 1) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_tuple::<{ core::direct_const_arg!((N, N + 1)) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_tuple::<{ core::direct_const_arg!((N, T::ASSOC + 1)) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block - takes_nested_tuple::<{ (N, (N, N + 1)) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block - takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); //~ ERROR generic parameters may not be used in const operations + takes_nested_tuple::<{ core::direct_const_arg!((N, (N, N + 1))) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_nested_tuple::<{ core::direct_const_arg!((N, (N, const { N + 1 }))) }>(); //~ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr index a9d412964da29..4bed120284c08 100644 --- a/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr +++ b/tests/ui/const-generics/mgca/tuple_expr_arg_complex.stderr @@ -1,26 +1,26 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/tuple_expr_arg_complex.rs:12:25 + --> $DIR/tuple_expr_arg_complex.rs:12:49 | -LL | takes_tuple::<{ (N, N + 1) }>(); - | ^^^^^ +LL | takes_tuple::<{ core::direct_const_arg!((N, N + 1)) }>(); + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/tuple_expr_arg_complex.rs:13:25 + --> $DIR/tuple_expr_arg_complex.rs:13:49 | -LL | takes_tuple::<{ (N, T::ASSOC + 1) }>(); - | ^^^^^^^^^^^^ +LL | takes_tuple::<{ core::direct_const_arg!((N, T::ASSOC + 1)) }>(); + | ^^^^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/tuple_expr_arg_complex.rs:15:36 + --> $DIR/tuple_expr_arg_complex.rs:15:60 | -LL | takes_nested_tuple::<{ (N, (N, N + 1)) }>(); - | ^^^^^ +LL | takes_nested_tuple::<{ core::direct_const_arg!((N, (N, N + 1))) }>(); + | ^^^^^ error: generic parameters may not be used in const operations - --> $DIR/tuple_expr_arg_complex.rs:16:44 + --> $DIR/tuple_expr_arg_complex.rs:16:68 | -LL | takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); - | ^ +LL | takes_nested_tuple::<{ core::direct_const_arg!((N, (N, const { N + 1 }))) }>(); + | ^ | = help: add `#![feature(generic_const_args)]` to allow generic expressions as the RHS of const items diff --git a/tests/ui/const-generics/mgca/type-const-free-anon-const-mismatch.stderr b/tests/ui/const-generics/mgca/type-const-free-anon-const-mismatch.stderr index d0339d09cdc7a..52ef108a84dbf 100644 --- a/tests/ui/const-generics/mgca/type-const-free-anon-const-mismatch.stderr +++ b/tests/ui/const-generics/mgca/type-const-free-anon-const-mismatch.stderr @@ -4,7 +4,7 @@ error[E0284]: type annotations needed LL | type const X: usize = const { N }; | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` | - = note: cannot satisfy `X::{constant#0} == _` + = note: cannot satisfy `X::{constant#0}::{constant#0} == _` error: the constant `"this isn't a usize"` is not of type `usize` --> $DIR/type-const-free-anon-const-mismatch.rs:8:1 diff --git a/tests/ui/const-generics/mgca/type-const-free-value-type-mismatch.next.stderr b/tests/ui/const-generics/mgca/type-const-free-value-type-mismatch.next.stderr index d96726829ee0b..3ef6ede90d933 100644 --- a/tests/ui/const-generics/mgca/type-const-free-value-type-mismatch.next.stderr +++ b/tests/ui/const-generics/mgca/type-const-free-value-type-mismatch.next.stderr @@ -10,7 +10,7 @@ error[E0284]: type annotations needed LL | fn f() -> [u8; const { N }] {} | ^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` | - = note: cannot satisfy `f::{constant#0} == _` + = note: cannot satisfy `f::{constant#0}::{constant#0} == _` error[E0308]: mismatched types --> $DIR/type-const-free-value-type-mismatch.rs:11:11 diff --git a/tests/ui/const-generics/mgca/type-const-inherent-value-type-mismatch.next.stderr b/tests/ui/const-generics/mgca/type-const-inherent-value-type-mismatch.next.stderr index eeabde2d06320..551a1d496e910 100644 --- a/tests/ui/const-generics/mgca/type-const-inherent-value-type-mismatch.next.stderr +++ b/tests/ui/const-generics/mgca/type-const-inherent-value-type-mismatch.next.stderr @@ -4,7 +4,7 @@ error[E0284]: type annotations needed LL | fn f() -> [u8; const { Struct::N }] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` | - = note: cannot satisfy `f::{constant#0} == _` + = note: cannot satisfy `f::{constant#0}::{constant#0} == _` error: the constant `"this isn't a usize"` is not of type `usize` --> $DIR/type-const-inherent-value-type-mismatch.rs:13:5 diff --git a/tests/ui/const-generics/mgca/type-const-value-type-mismatch.next.stderr b/tests/ui/const-generics/mgca/type-const-value-type-mismatch.next.stderr index 123c442a3938d..748ffe1294e0a 100644 --- a/tests/ui/const-generics/mgca/type-const-value-type-mismatch.next.stderr +++ b/tests/ui/const-generics/mgca/type-const-value-type-mismatch.next.stderr @@ -16,7 +16,7 @@ error[E0284]: type annotations needed LL | fn arr() -> [u8; const { Self::LEN }] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `_` | - = note: cannot satisfy `::arr::{constant#0} == _` + = note: cannot satisfy `::arr::{constant#0}::{constant#0} == _` error[E0308]: mismatched types --> $DIR/type-const-value-type-mismatch.rs:21:17 diff --git a/tests/ui/delegation/hir-crate-items-before-lowering-ices.ice_155125.stderr b/tests/ui/delegation/hir-crate-items-before-lowering-ices.ice_155125.stderr index d2f0e87ecb593..6675831bddc86 100644 --- a/tests/ui/delegation/hir-crate-items-before-lowering-ices.ice_155125.stderr +++ b/tests/ui/delegation/hir-crate-items-before-lowering-ices.ice_155125.stderr @@ -9,13 +9,14 @@ LL | reuse foo; = note: `foo` must be defined only once in the value namespace of this block error: complex const arguments must be placed inside of a `const` block - --> $DIR/hir-crate-items-before-lowering-ices.rs:10:13 + --> $DIR/hir-crate-items-before-lowering-ices.rs:10:37 | -LL | / { +LL | core::direct_const_arg!({ + | _____________________________________^ LL | | fn foo() {} LL | | reuse foo; LL | | 2 -LL | | }, +LL | | }), | |_____________^ error: aborting due to 2 previous errors diff --git a/tests/ui/delegation/hir-crate-items-before-lowering-ices.ice_155164.stderr b/tests/ui/delegation/hir-crate-items-before-lowering-ices.ice_155164.stderr index 34d1a92ccd225..6164dabe74bff 100644 --- a/tests/ui/delegation/hir-crate-items-before-lowering-ices.ice_155164.stderr +++ b/tests/ui/delegation/hir-crate-items-before-lowering-ices.ice_155164.stderr @@ -1,12 +1,13 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/hir-crate-items-before-lowering-ices.rs:47:13 + --> $DIR/hir-crate-items-before-lowering-ices.rs:47:37 | -LL | / { +LL | core::direct_const_arg!({ + | _____________________________________^ LL | | LL | | struct W; LL | | impl W { ... | -LL | | }, +LL | | }), | |_____________^ error: aborting due to 1 previous error diff --git a/tests/ui/delegation/hir-crate-items-before-lowering-ices.rs b/tests/ui/delegation/hir-crate-items-before-lowering-ices.rs index b9a7a73732cf3..07f5a1ad1712f 100644 --- a/tests/ui/delegation/hir-crate-items-before-lowering-ices.rs +++ b/tests/ui/delegation/hir-crate-items-before-lowering-ices.rs @@ -7,11 +7,11 @@ mod ice_155125 { struct S; impl S< - { //[ice_155125]~ ERROR: complex const arguments must be placed inside of a `const` block + core::direct_const_arg!({ //[ice_155125]~ ERROR: complex const arguments must be placed inside of a `const` block fn foo() {} reuse foo; //[ice_155125]~ ERROR: the name `foo` is defined multiple times 2 - }, + }), > { } @@ -44,13 +44,13 @@ mod ice_155128 { mod ice_155164 { struct X { inner: std::iter::Map< - { + core::direct_const_arg!({ //[ice_155164]~^ ERROR: complex const arguments must be placed inside of a `const` block struct W; impl W { reuse Iterator::fold; } - }, + }), F, >, } diff --git a/tests/ui/delegation/inside-const-body-ice-155300.rs b/tests/ui/delegation/inside-const-body-ice-155300.rs index 06addf7e5412d..2d13007bc807b 100644 --- a/tests/ui/delegation/inside-const-body-ice-155300.rs +++ b/tests/ui/delegation/inside-const-body-ice-155300.rs @@ -5,12 +5,13 @@ pub struct S; impl S< - { //~ ERROR: complex const arguments must be placed inside of a `const` block + core::direct_const_arg!({ + //~^ ERROR: complex const arguments must be placed inside of a `const` block fn foo() {} reuse foo::<> as bar; reuse bar; //~^ ERROR: the name `bar` is defined multiple times - }, + }), > { } diff --git a/tests/ui/delegation/inside-const-body-ice-155300.stderr b/tests/ui/delegation/inside-const-body-ice-155300.stderr index 0d2020c997200..f0cb830109f8a 100644 --- a/tests/ui/delegation/inside-const-body-ice-155300.stderr +++ b/tests/ui/delegation/inside-const-body-ice-155300.stderr @@ -1,5 +1,5 @@ error[E0428]: the name `bar` is defined multiple times - --> $DIR/inside-const-body-ice-155300.rs:11:13 + --> $DIR/inside-const-body-ice-155300.rs:12:13 | LL | reuse foo::<> as bar; | --------------------- previous definition of the value `bar` here @@ -9,14 +9,15 @@ LL | reuse bar; = note: `bar` must be defined only once in the value namespace of this block error: complex const arguments must be placed inside of a `const` block - --> $DIR/inside-const-body-ice-155300.rs:8:9 + --> $DIR/inside-const-body-ice-155300.rs:8:33 | -LL | / { +LL | core::direct_const_arg!({ + | _________________________________^ +LL | | LL | | fn foo() {} LL | | reuse foo::<> as bar; -LL | | reuse bar; -LL | | -LL | | }, +... | +LL | | }), | |_________^ error: aborting due to 2 previous errors From de73ac0de32872979092ebc6397265de9930447c Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Wed, 24 Jun 2026 01:21:05 +0200 Subject: [PATCH 29/43] 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 30/43] 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 31/43] 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 32/43] 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 042e779afae728bfd491bcfb690908dc762d82b5 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 7 Jul 2026 00:15:26 -0700 Subject: [PATCH 33/43] Add diagram to comment Co-authored-by: lolbinarycat --- compiler/rustc_resolve/src/rustdoc.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index f1e94b415787b..301ea7c71da06 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -719,6 +719,12 @@ pub fn source_span_for_markdown_range_inner( // but we found a non-empty non-markdown line. // This could be an attribute, and we don't want a diagnostic // suggesting to delete that attribute, so we return None to be safe. + // 1| /** doc */ + // 2 | #[inline] + // ^^^^^^^^^ + // | this + // 3| /** doc2 */ + // 4| fn foo() {} return None; } else { end_bytes += source_line.len() + 1; From 8f1fd2c6e4bf7e44dfca254e162120d260144983 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 7 Jul 2026 00:16:01 -0700 Subject: [PATCH 34/43] Fix wrong diagram in comment Co-authored-by: lolbinarycat --- compiler/rustc_resolve/src/rustdoc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 301ea7c71da06..ddf5600f76659 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -690,7 +690,7 @@ pub fn source_span_for_markdown_range_inner( // ^^^^^^^^^ // | this // - // 2| /** doc2 */ fn foo() {} + // 2| /** doc2 */ // 3| fn foo() {} return None; } From fd07857db3c77538b9214c4125aaa91ee48481d4 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 7 Jul 2026 00:17:23 -0700 Subject: [PATCH 35/43] Use better name for lint struct Co-authored-by: lolbinarycat --- .../passes/lint/redundant_explicit_links.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index ad45b6e1d1c5b..cd7b7caac69ad 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -154,13 +154,13 @@ fn check_redundant_explicit_link<'md>( } } -struct RedundantExplicitLinksCannotSuggest { +struct RedundantExplicitLinksWithoutSuggestion { attr_span: Span, display_link: String, dest_link: String, } -impl<'a> Diagnostic<'a, ()> for RedundantExplicitLinksCannotSuggest { +impl<'a> Diagnostic<'a, ()> for RedundantExplicitLinksWithoutSuggestion { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { let Self { attr_span, display_link, dest_link } = self; @@ -186,7 +186,7 @@ fn check_inline_or_reference_unknown_redundancy( dest: String, link_data: LinkData, (open, close): (u8, u8), -) -> Result<(), RedundantExplicitLinksCannotSuggest> { +) -> Result<(), RedundantExplicitLinksWithoutSuggestion> { struct RedundantExplicitLinks { explicit_span: Span, display_span: Span, @@ -256,7 +256,7 @@ fn check_inline_or_reference_unknown_redundancy( Some((_, true)) => return Ok(()), // Cannot give a contiguous span for this link. None => { - return Err(RedundantExplicitLinksCannotSuggest { + return Err(RedundantExplicitLinksWithoutSuggestion { display_link: resolvable_link.clone(), dest_link: dest.to_string(), attr_span, @@ -274,7 +274,7 @@ fn check_inline_or_reference_unknown_redundancy( Some((_, true)) => return Ok(()), // Cannot give a contiguous span for this link. None => { - return Err(RedundantExplicitLinksCannotSuggest { + return Err(RedundantExplicitLinksWithoutSuggestion { display_link: resolvable_link.clone(), dest_link: dest.to_string(), attr_span, @@ -308,7 +308,7 @@ fn check_reference_redundancy( link_range: Range, dest: &CowStr<'_>, link_data: LinkData, -) -> Result<(), RedundantExplicitLinksCannotSuggest> { +) -> Result<(), RedundantExplicitLinksWithoutSuggestion> { struct RedundantExplicitLinkTarget { explicit_span: Span, display_span: Span, @@ -378,7 +378,7 @@ fn check_reference_redundancy( Some((_, true)) => return Ok(()), // Cannot give a contiguous span for this link. None => { - return Err(RedundantExplicitLinksCannotSuggest { + return Err(RedundantExplicitLinksWithoutSuggestion { display_link: resolvable_link.clone(), dest_link: dest.to_string(), attr_span, @@ -396,7 +396,7 @@ fn check_reference_redundancy( Some((_, true)) => return Ok(()), // Cannot give a contiguous span for this link. None => { - return Err(RedundantExplicitLinksCannotSuggest { + return Err(RedundantExplicitLinksWithoutSuggestion { display_link: resolvable_link.clone(), dest_link: dest.to_string(), attr_span, @@ -412,7 +412,7 @@ fn check_reference_redundancy( Some((def_span, _)) => def_span, // Cannot give a contiguous span for this link. None => { - return Err(RedundantExplicitLinksCannotSuggest { + return Err(RedundantExplicitLinksWithoutSuggestion { display_link: resolvable_link.clone(), dest_link: dest.to_string(), attr_span, From 66beceb52082bf2a32f9bfcb0b8613058dd6e3bd Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 7 Jul 2026 13:42:44 +0300 Subject: [PATCH 36/43] 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 37/43] 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 38/43] 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 39/43] 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 40/43] 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 41/43] 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 42/43] 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 43/43] 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> {} | ^^^ -- --