From 699184bba4f5e6df163d5d08883e09509ac79e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 24 Nov 2025 11:36:57 +0100 Subject: [PATCH 01/10] implement and test `Iterator::{exactly_one, collect_array}` --- library/core/src/iter/traits/iterator.rs | 56 ++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 29230b1665380..f898382086512 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -4034,6 +4034,62 @@ pub trait Iterator { { unreachable!("Always specialized"); } + + /// Checks if the iterator contains *exactly* one element. + /// If so, returns this one element. + /// + /// See also [`collect_array`](Iterator::collect_array) for lengths other than `1`. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_length_collection)] + /// + /// assert_eq!([1].into_iter().exactly_one(), Some(1)); + /// assert_eq!([].into_iter().exactly_one(), None::<()>); + /// + /// // There is exactly one even integer in the array: + /// assert_eq!([1, 2, 3].into_iter().filter(|x| x % 2 == 0).exactly_one(), Some(2)); + /// // But there are two odds, which is too many: + /// assert_eq!([1, 2, 3].into_iter().filter(|x| x % 2 == 1).exactly_one(), None); + /// ``` + #[inline] + #[unstable(feature = "exact_length_collection", issue = "149266")] + fn exactly_one(self) -> Option + where + Self: Sized, + { + self.collect_array::<1>().map(|[i]| i) + } + + /// Checks if an iterator has *exactly* `N` elements. + /// If so, returns those `N` elements in an array. + /// + /// See also [`exactly_one`](Iterator::exactly_one) when expecting a single element. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_length_collection)] + /// + /// assert_eq!([1, 2, 3, 4].into_iter().collect_array(), Some([1, 2, 3, 4])); + /// assert_eq!([1, 2].into_iter().chain([3, 4]).collect_array(), Some([1, 2, 3, 4])); + /// + /// // Iterator contains too few elements: + /// assert_eq!([1, 2].into_iter().collect_array::<4>(), None); + /// // Iterator contains too many elements: + /// assert_eq!([1, 2, 3, 4, 5].into_iter().collect_array::<4>(), None); + /// // Taking 4 makes it work again: + /// assert_eq!([1, 2, 3, 4, 5].into_iter().take(4).collect_array(), Some([1, 2, 3, 4])); + /// ``` + #[inline] + #[unstable(feature = "exact_length_collection", issue = "149266")] + fn collect_array(mut self) -> Option<[Self::Item; N]> + where + Self: Sized, + { + self.next_chunk().ok().filter(|_| self.next().is_none()) + } } trait SpecIterEq: Iterator { From f20175293aa8372766250e56e2570f3c06640e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 24 Nov 2025 11:36:57 +0100 Subject: [PATCH 02/10] fixup warnings around the compiler --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 3 ++- src/librustdoc/html/format.rs | 6 ++++-- src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs | 6 ++++-- .../crates/hir-expand/src/builtin/fn_macro.rs | 3 ++- .../crates/ide-assists/src/handlers/convert_bool_then.rs | 3 ++- .../ide-assists/src/handlers/convert_range_for_to_while.rs | 2 +- .../crates/ide-completion/src/tests/raw_identifiers.rs | 5 ++--- .../crates/rust-analyzer/tests/slow-tests/support.rs | 3 ++- tests/ui/const-generics/type-dependent/issue-71805.rs | 4 ++-- tests/ui/mir/mir-inlining/ice-issue-77564.rs | 7 ++++--- 10 files changed, 25 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 6dff79374f20f..5a49d0f07a490 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -86,7 +86,8 @@ impl MetadataLoader for DefaultMetadataLoader { format!("failed to parse aix dylib '{}': {}", path.display(), e) })?; - match archive.members().exactly_one() { + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + match Itertools::exactly_one(archive.members()) { Ok(lib) => { let lib = lib.map_err(|e| { format!("failed to parse aix dylib '{}': {}", path.display(), e) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index dd91cec531f59..7fdbde51480bc 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1126,7 +1126,8 @@ pub(crate) fn print_impl( } if impl_.kind.is_fake_variadic() && let Some(generics) = ty.generics() - && let Ok(inner_type) = generics.exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + && let Ok(inner_type) = Itertools::exactly_one(generics) { let last = ty.last(); if f.alternate() { @@ -1206,7 +1207,8 @@ impl clean::Impl { } } else if let clean::Type::Path { path } = type_ && let Some(generics) = path.generics() - && let Ok(ty) = generics.exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + && let Ok(ty) = Itertools::exactly_one(generics) && self.kind.is_fake_variadic() { print_anchor(path.def_id(), path.last(), cx).fmt(f)?; diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 0d783fde33131..08e7c7593cb27 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -92,7 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id))) .then_some((v.def_id, v.span)) }); - if let Ok((id, span)) = iter.exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + if let Ok((id, span)) = Itertools::exactly_one(iter) && !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..)) { self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); @@ -104,7 +105,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { .iter() .filter(|field| !cx.effective_visibilities.is_exported(field.def_id)); if fields.len() > 1 - && let Ok(field) = private_fields.exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + && let Ok(field) = Itertools::exactly_one(private_fields) && let TyKind::Tup([]) = field.ty.kind { span_lint_and_then( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 6fe63f249cd4a..78fac8ff13517 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -786,7 +786,8 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> { && let DelimiterKind::Parenthesis | DelimiterKind::Invisible = sub.delimiter.kind { tt = - tt_iter.exactly_one().map_err(|_| sub.delimiter.open.cover(sub.delimiter.close))?; + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + Itertools::exactly_one(tt_iter).map_err(|_| sub.delimiter.open.cover(sub.delimiter.close))?; } match tt { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index 9d5d3f223707a..91cee59ad8d00 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -163,7 +163,8 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> let name_ref = ctx.find_node_at_offset::()?; let mcall = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?; let receiver = mcall.receiver()?; - let closure_body = mcall.arg_list()?.args().exactly_one().ok()?; + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + let closure_body = Itertools::exactly_one(mcall.arg_list()?.args()).ok()?; let closure_body = match closure_body { ast::Expr::ClosureExpr(expr) => expr.body()?, _ => return None, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs index 68cb764030956..ba577b217df78 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_range_for_to_while.rs @@ -113,7 +113,7 @@ fn extract_range(iterable: &ast::Expr) -> Option<(ast::Expr, Option, (range.start()?, range.end(), make::expr_literal("1").into(), inclusive) } ast::Expr::MethodCallExpr(call) if call.name_ref()?.text() == "step_by" => { - let [step] = call.arg_list()?.args().collect_array()?; + let [step] = Itertools::collect_array(call.arg_list()?.args())?; let (start, end, _, inclusive) = extract_range(&call.receiver()?)?; (start, end, step, inclusive) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs index 00977ea4e533b..66b16681f47af 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs @@ -8,9 +8,8 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let completions = completion_list_with_config_raw(TEST_CONFIG, ra_fixture, true, None); let (db, position) = position(ra_fixture); let mut actual = db.file_text(position.file_id).text(&db).to_string(); - completions - .into_iter() - .exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + Itertools::exactly_one(completions.into_iter()) .expect("more than one completion") .text_edit .apply(&mut actual); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 3464a9644b19d..b1b428e7068dc 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -113,7 +113,8 @@ impl Project<'_> { let mut buf = Vec::new(); flags::Lsif::run( flags::Lsif { - path: tmp_dir_path.join(self.roots.iter().exactly_one().unwrap()).into(), + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + path: tmp_dir_path.join(Itertools::exactly_one(self.roots.iter()).unwrap()).into(), exclude_vendored_libraries: false, }, &mut buf, diff --git a/tests/ui/const-generics/type-dependent/issue-71805.rs b/tests/ui/const-generics/type-dependent/issue-71805.rs index 27c101df107c8..de04a809da60f 100644 --- a/tests/ui/const-generics/type-dependent/issue-71805.rs +++ b/tests/ui/const-generics/type-dependent/issue-71805.rs @@ -4,7 +4,7 @@ use std::mem::MaybeUninit; trait CollectSlice<'a>: Iterator { fn inner_array(&mut self) -> [Self::Item; N]; - fn collect_array(&mut self) -> [Self::Item; N] { + fn custom_collect_array(&mut self) -> [Self::Item; N] { let result = self.inner_array(); assert!(self.next().is_none()); result @@ -34,5 +34,5 @@ where fn main() { let mut foos = [0u64; 9].iter().cloned(); - let _bar: [u64; 9] = foos.collect_array::<9_usize>(); + let _bar: [u64; 9] = foos.custom_collect_array::<9_usize>(); } diff --git a/tests/ui/mir/mir-inlining/ice-issue-77564.rs b/tests/ui/mir/mir-inlining/ice-issue-77564.rs index fce6d1d174f66..256ff295184d7 100644 --- a/tests/ui/mir/mir-inlining/ice-issue-77564.rs +++ b/tests/ui/mir/mir-inlining/ice-issue-77564.rs @@ -29,10 +29,11 @@ where fn main() { assert_eq!( - [[1, 2], [3, 4]] + CollectArray::collect_array( + &mut [[1, 2], [3, 4]] .iter() - .map(|row| row.iter().collect_array()) - .collect_array(), + .map(|row| CollectArray::collect_array(&mut row.iter())) + ), [[&1, &2], [&3, &4]] ); } From 3faad7cc41b240e4730944162c3bf79ff09ea0db Mon Sep 17 00:00:00 2001 From: Kornel Date: Tue, 25 Nov 2025 00:55:38 +0000 Subject: [PATCH 03/10] Suggest _bytes versions of endian-converting methods --- library/core/src/num/int_macros.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 93fdf2823aeb7..21f9be8fc7695 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -372,6 +372,8 @@ macro_rules! int_impl { /// /// On big endian this is a no-op. On little endian the bytes are swapped. /// + /// See also [from_be_bytes()](Self::from_be_bytes). + /// /// # Examples /// /// ``` @@ -402,6 +404,8 @@ macro_rules! int_impl { /// /// On little endian this is a no-op. On big endian the bytes are swapped. /// + /// See also [from_le_bytes()](Self::from_le_bytes). + /// /// # Examples /// /// ``` @@ -428,9 +432,15 @@ macro_rules! int_impl { } } - /// Converts `self` to big endian from the target's endianness. + /// Swaps bytes of `self` on little endian targets. /// - /// On big endian this is a no-op. On little endian the bytes are swapped. + /// On big endian this is a no-op. + /// + /// The returned value has the same type as `self`, and will be interpreted + /// as (a potentially different) value of a native-endian + #[doc = concat!("`", stringify!($SelfT), "`.")] + /// + /// See [`to_be_bytes()`](Self::to_be_bytes) for a type-safe alternative. /// /// # Examples /// @@ -459,9 +469,15 @@ macro_rules! int_impl { } } - /// Converts `self` to little endian from the target's endianness. + /// Swaps bytes of `self` on big endian targets. /// - /// On little endian this is a no-op. On big endian the bytes are swapped. + /// On little endian this is a no-op. + /// + /// The returned value has the same type as `self`, and will be interpreted + /// as (a potentially different) value of a native-endian + #[doc = concat!("`", stringify!($SelfT), "`.")] + /// + /// See [`to_le_bytes()`](Self::to_le_bytes) for a type-safe alternative. /// /// # Examples /// From 48bd321a71cb9d9b97da5dda2a01b93ce3b970d7 Mon Sep 17 00:00:00 2001 From: Asuka Minato Date: Wed, 26 Nov 2025 06:47:36 +0900 Subject: [PATCH 04/10] fix --- src/librustdoc/html/static/js/search.js | 8 +++++--- tests/rustdoc-js/generics-trait.js | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 2b381d64547b5..1a60d032cf7c0 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -5050,9 +5050,11 @@ ${obj.displayPath}${name}\ if (query.proposeCorrectionFrom !== null && isTypeSearch) { const orig = query.proposeCorrectionFrom; const targ = query.proposeCorrectionTo; - correctionOutput = "

" + - `Type "${orig}" not found and used as generic parameter. ` + - `Consider searching for "${targ}" instead.

`; + const parts = [`Type "${orig}" not found and used as generic parameter.`]; + if (targ !== null) { + parts.push(`Consider searching for "${targ}" instead.`); + } + correctionOutput = `

${parts.join(" ")}

`; } if (firstResult.value) { if (correctionOutput !== "") { diff --git a/tests/rustdoc-js/generics-trait.js b/tests/rustdoc-js/generics-trait.js index cd100463e9a85..eb8e99e80f99f 100644 --- a/tests/rustdoc-js/generics-trait.js +++ b/tests/rustdoc-js/generics-trait.js @@ -95,3 +95,24 @@ const EXPECTED = [ ], }, ]; + +const PARSED = [ + { + 'query': 'Result', + 'userQuery': 'Result', + 'foundElems': 1, + 'returned': [], + 'error': null, + 'proposeCorrectionFrom': 'SomeTraiz', + 'proposeCorrectionTo': 'SomeTrait', + }, + { + 'query': 'Result', + 'userQuery': 'Result', + 'foundElems': 1, + 'returned': [], + 'error': null, + 'proposeCorrectionFrom': 'NoSuchTrait', + 'proposeCorrectionTo': null, + }, +]; From 69d3218ca219826a7ee658cf561f013a3e3570a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Nov 2025 14:40:29 +0100 Subject: [PATCH 05/10] float::clamp: make treatment of signed zeros unspecified --- library/core/src/num/f128.rs | 9 ++++++++- library/core/src/num/f16.rs | 9 ++++++++- library/core/src/num/f32.rs | 9 ++++++++- library/core/src/num/f64.rs | 9 ++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 2cf06b6d6a35a..377bb4f3a72e3 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -1236,7 +1236,8 @@ impl f128 { /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as - /// well. + /// well. If the result is zero and among the three inputs `self`, `min`, and `max` there are + /// zeros with different sign, either `0.0` or `-0.0` is returned non-deterministically. /// /// # Panics /// @@ -1253,6 +1254,12 @@ impl f128 { /// assert!((0.0f128).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f128).clamp(-2.0, 1.0) == 1.0); /// assert!((f128::NAN).clamp(-2.0, 1.0).is_nan()); + /// + /// // These always returns zero, but the sign (which is ignored by `==`) is non-deterministic. + /// assert!((0.0f128).clamp(-0.0, -0.0) == 0.0); + /// assert!((1.0f128).clamp(-0.0, 0.0) == 0.0); + /// // This is definitely a negative zero. + /// assert!((-1.0f128).clamp(-0.0, 1.0).is_sign_negative()); /// # } /// ``` #[inline] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 51f803672e5c6..caa787db449c5 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1215,7 +1215,8 @@ impl f16 { /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as - /// well. + /// well. If the result is zero and among the three inputs `self`, `min`, and `max` there are + /// zeros with different sign, either `0.0` or `-0.0` is returned non-deterministically. /// /// # Panics /// @@ -1231,6 +1232,12 @@ impl f16 { /// assert!((0.0f16).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f16).clamp(-2.0, 1.0) == 1.0); /// assert!((f16::NAN).clamp(-2.0, 1.0).is_nan()); + /// + /// // These always returns zero, but the sign (which is ignored by `==`) is non-deterministic. + /// assert!((0.0f16).clamp(-0.0, -0.0) == 0.0); + /// assert!((1.0f16).clamp(-0.0, 0.0) == 0.0); + /// // This is definitely a negative zero. + /// assert!((-1.0f16).clamp(-0.0, 1.0).is_sign_negative()); /// # } /// ``` #[inline] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 3070e1dedbe43..6a77c4a477ae5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1395,7 +1395,8 @@ impl f32 { /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as - /// well. + /// well. If the result is zero and among the three inputs `self`, `min`, and `max` there are + /// zeros with different sign, either `0.0` or `-0.0` is returned non-deterministically. /// /// # Panics /// @@ -1408,6 +1409,12 @@ impl f32 { /// assert!((0.0f32).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f32).clamp(-2.0, 1.0) == 1.0); /// assert!((f32::NAN).clamp(-2.0, 1.0).is_nan()); + /// + /// // These always returns zero, but the sign (which is ignored by `==`) is non-deterministic. + /// assert!((0.0f32).clamp(-0.0, -0.0) == 0.0); + /// assert!((1.0f32).clamp(-0.0, 0.0) == 0.0); + /// // This is definitely a negative zero. + /// assert!((-1.0f32).clamp(-0.0, 1.0).is_sign_negative()); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index dc8ccc551b2da..024b90990db5d 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1393,7 +1393,8 @@ impl f64 { /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as - /// well. + /// well. If the result is zero and among the three inputs `self`, `min`, and `max` there are + /// zeros with different sign, either `0.0` or `-0.0` is returned non-deterministically. /// /// # Panics /// @@ -1406,6 +1407,12 @@ impl f64 { /// assert!((0.0f64).clamp(-2.0, 1.0) == 0.0); /// assert!((2.0f64).clamp(-2.0, 1.0) == 1.0); /// assert!((f64::NAN).clamp(-2.0, 1.0).is_nan()); + /// + /// // These always returns zero, but the sign (which is ignored by `==`) is non-deterministic. + /// assert!((0.0f64).clamp(-0.0, -0.0) == 0.0); + /// assert!((1.0f64).clamp(-0.0, 0.0) == 0.0); + /// // This is definitely a negative zero. + /// assert!((-1.0f64).clamp(-0.0, 1.0).is_sign_negative()); /// ``` #[must_use = "method returns a new number and does not mutate the original value"] #[stable(feature = "clamp", since = "1.50.0")] From 29639e355244966024165bd700bba0e2d1c44b20 Mon Sep 17 00:00:00 2001 From: Asuka Minato Date: Wed, 26 Nov 2025 20:10:37 +0900 Subject: [PATCH 06/10] use string --- src/librustdoc/html/static/js/search.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 1a60d032cf7c0..73bc28e4bc7d0 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -5050,11 +5050,11 @@ ${obj.displayPath}${name}\ if (query.proposeCorrectionFrom !== null && isTypeSearch) { const orig = query.proposeCorrectionFrom; const targ = query.proposeCorrectionTo; - const parts = [`Type "${orig}" not found and used as generic parameter.`]; + let message = `Type "${orig}" not found and used as generic parameter.`; if (targ !== null) { - parts.push(`Consider searching for "${targ}" instead.`); + message += ` Consider searching for "${targ}" instead.`; } - correctionOutput = `

${parts.join(" ")}

`; + correctionOutput = `

${message}

`; } if (firstResult.value) { if (correctionOutput !== "") { From e49f9615ce47f6587fac309f0bbdeb5d019ef17e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 26 Nov 2025 12:38:03 +0100 Subject: [PATCH 07/10] Fix typo in comment. --- library/core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4b1e013c2b445..7a80023ce64eb 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -625,7 +625,7 @@ impl<'a> Formatter<'a> { // // 2) Placeholders representation (e.g. format_args!("hello {name}\n")) // ┌────────────────────────────────┐ -// template: │ *const u8 │ ─▷ b"\x06hello \x80\x01\n\x00" +// template: │ *const u8 │ ─▷ b"\x06hello \xC0\x01\n\x00" // ├────────────────────────────────┤ // args: │ &'a [Argument<'a>; _] 0│ (lower bit is 0 due to alignment of Argument type) // └────────────────────────────────┘ From 941a17a15a51d28bfa1871358935a27f73c3f26e Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Wed, 26 Nov 2025 21:38:42 +0900 Subject: [PATCH 08/10] Relocate 5 tests from tests/ui/issues Relocate issues/issue-51154.rs to closures/box-generic-closure.rs Relocate issues/issue-51515.rs to borrowck/assignment-to-immutable-ref.rs Relocate issues/issue-53348.rs to mismatched_types/deref-string-assign.rs Relocate issues/issue-52717.rs to pattern/match-enum-struct-variant-field-missing.rs Relocate issues/issue-53300.rs to type/cannot-find-wrapper-with-impl-trait.rs --- .../assignment-to-immutable-ref.rs} | 4 ++++ .../assignment-to-immutable-ref.stderr} | 4 ++-- tests/ui/closures/box-generic-closure.rs | 10 ++++++++++ .../box-generic-closure.stderr} | 4 ++-- tests/ui/issues/issue-51154.rs | 6 ------ tests/ui/issues/issue-52717.rs | 13 ------------- tests/ui/issues/issue-52717.stderr | 12 ------------ .../assign-deref-string-to-string.rs} | 6 +++++- .../assign-deref-string-to-string.stderr} | 2 +- .../match-enum-struct-variant-field-missing.rs | 17 +++++++++++++++++ ...tch-enum-struct-variant-field-missing.stderr | 12 ++++++++++++ .../cannot-find-wrapper-with-impl-trait.rs} | 3 ++- .../cannot-find-wrapper-with-impl-trait.stderr} | 2 +- 13 files changed, 56 insertions(+), 39 deletions(-) rename tests/ui/{issues/issue-51515.rs => borrowck/assignment-to-immutable-ref.rs} (59%) rename tests/ui/{issues/issue-51515.stderr => borrowck/assignment-to-immutable-ref.stderr} (88%) create mode 100644 tests/ui/closures/box-generic-closure.rs rename tests/ui/{issues/issue-51154.stderr => closures/box-generic-closure.stderr} (84%) delete mode 100644 tests/ui/issues/issue-51154.rs delete mode 100644 tests/ui/issues/issue-52717.rs delete mode 100644 tests/ui/issues/issue-52717.stderr rename tests/ui/{issues/issue-53348.rs => mismatched_types/assign-deref-string-to-string.rs} (52%) rename tests/ui/{issues/issue-53348.stderr => mismatched_types/assign-deref-string-to-string.stderr} (87%) create mode 100644 tests/ui/pattern/match-enum-struct-variant-field-missing.rs create mode 100644 tests/ui/pattern/match-enum-struct-variant-field-missing.stderr rename tests/ui/{issues/issue-53300.rs => type/cannot-find-wrapper-with-impl-trait.rs} (53%) rename tests/ui/{issues/issue-53300.stderr => type/cannot-find-wrapper-with-impl-trait.stderr} (82%) diff --git a/tests/ui/issues/issue-51515.rs b/tests/ui/borrowck/assignment-to-immutable-ref.rs similarity index 59% rename from tests/ui/issues/issue-51515.rs rename to tests/ui/borrowck/assignment-to-immutable-ref.rs index 33a9bf85e23ea..c04c26f6ea2e7 100644 --- a/tests/ui/issues/issue-51515.rs +++ b/tests/ui/borrowck/assignment-to-immutable-ref.rs @@ -1,3 +1,7 @@ +//! Regression test for issue +//! Test that assigning through an immutable reference (`&`) correctly yields +//! an assignment error (E0594) and suggests using a mutable reference. + fn main() { let foo = &16; //~^ HELP consider changing this to be a mutable reference diff --git a/tests/ui/issues/issue-51515.stderr b/tests/ui/borrowck/assignment-to-immutable-ref.stderr similarity index 88% rename from tests/ui/issues/issue-51515.stderr rename to tests/ui/borrowck/assignment-to-immutable-ref.stderr index 5bf33b191c0eb..ec1be1acce0aa 100644 --- a/tests/ui/issues/issue-51515.stderr +++ b/tests/ui/borrowck/assignment-to-immutable-ref.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `*foo`, which is behind a `&` reference - --> $DIR/issue-51515.rs:4:5 + --> $DIR/assignment-to-immutable-ref.rs:8:5 | LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so it cannot be written to @@ -10,7 +10,7 @@ LL | let foo = &mut 16; | +++ error[E0594]: cannot assign to `*bar`, which is behind a `&` reference - --> $DIR/issue-51515.rs:8:5 + --> $DIR/assignment-to-immutable-ref.rs:12:5 | LL | *bar = 64; | ^^^^^^^^^ `bar` is a `&` reference, so it cannot be written to diff --git a/tests/ui/closures/box-generic-closure.rs b/tests/ui/closures/box-generic-closure.rs new file mode 100644 index 0000000000000..e526cf0012d6f --- /dev/null +++ b/tests/ui/closures/box-generic-closure.rs @@ -0,0 +1,10 @@ +//! Regression test for issue +//! Test that anonymous closure types cannot be coerced to a generic type +//! parameter (F: FnMut()) when trying to box them. + +fn foo() { + let _: Box = Box::new(|| ()); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/issues/issue-51154.stderr b/tests/ui/closures/box-generic-closure.stderr similarity index 84% rename from tests/ui/issues/issue-51154.stderr rename to tests/ui/closures/box-generic-closure.stderr index b7451ea28ee97..9b74a196c3ad4 100644 --- a/tests/ui/issues/issue-51154.stderr +++ b/tests/ui/closures/box-generic-closure.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-51154.rs:2:30 + --> $DIR/box-generic-closure.rs:6:30 | LL | fn foo() { | - expected this type parameter @@ -9,7 +9,7 @@ LL | let _: Box = Box::new(|| ()); | arguments to this function are incorrect | = note: expected type parameter `F` - found closure `{closure@$DIR/issue-51154.rs:2:30: 2:32}` + found closure `{closure@$DIR/box-generic-closure.rs:6:30: 6:32}` = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F` note: associated function defined here --> $SRC_DIR/alloc/src/boxed.rs:LL:COL diff --git a/tests/ui/issues/issue-51154.rs b/tests/ui/issues/issue-51154.rs deleted file mode 100644 index 12903f79010cb..0000000000000 --- a/tests/ui/issues/issue-51154.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() { - let _: Box = Box::new(|| ()); - //~^ ERROR mismatched types -} - -fn main() {} diff --git a/tests/ui/issues/issue-52717.rs b/tests/ui/issues/issue-52717.rs deleted file mode 100644 index f83232a4a2689..0000000000000 --- a/tests/ui/issues/issue-52717.rs +++ /dev/null @@ -1,13 +0,0 @@ -enum A { - A { - foo: usize, - } -} - -fn main() { - let x = A::A { foo: 3 }; - match x { - A::A { fob } => { println!("{}", fob); } -//~^ ERROR does not have a field named `fob` - } -} diff --git a/tests/ui/issues/issue-52717.stderr b/tests/ui/issues/issue-52717.stderr deleted file mode 100644 index ab8c37225cae6..0000000000000 --- a/tests/ui/issues/issue-52717.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0026]: variant `A::A` does not have a field named `fob` - --> $DIR/issue-52717.rs:10:12 - | -LL | A::A { fob } => { println!("{}", fob); } - | ^^^ - | | - | variant `A::A` does not have this field - | help: a field with a similar name exists: `foo` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0026`. diff --git a/tests/ui/issues/issue-53348.rs b/tests/ui/mismatched_types/assign-deref-string-to-string.rs similarity index 52% rename from tests/ui/issues/issue-53348.rs rename to tests/ui/mismatched_types/assign-deref-string-to-string.rs index 66800d9e92961..82498a6e63e21 100644 --- a/tests/ui/issues/issue-53348.rs +++ b/tests/ui/mismatched_types/assign-deref-string-to-string.rs @@ -1,9 +1,13 @@ +//! Regression test for issue https://github.com/rust-lang/rust/issues/53348 +//! Test that attempting to assign a dereferenced `String` (which is `str`) +//! to a `String` variable correctly results in a mismatched types error (E0308). + fn main() { let mut v = vec!["hello", "this", "is", "a", "test"]; let v2 = Vec::new(); - v.into_iter().map(|s|s.to_owned()).collect::>(); + v.into_iter().map(|s| s.to_owned()).collect::>(); let mut a = String::new(); //~ NOTE expected due to this value for i in v { diff --git a/tests/ui/issues/issue-53348.stderr b/tests/ui/mismatched_types/assign-deref-string-to-string.stderr similarity index 87% rename from tests/ui/issues/issue-53348.stderr rename to tests/ui/mismatched_types/assign-deref-string-to-string.stderr index 38fa98e65e138..8cc3cb6b9bef0 100644 --- a/tests/ui/issues/issue-53348.stderr +++ b/tests/ui/mismatched_types/assign-deref-string-to-string.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-53348.rs:10:13 + --> $DIR/assign-deref-string-to-string.rs:14:13 | LL | let mut a = String::new(); | ------------- expected due to this value diff --git a/tests/ui/pattern/match-enum-struct-variant-field-missing.rs b/tests/ui/pattern/match-enum-struct-variant-field-missing.rs new file mode 100644 index 0000000000000..0a281b0efe052 --- /dev/null +++ b/tests/ui/pattern/match-enum-struct-variant-field-missing.rs @@ -0,0 +1,17 @@ +//! Regression test for issue +//! Test that matching an enum struct variant with a missing or incorrect field name +//! correctly yields a "does not have a field named" error. + +enum A { + A { foo: usize }, +} + +fn main() { + let x = A::A { foo: 3 }; + match x { + A::A { fob } => { + //~^ ERROR does not have a field named `fob` + println!("{fob}"); + } + } +} diff --git a/tests/ui/pattern/match-enum-struct-variant-field-missing.stderr b/tests/ui/pattern/match-enum-struct-variant-field-missing.stderr new file mode 100644 index 0000000000000..326595a7cb706 --- /dev/null +++ b/tests/ui/pattern/match-enum-struct-variant-field-missing.stderr @@ -0,0 +1,12 @@ +error[E0026]: variant `A::A` does not have a field named `fob` + --> $DIR/match-enum-struct-variant-field-missing.rs:12:16 + | +LL | A::A { fob } => { + | ^^^ + | | + | variant `A::A` does not have this field + | help: a field with a similar name exists: `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0026`. diff --git a/tests/ui/issues/issue-53300.rs b/tests/ui/type/cannot-find-wrapper-with-impl-trait.rs similarity index 53% rename from tests/ui/issues/issue-53300.rs rename to tests/ui/type/cannot-find-wrapper-with-impl-trait.rs index 09f0fe9d93553..48ff4c38f7db3 100644 --- a/tests/ui/issues/issue-53300.rs +++ b/tests/ui/type/cannot-find-wrapper-with-impl-trait.rs @@ -1,4 +1,5 @@ -// issue 53300 +//! Regression test for issue +//! Tests that an undefined type (Wrapper) used with impl Trait correctly gives E0412. pub trait A { fn add(&self, b: i32) -> i32; diff --git a/tests/ui/issues/issue-53300.stderr b/tests/ui/type/cannot-find-wrapper-with-impl-trait.stderr similarity index 82% rename from tests/ui/issues/issue-53300.stderr rename to tests/ui/type/cannot-find-wrapper-with-impl-trait.stderr index 293465ecb8140..ac7f2e5134a2c 100644 --- a/tests/ui/issues/issue-53300.stderr +++ b/tests/ui/type/cannot-find-wrapper-with-impl-trait.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Wrapper` in this scope - --> $DIR/issue-53300.rs:7:18 + --> $DIR/cannot-find-wrapper-with-impl-trait.rs:8:18 | LL | fn addition() -> Wrapper {} | ^^^^^^^ not found in this scope From 4af0b97075a0cbb0a618611eb867c32d5b2fc0d5 Mon Sep 17 00:00:00 2001 From: anishamahuli Date: Wed, 26 Nov 2025 11:06:38 -0500 Subject: [PATCH 09/10] Warn about build.description compatibility issues --- bootstrap.example.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 6a8da0305464a..4e850810a30a9 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -220,6 +220,11 @@ # which is also used in places like debuginfo `DW_AT_producer`. This may be useful for # supplementary build information, like distro-specific package versions. # +# IMPORTANT: Changing this value changes crate IDs and symbol name mangling, making +# compiled artifacts incompatible. PGO profiles cannot be reused across different +# descriptions, and incremental compilation caches are invalidated. Keep this value +# consistent when reusing build artifacts. +# # The Rust compiler will differentiate between versions of itself, including # based on this string, which means that if you wish to be compatible with # upstream Rust you need to set this to "". However, note that if you set this to "" but From 440857305c1e2826351f471bbd2c4933763fbbcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 26 Nov 2025 21:36:36 +0100 Subject: [PATCH 10/10] Enable CI download for windows-gnullvm --- src/bootstrap/src/core/build_steps/llvm.rs | 4 +++- src/bootstrap/src/core/download.rs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 7e1b59351e042..a591be05291fa 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -206,7 +206,6 @@ pub(crate) fn is_ci_llvm_available_for_target( ("aarch64-unknown-linux-gnu", false), ("aarch64-apple-darwin", false), ("aarch64-pc-windows-msvc", false), - ("i686-pc-windows-gnu", false), ("i686-pc-windows-msvc", false), ("i686-unknown-linux-gnu", false), ("x86_64-unknown-linux-gnu", true), @@ -215,9 +214,11 @@ pub(crate) fn is_ci_llvm_available_for_target( ("x86_64-pc-windows-msvc", true), // tier 2 with host tools ("aarch64-unknown-linux-musl", false), + ("aarch64-pc-windows-gnullvm", false), ("arm-unknown-linux-gnueabi", false), ("arm-unknown-linux-gnueabihf", false), ("armv7-unknown-linux-gnueabihf", false), + ("i686-pc-windows-gnu", false), ("loongarch64-unknown-linux-gnu", false), ("loongarch64-unknown-linux-musl", false), ("powerpc-unknown-linux-gnu", false), @@ -226,6 +227,7 @@ pub(crate) fn is_ci_llvm_available_for_target( ("powerpc64le-unknown-linux-musl", false), ("riscv64gc-unknown-linux-gnu", false), ("s390x-unknown-linux-gnu", false), + ("x86_64-pc-windows-gnullvm", true), ("x86_64-unknown-freebsd", false), ("x86_64-unknown-illumos", false), ("x86_64-unknown-linux-musl", false), diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index a096d116e73fa..d950dc1a1c582 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -447,6 +447,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo // All tier 1 targets and tier 2 targets with host tools. const SUPPORTED_PLATFORMS: &[&str] = &[ "aarch64-apple-darwin", + "aarch64-pc-windows-gnullvm", "aarch64-pc-windows-msvc", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", @@ -465,6 +466,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo "s390x-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-gnu", + "x86_64-pc-windows-gnullvm", "x86_64-pc-windows-msvc", "x86_64-unknown-freebsd", "x86_64-unknown-illumos",