about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs3
-rw-r--r--compiler/rustc_middle/Cargo.toml1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs5
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs5
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs9
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/slice.rs2
-rw-r--r--library/alloc/tests/vec_deque.rs8
-rw-r--r--library/core/src/fmt/mod.rs2
-rw-r--r--library/core/src/iter/mod.rs2
-rw-r--r--library/core/src/iter/sources.rs4
-rw-r--r--library/core/src/iter/sources/repeat_n.rs195
-rw-r--r--library/core/tests/iter/sources.rs49
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--src/test/codegen/iter-repeat-n-trivial-drop.rs56
-rw-r--r--src/test/ui/suggestions/issue-104287.rs9
-rw-r--r--src/test/ui/suggestions/issue-104287.stderr36
19 files changed, 377 insertions, 14 deletions
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index c02680b77fb..6c7063ca28b 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -495,7 +495,6 @@ fn try_match_macro<'matcher, T: Tracker<'matcher>>(
     // hacky, but speeds up the `html5ever` benchmark significantly. (Issue
     // 68836 suggests a more comprehensive but more complex change to deal with
     // this situation.)
-    // FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
     let parser = parser_from_cx(sess, arg.clone(), T::recovery());
     // Try each arm's matchers.
     let mut tt_parser = TtParser::new(name);
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 4359124646d..9c77387c238 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -728,7 +728,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         && let Some(trait_path_segment) = path.segments.get(0) {
             let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params();
 
-            if num_assoc_fn_excess_args == num_trait_generics_except_self - num_generic_args_supplied_to_trait {
+            if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self
+            {
                 if let Some(span) = self.gen_args.span_ext()
                 && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                     let sugg = vec![
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 5f6e498dbea..fc1167c105a 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
 edition = "2021"
 
 [lib]
-doctest = false
 
 [dependencies]
 bitflags = "1.2.1"
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 1564cf414bd..02772013437 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1648,6 +1648,8 @@ rustc_queries! {
     /// a generic type parameter will panic if you call this method on it:
     ///
     /// ```
+    /// use std::fmt::Debug;
+    ///
     /// pub trait Foo<T: Debug> {}
     /// ```
     ///
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 279a728ea39..786eced61d6 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -5,7 +5,7 @@
 //!
 //! # Example
 //! ```rust
-//! enum Void {}
+//! #![feature(never_type)]
 //! mod a {
 //!     pub mod b {
 //!         pub struct SecretlyUninhabited {
@@ -15,6 +15,7 @@
 //! }
 //!
 //! mod c {
+//!     enum Void {}
 //!     pub struct AlsoSecretlyUninhabited {
 //!         _priv: Void,
 //!     }
@@ -35,7 +36,7 @@
 //! `Foo`.
 //!
 //! # Example
-//! ```rust
+//! ```ignore(illustrative)
 //! let foo_result: Result<T, Foo> = ... ;
 //! let Ok(t) = foo_result;
 //! ```
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 9f680a60613..fe7401786a0 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2078,12 +2078,7 @@ impl<'a> Parser<'a> {
 
         if self.token.kind == TokenKind::Semi
             && matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _)))
-            // HACK: This is needed so we can detect whether we're inside a macro,
-            // where regular assumptions about what tokens can follow other tokens
-            // don't necessarily apply.
             && self.may_recover()
-            // FIXME(Nilstrieb): Remove this check once `may_recover` actually stops recovery
-            && self.subparser_name.is_none()
         {
             // It is likely that the closure body is a block but where the
             // braces have been removed. We will recover and eat the next
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 2a57dad89a7..537fe22a4be 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -10,7 +10,7 @@
 use core::cmp::{self, Ordering};
 use core::fmt;
 use core::hash::{Hash, Hasher};
-use core::iter::{repeat_with, FromIterator};
+use core::iter::{repeat_n, repeat_with, FromIterator};
 use core::marker::PhantomData;
 use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};
 use core::ops::{Index, IndexMut, Range, RangeBounds};
@@ -2833,7 +2833,12 @@ impl<T: Clone, A: Allocator> VecDeque<T, A> {
     /// ```
     #[stable(feature = "deque_extras", since = "1.16.0")]
     pub fn resize(&mut self, new_len: usize, value: T) {
-        self.resize_with(new_len, || value.clone());
+        if new_len > self.len() {
+            let extra = new_len - self.len();
+            self.extend(repeat_n(value, extra))
+        } else {
+            self.truncate(new_len);
+        }
     }
 }
 
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 008926666c1..5e13547abcb 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -124,6 +124,7 @@
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
 #![feature(iter_next_chunk)]
+#![feature(iter_repeat_n)]
 #![feature(layout_for_ptr)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index a5e7bf2a1a9..1b61ede3476 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -458,7 +458,7 @@ impl<T> [T] {
         hack::into_vec(self)
     }
 
-    /// Creates a vector by repeating a slice `n` times.
+    /// Creates a vector by copying a slice `n` times.
     ///
     /// # Panics
     ///
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index 019d73c0b16..c1b9e7af9d8 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -1727,3 +1727,11 @@ fn test_from_zero_sized_vec() {
     let queue = VecDeque::from(v);
     assert_eq!(queue.len(), 100);
 }
+
+#[test]
+fn test_resize_keeps_reserved_space_from_item() {
+    let v = Vec::<i32>::with_capacity(1234);
+    let mut d = VecDeque::new();
+    d.resize(1, v);
+    assert_eq!(d[0].capacity(), 1234);
+}
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 2adc968bd46..48b6177434b 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -510,7 +510,7 @@ impl<'a> Arguments<'a> {
     /// assert_eq!(format_args!("{}", 1).as_str(), None);
     /// ```
     #[stable(feature = "fmt_as_str", since = "1.52.0")]
-    #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "none")]
+    #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
     #[must_use]
     #[inline]
     pub const fn as_str(&self) -> Option<&'static str> {
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index ef0f397825b..bb35d50b4bf 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -401,6 +401,8 @@ pub use self::sources::{once, Once};
 pub use self::sources::{once_with, OnceWith};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::sources::{repeat, Repeat};
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+pub use self::sources::{repeat_n, RepeatN};
 #[stable(feature = "iterator_repeat_with", since = "1.28.0")]
 pub use self::sources::{repeat_with, RepeatWith};
 #[stable(feature = "iter_successors", since = "1.34.0")]
diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs
index d34772cd304..3ec426a3ad9 100644
--- a/library/core/src/iter/sources.rs
+++ b/library/core/src/iter/sources.rs
@@ -4,6 +4,7 @@ mod from_generator;
 mod once;
 mod once_with;
 mod repeat;
+mod repeat_n;
 mod repeat_with;
 mod successors;
 
@@ -16,6 +17,9 @@ pub use self::empty::{empty, Empty};
 #[stable(feature = "iter_once", since = "1.2.0")]
 pub use self::once::{once, Once};
 
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+pub use self::repeat_n::{repeat_n, RepeatN};
+
 #[stable(feature = "iterator_repeat_with", since = "1.28.0")]
 pub use self::repeat_with::{repeat_with, RepeatWith};
 
diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs
new file mode 100644
index 00000000000..dc69bf4df59
--- /dev/null
+++ b/library/core/src/iter/sources/repeat_n.rs
@@ -0,0 +1,195 @@
+use crate::iter::{FusedIterator, TrustedLen};
+use crate::mem::ManuallyDrop;
+
+/// Creates a new iterator that repeats a single element a given number of times.
+///
+/// The `repeat_n()` function repeats a single value exactly `n` times.
+///
+/// This is very similar to using [`repeat()`] with [`Iterator::take()`],
+/// but there are two differences:
+/// - `repeat_n()` can return the original value, rather than always cloning.
+/// - `repeat_n()` produces an [`ExactSizeIterator`].
+///
+/// [`repeat()`]: crate::iter::repeat
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// #![feature(iter_repeat_n)]
+/// use std::iter;
+///
+/// // four of the the number four:
+/// let mut four_fours = iter::repeat_n(4, 4);
+///
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+///
+/// // no more fours
+/// assert_eq!(None, four_fours.next());
+/// ```
+///
+/// For non-`Copy` types,
+///
+/// ```
+/// #![feature(iter_repeat_n)]
+/// use std::iter;
+///
+/// let v: Vec<i32> = Vec::with_capacity(123);
+/// let mut it = iter::repeat_n(v, 5);
+///
+/// for i in 0..4 {
+///     // It starts by cloning things
+///     let cloned = it.next().unwrap();
+///     assert_eq!(cloned.len(), 0);
+///     assert_eq!(cloned.capacity(), 0);
+/// }
+///
+/// // ... but the last item is the original one
+/// let last = it.next().unwrap();
+/// assert_eq!(last.len(), 0);
+/// assert_eq!(last.capacity(), 123);
+///
+/// // ... and now we're done
+/// assert_eq!(None, it.next());
+/// ```
+#[inline]
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+#[doc(hidden)] // waiting on ACP#120 to decide whether to expose publicly
+pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
+    let mut element = ManuallyDrop::new(element);
+
+    if count == 0 {
+        // SAFETY: we definitely haven't dropped it yet, since we only just got
+        // passed it in, and because the count is zero the instance we're about
+        // to create won't drop it, so to avoid leaking we need to now.
+        unsafe { ManuallyDrop::drop(&mut element) };
+    }
+
+    RepeatN { element, count }
+}
+
+/// An iterator that repeats an element an exact number of times.
+///
+/// This `struct` is created by the [`repeat_n()`] function.
+/// See its documentation for more.
+#[derive(Clone, Debug)]
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+#[doc(hidden)] // waiting on ACP#120 to decide whether to expose publicly
+pub struct RepeatN<A> {
+    count: usize,
+    // Invariant: has been dropped iff count == 0.
+    element: ManuallyDrop<A>,
+}
+
+impl<A> RepeatN<A> {
+    /// If we haven't already dropped the element, return it in an option.
+    ///
+    /// Clears the count so it won't be dropped again later.
+    #[inline]
+    fn take_element(&mut self) -> Option<A> {
+        if self.count > 0 {
+            self.count = 0;
+            // SAFETY: We just set count to zero so it won't be dropped again,
+            // and it used to be non-zero so it hasn't already been dropped.
+            unsafe { Some(ManuallyDrop::take(&mut self.element)) }
+        } else {
+            None
+        }
+    }
+}
+
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+impl<A> Drop for RepeatN<A> {
+    fn drop(&mut self) {
+        self.take_element();
+    }
+}
+
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+impl<A: Clone> Iterator for RepeatN<A> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        if self.count == 0 {
+            return None;
+        }
+
+        self.count -= 1;
+        Some(if self.count == 0 {
+            // SAFETY: the check above ensured that the count used to be non-zero,
+            // so element hasn't been dropped yet, and we just lowered the count to
+            // zero so it won't be dropped later, and thus it's okay to take it here.
+            unsafe { ManuallyDrop::take(&mut self.element) }
+        } else {
+            A::clone(&mut self.element)
+        })
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let len = self.len();
+        (len, Some(len))
+    }
+
+    #[inline]
+    fn advance_by(&mut self, skip: usize) -> Result<(), usize> {
+        let len = self.count;
+
+        if skip >= len {
+            self.take_element();
+        }
+
+        if skip > len {
+            Err(len)
+        } else {
+            self.count = len - skip;
+            Ok(())
+        }
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<A> {
+        self.take_element()
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+}
+
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+impl<A: Clone> ExactSizeIterator for RepeatN<A> {
+    fn len(&self) -> usize {
+        self.count
+    }
+}
+
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        self.next()
+    }
+
+    #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+        self.advance_by(n)
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<A> {
+        self.nth(n)
+    }
+}
+
+#[unstable(feature = "iter_repeat_n", issue = "104434")]
+impl<A: Clone> FusedIterator for RepeatN<A> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: Clone> TrustedLen for RepeatN<A> {}
diff --git a/library/core/tests/iter/sources.rs b/library/core/tests/iter/sources.rs
index d0114ade6e4..a15f3a5148f 100644
--- a/library/core/tests/iter/sources.rs
+++ b/library/core/tests/iter/sources.rs
@@ -106,3 +106,52 @@ fn test_empty() {
     let mut it = empty::<i32>();
     assert_eq!(it.next(), None);
 }
+
+#[test]
+fn test_repeat_n_drop() {
+    #[derive(Clone, Debug)]
+    struct DropCounter<'a>(&'a Cell<usize>);
+    impl Drop for DropCounter<'_> {
+        fn drop(&mut self) {
+            self.0.set(self.0.get() + 1);
+        }
+    }
+
+    // `repeat_n(x, 0)` drops `x` immediately
+    let count = Cell::new(0);
+    let item = DropCounter(&count);
+    let mut it = repeat_n(item, 0);
+    assert_eq!(count.get(), 1);
+    assert!(it.next().is_none());
+    assert_eq!(count.get(), 1);
+    drop(it);
+    assert_eq!(count.get(), 1);
+
+    // Dropping the iterator needs to drop the item if it's non-empty
+    let count = Cell::new(0);
+    let item = DropCounter(&count);
+    let it = repeat_n(item, 3);
+    assert_eq!(count.get(), 0);
+    drop(it);
+    assert_eq!(count.get(), 1);
+
+    // Dropping the iterator doesn't drop the item if it was exhausted
+    let count = Cell::new(0);
+    let item = DropCounter(&count);
+    let mut it = repeat_n(item, 3);
+    assert_eq!(count.get(), 0);
+    let x0 = it.next().unwrap();
+    assert_eq!(count.get(), 0);
+    let x1 = it.next().unwrap();
+    assert_eq!(count.get(), 0);
+    let x2 = it.next().unwrap();
+    assert_eq!(count.get(), 0);
+    assert!(it.next().is_none());
+    assert_eq!(count.get(), 0);
+    assert!(it.next().is_none());
+    assert_eq!(count.get(), 0);
+    drop(it);
+    assert_eq!(count.get(), 0);
+    drop((x0, x1, x2));
+    assert_eq!(count.get(), 3);
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 66d28770b87..4c0c0da652f 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -75,6 +75,7 @@
 #![feature(iter_is_partitioned)]
 #![feature(iter_next_chunk)]
 #![feature(iter_order_by)]
+#![feature(iter_repeat_n)]
 #![feature(iterator_try_collect)]
 #![feature(iterator_try_reduce)]
 #![feature(const_mut_refs)]
diff --git a/src/test/codegen/iter-repeat-n-trivial-drop.rs b/src/test/codegen/iter-repeat-n-trivial-drop.rs
new file mode 100644
index 00000000000..20e1d9b4d59
--- /dev/null
+++ b/src/test/codegen/iter-repeat-n-trivial-drop.rs
@@ -0,0 +1,56 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+#![feature(iter_repeat_n)]
+
+#[derive(Clone)]
+pub struct NotCopy(u16);
+
+impl Drop for NotCopy {
+    fn drop(&mut self) {}
+}
+
+// For a type where `Drop::drop` doesn't do anything observable and a clone is the
+// same as a move, make sure that the extra case for the last item disappears.
+
+#[no_mangle]
+// CHECK-LABEL: @iter_repeat_n_next
+pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCopy> {
+    // CHECK-NEXT: start:
+    // CHECK-NOT: br
+    // CHECK: %[[COUNT:.+]] = load i64
+    // CHECK-NEXT: %[[COUNT_ZERO:.+]] = icmp eq i64 %[[COUNT]], 0
+    // CHECK-NEXT: br i1 %[[COUNT_ZERO]], label %[[EMPTY:.+]], label %[[NOT_EMPTY:.+]]
+
+    // CHECK: [[NOT_EMPTY]]:
+    // CHECK-NEXT: %[[DEC:.+]] = add i64 %[[COUNT]], -1
+    // CHECK-NEXT: store i64 %[[DEC]]
+    // CHECK-NOT: br
+    // CHECK: %[[VAL:.+]] = load i16
+    // CHECK-NEXT: br label %[[EMPTY]]
+
+    // CHECK: [[EMPTY]]:
+    // CHECK-NOT: br
+    // CHECK: phi i16 [ undef, %start ], [ %[[VAL]], %[[NOT_EMPTY]] ]
+    // CHECK-NOT: br
+    // CHECK: ret
+
+    it.next()
+}
+
+// And as a result, using the iterator can optimize without special cases for
+// the last iteration, like `memset`ing all the items in one call.
+
+#[no_mangle]
+// CHECK-LABEL: @vec_extend_via_iter_repeat_n
+pub fn vec_extend_via_iter_repeat_n() -> Vec<u8> {
+    // CHECK: %[[ADDR:.+]] = tail call dereferenceable_or_null(1234) ptr @__rust_alloc(i64 1234, i64 1)
+    // CHECK: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(1234) %[[ADDR]], i8 42, i64 1234,
+
+    let n = 1234_usize;
+    let mut v = Vec::with_capacity(n);
+    v.extend(std::iter::repeat_n(42_u8, n));
+    v
+}
diff --git a/src/test/ui/suggestions/issue-104287.rs b/src/test/ui/suggestions/issue-104287.rs
new file mode 100644
index 00000000000..b7601a548b9
--- /dev/null
+++ b/src/test/ui/suggestions/issue-104287.rs
@@ -0,0 +1,9 @@
+// The purpose of this test is not to validate the output of the compiler.
+// Instead, it ensures the suggestion is generated without performing an arithmetic overflow.
+
+fn main() {
+    let x = not_found; //~ ERROR cannot find value `not_found` in this scope
+    simd_gt::<()>(x);
+    //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied
+    //~| ERROR cannot find function `simd_gt` in this scope
+}
diff --git a/src/test/ui/suggestions/issue-104287.stderr b/src/test/ui/suggestions/issue-104287.stderr
new file mode 100644
index 00000000000..4b302dd6509
--- /dev/null
+++ b/src/test/ui/suggestions/issue-104287.stderr
@@ -0,0 +1,36 @@
+error[E0425]: cannot find value `not_found` in this scope
+  --> $DIR/issue-104287.rs:5:13
+   |
+LL |     let x = not_found;
+   |             ^^^^^^^^^ not found in this scope
+
+error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-104287.rs:6:5
+   |
+LL |     simd_gt::<()>(x);
+   |     ^^^^^^^------ help: remove these generics
+   |     |
+   |     expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/ord.rs:LL:COL
+   |
+LL |     fn simd_gt(self, other: Self) -> Self::Mask;
+   |        ^^^^^^^
+
+error[E0425]: cannot find function `simd_gt` in this scope
+  --> $DIR/issue-104287.rs:6:5
+   |
+LL |     simd_gt::<()>(x);
+   |     ^^^^^^^ not found in this scope
+   |
+help: use the `.` operator to call the method `SimdPartialOrd::simd_gt` on `[type error]`
+   |
+LL -     simd_gt::<()>(x);
+LL +     x.simd_gt();
+   |
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0107, E0425.
+For more information about an error, try `rustc --explain E0107`.