From 4da823ba4be74cdd840c6db854ee57cc0c864d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 19 Feb 2026 22:11:58 +0100 Subject: [PATCH 01/33] Do not enable split debuginfo for windows-gnu Because rustc doesn't handle split debuginfo for these targets, enabling that option causes them to be missing some of the debuginfo. --- bootstrap.example.toml | 7 ++++--- src/bootstrap/src/core/config/target_selection.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index e0cbb0c0e747c..432a681403614 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -1008,9 +1008,10 @@ # its historical default, but when compiling the compiler itself, we skip it by # default since we know it's safe to do so in that case. # -# On Windows platforms, packed debuginfo is the only supported option, -# producing a `.pdb` file. -#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked } +# On Windows MSVC platforms, packed debuginfo is the only supported option, +# producing a `.pdb` file. On Windows GNU rustc doesn't support splitting debuginfo, +# and enabling it causes issues. +#split-debuginfo = if linux || windows-gnu { off } else if windows-msvc { packed } else if apple { unpacked } # Path to the `llvm-config` binary of the installation of a custom LLVM to link # against. Note that if this is specified we don't compile LLVM at all for this diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs index 47f6d6f386dfb..8457607b897dd 100644 --- a/src/bootstrap/src/core/config/target_selection.rs +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -142,7 +142,7 @@ impl SplitDebuginfo { pub fn default_for_platform(target: TargetSelection) -> Self { if target.contains("apple") { SplitDebuginfo::Unpacked - } else if target.is_windows() { + } else if target.is_msvc() { SplitDebuginfo::Packed } else { SplitDebuginfo::Off From 7adb9bac0c7d2bf469e6b76c6cc47099afb02123 Mon Sep 17 00:00:00 2001 From: "LevitatingBusinessMan (Rein Fernhout)" Date: Fri, 27 Feb 2026 09:30:27 +0100 Subject: [PATCH 02/33] Add is_disconnected functions to mpsc and mpmc channels --- library/std/src/sync/mpmc/mod.rs | 46 +++++++++++++++++++++++++++++++ library/std/src/sync/mpmc/zero.rs | 6 ++++ library/std/src/sync/mpsc.rs | 38 +++++++++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 8df81a580f7b8..6249e8a033e8d 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -623,6 +623,29 @@ impl Sender { _ => false, } } + + /// Returns `true` if the channel is disconnected. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// + /// let (tx, rx) = channel::(); + /// assert!(!tx.is_disconnected()); + /// drop(rx); + /// assert!(tx.is_disconnected()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] + pub fn is_disconnected(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.is_disconnected(), + SenderFlavor::List(chan) => chan.is_disconnected(), + SenderFlavor::Zero(chan) => chan.is_disconnected(), + } + } } #[unstable(feature = "mpmc_channel", issue = "126840")] @@ -1349,6 +1372,29 @@ impl Receiver { pub fn iter(&self) -> Iter<'_, T> { Iter { rx: self } } + + /// Returns `true` if the channel is disconnected. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// + /// let (tx, rx) = channel::(); + /// assert!(!rx.is_disconnected()); + /// drop(tx); + /// assert!(rx.is_disconnected()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] + pub fn is_disconnected(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.is_disconnected(), + ReceiverFlavor::List(chan) => chan.is_disconnected(), + ReceiverFlavor::Zero(chan) => chan.is_disconnected(), + } + } } #[unstable(feature = "mpmc_channel", issue = "126840")] diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index f1ecf80fcb9f6..c743462501922 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -316,4 +316,10 @@ impl Channel { pub(crate) fn is_full(&self) -> bool { true } + + /// Returns `true` if the channel is disconnected. + pub(crate) fn is_disconnected(&self) -> bool { + let inner = self.inner.lock().unwrap(); + inner.is_disconnected + } } diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index 0ae23f6e13bf2..81bb5849fb77f 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -607,6 +607,25 @@ impl Sender { pub fn send(&self, t: T) -> Result<(), SendError> { self.inner.send(t) } + + /// Returns `true` if the channel is disconnected. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpsc_is_disconnected)] + /// + /// use std::sync::mpsc::channel; + /// + /// let (tx, rx) = channel::(); + /// assert!(!tx.is_disconnected()); + /// drop(rx); + /// assert!(tx.is_disconnected()); + /// ``` + #[unstable(feature = "mpsc_is_disconnected", issue = "none")] + pub fn is_disconnected(&self) -> bool { + self.inner.is_disconnected() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1038,6 +1057,25 @@ impl Receiver { pub fn try_iter(&self) -> TryIter<'_, T> { TryIter { rx: self } } + + /// Returns `true` if the channel is disconnected. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpsc_is_disconnected)] + /// + /// use std::sync::mpsc::channel; + /// + /// let (tx, rx) = channel::(); + /// assert!(!rx.is_disconnected()); + /// drop(tx); + /// assert!(rx.is_disconnected()); + /// ``` + #[unstable(feature = "mpsc_is_disconnected", issue = "none")] + pub fn is_disconnected(&self) -> bool { + self.inner.is_disconnected() + } } #[stable(feature = "rust1", since = "1.0.0")] From feef7b4eafedfae6c8fd40caf711343b6cc3fe43 Mon Sep 17 00:00:00 2001 From: "LevitatingBusinessMan (Rein Fernhout)" Date: Sat, 28 Feb 2026 19:52:50 +0100 Subject: [PATCH 03/33] warn of possible race condition in channel is_disconnected doc --- library/std/src/sync/mpmc/mod.rs | 8 ++++++++ library/std/src/sync/mpsc.rs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 6249e8a033e8d..16ae8a88370be 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -626,6 +626,10 @@ impl Sender { /// Returns `true` if the channel is disconnected. /// + /// Note that a return value of `false` does not guarantee the channel will + /// remain connected. The channel may be disconnected immediately after this method + /// returns, so a subsequent [`Sender::send`] may still fail with [`SendError`]. + /// /// # Examples /// /// ``` @@ -1375,6 +1379,10 @@ impl Receiver { /// Returns `true` if the channel is disconnected. /// + /// Note that a return value of `false` does not guarantee the channel will + /// remain connected. The channel may be disconnected immediately after this method + /// returns, so a subsequent [`Receiver::recv`] may still fail with [`RecvError`]. + /// /// # Examples /// /// ``` diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index 81bb5849fb77f..2abf7bfe341d4 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -610,6 +610,10 @@ impl Sender { /// Returns `true` if the channel is disconnected. /// + /// Note that a return value of `false` does not guarantee the channel will + /// remain connected. The channel may be disconnected immediately after this method + /// returns, so a subsequent [`Sender::send`] may still fail with [`SendError`]. + /// /// # Examples /// /// ``` @@ -1060,6 +1064,10 @@ impl Receiver { /// Returns `true` if the channel is disconnected. /// + /// Note that a return value of `false` does not guarantee the channel will + /// remain connected. The channel may be disconnected immediately after this method + /// returns, so a subsequent [`Receiver::recv`] may still fail with [`RecvError`]. + /// /// # Examples /// /// ``` From f5a2bb6263ad332ceb2d9b3b82afe935259a7723 Mon Sep 17 00:00:00 2001 From: "Andrew V. Teylu" Date: Mon, 2 Mar 2026 20:28:16 +0000 Subject: [PATCH 04/33] Add hygiene annotations for tokens in macro_rules! bodies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `-Zunpretty=expanded,hygiene` was not printing syntax context annotations for identifiers and lifetimes inside `macro_rules!` bodies. These tokens are printed via `print_tt()` → `token_to_string_ext()`, which converts tokens to strings without calling `ann_post()`. This meant that macro-generated `macro_rules!` definitions with hygienic metavar parameters (e.g. multiple `$marg` distinguished only by hygiene) were printed with no way to tell them apart. This was fixed by adding a match on `token.kind` in `print_tt()` to call `ann_post()` for `Ident`, `NtIdent`, `Lifetime`, and `NtLifetime` tokens, matching how `print_ident()` and `print_lifetime()` already handle AST-level identifiers and lifetimes. Signed-off-by: Andrew V. Teylu --- compiler/rustc_ast_pretty/src/pprust/state.rs | 17 ++++++ .../hygiene/unpretty-debug-lifetimes.stdout | 8 +-- tests/ui/hygiene/unpretty-debug-metavars.rs | 25 +++++++++ .../ui/hygiene/unpretty-debug-metavars.stdout | 52 +++++++++++++++++++ tests/ui/hygiene/unpretty-debug.stdout | 10 +++- tests/ui/proc-macro/meta-macro-hygiene.stdout | 5 +- .../nonterminal-token-hygiene.stdout | 17 ++++-- 7 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 tests/ui/hygiene/unpretty-debug-metavars.rs create mode 100644 tests/ui/hygiene/unpretty-debug-metavars.stdout diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f4168301bc5df..7d963dd2037c5 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -735,6 +735,23 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere TokenTree::Token(token, spacing) => { let token_str = self.token_to_string_ext(token, convert_dollar_crate); self.word(token_str); + // Emit hygiene annotations for identity-bearing tokens, + // matching how print_ident() and print_lifetime() call ann_post(). + match token.kind { + token::Ident(name, _) => { + self.ann_post(Ident::new(name, token.span)); + } + token::NtIdent(ident, _) => { + self.ann_post(ident); + } + token::Lifetime(name, _) => { + self.ann_post(Ident::new(name, token.span)); + } + token::NtLifetime(ident, _) => { + self.ann_post(ident); + } + _ => {} + } if let token::DocComment(..) = token.kind { self.hardbreak() } diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout index 28a5c70a02d79..689453326c0b5 100644 --- a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout +++ b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout @@ -7,15 +7,17 @@ // Don't break whenever Symbol numbering changes //@ normalize-stdout: "\d+#" -> "0#" -#![feature /* 0#0 */(decl_macro)] -#![feature /* 0#0 */(no_core)] +#![feature /* 0#0 */(decl_macro /* 0#0 */)] +#![feature /* 0#0 */(no_core /* 0#0 */)] #![no_core /* 0#0 */] macro lifetime_hygiene /* 0#0 */ { - ($f:ident<$a:lifetime>) => { fn $f<$a, 'a>() {} } + ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 */>) + => + { fn /* 0#0 */ $f /* 0#0 */<$a /* 0#0 */, 'a /* 0#0 */>() {} } } fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {} diff --git a/tests/ui/hygiene/unpretty-debug-metavars.rs b/tests/ui/hygiene/unpretty-debug-metavars.rs new file mode 100644 index 0000000000000..a0c47bec3ccf7 --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-metavars.rs @@ -0,0 +1,25 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test: metavar parameters in macro-generated macro_rules! +// definitions should have hygiene annotations so that textually identical +// `$marg` bindings are distinguishable by their syntax contexts. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature(no_core)] +#![no_core] + +macro_rules! make_macro { + (@inner $name:ident ($dol:tt) $a:ident) => { + macro_rules! $name { + ($dol $a : expr, $dol marg : expr) => {} + } + }; + ($name:ident) => { + make_macro!{@inner $name ($) marg} + }; +} + +make_macro!(add2); diff --git a/tests/ui/hygiene/unpretty-debug-metavars.stdout b/tests/ui/hygiene/unpretty-debug-metavars.stdout new file mode 100644 index 0000000000000..307c5e1b8de97 --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-metavars.stdout @@ -0,0 +1,52 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test: metavar parameters in macro-generated macro_rules! +// definitions should have hygiene annotations so that textually identical +// `$marg` bindings are distinguishable by their syntax contexts. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature /* 0#0 */(no_core /* 0#0 */)] +#![no_core /* 0#0 */] + +macro_rules! make_macro + /* + 0#0 + */ { + (@inner /* 0#0 */ $name /* 0#0 */:ident /* 0#0 + */($dol /* 0#0 */:tt /* 0#0 */) $a /* 0#0 */:ident /* 0#0 */) + => + { + macro_rules /* 0#0 */! $name /* 0#0 */ + { + ($dol /* 0#0 */ $a /* 0#0 */ : expr /* 0#0 */, $dol /* + 0#0 */ marg /* 0#0 */ : expr /* 0#0 */) => {} + } + }; ($name /* 0#0 */:ident /* 0#0 */) => + { + make_macro /* 0#0 + */!{@inner /* 0#0 */ $name /* 0#0 */($) marg /* 0#0 */} + }; +} +macro_rules! add2 + /* + 0#0 + */ { + ($ marg /* 0#1 */ : expr /* 0#2 */, $marg /* 0#2 */ : expr /* + 0#2 */) => {} +} + + +/* +Expansions: +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "make_macro") +crate0::{{expn2}}: parent: crate0::{{expn1}}, call_site_ctxt: #1, def_site_ctxt: #0, kind: Macro(Bang, "make_macro") + +SyntaxContexts: +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque) +#2: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque) +*/ diff --git a/tests/ui/hygiene/unpretty-debug.stdout b/tests/ui/hygiene/unpretty-debug.stdout index f35bd7a7cb2ca..ac6051e2d542e 100644 --- a/tests/ui/hygiene/unpretty-debug.stdout +++ b/tests/ui/hygiene/unpretty-debug.stdout @@ -5,10 +5,16 @@ //@ normalize-stdout: "\d+#" -> "0#" // minimal junk -#![feature /* 0#0 */(no_core)] +#![feature /* 0#0 */(no_core /* 0#0 */)] #![no_core /* 0#0 */] -macro_rules! foo /* 0#0 */ { ($x: ident) => { y + $x } } +macro_rules! foo + /* + 0#0 + */ { + ($x /* 0#0 */: ident /* 0#0 */) => + { y /* 0#0 */ + $x /* 0#0 */ } +} fn bar /* 0#0 */() { let x /* 0#0 */ = 1; diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index b5db9922b31a8..a03e567bd48aa 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,7 +1,7 @@ Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:26:37: 26:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:26:43: 26:44 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:26:44: 26:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:26:45: 26:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:26:50: 26:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:26:51: 26:53 (#3) }] Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }] -#![feature /* 0#0 */(prelude_import)] +#![feature /* 0#0 */(prelude_import /* 0#0 */)] //@ aux-build:make-macro.rs //@ proc-macro: meta-macro.rs //@ edition:2018 @@ -30,7 +30,8 @@ macro_rules! produce_it */ { () => { - meta_macro::print_def_site!($crate::dummy!()); + meta_macro /* 0#0 */::print_def_site /* 0#0 + */!($crate /* 0#0 */::dummy /* 0#0 */!()); // `print_def_site!` will respan the `$crate` identifier // with `Span::def_site()`. This should cause it to resolve // relative to `meta_macro`, *not* `make_macro` (despite diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index e45abab03b4c4..61b55782e6e9d 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -20,7 +20,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nonterminal-token-hygiene.rs:23:27: 23:32 (#4), }, ] -#![feature /* 0#0 */(prelude_import)] +#![feature /* 0#0 */(prelude_import /* 0#0 */)] #![no_std /* 0#0 */] // Make sure that marks from declarative macros are applied to tokens in nonterminal. @@ -34,7 +34,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ //@ proc-macro: test-macros.rs //@ edition: 2015 -#![feature /* 0#0 */(decl_macro)] +#![feature /* 0#0 */(decl_macro /* 0#0 */)] #![no_std /* 0#0 */] extern crate core /* 0#2 */; #[prelude_import /* 0#1 */] @@ -49,15 +49,22 @@ macro_rules! outer /* 0#0 */ { - ($item:item) => + ($item /* 0#0 */:item /* 0#0 */) => { - macro inner() { print_bang! { $item } } inner!(); + macro /* 0#0 */ inner /* 0#0 */() + { print_bang /* 0#0 */! { $item /* 0#0 */ } } inner /* 0#0 + */!(); }; } struct S /* 0#0 */; -macro inner /* 0#3 */ { () => { print_bang! { struct S; } } } +macro inner + /* + 0#3 + */ { + () => { print_bang /* 0#3 */! { struct /* 0#0 */ S /* 0#0 */; } } +} struct S /* 0#5 */; // OK, not a duplicate definition of `S` From bf6db4f345799e1f922b3109a7278d8be11f3058 Mon Sep 17 00:00:00 2001 From: "Andrew V. Teylu" Date: Tue, 3 Mar 2026 13:06:55 +0000 Subject: [PATCH 05/33] Add regression tests for token hygiene annotations in macro bodies Add `unpretty-debug-shadow` test covering macro body tokens that reference a shadowed variable, and simplify the `unpretty-debug-metavars` test macro. Signed-off-by: Andrew V. Teylu --- tests/ui/hygiene/unpretty-debug-metavars.rs | 7 +++-- .../ui/hygiene/unpretty-debug-metavars.stdout | 7 +++-- tests/ui/hygiene/unpretty-debug-shadow.rs | 20 +++++++++++++ tests/ui/hygiene/unpretty-debug-shadow.stdout | 30 +++++++++++++++++++ 4 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 tests/ui/hygiene/unpretty-debug-shadow.rs create mode 100644 tests/ui/hygiene/unpretty-debug-shadow.stdout diff --git a/tests/ui/hygiene/unpretty-debug-metavars.rs b/tests/ui/hygiene/unpretty-debug-metavars.rs index a0c47bec3ccf7..41bf75cd0d98b 100644 --- a/tests/ui/hygiene/unpretty-debug-metavars.rs +++ b/tests/ui/hygiene/unpretty-debug-metavars.rs @@ -1,9 +1,10 @@ //@ check-pass //@ compile-flags: -Zunpretty=expanded,hygiene -// Regression test: metavar parameters in macro-generated macro_rules! -// definitions should have hygiene annotations so that textually identical -// `$marg` bindings are distinguishable by their syntax contexts. +// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, metavar parameters in macro-generated macro_rules! definitions +// were missing hygiene annotations, making identical `$marg` bindings +// indistinguishable. // Don't break whenever Symbol numbering changes //@ normalize-stdout: "\d+#" -> "0#" diff --git a/tests/ui/hygiene/unpretty-debug-metavars.stdout b/tests/ui/hygiene/unpretty-debug-metavars.stdout index 307c5e1b8de97..89658bc909a13 100644 --- a/tests/ui/hygiene/unpretty-debug-metavars.stdout +++ b/tests/ui/hygiene/unpretty-debug-metavars.stdout @@ -1,9 +1,10 @@ //@ check-pass //@ compile-flags: -Zunpretty=expanded,hygiene -// Regression test: metavar parameters in macro-generated macro_rules! -// definitions should have hygiene annotations so that textually identical -// `$marg` bindings are distinguishable by their syntax contexts. +// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, metavar parameters in macro-generated macro_rules! definitions +// were missing hygiene annotations, making identical `$marg` bindings +// indistinguishable. // Don't break whenever Symbol numbering changes //@ normalize-stdout: "\d+#" -> "0#" diff --git a/tests/ui/hygiene/unpretty-debug-shadow.rs b/tests/ui/hygiene/unpretty-debug-shadow.rs new file mode 100644 index 0000000000000..2aa68c8aec110 --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-shadow.rs @@ -0,0 +1,20 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, tokens in macro_rules! bodies were missing hygiene annotations, +// making it impossible to see how a macro's reference to a shadowed variable +// is distinguished from the shadowing binding. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature(no_core)] +#![no_core] + +fn f() { + let x = 0; + macro_rules! use_x { () => { x }; } + let x = 1; + use_x!(); +} diff --git a/tests/ui/hygiene/unpretty-debug-shadow.stdout b/tests/ui/hygiene/unpretty-debug-shadow.stdout new file mode 100644 index 0000000000000..36076b6a968fe --- /dev/null +++ b/tests/ui/hygiene/unpretty-debug-shadow.stdout @@ -0,0 +1,30 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded,hygiene + +// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene +// Previously, tokens in macro_rules! bodies were missing hygiene annotations, +// making it impossible to see how a macro's reference to a shadowed variable +// is distinguished from the shadowing binding. + +// Don't break whenever Symbol numbering changes +//@ normalize-stdout: "\d+#" -> "0#" + +#![feature /* 0#0 */(no_core /* 0#0 */)] +#![no_core /* 0#0 */] + +fn f /* 0#0 */() { + let x /* 0#0 */ = 0; + macro_rules! use_x /* 0#0 */ { () => { x /* 0#0 */ }; } + let x /* 0#0 */ = 1; + x /* 0#1 */; +} + +/* +Expansions: +crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "use_x") + +SyntaxContexts: +#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) +#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque) +*/ From ce2de643fc94a687f8fc2ba89495fa754bd87624 Mon Sep 17 00:00:00 2001 From: "LevitatingBusinessMan (Rein Fernhout)" Date: Tue, 10 Mar 2026 19:21:19 +0100 Subject: [PATCH 06/33] assign mpsc_is_disconnected issue 153668 --- library/std/src/sync/mpsc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index 2abf7bfe341d4..a1c49bb83010c 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -626,7 +626,7 @@ impl Sender { /// drop(rx); /// assert!(tx.is_disconnected()); /// ``` - #[unstable(feature = "mpsc_is_disconnected", issue = "none")] + #[unstable(feature = "mpsc_is_disconnected", issue = "153668")] pub fn is_disconnected(&self) -> bool { self.inner.is_disconnected() } @@ -1080,7 +1080,7 @@ impl Receiver { /// drop(tx); /// assert!(rx.is_disconnected()); /// ``` - #[unstable(feature = "mpsc_is_disconnected", issue = "none")] + #[unstable(feature = "mpsc_is_disconnected", issue = "153668")] pub fn is_disconnected(&self) -> bool { self.inner.is_disconnected() } From b36ee95a648153c1f00c27e6e741e2eeb838d34a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 10 Mar 2026 17:06:59 -0700 Subject: [PATCH 07/33] ci: add runners for vanilla LLVM 22 Ubuntu 26.04 has `llvm-22` packages that we can test with. The `Dockerfile` is otherwise the same as the `llvm-21` runners. --- .../host-x86_64/x86_64-gnu-llvm-22/Dockerfile | 66 +++++++++++++++++++ src/ci/github-actions/jobs.yml | 25 +++++++ 2 files changed, 91 insertions(+) create mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile new file mode 100644 index 0000000000000..a22e8de90804f --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile @@ -0,0 +1,66 @@ +FROM ubuntu:26.04 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bzip2 \ + g++ \ + gcc-multilib \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-22-tools \ + llvm-22-dev \ + libedit-dev \ + libssl-dev \ + pkg-config \ + zlib1g-dev \ + xz-utils \ + nodejs \ + mingw-w64 \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install powershell (universal package) so we can test x.ps1 on Linux +# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep. +RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ + dpkg --ignore-depends=libicu72 -i powershell.deb && \ + rm -f powershell.deb + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# We are disabling CI LLVM since this builder is intentionally using a host +# LLVM, rather than the typical src/llvm-project LLVM. +ENV NO_DOWNLOAD_CI_LLVM 1 +ENV EXTERNAL_LLVM 1 + +# Using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-22 \ + --enable-llvm-link-shared \ + --set rust.randomize-layout=true \ + --set rust.thin-lto-import-instr-limit=10 + +COPY scripts/shared.sh /scripts/ + +COPY scripts/x86_64-gnu-llvm.sh /scripts/ +COPY scripts/x86_64-gnu-llvm2.sh /scripts/ +COPY scripts/x86_64-gnu-llvm3.sh /scripts/ +COPY scripts/stage_2_test_set1.sh /scripts/ +COPY scripts/stage_2_test_set2.sh /scripts/ + +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 0687d142a3504..fd4d6bdb3ba38 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -426,6 +426,31 @@ auto: DOCKER_SCRIPT: x86_64-gnu-llvm3.sh <<: *job-linux-4c + # The x86_64-gnu-llvm-22 job is split into multiple jobs to run tests in parallel. + # x86_64-gnu-llvm-22-1 skips tests that run in x86_64-gnu-llvm-22-{2,3}. + - name: x86_64-gnu-llvm-22-1 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-22 + DOCKER_SCRIPT: stage_2_test_set2.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-22-{1,3} + - name: x86_64-gnu-llvm-22-2 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-22 + DOCKER_SCRIPT: x86_64-gnu-llvm2.sh + <<: *job-linux-4c + + # Skip tests that run in x86_64-gnu-llvm-22-{1,2} + - name: x86_64-gnu-llvm-22-3 + env: + RUST_BACKTRACE: 1 + IMAGE: x86_64-gnu-llvm-22 + DOCKER_SCRIPT: x86_64-gnu-llvm3.sh + <<: *job-linux-4c + - name: x86_64-gnu-nopt <<: *job-linux-4c From b3b6627dbb183c9b3012f13ca1775eeaa92b3193 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Thu, 12 Mar 2026 19:55:48 -0700 Subject: [PATCH 08/33] Derive Macro Eq: link to more detailed documentation Match the other derive macros in the module (Ord, PartialEq, PartialOrd) by linking to the section in the trait documentation about how the derive macro works. --- library/core/src/cmp.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index b3dc435dda176..49d7487c2803b 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -357,6 +357,7 @@ pub const trait Eq: [const] PartialEq + PointeeSized { } /// Derive macro generating an impl of the trait [`Eq`]. +/// The behavior of this macro is described in detail [here](Eq#derivable). #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics, derive_eq_internals, structural_match)] From 6e7d6d78217f0311ed37d67ec85119020a1e847d Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 12 Mar 2026 16:43:36 +0100 Subject: [PATCH 09/33] Add `Wake` diagnostic item for `alloc::task::Wake` --- library/alloc/src/task.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index aa1901314e37c..bc668f78bf740 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -87,6 +87,7 @@ use crate::sync::Arc; /// ``` #[cfg(target_has_atomic = "ptr")] #[stable(feature = "wake_trait", since = "1.51.0")] +#[rustc_diagnostic_item = "Wake"] pub trait Wake { /// Wake this task. #[stable(feature = "wake_trait", since = "1.51.0")] From 02ac1909090fa115fef35fa454cdad80839d19f0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 31 Jan 2026 02:10:07 -0600 Subject: [PATCH 10/33] dec2flt: Rename `Integer` to `Int` This is more consistent with what the trait is called elsewhere in tree (specifically compiler-builtins and test-float-parse). --- library/core/src/num/imp/dec2flt/float.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/imp/dec2flt/float.rs b/library/core/src/num/imp/dec2flt/float.rs index 21aabdc8addb4..1ccc50fde5904 100644 --- a/library/core/src/num/imp/dec2flt/float.rs +++ b/library/core/src/num/imp/dec2flt/float.rs @@ -12,7 +12,7 @@ pub trait CastInto: Copy { } /// Collection of traits that allow us to be generic over integer size. -pub trait Integer: +pub trait Int: Sized + Clone + Copy @@ -37,7 +37,7 @@ macro_rules! int { } } - impl Integer for $ty { + impl Int for $ty { const ZERO: Self = 0; const ONE: Self = 1; } @@ -68,7 +68,7 @@ pub trait RawFloat: + Debug { /// The unsigned integer with the same size as the float - type Int: Integer + Into; + type Int: Int + Into; /* general constants */ From b07c0439a4d2da5c67ab50ceff6415071049a474 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 31 Jan 2026 02:57:22 -0600 Subject: [PATCH 11/33] dec2flt: Split up the `RawFloat` trait `RawFloat` is currently used specifically for the implementation of the lemire algorithm, but it is useful for more than that. Split it into three different traits: * `Float`: Anything that is reasonably applicable to all floating point types. * `FloatExt`: Items that should be part of `Float` but don't work for all float types. This will eventually be merged back into `Float`. * `Lemire`: Items that are specific to the Lemire algorithm. --- library/core/src/num/imp/dec2flt/decimal.rs | 9 +- library/core/src/num/imp/dec2flt/float.rs | 161 ++++++++++-------- library/core/src/num/imp/dec2flt/lemire.rs | 4 +- library/core/src/num/imp/dec2flt/mod.rs | 6 +- library/core/src/num/imp/dec2flt/parse.rs | 4 +- library/core/src/num/imp/dec2flt/slow.rs | 4 +- library/core/src/num/imp/flt2dec/decoder.rs | 4 +- library/coretests/tests/num/dec2flt/float.rs | 95 ++++++----- library/coretests/tests/num/dec2flt/lemire.rs | 2 +- 9 files changed, 156 insertions(+), 133 deletions(-) diff --git a/library/core/src/num/imp/dec2flt/decimal.rs b/library/core/src/num/imp/dec2flt/decimal.rs index 27a53d4b9e75b..583f6bcf3302c 100644 --- a/library/core/src/num/imp/dec2flt/decimal.rs +++ b/library/core/src/num/imp/dec2flt/decimal.rs @@ -1,9 +1,8 @@ //! Representation of a float as the significant digits and exponent. -use dec2flt::float::RawFloat; -use dec2flt::fpu::set_precision; - use crate::num::imp::dec2flt; +use dec2flt::float::Lemire; +use dec2flt::fpu::set_precision; const INT_POW10: [u64; 16] = [ 1, @@ -36,7 +35,7 @@ pub struct Decimal { impl Decimal { /// Detect if the float can be accurately reconstructed from native floats. #[inline] - fn can_use_fast_path(&self) -> bool { + fn can_use_fast_path(&self) -> bool { F::MIN_EXPONENT_FAST_PATH <= self.exponent && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH && self.mantissa <= F::MAX_MANTISSA_FAST_PATH @@ -53,7 +52,7 @@ impl Decimal { /// /// There is an exception: disguised fast-path cases, where we can shift /// powers-of-10 from the exponent to the significant digits. - pub fn try_fast_path(&self) -> Option { + pub fn try_fast_path(&self) -> Option { // Here we need to work around . // The fast path crucially depends on arithmetic being rounded to the correct number of bits // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision diff --git a/library/core/src/num/imp/dec2flt/float.rs b/library/core/src/num/imp/dec2flt/float.rs index 1ccc50fde5904..da581a457f495 100644 --- a/library/core/src/num/imp/dec2flt/float.rs +++ b/library/core/src/num/imp/dec2flt/float.rs @@ -48,12 +48,8 @@ macro_rules! int { int!(u16, u32, u64); /// A helper trait to avoid duplicating basically all the conversion code for IEEE floats. -/// -/// See the parent module's doc comment for why this is necessary. -/// -/// Should **never ever** be implemented for other types or be used outside the `dec2flt` module. #[doc(hidden)] -pub trait RawFloat: +pub trait Float: Sized + Div + Neg @@ -128,8 +124,6 @@ pub trait RawFloat: const MIN_EXPONENT_ROUND_TO_EVEN: i32; const MAX_EXPONENT_ROUND_TO_EVEN: i32; - /* limits related to Fast pathing */ - /// Largest decimal exponent for a non-infinite value. /// /// This is the max exponent in binary converted to the max exponent in decimal. Allows fast @@ -151,41 +145,19 @@ pub trait RawFloat: /// compile time since intermediates exceed the range of an `f64`. const SMALLEST_POWER_OF_TEN: i32; - /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` - // assuming FLT_EVAL_METHOD = 0 - const MAX_EXPONENT_FAST_PATH: i64 = { - let log2_5 = f64::consts::LOG2_10 - 1.0; - (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 - }; - - /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` - const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; - - /// Maximum exponent that can be represented for a disguised-fast path case. - /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` - const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = - Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; - - /// Maximum mantissa for the fast-path (`1 << 53` for f64). - const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; - - /// Converts integer into float through an as cast. - /// This is only called in the fast-path algorithm, and therefore - /// will not lose precision, since the value will always have - /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. - fn from_u64(v: u64) -> Self; - - /// Performs a raw transmutation from an integer. - fn from_u64_bits(v: u64) -> Self; - - /// Gets a small power-of-ten for fast-path multiplication. - fn pow10_fast_path(exponent: usize) -> Self; - /// Returns the category that this number falls into. fn classify(self) -> FpCategory; /// Transmute to the integer representation fn to_bits(self) -> Self::Int; +} + +/// Items that ideally would be on `Float`, but don't apply to all float types because they +/// rely on the mantissa fitting into a `u64` (which isn't true for `f128`). +#[doc(hidden)] +pub trait FloatExt: Float { + /// Performs a raw transmutation from an integer. + fn from_u64_bits(v: u64) -> Self; /// Returns the mantissa, exponent and sign as integers. /// @@ -212,6 +184,41 @@ pub trait RawFloat: } } +/// Extension to `Float` that are necessary for parsing using the Lemire method. +/// +/// See the parent module's doc comment for why this is necessary. +/// +/// Not intended for use outside of the `dec2flt` module. +#[doc(hidden)] +pub trait Lemire: FloatExt { + /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` + // assuming FLT_EVAL_METHOD = 0 + const MAX_EXPONENT_FAST_PATH: i64 = { + let log2_5 = f64::consts::LOG2_10 - 1.0; + (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 + }; + + /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` + const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; + + /// Maximum exponent that can be represented for a disguised-fast path case. + /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` + const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = + Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; + + /// Maximum mantissa for the fast-path (`1 << 53` for f64). + const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; + + /// Gets a small power-of-ten for fast-path multiplication. + fn pow10_fast_path(exponent: usize) -> Self; + + /// Converts integer into float through an as cast. + /// This is only called in the fast-path algorithm, and therefore + /// will not lose precision, since the value will always have + /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. + fn from_u64(v: u64) -> Self; +} + /// Solve for `b` in `10^b = 2^a` const fn pow2_to_pow10(a: i64) -> i64 { let res = (a as f64) / f64::consts::LOG2_10; @@ -219,7 +226,7 @@ const fn pow2_to_pow10(a: i64) -> i64 { } #[cfg(target_has_reliable_f16)] -impl RawFloat for f16 { +impl Float for f16 { type Int = u16; const INFINITY: Self = Self::INFINITY; @@ -236,33 +243,39 @@ impl RawFloat for f16 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5; const SMALLEST_POWER_OF_TEN: i32 = -27; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ + fn to_bits(self) -> Self::Int { + self.to_bits() + } + + fn classify(self) -> FpCategory { + self.classify() } +} +#[cfg(target_has_reliable_f16)] +impl FloatExt for f16 { #[inline] fn from_u64_bits(v: u64) -> Self { Self::from_bits((v & 0xFFFF) as u16) } +} +#[cfg(target_has_reliable_f16)] +impl Lemire for f16 { fn pow10_fast_path(exponent: usize) -> Self { #[allow(clippy::use_self)] const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.]; TABLE[exponent & 7] } - fn to_bits(self) -> Self::Int { - self.to_bits() - } - - fn classify(self) -> FpCategory { - self.classify() + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ } } -impl RawFloat for f32 { +impl Float for f32 { type Int = u32; const INFINITY: Self = f32::INFINITY; @@ -279,17 +292,23 @@ impl RawFloat for f32 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10; const SMALLEST_POWER_OF_TEN: i32 = -65; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ + fn to_bits(self) -> Self::Int { + self.to_bits() } + fn classify(self) -> FpCategory { + self.classify() + } +} + +impl FloatExt for f32 { #[inline] fn from_u64_bits(v: u64) -> Self { f32::from_bits((v & 0xFFFFFFFF) as u32) } +} +impl Lemire for f32 { fn pow10_fast_path(exponent: usize) -> Self { #[allow(clippy::use_self)] const TABLE: [f32; 16] = @@ -297,16 +316,14 @@ impl RawFloat for f32 { TABLE[exponent & 15] } - fn to_bits(self) -> Self::Int { - self.to_bits() - } - - fn classify(self) -> FpCategory { - self.classify() + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ } } -impl RawFloat for f64 { +impl Float for f64 { type Int = u64; const INFINITY: Self = Self::INFINITY; @@ -323,17 +340,23 @@ impl RawFloat for f64 { const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23; const SMALLEST_POWER_OF_TEN: i32 = -342; - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ + fn to_bits(self) -> Self::Int { + self.to_bits() } + fn classify(self) -> FpCategory { + self.classify() + } +} + +impl FloatExt for f64 { #[inline] fn from_u64_bits(v: u64) -> Self { f64::from_bits(v) } +} +impl Lemire for f64 { fn pow10_fast_path(exponent: usize) -> Self { const TABLE: [f64; 32] = [ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, @@ -342,11 +365,9 @@ impl RawFloat for f64 { TABLE[exponent & 31] } - fn to_bits(self) -> Self::Int { - self.to_bits() - } - - fn classify(self) -> FpCategory { - self.classify() + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ } } diff --git a/library/core/src/num/imp/dec2flt/lemire.rs b/library/core/src/num/imp/dec2flt/lemire.rs index c3f2723509d05..8a97618cf7385 100644 --- a/library/core/src/num/imp/dec2flt/lemire.rs +++ b/library/core/src/num/imp/dec2flt/lemire.rs @@ -1,7 +1,7 @@ //! Implementation of the Eisel-Lemire algorithm. use dec2flt::common::BiasedFp; -use dec2flt::float::RawFloat; +use dec2flt::float::Float; use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE}; use crate::num::imp::dec2flt; @@ -24,7 +24,7 @@ use crate::num::imp::dec2flt; /// at a Gigabyte per Second" in section 5, "Fast Algorithm", and /// section 6, "Exact Numbers And Ties", available online: /// . -pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { +pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { let fp_zero = BiasedFp::zero_pow2(0); let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER); let fp_error = BiasedFp::zero_pow2(-1); diff --git a/library/core/src/num/imp/dec2flt/mod.rs b/library/core/src/num/imp/dec2flt/mod.rs index 3f5724add62bb..33e606694bc3e 100644 --- a/library/core/src/num/imp/dec2flt/mod.rs +++ b/library/core/src/num/imp/dec2flt/mod.rs @@ -88,7 +88,7 @@ )] use common::BiasedFp; -use float::RawFloat; +use float::{FloatExt, Lemire}; use lemire::compute_float; use parse::{parse_inf_nan, parse_number}; use slow::parse_long_mantissa; @@ -120,7 +120,7 @@ pub fn pfe_invalid() -> ParseFloatError { } /// Converts a `BiasedFp` to the closest machine float type. -fn biased_fp_to_float(x: BiasedFp) -> F { +fn biased_fp_to_float(x: BiasedFp) -> F { let mut word = x.m; word |= (x.p_biased as u64) << F::SIG_BITS; F::from_u64_bits(word) @@ -128,7 +128,7 @@ fn biased_fp_to_float(x: BiasedFp) -> F { /// Converts a decimal string into a floating point number. #[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above -pub fn dec2flt(s: &str) -> Result { +pub fn dec2flt(s: &str) -> Result { let mut s = s.as_bytes(); let Some(&c) = s.first() else { return Err(pfe_empty()) }; let negative = c == b'-'; diff --git a/library/core/src/num/imp/dec2flt/parse.rs b/library/core/src/num/imp/dec2flt/parse.rs index e4049bc164c61..e4e3e5bc0c0e3 100644 --- a/library/core/src/num/imp/dec2flt/parse.rs +++ b/library/core/src/num/imp/dec2flt/parse.rs @@ -2,7 +2,7 @@ use dec2flt::common::{ByteSlice, is_8digits}; use dec2flt::decimal::Decimal; -use dec2flt::float::RawFloat; +use dec2flt::float::Float; use crate::num::imp::dec2flt; @@ -197,7 +197,7 @@ pub fn parse_number(s: &[u8]) -> Option { } /// Try to parse a special, non-finite float. -pub(crate) fn parse_inf_nan(s: &[u8], negative: bool) -> Option { +pub(crate) fn parse_inf_nan(s: &[u8], negative: bool) -> Option { // Since a valid string has at most the length 8, we can load // all relevant characters into a u64 and work from there. // This also generates much better code. diff --git a/library/core/src/num/imp/dec2flt/slow.rs b/library/core/src/num/imp/dec2flt/slow.rs index 089b12f5be22e..784f3e00f5b48 100644 --- a/library/core/src/num/imp/dec2flt/slow.rs +++ b/library/core/src/num/imp/dec2flt/slow.rs @@ -2,7 +2,7 @@ use dec2flt::common::BiasedFp; use dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; -use dec2flt::float::RawFloat; +use dec2flt::float::Float; use crate::num::imp::dec2flt; @@ -25,7 +25,7 @@ use crate::num::imp::dec2flt; /// /// The algorithms described here are based on "Processing Long Numbers Quickly", /// available here: . -pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { +pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { const MAX_SHIFT: usize = 60; const NUM_POWERS: usize = 19; const POWERS: [u8; 19] = diff --git a/library/core/src/num/imp/flt2dec/decoder.rs b/library/core/src/num/imp/flt2dec/decoder.rs index 3d6ad6608efe3..6f8fb2b954f3a 100644 --- a/library/core/src/num/imp/flt2dec/decoder.rs +++ b/library/core/src/num/imp/flt2dec/decoder.rs @@ -1,7 +1,7 @@ //! Decodes a floating-point value into individual parts and error ranges. use crate::num::FpCategory; -use crate::num::imp::dec2flt::float::RawFloat; +use crate::num::imp::dec2flt::float::FloatExt; /// Decoded unsigned finite value, such that: /// @@ -40,7 +40,7 @@ pub enum FullDecoded { } /// A floating point type which can be `decode`d. -pub trait DecodableFloat: RawFloat + Copy { +pub trait DecodableFloat: FloatExt + Copy { /// The minimum positive normalized value. fn min_pos_norm_value() -> Self; } diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index 25e12435b4728..aa4c59dd66ea0 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -1,4 +1,4 @@ -use core::num::imp::dec2flt::float::RawFloat; +use core::num::imp::dec2flt::float::{Float, FloatExt, Lemire}; use crate::num::{ldexp_f32, ldexp_f64}; @@ -56,57 +56,60 @@ fn test_f64_integer_decode() { #[test] #[cfg(target_has_reliable_f16)] fn test_f16_consts() { - assert_eq!(::INFINITY, f16::INFINITY); - assert_eq!(::NEG_INFINITY, -f16::INFINITY); - assert_eq!(::NAN.to_bits(), f16::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f16::NAN).to_bits()); - assert_eq!(::SIG_BITS, 10); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -22); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 5); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -4); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 4); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 7); - assert_eq!(::EXP_MIN, -14); - assert_eq!(::EXP_SAT, 0x1f); - assert_eq!(::SMALLEST_POWER_OF_TEN, -27); - assert_eq!(::LARGEST_POWER_OF_TEN, 4); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 2048); + assert_eq!(::INFINITY, f16::INFINITY); + assert_eq!(::NEG_INFINITY, -f16::INFINITY); + assert_eq!(::NAN.to_bits(), f16::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f16::NAN).to_bits()); + assert_eq!(::SIG_BITS, 10); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -22); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 5); + assert_eq!(::EXP_MIN, -14); + assert_eq!(::EXP_SAT, 0x1f); + assert_eq!(::SMALLEST_POWER_OF_TEN, -27); + assert_eq!(::LARGEST_POWER_OF_TEN, 4); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -4); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 4); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 7); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 2048); } #[test] fn test_f32_consts() { - assert_eq!(::INFINITY, f32::INFINITY); - assert_eq!(::NEG_INFINITY, -f32::INFINITY); - assert_eq!(::NAN.to_bits(), f32::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f32::NAN).to_bits()); - assert_eq!(::SIG_BITS, 23); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -17); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 10); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -10); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 10); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 17); - assert_eq!(::EXP_MIN, -126); - assert_eq!(::EXP_SAT, 0xff); - assert_eq!(::SMALLEST_POWER_OF_TEN, -65); - assert_eq!(::LARGEST_POWER_OF_TEN, 38); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 16777216); + assert_eq!(::INFINITY, f32::INFINITY); + assert_eq!(::NEG_INFINITY, -f32::INFINITY); + assert_eq!(::NAN.to_bits(), f32::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f32::NAN).to_bits()); + assert_eq!(::SIG_BITS, 23); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -17); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 10); + assert_eq!(::EXP_MIN, -126); + assert_eq!(::EXP_SAT, 0xff); + assert_eq!(::SMALLEST_POWER_OF_TEN, -65); + assert_eq!(::LARGEST_POWER_OF_TEN, 38); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -10); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 10); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 17); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 16777216); } #[test] fn test_f64_consts() { - assert_eq!(::INFINITY, f64::INFINITY); - assert_eq!(::NEG_INFINITY, -f64::INFINITY); - assert_eq!(::NAN.to_bits(), f64::NAN.to_bits()); - assert_eq!(::NEG_NAN.to_bits(), (-f64::NAN).to_bits()); - assert_eq!(::SIG_BITS, 52); - assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -4); - assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 23); - assert_eq!(::MIN_EXPONENT_FAST_PATH, -22); - assert_eq!(::MAX_EXPONENT_FAST_PATH, 22); - assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 37); - assert_eq!(::EXP_MIN, -1022); - assert_eq!(::EXP_SAT, 0x7ff); - assert_eq!(::SMALLEST_POWER_OF_TEN, -342); - assert_eq!(::LARGEST_POWER_OF_TEN, 308); - assert_eq!(::MAX_MANTISSA_FAST_PATH, 9007199254740992); + assert_eq!(::INFINITY, f64::INFINITY); + assert_eq!(::NEG_INFINITY, -f64::INFINITY); + assert_eq!(::NAN.to_bits(), f64::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f64::NAN).to_bits()); + assert_eq!(::SIG_BITS, 52); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -4); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 23); + assert_eq!(::EXP_MIN, -1022); + assert_eq!(::EXP_SAT, 0x7ff); + assert_eq!(::SMALLEST_POWER_OF_TEN, -342); + assert_eq!(::LARGEST_POWER_OF_TEN, 308); + + assert_eq!(::MIN_EXPONENT_FAST_PATH, -22); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 22); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 37); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 9007199254740992); } diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs index e4ce533ba44da..6679dca148aa6 100644 --- a/library/coretests/tests/num/dec2flt/lemire.rs +++ b/library/coretests/tests/num/dec2flt/lemire.rs @@ -1,6 +1,6 @@ use core::num::imp::dec2flt; -use dec2flt::float::RawFloat; +use dec2flt::float::Float; use dec2flt::lemire::compute_float; #[cfg(target_has_reliable_f16)] From bec94a33d541667abb706e8bab4dc791e64e87cc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 31 Jan 2026 03:13:08 -0600 Subject: [PATCH 12/33] dec2flt: Move internal traits to better locations `Float` and `FloatExt` are already used by both parsing and printing, so move them out of `dec2flt` to a new module in `num::imp`. `Int` `Cast` have the potential to be used more places in the future, so move them there as well. `Lemire` is the only remaining trait; since it is small, move it into the `dec2flt` root. The `fmt::LowerExp` bound is removed from `Float` here since the trait is moving into a module without `#[cfg(not(no_fp_fmt_parse))]` and it isn't implemented with that config (it's not easily possible to add `cfg` attributes to a single supertrait, unfortunately). This isn't a problem since it isn't actually being used. --- library/core/src/num/imp/dec2flt/decimal.rs | 5 +- library/core/src/num/imp/dec2flt/lemire.rs | 3 +- library/core/src/num/imp/dec2flt/mod.rs | 90 ++++++++++++++- library/core/src/num/imp/dec2flt/parse.rs | 3 +- library/core/src/num/imp/dec2flt/slow.rs | 3 +- library/core/src/num/imp/flt2dec/decoder.rs | 2 +- library/core/src/num/imp/mod.rs | 3 + .../num/imp/{dec2flt/float.rs => traits.rs} | 106 +++--------------- library/coretests/tests/lib.rs | 1 + library/coretests/tests/num/dec2flt/float.rs | 3 +- library/coretests/tests/num/dec2flt/lemire.rs | 3 +- 11 files changed, 113 insertions(+), 109 deletions(-) rename library/core/src/num/imp/{dec2flt/float.rs => traits.rs} (74%) diff --git a/library/core/src/num/imp/dec2flt/decimal.rs b/library/core/src/num/imp/dec2flt/decimal.rs index 583f6bcf3302c..c9b0cc531b386 100644 --- a/library/core/src/num/imp/dec2flt/decimal.rs +++ b/library/core/src/num/imp/dec2flt/decimal.rs @@ -1,9 +1,10 @@ //! Representation of a float as the significant digits and exponent. -use crate::num::imp::dec2flt; -use dec2flt::float::Lemire; +use dec2flt::Lemire; use dec2flt::fpu::set_precision; +use crate::num::imp::dec2flt; + const INT_POW10: [u64; 16] = [ 1, 10, diff --git a/library/core/src/num/imp/dec2flt/lemire.rs b/library/core/src/num/imp/dec2flt/lemire.rs index 8a97618cf7385..f89d16c843477 100644 --- a/library/core/src/num/imp/dec2flt/lemire.rs +++ b/library/core/src/num/imp/dec2flt/lemire.rs @@ -1,10 +1,9 @@ //! Implementation of the Eisel-Lemire algorithm. use dec2flt::common::BiasedFp; -use dec2flt::float::Float; use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE}; -use crate::num::imp::dec2flt; +use crate::num::imp::{Float, dec2flt}; /// Compute w * 10^q using an extended-precision float representation. /// diff --git a/library/core/src/num/imp/dec2flt/mod.rs b/library/core/src/num/imp/dec2flt/mod.rs index 33e606694bc3e..76b8d416ee0f1 100644 --- a/library/core/src/num/imp/dec2flt/mod.rs +++ b/library/core/src/num/imp/dec2flt/mod.rs @@ -88,24 +88,104 @@ )] use common::BiasedFp; -use float::{FloatExt, Lemire}; use lemire::compute_float; use parse::{parse_inf_nan, parse_number}; use slow::parse_long_mantissa; +use crate::f64; use crate::num::ParseFloatError; use crate::num::float_parse::FloatErrorKind; +use crate::num::imp::FloatExt; mod common; pub mod decimal; pub mod decimal_seq; mod fpu; -mod slow; -mod table; -// float is used in flt2dec, and all are used in unit tests. -pub mod float; pub mod lemire; pub mod parse; +mod slow; +mod table; + +/// Extension to `Float` that are necessary for parsing using the Lemire method. +/// +/// See the parent module's doc comment for why this is necessary. +/// +/// Not intended for use outside of the `dec2flt` module. +#[doc(hidden)] +pub trait Lemire: FloatExt { + /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` + // assuming FLT_EVAL_METHOD = 0 + const MAX_EXPONENT_FAST_PATH: i64 = { + let log2_5 = f64::consts::LOG2_10 - 1.0; + (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 + }; + + /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` + const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; + + /// Maximum exponent that can be represented for a disguised-fast path case. + /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` + const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = + Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; + + /// Maximum mantissa for the fast-path (`1 << 53` for f64). + const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; + + /// Gets a small power-of-ten for fast-path multiplication. + fn pow10_fast_path(exponent: usize) -> Self; + + /// Converts integer into float through an as cast. + /// This is only called in the fast-path algorithm, and therefore + /// will not lose precision, since the value will always have + /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. + fn from_u64(v: u64) -> Self; +} + +#[cfg(target_has_reliable_f16)] +impl Lemire for f16 { + fn pow10_fast_path(exponent: usize) -> Self { + #[allow(clippy::use_self)] + const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.]; + TABLE[exponent & 7] + } + + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } +} + +impl Lemire for f32 { + fn pow10_fast_path(exponent: usize) -> Self { + #[allow(clippy::use_self)] + const TABLE: [f32; 16] = + [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.]; + TABLE[exponent & 15] + } + + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } +} + +impl Lemire for f64 { + fn pow10_fast_path(exponent: usize) -> Self { + const TABLE: [f64; 32] = [ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, + 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0., + ]; + TABLE[exponent & 31] + } + + #[inline] + fn from_u64(v: u64) -> Self { + debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); + v as _ + } +} #[inline] pub(super) fn pfe_empty() -> ParseFloatError { diff --git a/library/core/src/num/imp/dec2flt/parse.rs b/library/core/src/num/imp/dec2flt/parse.rs index e4e3e5bc0c0e3..ee55eadbc7b9e 100644 --- a/library/core/src/num/imp/dec2flt/parse.rs +++ b/library/core/src/num/imp/dec2flt/parse.rs @@ -2,9 +2,8 @@ use dec2flt::common::{ByteSlice, is_8digits}; use dec2flt::decimal::Decimal; -use dec2flt::float::Float; -use crate::num::imp::dec2flt; +use crate::num::imp::{Float, dec2flt}; const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000; diff --git a/library/core/src/num/imp/dec2flt/slow.rs b/library/core/src/num/imp/dec2flt/slow.rs index 784f3e00f5b48..f1b2525cf38e6 100644 --- a/library/core/src/num/imp/dec2flt/slow.rs +++ b/library/core/src/num/imp/dec2flt/slow.rs @@ -2,9 +2,8 @@ use dec2flt::common::BiasedFp; use dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; -use dec2flt::float::Float; -use crate::num::imp::dec2flt; +use crate::num::imp::{Float, dec2flt}; /// Parse the significant digits and biased, binary exponent of a float. /// diff --git a/library/core/src/num/imp/flt2dec/decoder.rs b/library/core/src/num/imp/flt2dec/decoder.rs index 6f8fb2b954f3a..5ccc91f4c9faf 100644 --- a/library/core/src/num/imp/flt2dec/decoder.rs +++ b/library/core/src/num/imp/flt2dec/decoder.rs @@ -1,7 +1,7 @@ //! Decodes a floating-point value into individual parts and error ranges. use crate::num::FpCategory; -use crate::num::imp::dec2flt::float::FloatExt; +use crate::num::imp::FloatExt; /// Decoded unsigned finite value, such that: /// diff --git a/library/core/src/num/imp/mod.rs b/library/core/src/num/imp/mod.rs index d35409f91bde9..6fccfd1c238ed 100644 --- a/library/core/src/num/imp/mod.rs +++ b/library/core/src/num/imp/mod.rs @@ -16,3 +16,6 @@ pub(crate) mod int_log10; pub(crate) mod int_sqrt; pub(crate) mod libm; pub(crate) mod overflow_panic; +mod traits; + +pub use traits::{Float, FloatExt, Int}; diff --git a/library/core/src/num/imp/dec2flt/float.rs b/library/core/src/num/imp/traits.rs similarity index 74% rename from library/core/src/num/imp/dec2flt/float.rs rename to library/core/src/num/imp/traits.rs index da581a457f495..7b84f7a4a5aa2 100644 --- a/library/core/src/num/imp/dec2flt/float.rs +++ b/library/core/src/num/imp/traits.rs @@ -1,10 +1,14 @@ -//! Helper trait for generic float types. +//! Numeric traits used for internal implementations. -use core::f64; +#![doc(hidden)] +#![unstable( + feature = "num_internals", + reason = "internal routines only exposed for testing", + issue = "none" +)] -use crate::fmt::{Debug, LowerExp}; use crate::num::FpCategory; -use crate::ops::{self, Add, Div, Mul, Neg}; +use crate::{f64, fmt, ops}; /// Lossy `as` casting between two types. pub trait CastInto: Copy { @@ -16,7 +20,7 @@ pub trait Int: Sized + Clone + Copy - + Debug + + fmt::Debug + ops::Shr + ops::Shl + ops::BitAnd @@ -51,17 +55,16 @@ int!(u16, u32, u64); #[doc(hidden)] pub trait Float: Sized - + Div - + Neg - + Mul - + Add - + LowerExp + + ops::Div + + ops::Neg + + ops::Mul + + ops::Add + + fmt::Debug + PartialEq + PartialOrd + Default + Clone + Copy - + Debug { /// The unsigned integer with the same size as the float type Int: Int + Into; @@ -184,41 +187,6 @@ pub trait FloatExt: Float { } } -/// Extension to `Float` that are necessary for parsing using the Lemire method. -/// -/// See the parent module's doc comment for why this is necessary. -/// -/// Not intended for use outside of the `dec2flt` module. -#[doc(hidden)] -pub trait Lemire: FloatExt { - /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` - // assuming FLT_EVAL_METHOD = 0 - const MAX_EXPONENT_FAST_PATH: i64 = { - let log2_5 = f64::consts::LOG2_10 - 1.0; - (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 - }; - - /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` - const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; - - /// Maximum exponent that can be represented for a disguised-fast path case. - /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` - const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = - Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; - - /// Maximum mantissa for the fast-path (`1 << 53` for f64). - const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; - - /// Gets a small power-of-ten for fast-path multiplication. - fn pow10_fast_path(exponent: usize) -> Self; - - /// Converts integer into float through an as cast. - /// This is only called in the fast-path algorithm, and therefore - /// will not lose precision, since the value will always have - /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH. - fn from_u64(v: u64) -> Self; -} - /// Solve for `b` in `10^b = 2^a` const fn pow2_to_pow10(a: i64) -> i64 { let res = (a as f64) / f64::consts::LOG2_10; @@ -260,21 +228,6 @@ impl FloatExt for f16 { } } -#[cfg(target_has_reliable_f16)] -impl Lemire for f16 { - fn pow10_fast_path(exponent: usize) -> Self { - #[allow(clippy::use_self)] - const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.]; - TABLE[exponent & 7] - } - - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } -} - impl Float for f32 { type Int = u32; @@ -308,21 +261,6 @@ impl FloatExt for f32 { } } -impl Lemire for f32 { - fn pow10_fast_path(exponent: usize) -> Self { - #[allow(clippy::use_self)] - const TABLE: [f32; 16] = - [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.]; - TABLE[exponent & 15] - } - - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } -} - impl Float for f64 { type Int = u64; @@ -355,19 +293,3 @@ impl FloatExt for f64 { f64::from_bits(v) } } - -impl Lemire for f64 { - fn pow10_fast_path(exponent: usize) -> Self { - const TABLE: [f64; 32] = [ - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, - 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0., - ]; - TABLE[exponent & 31] - } - - #[inline] - fn from_u64(v: u64) -> Self { - debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH); - v as _ - } -} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 72112f8b01133..b3fd53cbb9dce 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -88,6 +88,7 @@ #![feature(next_index)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(nonzero_from_str_radix)] +#![feature(num_internals)] #![feature(numfmt)] #![feature(one_sided_range)] #![feature(panic_internals)] diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index aa4c59dd66ea0..0713c5c651fb3 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -1,4 +1,5 @@ -use core::num::imp::dec2flt::float::{Float, FloatExt, Lemire}; +use core::num::imp::dec2flt::Lemire; +use core::num::imp::{Float, FloatExt}; use crate::num::{ldexp_f32, ldexp_f64}; diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs index 6679dca148aa6..e5a7ae346f425 100644 --- a/library/coretests/tests/num/dec2flt/lemire.rs +++ b/library/coretests/tests/num/dec2flt/lemire.rs @@ -1,6 +1,5 @@ -use core::num::imp::dec2flt; +use core::num::imp::{Float, dec2flt}; -use dec2flt::float::Float; use dec2flt::lemire::compute_float; #[cfg(target_has_reliable_f16)] From 24d86b5f2b69665d6b6c0868239e37da221f2e19 Mon Sep 17 00:00:00 2001 From: Bhavya Gautam Date: Tue, 3 Mar 2026 06:35:43 +0000 Subject: [PATCH 13/33] Fix rust build failure for vxworks --- library/std/build.rs | 24 +++++++++++++++ library/std/src/os/vxworks/fs.rs | 30 +++++++++++++++++++ library/std/src/sys/fs/unix.rs | 18 ++++++++--- src/doc/rustc/src/platform-support/vxworks.md | 6 ++++ 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/library/std/build.rs b/library/std/build.rs index c0a6e30b38082..5f2e441bf7d83 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -79,4 +79,28 @@ fn main() { println!("cargo:rustc-cfg=backtrace_in_libstd"); println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap()); + + println!("cargo:rustc-check-cfg=cfg(vxworks_lt_25_09)"); + + if target_os == "vxworks" { + match vxworks_version_code() { + Some((major, minor)) if (major, minor) < (25, 9) => { + println!("cargo:rustc-cfg=vxworks_lt_25_09"); + } + _ => {} + } + } +} + +/// Retrieve the VxWorks release version from the environment variable set by the VxWorks build +/// environment, in `(minor, patch)` form. +fn vxworks_version_code() -> Option<(u32, u32)> { + let version = env::var("WIND_RELEASE_ID").ok()?; + + let mut pieces = version.trim().split(['.']); + + let major: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + let minor: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0); + + Some((major, minor)) } diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs index b88ed19b067a5..a21748ce9fe00 100644 --- a/library/std/src/os/vxworks/fs.rs +++ b/library/std/src/os/vxworks/fs.rs @@ -69,24 +69,54 @@ impl MetadataExt for Metadata { fn st_size(&self) -> u64 { self.as_inner().as_inner().st_size as u64 } + #[cfg(vxworks_lt_25_09)] fn st_atime(&self) -> i64 { self.as_inner().as_inner().st_atime as i64 } + #[cfg(not(vxworks_lt_25_09))] + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_sec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_atime_nsec(&self) -> i64 { 0 } + #[cfg(not(vxworks_lt_25_09))] + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_nsec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_mtime(&self) -> i64 { self.as_inner().as_inner().st_mtime as i64 } + #[cfg(not(vxworks_lt_25_09))] + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_sec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_mtime_nsec(&self) -> i64 { 0 } + #[cfg(not(vxworks_lt_25_09))] + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_nsec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_ctime(&self) -> i64 { self.as_inner().as_inner().st_ctime as i64 } + #[cfg(not(vxworks_lt_25_09))] + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_sec as i64 + } + #[cfg(vxworks_lt_25_09)] fn st_ctime_nsec(&self) -> i64 { 0 } + #[cfg(not(vxworks_lt_25_09))] + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_nsec as i64 + } fn st_blksize(&self) -> u64 { self.as_inner().as_inner().st_blksize as u64 } diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 7db474544f04a..2a8571871b732 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -634,7 +634,7 @@ impl FileAttr { } #[cfg(any( - target_os = "vxworks", + all(target_os = "vxworks", vxworks_lt_25_09), target_os = "espidf", target_os = "vita", target_os = "rtems", @@ -643,7 +643,12 @@ impl FileAttr { SystemTime::new(self.stat.st_mtime as i64, 0) } - #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))] + #[cfg(any( + target_os = "horizon", + target_os = "hurd", + target_os = "nuttx", + all(target_os = "vxworks", not(vxworks_lt_25_09)) + ))] pub fn modified(&self) -> io::Result { SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64) } @@ -669,7 +674,7 @@ impl FileAttr { } #[cfg(any( - target_os = "vxworks", + all(target_os = "vxworks", vxworks_lt_25_09), target_os = "espidf", target_os = "vita", target_os = "rtems" @@ -678,7 +683,12 @@ impl FileAttr { SystemTime::new(self.stat.st_atime as i64, 0) } - #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))] + #[cfg(any( + target_os = "horizon", + target_os = "hurd", + target_os = "nuttx", + all(target_os = "vxworks", not(vxworks_lt_25_09)) + ))] pub fn accessed(&self) -> io::Result { SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64) } diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md index 091c757a2ee36..0cf3822f759e7 100644 --- a/src/doc/rustc/src/platform-support/vxworks.md +++ b/src/doc/rustc/src/platform-support/vxworks.md @@ -28,6 +28,12 @@ Target triplets available: The minimum supported version is VxWorks 7. +### Environment + +#### `WIND_RELEASE_ID` + +In VxWorks build environment, the environment variable `WIND_RELEASE_ID` indicates the VxWorks release version used for the build. The `WIND_RELEASE_ID` can be used to conditionally compile features/code or handle version specific behaviour. + ## Building Rust for each target can be cross-compiled with its specific target vsb configuration. Std support is added but not yet fully tested. From 7ec77fd4d5cb035b81a8477c50763c727ceb09c1 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 15 Mar 2026 20:29:39 +0900 Subject: [PATCH 14/33] Fix invalid suggestion on `for-loops-over-fallibles` --- .../src/for_loops_over_fallibles.rs | 2 ++ .../macro-iterator-next.rs | 21 ++++++++++++++++ .../macro-iterator-next.stderr | 24 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs create mode 100644 tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index fe95a682c6376..24220e035b1dd 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -77,6 +77,8 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { }; let sub = if let Some(recv) = extract_iterator_next_call(cx, arg) + && recv.span.can_be_used_for_suggestions() + && recv.span.between(arg_span.shrink_to_hi()).can_be_used_for_suggestions() && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span) { ForLoopsOverFalliblesLoopSub::RemoveNext { diff --git a/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs b/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs new file mode 100644 index 0000000000000..0fe88734099c7 --- /dev/null +++ b/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs @@ -0,0 +1,21 @@ +// This test ensures that the `for-loops-over-fallibles` lint doesn't suggest +// removing `next`. +// ref. + +#![forbid(for_loops_over_fallibles)] +//~^ NOTE: the lint level is defined here + +fn main() { + macro_rules! mac { + (next $e:expr) => { + $e.iter().next() + }; + } + + for _ in mac!(next [1, 2]) {} + //~^ ERROR: for loop over an `Option`. This is more readably written as an `if let` statement + //~| NOTE: in this expansion of desugaring of `for` loop + //~| NOTE: in this expansion of desugaring of `for` loop + //~| HELP: to check pattern in a loop use `while let` + //~| HELP: consider using `if let` to clear intent +} diff --git a/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr b/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr new file mode 100644 index 0000000000000..36848fffa4394 --- /dev/null +++ b/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr @@ -0,0 +1,24 @@ +error: for loop over an `Option`. This is more readably written as an `if let` statement + --> $DIR/macro-iterator-next.rs:15:14 + | +LL | for _ in mac!(next [1, 2]) {} + | ^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/macro-iterator-next.rs:5:11 + | +LL | #![forbid(for_loops_over_fallibles)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: to check pattern in a loop use `while let` + | +LL - for _ in mac!(next [1, 2]) {} +LL + while let Some(_) = mac!(next [1, 2]) {} + | +help: consider using `if let` to clear intent + | +LL - for _ in mac!(next [1, 2]) {} +LL + if let Some(_) = mac!(next [1, 2]) {} + | + +error: aborting due to 1 previous error + From 924374c75b6ec99c5d95847f6c54554d8d590716 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 17 Mar 2026 06:30:04 +0000 Subject: [PATCH 15/33] mGCA: Lower const generic args to infer when needed --- compiler/rustc_ast_lowering/src/lib.rs | 10 +++-- .../const-generics/mgca/braced-const-infer.rs | 9 ++++ .../mgca/braced-const-infer.stderr | 9 ++++ .../mgca/macro-const-arg-infer.rs | 20 +++++++++ .../mgca/macro-const-arg-infer.stderr | 44 +++++++++++++++++++ 5 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 tests/ui/const-generics/mgca/braced-const-infer.rs create mode 100644 tests/ui/const-generics/mgca/braced-const-infer.stderr create mode 100644 tests/ui/const-generics/mgca/macro-const-arg-infer.rs create mode 100644 tests/ui/const-generics/mgca/macro-const-arg-infer.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e8092b540ec87..7a0537b0e7c6e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1269,9 +1269,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap()) } - ast::GenericArg::Const(ct) => GenericArg::Const( - self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(), - ), + ast::GenericArg::Const(ct) => { + let ct = self.lower_anon_const_to_const_arg_and_alloc(ct); + match ct.try_as_ambig_ct() { + Some(ct) => GenericArg::Const(ct), + None => GenericArg::Infer(hir::InferArg { hir_id: ct.hir_id, span: ct.span }), + } + } } } diff --git a/tests/ui/const-generics/mgca/braced-const-infer.rs b/tests/ui/const-generics/mgca/braced-const-infer.rs new file mode 100644 index 0000000000000..9b007d338d1da --- /dev/null +++ b/tests/ui/const-generics/mgca/braced-const-infer.rs @@ -0,0 +1,9 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/153198 +#![feature(min_generic_const_args)] +#![allow(incomplete_features, rust_2021_compatibility)] + +trait Trait {} + +impl dyn Trait<{_}> {} //~ ERROR: the placeholder `_` is not allowed within types on item signatures + +fn main() {} diff --git a/tests/ui/const-generics/mgca/braced-const-infer.stderr b/tests/ui/const-generics/mgca/braced-const-infer.stderr new file mode 100644 index 0000000000000..d8ffee4cd0e8f --- /dev/null +++ b/tests/ui/const-generics/mgca/braced-const-infer.stderr @@ -0,0 +1,9 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations + --> $DIR/braced-const-infer.rs:7:17 + | +LL | impl dyn Trait<{_}> {} + | ^ not allowed in type signatures + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.rs b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs new file mode 100644 index 0000000000000..017c63d8b0db5 --- /dev/null +++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs @@ -0,0 +1,20 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/153198 +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] +macro_rules! y { + ( $($matcher:tt)*) => { + _ //~ ERROR: the placeholder `_` is not allowed within types on item signatures + }; +} + +struct A; //~ ERROR: type parameter `T` is never used + +const y: A< + { + y! { + x + } + }, +> = 1; //~ ERROR: mismatched types + +fn main() {} diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr new file mode 100644 index 0000000000000..406206c59e18f --- /dev/null +++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr @@ -0,0 +1,44 @@ +error[E0392]: type parameter `T` is never used + --> $DIR/macro-const-arg-infer.rs:10:10 + | +LL | struct A; + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error[E0308]: mismatched types + --> $DIR/macro-const-arg-infer.rs:18:5 + | +LL | const y: A< + | __________- +LL | | { +LL | | y! { +LL | | x +LL | | } +LL | | }, +LL | | > = 1; + | | - ^ expected `A<_>`, found integer + | |_| + | expected because of the type of the constant + | + = note: expected struct `A<_>` + found type `{integer}` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/macro-const-arg-infer.rs:6:9 + | +LL | _ + | ^ not allowed in type signatures +... +LL | / y! { +LL | | x +LL | | } + | |_________- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0121, E0308, E0392. +For more information about an error, try `rustc --explain E0121`. From 11810b8dd9d5ea1dad36eb5f6c77fa5d95871a81 Mon Sep 17 00:00:00 2001 From: human9000 Date: Sun, 8 Mar 2026 10:49:21 +0500 Subject: [PATCH 16/33] fix inference variables leaking into HIR const lowering logic --- .../src/hir_ty_lowering/mod.rs | 6 ++++++ .../mgca/infer-vars-in-const-args.rs | 16 ++++++++++++++ .../mgca/infer-vars-in-const-args.stderr | 21 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 tests/ui/const-generics/mgca/infer-vars-in-const-args.rs create mode 100644 tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index bf97bfb1ebbce..00791ed194c52 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2874,6 +2874,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Const<'tcx> { let tcx = self.tcx(); + + if ty.has_infer() { + let e = self.dcx().span_err(span, "inference variables are not supported in constants"); + return ty::Const::new_error(tcx, e); + } + if let LitKind::Err(guar) = *kind { return ty::Const::new_error(tcx, guar); } diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs new file mode 100644 index 0000000000000..cbc59d461694f --- /dev/null +++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs @@ -0,0 +1,16 @@ +#![allow(incomplete_features)] +#![feature(adt_const_params, min_generic_const_args, generic_const_parameter_types)] + +fn main() { + foo::<_, { 2 }>(); + //~^ ERROR: inference variables are not supported in constants + let _: PC<_, { 42 }> = PC { a: 1, b: 1 }; + //~^ ERROR: inference variables are not supported in constants +} + +struct PC { +//~^ ERROR: `T` can't be used as a const parameter type [E0741] + a: T, +} + +fn foo() {} diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr b/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr new file mode 100644 index 0000000000000..0f64582c1cef6 --- /dev/null +++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr @@ -0,0 +1,21 @@ +error[E0741]: `T` can't be used as a const parameter type + --> $DIR/infer-vars-in-const-args.rs:11:23 + | +LL | struct PC { + | ^ + +error: inference variables are not supported in constants + --> $DIR/infer-vars-in-const-args.rs:5:16 + | +LL | foo::<_, { 2 }>(); + | ^ + +error: inference variables are not supported in constants + --> $DIR/infer-vars-in-const-args.rs:7:20 + | +LL | let _: PC<_, { 42 }> = PC { a: 1, b: 1 }; + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0741`. From 5113488163ac3fdbb2adb665308b0bd3f524c44f Mon Sep 17 00:00:00 2001 From: human9000 Date: Tue, 17 Mar 2026 09:36:08 +0500 Subject: [PATCH 17/33] Improve `ty::Infer` handling during const literal lowering Co-authored-by: BoxyUwU --- .../src/hir_ty_lowering/mod.rs | 15 +++++++------ compiler/rustc_middle/src/ty/consts/lit.rs | 5 ++++- .../src/builder/expr/as_constant.rs | 5 ++++- compiler/rustc_mir_build/src/thir/constant.rs | 22 ++++++++++--------- .../rustc_mir_build/src/thir/pattern/mod.rs | 2 +- compiler/rustc_ty_utils/src/consts.rs | 3 ++- ...> infer-vars-in-const-args-conflicting.rs} | 9 ++++++-- ...fer-vars-in-const-args-conflicting.stderr} | 10 ++++----- .../mgca/infer-vars-in-const-args-correct.rs | 22 +++++++++++++++++++ 9 files changed, 65 insertions(+), 28 deletions(-) rename tests/ui/const-generics/mgca/{infer-vars-in-const-args.rs => infer-vars-in-const-args-conflicting.rs} (52%) rename tests/ui/const-generics/mgca/{infer-vars-in-const-args.stderr => infer-vars-in-const-args-conflicting.stderr} (58%) create mode 100644 tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 00791ed194c52..9396bf6352c59 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2875,10 +2875,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Const<'tcx> { let tcx = self.tcx(); - if ty.has_infer() { - let e = self.dcx().span_err(span, "inference variables are not supported in constants"); - return ty::Const::new_error(tcx, e); - } + let ty = if !ty.has_infer() { Some(ty) } else { None }; if let LitKind::Err(guar) = *kind { return ty::Const::new_error(tcx, guar); @@ -2911,16 +2908,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let lit_input = match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }), + hir::ExprKind::Lit(lit) => { + Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: false }) + } hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { - hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }), + hir::ExprKind::Lit(lit) => { + Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: true }) + } _ => None, }, _ => None, }; lit_input.and_then(|l| { - if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) { + if const_lit_matches_ty(tcx, &l.lit, ty, l.neg) { tcx.at(expr.span) .lit_to_const(l) .map(|value| ty::Const::new_value(tcx, value.valtree, value.ty)) diff --git a/compiler/rustc_middle/src/ty/consts/lit.rs b/compiler/rustc_middle/src/ty/consts/lit.rs index be6dfb20e0433..7be225a9e9215 100644 --- a/compiler/rustc_middle/src/ty/consts/lit.rs +++ b/compiler/rustc_middle/src/ty/consts/lit.rs @@ -10,7 +10,10 @@ pub struct LitToConstInput<'tcx> { /// The absolute value of the resultant constant. pub lit: LitKind, /// The type of the constant. - pub ty: Ty<'tcx>, + /// + /// `None` is used by const generics when the type of the constant is unknown, e.g. + /// if there are inference variables + pub ty: Option>, /// If the constant is negative. pub neg: bool, } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index ad6c1f7dce5b8..c67d99a8eb7de 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -50,7 +50,8 @@ pub(crate) fn as_constant_inner<'tcx>( match *kind { ExprKind::Literal { lit, neg } => { - let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg }); + let const_ = + lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty: Some(ty), neg }); ConstOperand { span, user_ty: None, const_ } } @@ -109,6 +110,8 @@ pub(crate) fn as_constant_inner<'tcx>( fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> { let LitToConstInput { lit, ty, neg } = lit_input; + let ty = ty.expect("type of literal must be known at this point"); + if let Err(guar) = ty.error_reported() { return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)); } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b4eedb15033c8..019af24613541 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -31,25 +31,27 @@ pub(crate) fn lit_to_const<'tcx>( .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)) }; - let (valtree, valtree_ty) = match (lit, expected_ty.kind()) { + let (valtree, valtree_ty) = match (lit, expected_ty.map(|ty| ty.kind())) { (ast::LitKind::Str(s, _), _) => { let str_bytes = s.as_str().as_bytes(); let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_); (ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty) } - (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) + (ast::LitKind::ByteStr(byte_sym, _), Some(ty::Ref(_, inner_ty, _))) if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() && let ty::Uint(UintTy::U8) = ty.kind() => { - (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty) + (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap()) } - (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) - if tcx.features().deref_patterns() - && let ty::Uint(UintTy::U8) = inner_ty.kind() => + ( + ast::LitKind::ByteStr(byte_sym, _), + Some(ty::Slice(inner_ty) | ty::Array(inner_ty, _)), + ) if tcx.features().deref_patterns() + && let ty::Uint(UintTy::U8) = inner_ty.kind() => { // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is // enabled, in order to allow, e.g., `deref!(b"..."): Vec`. - (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty) + (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap()) } (ast::LitKind::ByteStr(byte_sym, _), _) => { let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); @@ -79,11 +81,11 @@ pub(crate) fn lit_to_const<'tcx>( trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned()); (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i)) } - (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => { + (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Uint(ui))) if !neg => { let scalar_int = trunc(n.get(), *ui); (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui)) } - (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => { + (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Int(i))) => { // Unsigned "negation" has the same bitwise effect as signed negation, // which gets the result we want without additional casts. let scalar_int = @@ -101,7 +103,7 @@ pub(crate) fn lit_to_const<'tcx>( let bits = parse_float_into_scalar(n, fty, neg)?; (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty)) } - (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => { + (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), Some(ty::Float(fty))) => { let bits = parse_float_into_scalar(n, *fty, neg)?; (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty)) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 67cde0e2c8866..fec2fb9ca5719 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -696,7 +696,7 @@ impl<'tcx> PatCtxt<'tcx> { // patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`. let pat_ty = self.typeck_results.node_type(pat.hir_id); - let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; + let lit_input = LitToConstInput { lit: lit.node, ty: Some(pat_ty), neg: *negated }; let constant = const_lit_matches_ty(self.tcx, &lit.node, pat_ty, *negated) .then(|| self.tcx.at(expr.span).lit_to_const(lit_input)) .flatten() diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 1d444079f8968..49e0bdde37870 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -58,7 +58,8 @@ fn recurse_build<'tcx>( } &ExprKind::Literal { lit, neg } => { let sp = node.span; - match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) { + match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: Some(node.ty), neg }) + { Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty), None => ty::Const::new_misc_error(tcx), } diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs similarity index 52% rename from tests/ui/const-generics/mgca/infer-vars-in-const-args.rs rename to tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs index cbc59d461694f..eeb76683eedf1 100644 --- a/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs +++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs @@ -1,11 +1,16 @@ +//! This test ensures compilation failure when trying to pass literals +//! without explicitly stated type as inference variables in generic arguments. +//! +//! See https://github.com/rust-lang/rust/pull/153557 + #![allow(incomplete_features)] #![feature(adt_const_params, min_generic_const_args, generic_const_parameter_types)] fn main() { foo::<_, { 2 }>(); - //~^ ERROR: inference variables are not supported in constants + //~^ ERROR: type annotations needed for the literal let _: PC<_, { 42 }> = PC { a: 1, b: 1 }; - //~^ ERROR: inference variables are not supported in constants + //~^ ERROR: type annotations needed for the literal } struct PC { diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr similarity index 58% rename from tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr rename to tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr index 0f64582c1cef6..a4b13f41aef07 100644 --- a/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr +++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr @@ -1,17 +1,17 @@ error[E0741]: `T` can't be used as a const parameter type - --> $DIR/infer-vars-in-const-args.rs:11:23 + --> $DIR/infer-vars-in-const-args-conflicting.rs:16:23 | LL | struct PC { | ^ -error: inference variables are not supported in constants - --> $DIR/infer-vars-in-const-args.rs:5:16 +error: type annotations needed for the literal + --> $DIR/infer-vars-in-const-args-conflicting.rs:10:16 | LL | foo::<_, { 2 }>(); | ^ -error: inference variables are not supported in constants - --> $DIR/infer-vars-in-const-args.rs:7:20 +error: type annotations needed for the literal + --> $DIR/infer-vars-in-const-args-conflicting.rs:12:20 | LL | let _: PC<_, { 42 }> = PC { a: 1, b: 1 }; | ^^ diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs new file mode 100644 index 0000000000000..f1c0e0b2b4c30 --- /dev/null +++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs @@ -0,0 +1,22 @@ +//! This test ensures no errors are emitted when lowering literals with +//! explicitly stated types and inference variables in the type of the const +//! generic parameter. +//! +//! See https://github.com/rust-lang/rust/pull/153557 + +//@check-pass + +#![allow(incomplete_features)] +#![feature(adt_const_params, + min_generic_const_args, + generic_const_parameter_types, + unsized_const_params +)] + +use std::marker::ConstParamTy_; + +fn main() { + foo::<_, 2_i32>(); +} + +fn foo() {} From 69fd61e40e854ecd75e19b32ebb913d1a8c7d121 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 17 Mar 2026 16:15:14 +0000 Subject: [PATCH 18/33] merge `kindck/send-*` tests --- tests/ui/kindck/kindck-send-object.rs | 26 ---- tests/ui/kindck/kindck-send-object.stderr | 33 ----- tests/ui/kindck/kindck-send-object1.rs | 33 ----- tests/ui/kindck/kindck-send-object1.stderr | 41 ------ tests/ui/kindck/kindck-send-object2.rs | 24 ---- tests/ui/kindck/kindck-send-object2.stderr | 33 ----- tests/ui/kindck/kindck-send-owned.rs | 16 --- tests/ui/kindck/kindck-send-owned.stderr | 19 --- tests/ui/kindck/kindck-send-unsafe.rs | 15 --- tests/ui/kindck/kindck-send-unsafe.stderr | 29 ---- tests/ui/kindck/send-trait-objects-basic.rs | 55 ++++++++ .../ui/kindck/send-trait-objects-basic.stderr | 127 ++++++++++++++++++ 12 files changed, 182 insertions(+), 269 deletions(-) delete mode 100644 tests/ui/kindck/kindck-send-object.rs delete mode 100644 tests/ui/kindck/kindck-send-object.stderr delete mode 100644 tests/ui/kindck/kindck-send-object1.rs delete mode 100644 tests/ui/kindck/kindck-send-object1.stderr delete mode 100644 tests/ui/kindck/kindck-send-object2.rs delete mode 100644 tests/ui/kindck/kindck-send-object2.stderr delete mode 100644 tests/ui/kindck/kindck-send-owned.rs delete mode 100644 tests/ui/kindck/kindck-send-owned.stderr delete mode 100644 tests/ui/kindck/kindck-send-unsafe.rs delete mode 100644 tests/ui/kindck/kindck-send-unsafe.stderr create mode 100644 tests/ui/kindck/send-trait-objects-basic.rs create mode 100644 tests/ui/kindck/send-trait-objects-basic.stderr diff --git a/tests/ui/kindck/kindck-send-object.rs b/tests/ui/kindck/kindck-send-object.rs deleted file mode 100644 index f5d44246efe5a..0000000000000 --- a/tests/ui/kindck/kindck-send-object.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Test which of the builtin types are considered sendable. The tests -// in this file all test the "kind" violates detected during kindck. -// See all `regions-bounded-by-send.rs` - -fn assert_send() { } -trait Dummy { } -trait Message : Send { } - -// careful with object types, who knows what they close over... - -fn object_ref_with_static_bound_not_ok() { - assert_send::<&'static (dyn Dummy + 'static)>(); - //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277] -} - -fn box_object_with_no_bound_not_ok<'a>() { - assert_send::>(); - //~^ ERROR `dyn Dummy` cannot be sent between threads safely -} - -fn object_with_send_bound_ok() { - assert_send::<&'static (dyn Dummy + Sync)>(); - assert_send::>(); -} - -fn main() { } diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr deleted file mode 100644 index b71d4029350e1..0000000000000 --- a/tests/ui/kindck/kindck-send-object.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely - --> $DIR/kindck-send-object.rs:12:19 - | -LL | assert_send::<&'static (dyn Dummy + 'static)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely - | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` - = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object.rs:5:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error[E0277]: `dyn Dummy` cannot be sent between threads safely - --> $DIR/kindck-send-object.rs:17:19 - | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `dyn Dummy` - = note: required for `std::ptr::Unique` to implement `Send` -note: required because it appears within the type `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object.rs:5:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-object1.rs b/tests/ui/kindck/kindck-send-object1.rs deleted file mode 100644 index 76a9fc6019abc..0000000000000 --- a/tests/ui/kindck/kindck-send-object1.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Test which object types are considered sendable. This test -// is broken into two parts because some errors occur in distinct -// phases in the compiler. See kindck-send-object2.rs as well! - -fn assert_send() { } -trait Dummy { } - -// careful with object types, who knows what they close over... -fn test51<'a>() { - assert_send::<&'a dyn Dummy>(); - //~^ ERROR `&'a (dyn Dummy + 'a)` cannot be sent between threads safely [E0277] -} -fn test52<'a>() { - assert_send::<&'a (dyn Dummy + Sync)>(); - //~^ ERROR: lifetime may not live long enough -} - -// ...unless they are properly bounded -fn test60() { - assert_send::<&'static (dyn Dummy + Sync)>(); -} -fn test61() { - assert_send::>(); -} - -// closure and object types can have lifetime bounds which make -// them not ok -fn test_71<'a>() { - assert_send::>(); - //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely -} - -fn main() { } diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr deleted file mode 100644 index 2184ae704673d..0000000000000 --- a/tests/ui/kindck/kindck-send-object1.stderr +++ /dev/null @@ -1,41 +0,0 @@ -error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely - --> $DIR/kindck-send-object1.rs:10:19 - | -LL | assert_send::<&'a dyn Dummy>(); - | ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely - | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` - = note: required for `&'a (dyn Dummy + 'a)` to implement `Send` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object1.rs:5:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely - --> $DIR/kindck-send-object1.rs:29:19 - | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` - = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send` -note: required because it appears within the type `Box<(dyn Dummy + 'a)>` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object1.rs:5:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error: lifetime may not live long enough - --> $DIR/kindck-send-object1.rs:14:5 - | -LL | fn test52<'a>() { - | -- lifetime `'a` defined here -LL | assert_send::<&'a (dyn Dummy + Sync)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-object2.rs b/tests/ui/kindck/kindck-send-object2.rs deleted file mode 100644 index d37074e657462..0000000000000 --- a/tests/ui/kindck/kindck-send-object2.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Continue kindck-send-object1.rs. - -fn assert_send() { } -trait Dummy { } - -fn test50() { - assert_send::<&'static dyn Dummy>(); - //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277] -} - -fn test53() { - assert_send::>(); - //~^ ERROR `dyn Dummy` cannot be sent between threads safely -} - -// ...unless they are properly bounded -fn test60() { - assert_send::<&'static (dyn Dummy + Sync)>(); -} -fn test61() { - assert_send::>(); -} - -fn main() { } diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr deleted file mode 100644 index 52a7055b42291..0000000000000 --- a/tests/ui/kindck/kindck-send-object2.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely - --> $DIR/kindck-send-object2.rs:7:19 - | -LL | assert_send::<&'static dyn Dummy>(); - | ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely - | - = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` - = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object2.rs:3:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error[E0277]: `dyn Dummy` cannot be sent between threads safely - --> $DIR/kindck-send-object2.rs:12:19 - | -LL | assert_send::>(); - | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `dyn Dummy` - = note: required for `std::ptr::Unique` to implement `Send` -note: required because it appears within the type `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: required by a bound in `assert_send` - --> $DIR/kindck-send-object2.rs:3:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-owned.rs b/tests/ui/kindck/kindck-send-owned.rs deleted file mode 100644 index 65efb69041d59..0000000000000 --- a/tests/ui/kindck/kindck-send-owned.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Test which of the builtin types are considered sendable. - -fn assert_send() { } - -// owned content are ok -fn test30() { assert_send::>(); } -fn test31() { assert_send::(); } -fn test32() { assert_send:: >(); } - -// but not if they own a bad thing -fn test40() { - assert_send::>(); - //~^ ERROR `*mut u8` cannot be sent between threads safely -} - -fn main() { } diff --git a/tests/ui/kindck/kindck-send-owned.stderr b/tests/ui/kindck/kindck-send-owned.stderr deleted file mode 100644 index c433d80cf140c..0000000000000 --- a/tests/ui/kindck/kindck-send-owned.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: `*mut u8` cannot be sent between threads safely - --> $DIR/kindck-send-owned.rs:12:19 - | -LL | assert_send::>(); - | ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `*mut u8` - = note: required for `std::ptr::Unique<*mut u8>` to implement `Send` -note: required because it appears within the type `Box<*mut u8>` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -note: required by a bound in `assert_send` - --> $DIR/kindck-send-owned.rs:3:18 - | -LL | fn assert_send() { } - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-send-unsafe.rs b/tests/ui/kindck/kindck-send-unsafe.rs deleted file mode 100644 index eb1f2a549b16b..0000000000000 --- a/tests/ui/kindck/kindck-send-unsafe.rs +++ /dev/null @@ -1,15 +0,0 @@ -extern crate core; - -fn assert_send() {} - -fn test70() { - assert_send::<*mut isize>(); - //~^ ERROR `*mut isize` cannot be sent between threads safely -} - -fn test71<'a>() { - assert_send::<*mut &'a isize>(); - //~^ ERROR `*mut &'a isize` cannot be sent between threads safely -} - -fn main() {} diff --git a/tests/ui/kindck/kindck-send-unsafe.stderr b/tests/ui/kindck/kindck-send-unsafe.stderr deleted file mode 100644 index f1a5054abbc47..0000000000000 --- a/tests/ui/kindck/kindck-send-unsafe.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0277]: `*mut isize` cannot be sent between threads safely - --> $DIR/kindck-send-unsafe.rs:6:19 - | -LL | assert_send::<*mut isize>(); - | ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `*mut isize` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-unsafe.rs:3:19 - | -LL | fn assert_send() {} - | ^^^^ required by this bound in `assert_send` - -error[E0277]: `*mut &'a isize` cannot be sent between threads safely - --> $DIR/kindck-send-unsafe.rs:11:19 - | -LL | assert_send::<*mut &'a isize>(); - | ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `*mut &'a isize` -note: required by a bound in `assert_send` - --> $DIR/kindck-send-unsafe.rs:3:19 - | -LL | fn assert_send() {} - | ^^^^ required by this bound in `assert_send` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/send-trait-objects-basic.rs b/tests/ui/kindck/send-trait-objects-basic.rs new file mode 100644 index 0000000000000..c999d4d0f6950 --- /dev/null +++ b/tests/ui/kindck/send-trait-objects-basic.rs @@ -0,0 +1,55 @@ +// Test which trait objects and basic types are considered sendable, considering lifetimes. + +fn assert_send_static() {} +fn assert_send() {} + +trait Dummy {} + +fn test1<'a>() { + assert_send_static::<&'a dyn Dummy>(); + //~^ ERROR `&'a (dyn Dummy + 'a)` cannot be sent between threads safely [E0277] +} + +fn test2<'a>() { + assert_send_static::<&'a (dyn Dummy + Sync)>(); + //~^ ERROR: lifetime may not live long enough +} + +fn test3<'a>() { + assert_send_static::>(); + //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely +} + +fn test4<'a>() { + assert_send::<*mut &'a isize>(); + //~^ ERROR `*mut &'a isize` cannot be sent between threads safely +} + +fn main() { + assert_send_static::<&'static (dyn Dummy + Sync)>(); + assert_send_static::>(); + + assert_send::<&'static dyn Dummy>(); + //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277] + assert_send::>(); + //~^ ERROR `dyn Dummy` cannot be sent between threads safely + assert_send::<&'static (dyn Dummy + Sync)>(); + assert_send::>(); + + // owned content is ok + assert_send::>(); + assert_send::(); + assert_send::>(); + + // but not if it owns a bad thing + assert_send::>(); + //~^ ERROR `*mut u8` cannot be sent between threads safely + + assert_send::<*mut isize>(); + //~^ ERROR `*mut isize` cannot be sent between threads safely +} + +fn object_ref_with_static_bound_not_ok() { + assert_send::<&'static (dyn Dummy + 'static)>(); + //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277] +} diff --git a/tests/ui/kindck/send-trait-objects-basic.stderr b/tests/ui/kindck/send-trait-objects-basic.stderr new file mode 100644 index 0000000000000..0393f7bc19df7 --- /dev/null +++ b/tests/ui/kindck/send-trait-objects-basic.stderr @@ -0,0 +1,127 @@ +error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:9:26 + | +LL | assert_send_static::<&'a dyn Dummy>(); + | ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely + | + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` + = note: required for `&'a (dyn Dummy + 'a)` to implement `Send` +note: required by a bound in `assert_send_static` + --> $DIR/send-trait-objects-basic.rs:3:26 + | +LL | fn assert_send_static() {} + | ^^^^ required by this bound in `assert_send_static` + +error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:19:26 + | +LL | assert_send_static::>(); + | ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` + = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send` +note: required because it appears within the type `Box<(dyn Dummy + 'a)>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +note: required by a bound in `assert_send_static` + --> $DIR/send-trait-objects-basic.rs:3:26 + | +LL | fn assert_send_static() {} + | ^^^^ required by this bound in `assert_send_static` + +error[E0277]: `*mut &'a isize` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:24:19 + | +LL | assert_send::<*mut &'a isize>(); + | ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `*mut &'a isize` +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:32:19 + | +LL | assert_send::<&'static dyn Dummy>(); + | ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely + | + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `dyn Dummy` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:34:19 + | +LL | assert_send::>(); + | ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `dyn Dummy` + = note: required for `std::ptr::Unique` to implement `Send` +note: required because it appears within the type `Box` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `*mut u8` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:45:19 + | +LL | assert_send::>(); + | ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `*mut u8` + = note: required for `std::ptr::Unique<*mut u8>` to implement `Send` +note: required because it appears within the type `Box<*mut u8>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `*mut isize` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:48:19 + | +LL | assert_send::<*mut isize>(); + | ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `*mut isize` +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely + --> $DIR/send-trait-objects-basic.rs:53:19 + | +LL | assert_send::<&'static (dyn Dummy + 'static)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely + | + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` +note: required by a bound in `assert_send` + --> $DIR/send-trait-objects-basic.rs:4:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error: lifetime may not live long enough + --> $DIR/send-trait-objects-basic.rs:14:5 + | +LL | fn test2<'a>() { + | -- lifetime `'a` defined here +LL | assert_send_static::<&'a (dyn Dummy + Sync)>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0277`. From b4c1677fff43d9ea04002de85aef77915092be7d Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 15 Mar 2026 20:34:25 +0900 Subject: [PATCH 19/33] Do not lint `for-loops-over-fallibles` on external macros --- .../rustc_lint/src/for_loops_over_fallibles.rs | 5 +++++ tests/crashes/147973.rs | 14 -------------- .../auxiliary/external-macro-issue-148114.rs | 13 +++++++++++++ .../external-macro-issue-148114.rs | 14 ++++++++++++++ 4 files changed, 32 insertions(+), 14 deletions(-) delete mode 100644 tests/crashes/147973.rs create mode 100644 tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs create mode 100644 tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index 24220e035b1dd..a7c5943c250b8 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -49,6 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let Some((pat, arg)) = extract_for_loop(expr) else { return }; + // Do not put suggestions for external macros. + if pat.span.from_expansion() { + return; + } + let arg_span = arg.span.source_callsite(); let ty = cx.typeck_results().expr_ty(arg); diff --git a/tests/crashes/147973.rs b/tests/crashes/147973.rs deleted file mode 100644 index 7271c54846f15..0000000000000 --- a/tests/crashes/147973.rs +++ /dev/null @@ -1,14 +0,0 @@ -// This is part of series of regression tests for some diagnostics ICEs encountered in the wild with -// suggestions having overlapping parts under https://github.com/rust-lang/rust/pull/146121. -// This is one MCVE from the beta crater run regressions from issue 147973. - -//@ needs-rustc-debug-assertions -//@ known-bug: #147973 - -//@ aux-build: overlapping_spans_helper.rs -extern crate overlapping_spans_helper; - -fn main() { - let _name = Some(1); - overlapping_spans_helper::do_loop!(_name); -} diff --git a/tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs new file mode 100644 index 0000000000000..68eff33cb3f10 --- /dev/null +++ b/tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs @@ -0,0 +1,13 @@ +#[macro_export] +macro_rules! identity { + ($x:ident) => { + $x + }; +} + +#[macro_export] +macro_rules! do_loop { + ($x:ident) => { + for $crate::identity!($x) in $x {} + }; +} diff --git a/tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs new file mode 100644 index 0000000000000..ca3ac3b9a8647 --- /dev/null +++ b/tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ aux-build:external-macro-issue-148114.rs + +// This test ensures we do not trigger the lint on external macros +// ref. + +#![deny(for_loops_over_fallibles)] + +extern crate external_macro_issue_148114 as dep; + +fn main() { + let _name = Some(1); + dep::do_loop!(_name); +} From cfe18cfd37e3aefe0a9a653d3faac825c3a7868a Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 15 Mar 2026 20:35:16 +0900 Subject: [PATCH 20/33] Correct dir name --- .../auxiliary/external-macro-issue-148114.rs | 0 .../external-macro-issue-148114.rs | 0 .../macro-issue-140747.rs | 0 .../macro-issue-140747.stderr | 0 .../macro-iterator-next.rs | 0 .../macro-iterator-next.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/auxiliary/external-macro-issue-148114.rs (100%) rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/external-macro-issue-148114.rs (100%) rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/macro-issue-140747.rs (100%) rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/macro-issue-140747.stderr (100%) rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/macro-iterator-next.rs (100%) rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/macro-iterator-next.stderr (100%) diff --git a/tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs similarity index 100% rename from tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs rename to tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs diff --git a/tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs similarity index 100% rename from tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs rename to tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs b/tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.rs similarity index 100% rename from tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs rename to tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.rs diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr b/tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.stderr similarity index 100% rename from tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr rename to tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.stderr diff --git a/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs similarity index 100% rename from tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs rename to tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs diff --git a/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr similarity index 100% rename from tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr rename to tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr From caeda1869aab15cdd25d43d2de43d43b4cfbee07 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 17 Mar 2026 21:49:58 +0000 Subject: [PATCH 21/33] reformat and update remaining `ui/kindck` tests --- tests/ui/kindck/kindck-copy.rs | 31 ++++----- tests/ui/kindck/kindck-copy.stderr | 68 +++++++++---------- tests/ui/kindck/kindck-impl-type-params-2.rs | 15 ---- .../kindck/kindck-impl-type-params-2.stderr | 24 ------- tests/ui/kindck/kindck-impl-type-params.rs | 6 +- .../ui/kindck/kindck-impl-type-params.stderr | 30 ++++---- .../kindck-inherited-copy-bound.curr.stderr | 56 --------------- .../ui/kindck/kindck-inherited-copy-bound.rs | 10 ++- .../kindck/kindck-inherited-copy-bound.stderr | 26 +++---- tests/ui/kindck/kindck-nonsendable-1.rs | 4 +- tests/ui/kindck/kindck-nonsendable-1.stderr | 18 ++--- 11 files changed, 96 insertions(+), 192 deletions(-) delete mode 100644 tests/ui/kindck/kindck-impl-type-params-2.rs delete mode 100644 tests/ui/kindck/kindck-impl-type-params-2.stderr delete mode 100644 tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr diff --git a/tests/ui/kindck/kindck-copy.rs b/tests/ui/kindck/kindck-copy.rs index 36bf0d2b785f6..c953b60260df4 100644 --- a/tests/ui/kindck/kindck-copy.rs +++ b/tests/ui/kindck/kindck-copy.rs @@ -2,9 +2,9 @@ use std::rc::Rc; -fn assert_copy() { } +fn assert_copy() {} -trait Dummy { } +trait Dummy {} #[derive(Copy, Clone)] struct MyStruct { @@ -16,8 +16,8 @@ struct MyNoncopyStruct { x: Box, } -fn test<'a,T,U:Copy>(_: &'a isize) { - // lifetime pointers are ok... +fn test<'a, T, U: Copy>(_: &'a isize) { + // references are ok... assert_copy::<&'static isize>(); assert_copy::<&'a isize>(); assert_copy::<&'a str>(); @@ -25,25 +25,25 @@ fn test<'a,T,U:Copy>(_: &'a isize) { // ...unless they are mutable assert_copy::<&'static mut isize>(); //~ ERROR : Copy` is not satisfied - assert_copy::<&'a mut isize>(); //~ ERROR : Copy` is not satisfied + assert_copy::<&'a mut isize>(); //~ ERROR : Copy` is not satisfied // boxes are not ok - assert_copy::>(); //~ ERROR : Copy` is not satisfied - assert_copy::(); //~ ERROR : Copy` is not satisfied - assert_copy:: >(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied + assert_copy::(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied assert_copy::>(); //~ ERROR : Copy` is not satisfied - // borrowed object types are generally ok + // borrowed trait objects are generally ok assert_copy::<&'a dyn Dummy>(); assert_copy::<&'a (dyn Dummy + Send)>(); assert_copy::<&'static (dyn Dummy + Send)>(); - // owned object types are not ok + // boxed trait objects are not ok assert_copy::>(); //~ ERROR : Copy` is not satisfied assert_copy::>(); //~ ERROR : Copy` is not satisfied - // mutable object types are not ok - assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : Copy` is not satisfied + // mutable references to trait objects are not ok + assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : Copy` is not satisfied // raw ptrs are ok assert_copy::<*const isize>(); @@ -55,7 +55,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::<()>(); // tuples are ok - assert_copy::<(isize,isize)>(); + assert_copy::<(isize, isize)>(); // structs of POD are ok assert_copy::(); @@ -64,8 +64,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::(); //~ ERROR : Copy` is not satisfied // ref counted types are not ok - assert_copy::>(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied } -pub fn main() { -} +pub fn main() {} diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/kindck/kindck-copy.stderr index f5623ddd4f795..01b4a5a646476 100644 --- a/tests/ui/kindck/kindck-copy.stderr +++ b/tests/ui/kindck/kindck-copy.stderr @@ -5,10 +5,10 @@ LL | assert_copy::<&'static mut isize>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` help: consider removing the leading `&`-reference | LL - assert_copy::<&'static mut isize>(); @@ -22,10 +22,10 @@ LL | assert_copy::<&'a mut isize>(); | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` help: consider removing the leading `&`-reference | LL - assert_copy::<&'a mut isize>(); @@ -39,10 +39,10 @@ LL | assert_copy::>(); | ^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-copy.rs:32:19 @@ -51,22 +51,22 @@ LL | assert_copy::(); | ^^^^^^ the trait `Copy` is not implemented for `String` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Vec: Copy` is not satisfied --> $DIR/kindck-copy.rs:33:19 | -LL | assert_copy:: >(); +LL | assert_copy::>(); | ^^^^^^^^^^ the trait `Copy` is not implemented for `Vec` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box<&'a mut isize>: Copy` is not satisfied --> $DIR/kindck-copy.rs:34:19 @@ -75,10 +75,10 @@ LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<&'a mut isize>` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:42:19 @@ -87,10 +87,10 @@ LL | assert_copy::>(); | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:43:19 @@ -99,10 +99,10 @@ LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not satisfied --> $DIR/kindck-copy.rs:46:19 @@ -111,10 +111,10 @@ LL | assert_copy::<&'a mut (dyn Dummy + Send)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied --> $DIR/kindck-copy.rs:64:19 @@ -128,10 +128,10 @@ help: the trait `Copy` is not implemented for `MyNoncopyStruct` LL | struct MyNoncopyStruct { | ^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Rc: Copy` is not satisfied --> $DIR/kindck-copy.rs:67:19 @@ -140,10 +140,10 @@ LL | assert_copy::>(); | ^^^^^^^^^ the trait `Copy` is not implemented for `Rc` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:18 + --> $DIR/kindck-copy.rs:5:19 | -LL | fn assert_copy() { } - | ^^^^ required by this bound in `assert_copy` +LL | fn assert_copy() {} + | ^^^^ required by this bound in `assert_copy` error: aborting due to 11 previous errors diff --git a/tests/ui/kindck/kindck-impl-type-params-2.rs b/tests/ui/kindck/kindck-impl-type-params-2.rs deleted file mode 100644 index 8b0771985dc3f..0000000000000 --- a/tests/ui/kindck/kindck-impl-type-params-2.rs +++ /dev/null @@ -1,15 +0,0 @@ -trait Foo { -} - - - -impl Foo for T { -} - -fn take_param(foo: &T) { } - -fn main() { - let x: Box<_> = Box::new(3); - take_param(&x); - //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied -} diff --git a/tests/ui/kindck/kindck-impl-type-params-2.stderr b/tests/ui/kindck/kindck-impl-type-params-2.stderr deleted file mode 100644 index 38dc94f9104d5..0000000000000 --- a/tests/ui/kindck/kindck-impl-type-params-2.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied - --> $DIR/kindck-impl-type-params-2.rs:13:16 - | -LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` - | | - | required by a bound introduced by this call - | -note: required for `Box<{integer}>` to implement `Foo` - --> $DIR/kindck-impl-type-params-2.rs:6:14 - | -LL | impl Foo for T { - | ---- ^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required by a bound in `take_param` - --> $DIR/kindck-impl-type-params-2.rs:9:17 - | -LL | fn take_param(foo: &T) { } - | ^^^ required by this bound in `take_param` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-impl-type-params.rs b/tests/ui/kindck/kindck-impl-type-params.rs index 707c5dbaec30e..ba54bc313c089 100644 --- a/tests/ui/kindck/kindck-impl-type-params.rs +++ b/tests/ui/kindck/kindck-impl-type-params.rs @@ -6,7 +6,9 @@ use std::marker; struct S(marker::PhantomData); trait Gettable { - fn get(&self) -> T { panic!() } + fn get(&self) -> T { + panic!() + } } impl Gettable for S {} @@ -45,4 +47,4 @@ fn foo3<'a>() { //~^ ERROR : Copy` is not satisfied } -fn main() { } +fn main() {} diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr index 0c9ab13f4774a..b2e52ae57ea4a 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/kindck/kindck-impl-type-params.stderr @@ -1,11 +1,11 @@ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/kindck-impl-type-params.rs:16:13 + --> $DIR/kindck-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/kindck-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -18,13 +18,13 @@ LL | fn f(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:16:13 + --> $DIR/kindck-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; | ^^ the trait `Copy` is not implemented for `T` | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/kindck-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -37,13 +37,13 @@ LL | fn f(val: T) { | +++++++++++++++++++ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/kindck-impl-type-params.rs:23:31 + --> $DIR/kindck-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; | ^^ `T` cannot be sent between threads safely | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/kindck-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -56,13 +56,13 @@ LL | fn g(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:23:31 + --> $DIR/kindck-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; | ^^ the trait `Copy` is not implemented for `T` | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/kindck-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -75,18 +75,18 @@ LL | fn g(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:36:13 + --> $DIR/kindck-impl-type-params.rs:38:13 | LL | let a = t as Box>; | ^ the trait `Copy` is not implemented for `String` | help: the trait `Gettable` is implemented for `S` - --> $DIR/kindck-impl-type-params.rs:12:1 + --> $DIR/kindck-impl-type-params.rs:14:1 | LL | impl Gettable for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/kindck-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -95,18 +95,18 @@ LL | impl Gettable for S {} = note: required for the cast from `Box>` to `Box>` error[E0277]: the trait bound `Foo: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:44:37 + --> $DIR/kindck-impl-type-params.rs:46:37 | LL | let a: Box> = t; | ^ the trait `Copy` is not implemented for `Foo` | help: the trait `Gettable` is implemented for `S` - --> $DIR/kindck-impl-type-params.rs:12:1 + --> $DIR/kindck-impl-type-params.rs:14:1 | LL | impl Gettable for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:12:32 + --> $DIR/kindck-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -120,7 +120,7 @@ LL | struct Foo; // does not impl Copy | error: lifetime may not live long enough - --> $DIR/kindck-impl-type-params.rs:30:13 + --> $DIR/kindck-impl-type-params.rs:32:13 | LL | fn foo<'a>() { | -- lifetime `'a` defined here diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr deleted file mode 100644 index 95048c4454b31..0000000000000 --- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ /dev/null @@ -1,56 +0,0 @@ -error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied - --> $DIR/kindck-inherited-copy-bound.rs:21:16 - | -LL | take_param(&x); - | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` - | | - | required by a bound introduced by this call - | -note: required for `Box<{integer}>` to implement `Foo` - --> $DIR/kindck-inherited-copy-bound.rs:14:14 - | -LL | impl Foo for T { - | ---- ^^^ ^ - | | - | unsatisfied trait bound introduced here -note: required by a bound in `take_param` - --> $DIR/kindck-inherited-copy-bound.rs:17:17 - | -LL | fn take_param(foo: &T) { } - | ^^^ required by this bound in `take_param` - -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/kindck-inherited-copy-bound.rs:28:19 - | -LL | let z = &x as &dyn Foo; - | ^^^^^^^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/kindck-inherited-copy-bound.rs:10:13 - | -LL | trait Foo : Copy { - | --- ^^^^ ...because it requires `Self: Sized` - | | - | this trait is not dyn compatible... - -error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/kindck-inherited-copy-bound.rs:28:13 - | -LL | let z = &x as &dyn Foo; - | ^^ `Foo` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/kindck-inherited-copy-bound.rs:10:13 - | -LL | trait Foo : Copy { - | --- ^^^^ ...because it requires `Self: Sized` - | | - | this trait is not dyn compatible... - = note: required for the cast from `&Box<{integer}>` to `&dyn Foo` - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0038, E0277. -For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/kindck/kindck-inherited-copy-bound.rs index 92c2b273c2c15..dd9fea3dcde35 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.rs +++ b/tests/ui/kindck/kindck-inherited-copy-bound.rs @@ -1,16 +1,14 @@ // Test that Copy bounds inherited by trait are checked. - use std::any::Any; -trait Foo : Copy { +trait Foo: Copy { fn foo(&self) {} } -impl Foo for T { -} +impl Foo for T {} -fn take_param(foo: &T) { } +fn take_param(foo: &T) {} fn a() { let x: Box<_> = Box::new(3); @@ -24,4 +22,4 @@ fn b() { //~^ ERROR E0038 } -fn main() { } +fn main() {} diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.stderr index c15aabacddd17..d6c9cab5b57a7 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied - --> $DIR/kindck-inherited-copy-bound.rs:17:16 + --> $DIR/kindck-inherited-copy-bound.rs:15:16 | LL | take_param(&x); | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` @@ -7,30 +7,30 @@ LL | take_param(&x); | required by a bound introduced by this call | note: required for `Box<{integer}>` to implement `Foo` - --> $DIR/kindck-inherited-copy-bound.rs:10:14 + --> $DIR/kindck-inherited-copy-bound.rs:9:15 | -LL | impl Foo for T { - | ---- ^^^ ^ - | | - | unsatisfied trait bound introduced here +LL | impl Foo for T {} + | ---- ^^^ ^ + | | + | unsatisfied trait bound introduced here note: required by a bound in `take_param` - --> $DIR/kindck-inherited-copy-bound.rs:13:17 + --> $DIR/kindck-inherited-copy-bound.rs:11:18 | -LL | fn take_param(foo: &T) { } - | ^^^ required by this bound in `take_param` +LL | fn take_param(foo: &T) {} + | ^^^ required by this bound in `take_param` error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/kindck-inherited-copy-bound.rs:23:24 + --> $DIR/kindck-inherited-copy-bound.rs:21:24 | LL | let z = &x as &dyn Foo; | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/kindck-inherited-copy-bound.rs:6:13 + --> $DIR/kindck-inherited-copy-bound.rs:5:12 | -LL | trait Foo : Copy { - | --- ^^^^ ...because it requires `Self: Sized` +LL | trait Foo: Copy { + | --- ^^^^ ...because it requires `Self: Sized` | | | this trait is not dyn compatible... diff --git a/tests/ui/kindck/kindck-nonsendable-1.rs b/tests/ui/kindck/kindck-nonsendable-1.rs index b32fd78624b8e..78ef834afabdb 100644 --- a/tests/ui/kindck/kindck-nonsendable-1.rs +++ b/tests/ui/kindck/kindck-nonsendable-1.rs @@ -2,10 +2,10 @@ use std::rc::Rc; fn foo(_x: Rc) {} -fn bar(_: F) { } +fn bar(_: F) {} fn main() { let x = Rc::new(3); - bar(move|| foo(x)); + bar(move || foo(x)); //~^ ERROR `Rc` cannot be sent between threads safely } diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/kindck/kindck-nonsendable-1.stderr index 8bb784d1d4966..4bf8e17e3ed96 100644 --- a/tests/ui/kindck/kindck-nonsendable-1.stderr +++ b/tests/ui/kindck/kindck-nonsendable-1.stderr @@ -1,24 +1,24 @@ error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/kindck-nonsendable-1.rs:9:9 | -LL | bar(move|| foo(x)); - | --- ------^^^^^^^ +LL | bar(move || foo(x)); + | --- -------^^^^^^^ | | | | | `Rc` cannot be sent between threads safely - | | within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}` + | | within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:16}` | required by a bound introduced by this call | - = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc` + = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:16}`, the trait `Send` is not implemented for `Rc` note: required because it's used within this closure --> $DIR/kindck-nonsendable-1.rs:9:9 | -LL | bar(move|| foo(x)); - | ^^^^^^ +LL | bar(move || foo(x)); + | ^^^^^^^ note: required by a bound in `bar` - --> $DIR/kindck-nonsendable-1.rs:5:21 + --> $DIR/kindck-nonsendable-1.rs:5:22 | -LL | fn bar(_: F) { } - | ^^^^ required by this bound in `bar` +LL | fn bar(_: F) {} + | ^^^^ required by this bound in `bar` error: aborting due to 1 previous error From 62b9fa15e72e613c1e318e895b84bf593768f9db Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 17 Mar 2026 22:02:05 +0000 Subject: [PATCH 22/33] move tests from `ui/kindck` to `ui/traits` --- tests/ui/README.md | 4 -- .../basic-copyable-types.rs} | 0 .../basic-copyable-types.stderr} | 46 +++++++++---------- .../closure-rc-not-send.rs} | 0 .../closure-rc-not-send.stderr} | 10 ++-- .../copy-bounds-impl-type-params.rs} | 0 .../copy-bounds-impl-type-params.stderr} | 30 ++++++------ .../inherited-copy-bound.rs} | 0 .../inherited-copy-bound.stderr} | 10 ++-- .../send-trait-objects-basic.rs | 0 .../send-trait-objects-basic.stderr | 0 11 files changed, 48 insertions(+), 52 deletions(-) rename tests/ui/{kindck/kindck-copy.rs => traits/basic-copyable-types.rs} (100%) rename tests/ui/{kindck/kindck-copy.stderr => traits/basic-copyable-types.stderr} (83%) rename tests/ui/{kindck/kindck-nonsendable-1.rs => traits/closure-rc-not-send.rs} (100%) rename tests/ui/{kindck/kindck-nonsendable-1.stderr => traits/closure-rc-not-send.stderr} (66%) rename tests/ui/{kindck/kindck-impl-type-params.rs => traits/copy-bounds-impl-type-params.rs} (100%) rename tests/ui/{kindck/kindck-impl-type-params.stderr => traits/copy-bounds-impl-type-params.stderr} (86%) rename tests/ui/{kindck/kindck-inherited-copy-bound.rs => traits/inherited-copy-bound.rs} (100%) rename tests/ui/{kindck/kindck-inherited-copy-bound.stderr => traits/inherited-copy-bound.stderr} (83%) rename tests/ui/{kindck => traits}/send-trait-objects-basic.rs (100%) rename tests/ui/{kindck => traits}/send-trait-objects-basic.stderr (100%) diff --git a/tests/ui/README.md b/tests/ui/README.md index 848df58f27143..845f02918de92 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -784,10 +784,6 @@ These tests revolve around the `--json` compiler flag. See [JSON Output](https:/ Tests exercising keywords, such as attempting to use them as identifiers when not contextual keywords. -## `tests/ui/kindck/` - -**FIXME**: `kindck` is no longer a thing, these tests probably need to be audited and rehomed. - ## `tests/ui/label/` Exercises block and loop `'label`s. diff --git a/tests/ui/kindck/kindck-copy.rs b/tests/ui/traits/basic-copyable-types.rs similarity index 100% rename from tests/ui/kindck/kindck-copy.rs rename to tests/ui/traits/basic-copyable-types.rs diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/traits/basic-copyable-types.stderr similarity index 83% rename from tests/ui/kindck/kindck-copy.stderr rename to tests/ui/traits/basic-copyable-types.stderr index 01b4a5a646476..b4fa957533357 100644 --- a/tests/ui/kindck/kindck-copy.stderr +++ b/tests/ui/traits/basic-copyable-types.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied - --> $DIR/kindck-copy.rs:27:19 + --> $DIR/basic-copyable-types.rs:27:19 | LL | assert_copy::<&'static mut isize>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` @@ -16,13 +16,13 @@ LL + assert_copy::(); | error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied - --> $DIR/kindck-copy.rs:28:19 + --> $DIR/basic-copyable-types.rs:28:19 | LL | assert_copy::<&'a mut isize>(); | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` @@ -33,114 +33,114 @@ LL + assert_copy::(); | error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:31:19 + --> $DIR/basic-copyable-types.rs:31:19 | LL | assert_copy::>(); | ^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/kindck-copy.rs:32:19 + --> $DIR/basic-copyable-types.rs:32:19 | LL | assert_copy::(); | ^^^^^^ the trait `Copy` is not implemented for `String` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Vec: Copy` is not satisfied - --> $DIR/kindck-copy.rs:33:19 + --> $DIR/basic-copyable-types.rs:33:19 | LL | assert_copy::>(); | ^^^^^^^^^^ the trait `Copy` is not implemented for `Vec` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box<&'a mut isize>: Copy` is not satisfied - --> $DIR/kindck-copy.rs:34:19 + --> $DIR/basic-copyable-types.rs:34:19 | LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<&'a mut isize>` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:42:19 + --> $DIR/basic-copyable-types.rs:42:19 | LL | assert_copy::>(); | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:43:19 + --> $DIR/basic-copyable-types.rs:43:19 | LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not satisfied - --> $DIR/kindck-copy.rs:46:19 + --> $DIR/basic-copyable-types.rs:46:19 | LL | assert_copy::<&'a mut (dyn Dummy + Send)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied - --> $DIR/kindck-copy.rs:64:19 + --> $DIR/basic-copyable-types.rs:64:19 | LL | assert_copy::(); | ^^^^^^^^^^^^^^^ unsatisfied trait bound | help: the trait `Copy` is not implemented for `MyNoncopyStruct` - --> $DIR/kindck-copy.rs:15:1 + --> $DIR/basic-copyable-types.rs:15:1 | LL | struct MyNoncopyStruct { | ^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Rc: Copy` is not satisfied - --> $DIR/kindck-copy.rs:67:19 + --> $DIR/basic-copyable-types.rs:67:19 | LL | assert_copy::>(); | ^^^^^^^^^ the trait `Copy` is not implemented for `Rc` | note: required by a bound in `assert_copy` - --> $DIR/kindck-copy.rs:5:19 + --> $DIR/basic-copyable-types.rs:5:19 | LL | fn assert_copy() {} | ^^^^ required by this bound in `assert_copy` diff --git a/tests/ui/kindck/kindck-nonsendable-1.rs b/tests/ui/traits/closure-rc-not-send.rs similarity index 100% rename from tests/ui/kindck/kindck-nonsendable-1.rs rename to tests/ui/traits/closure-rc-not-send.rs diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/traits/closure-rc-not-send.stderr similarity index 66% rename from tests/ui/kindck/kindck-nonsendable-1.stderr rename to tests/ui/traits/closure-rc-not-send.stderr index 4bf8e17e3ed96..5e73f13648d5c 100644 --- a/tests/ui/kindck/kindck-nonsendable-1.stderr +++ b/tests/ui/traits/closure-rc-not-send.stderr @@ -1,21 +1,21 @@ error[E0277]: `Rc` cannot be sent between threads safely - --> $DIR/kindck-nonsendable-1.rs:9:9 + --> $DIR/closure-rc-not-send.rs:9:9 | LL | bar(move || foo(x)); | --- -------^^^^^^^ | | | | | `Rc` cannot be sent between threads safely - | | within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:16}` + | | within this `{closure@$DIR/closure-rc-not-send.rs:9:9: 9:16}` | required by a bound introduced by this call | - = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:16}`, the trait `Send` is not implemented for `Rc` + = help: within `{closure@$DIR/closure-rc-not-send.rs:9:9: 9:16}`, the trait `Send` is not implemented for `Rc` note: required because it's used within this closure - --> $DIR/kindck-nonsendable-1.rs:9:9 + --> $DIR/closure-rc-not-send.rs:9:9 | LL | bar(move || foo(x)); | ^^^^^^^ note: required by a bound in `bar` - --> $DIR/kindck-nonsendable-1.rs:5:22 + --> $DIR/closure-rc-not-send.rs:5:22 | LL | fn bar(_: F) {} | ^^^^ required by this bound in `bar` diff --git a/tests/ui/kindck/kindck-impl-type-params.rs b/tests/ui/traits/copy-bounds-impl-type-params.rs similarity index 100% rename from tests/ui/kindck/kindck-impl-type-params.rs rename to tests/ui/traits/copy-bounds-impl-type-params.rs diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/traits/copy-bounds-impl-type-params.stderr similarity index 86% rename from tests/ui/kindck/kindck-impl-type-params.stderr rename to tests/ui/traits/copy-bounds-impl-type-params.stderr index b2e52ae57ea4a..08fde8fb5df35 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/traits/copy-bounds-impl-type-params.stderr @@ -1,11 +1,11 @@ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/kindck-impl-type-params.rs:18:13 + --> $DIR/copy-bounds-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:14:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -18,13 +18,13 @@ LL | fn f(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:18:13 + --> $DIR/copy-bounds-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; | ^^ the trait `Copy` is not implemented for `T` | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:14:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -37,13 +37,13 @@ LL | fn f(val: T) { | +++++++++++++++++++ error[E0277]: `T` cannot be sent between threads safely - --> $DIR/kindck-impl-type-params.rs:25:31 + --> $DIR/copy-bounds-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; | ^^ `T` cannot be sent between threads safely | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:14:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -56,13 +56,13 @@ LL | fn g(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:25:31 + --> $DIR/copy-bounds-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; | ^^ the trait `Copy` is not implemented for `T` | note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:14:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -75,18 +75,18 @@ LL | fn g(val: T) { | +++++++++++++++++++ error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:38:13 + --> $DIR/copy-bounds-impl-type-params.rs:38:13 | LL | let a = t as Box>; | ^ the trait `Copy` is not implemented for `String` | help: the trait `Gettable` is implemented for `S` - --> $DIR/kindck-impl-type-params.rs:14:1 + --> $DIR/copy-bounds-impl-type-params.rs:14:1 | LL | impl Gettable for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:14:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -95,18 +95,18 @@ LL | impl Gettable for S {} = note: required for the cast from `Box>` to `Box>` error[E0277]: the trait bound `Foo: Copy` is not satisfied - --> $DIR/kindck-impl-type-params.rs:46:37 + --> $DIR/copy-bounds-impl-type-params.rs:46:37 | LL | let a: Box> = t; | ^ the trait `Copy` is not implemented for `Foo` | help: the trait `Gettable` is implemented for `S` - --> $DIR/kindck-impl-type-params.rs:14:1 + --> $DIR/copy-bounds-impl-type-params.rs:14:1 | LL | impl Gettable for S {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required for `S` to implement `Gettable` - --> $DIR/kindck-impl-type-params.rs:14:32 + --> $DIR/copy-bounds-impl-type-params.rs:14:32 | LL | impl Gettable for S {} | ---- ^^^^^^^^^^^ ^^^^ @@ -120,7 +120,7 @@ LL | struct Foo; // does not impl Copy | error: lifetime may not live long enough - --> $DIR/kindck-impl-type-params.rs:32:13 + --> $DIR/copy-bounds-impl-type-params.rs:32:13 | LL | fn foo<'a>() { | -- lifetime `'a` defined here diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/traits/inherited-copy-bound.rs similarity index 100% rename from tests/ui/kindck/kindck-inherited-copy-bound.rs rename to tests/ui/traits/inherited-copy-bound.rs diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.stderr b/tests/ui/traits/inherited-copy-bound.stderr similarity index 83% rename from tests/ui/kindck/kindck-inherited-copy-bound.stderr rename to tests/ui/traits/inherited-copy-bound.stderr index d6c9cab5b57a7..c251d59224463 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.stderr +++ b/tests/ui/traits/inherited-copy-bound.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied - --> $DIR/kindck-inherited-copy-bound.rs:15:16 + --> $DIR/inherited-copy-bound.rs:15:16 | LL | take_param(&x); | ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>` @@ -7,27 +7,27 @@ LL | take_param(&x); | required by a bound introduced by this call | note: required for `Box<{integer}>` to implement `Foo` - --> $DIR/kindck-inherited-copy-bound.rs:9:15 + --> $DIR/inherited-copy-bound.rs:9:15 | LL | impl Foo for T {} | ---- ^^^ ^ | | | unsatisfied trait bound introduced here note: required by a bound in `take_param` - --> $DIR/kindck-inherited-copy-bound.rs:11:18 + --> $DIR/inherited-copy-bound.rs:11:18 | LL | fn take_param(foo: &T) {} | ^^^ required by this bound in `take_param` error[E0038]: the trait `Foo` is not dyn compatible - --> $DIR/kindck-inherited-copy-bound.rs:21:24 + --> $DIR/inherited-copy-bound.rs:21:24 | LL | let z = &x as &dyn Foo; | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit - --> $DIR/kindck-inherited-copy-bound.rs:5:12 + --> $DIR/inherited-copy-bound.rs:5:12 | LL | trait Foo: Copy { | --- ^^^^ ...because it requires `Self: Sized` diff --git a/tests/ui/kindck/send-trait-objects-basic.rs b/tests/ui/traits/send-trait-objects-basic.rs similarity index 100% rename from tests/ui/kindck/send-trait-objects-basic.rs rename to tests/ui/traits/send-trait-objects-basic.rs diff --git a/tests/ui/kindck/send-trait-objects-basic.stderr b/tests/ui/traits/send-trait-objects-basic.stderr similarity index 100% rename from tests/ui/kindck/send-trait-objects-basic.stderr rename to tests/ui/traits/send-trait-objects-basic.stderr From eda328c6cfce47bb99d2daba946bf938dad8f78e Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 17 Mar 2026 22:08:51 +0000 Subject: [PATCH 23/33] delete incorrect test --- .../kindck-implicit-close-over-mut-var.rs | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs diff --git a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs b/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs deleted file mode 100644 index 22ed8bd3beefa..0000000000000 --- a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ run-pass - -#![allow(unused_must_use)] -#![allow(dead_code)] -use std::thread; - -fn user(_i: isize) {} - -fn foo() { - // Here, i is *copied* into the proc (heap closure). - // Requires allocation. The proc's copy is not mutable. - let mut i = 0; - let t = thread::spawn(move|| { - user(i); - println!("spawned {}", i) - }); - i += 1; - println!("original {}", i); - t.join(); -} - -fn bar() { - // Here, the original i has not been moved, only copied, so is still - // mutable outside of the proc. - let mut i = 0; - while i < 10 { - let t = thread::spawn(move|| { - user(i); - }); - i += 1; - t.join(); - } -} - -fn car() { - // Here, i must be shadowed in the proc to be mutable. - let mut i = 0; - while i < 10 { - let t = thread::spawn(move|| { - let mut i = i; - i += 1; - user(i); - }); - i += 1; - t.join(); - } -} - -pub fn main() {} From 38aa32217bdfab5bf585bf2b6c5bf54a053e4810 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Mar 2026 08:32:52 +0100 Subject: [PATCH 24/33] borrowck/type_check: remove helper left-over from unsized locals --- compiler/rustc_borrowck/src/type_check/mod.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9aa8f7a2067a5..47f14dc3df62e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -374,10 +374,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.body } - fn unsized_feature_enabled(&self) -> bool { - self.tcx().features().unsized_fn_params() - } - /// Equate the inferred type and the annotated type for user type annotations #[instrument(skip(self), level = "debug")] fn check_user_type_annotations(&mut self) { @@ -660,7 +656,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } - if !self.unsized_feature_enabled() { + if !self.tcx().features().unsized_fn_params() { let trait_ref = ty::TraitRef::new( tcx, tcx.require_lang_item(LangItem::Sized, self.last_span), @@ -936,9 +932,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - // When `unsized_fn_params` is enabled, only function calls - // and nullary ops are checked in `check_call_dest`. - if !self.unsized_feature_enabled() { + // When `unsized_fn_params` is enabled, this is checked in `check_call_dest`, + // and `hir_typeck` still forces all non-argument locals to be sized (i.e., we don't + // fully re-check what was already checked on HIR). + if !self.tcx().features().unsized_fn_params() { match self.body.local_kind(local) { LocalKind::ReturnPointer | LocalKind::Arg => { // return values of normal functions are required to be @@ -1953,8 +1950,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // When `unsized_fn_params` is not enabled, - // this check is done at `check_local`. - if self.unsized_feature_enabled() { + // this check is done at `visit_local_decl`. + if self.tcx().features().unsized_fn_params() { let span = term.source_info.span; self.ensure_place_sized(dest_ty, span); } From 6b0fecf582cc6788d0f246a2d7e5a7471462c506 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 18 Mar 2026 09:37:35 +0000 Subject: [PATCH 25/33] merge `regions-outlives-nominal-type-*` tests into one file --- ...s-outlives-nominal-type-enum-region-rev.rs | 20 ----- ...gions-outlives-nominal-type-enum-region.rs | 20 ----- ...ons-outlives-nominal-type-enum-type-rev.rs | 20 ----- ...regions-outlives-nominal-type-enum-type.rs | 20 ----- ...outlives-nominal-type-struct-region-rev.rs | 20 ----- ...ons-outlives-nominal-type-struct-region.rs | 20 ----- ...s-outlives-nominal-type-struct-type-rev.rs | 20 ----- ...gions-outlives-nominal-type-struct-type.rs | 20 ----- .../regions/regions-outlives-nominal-type.rs | 80 +++++++++++++++++++ 9 files changed, 80 insertions(+), 160 deletions(-) delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-enum-region.rs delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-enum-type.rs delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-struct-region.rs delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-struct-type.rs create mode 100644 tests/ui/regions/regions-outlives-nominal-type.rs diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs deleted file mode 100644 index 3d4a305078843..0000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod rev_variant_struct_region { - struct Foo<'a> { - x: fn(&'a i32), - } - enum Bar<'a,'b> { - V(&'a Foo<'b>) - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs deleted file mode 100644 index 2e0d1b36ca59e..0000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_region { - struct Foo<'a> { - x: &'a i32, - } - enum Bar<'a,'b> { - V(&'a Foo<'b>) - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs deleted file mode 100644 index baf7874bc1a61..0000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_type { - struct Foo { - x: fn(T) - } - enum Bar<'a,'b> { - V(&'a Foo<&'b i32>) - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs deleted file mode 100644 index b8392c967b10a..0000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_type { - struct Foo { - x: T - } - enum Bar<'a,'b> { - V(&'a Foo<&'b i32>) - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs deleted file mode 100644 index 6a50248cb70b0..0000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod rev_variant_struct_region { - struct Foo<'a> { - x: fn(&'a i32), - } - struct Bar<'a,'b> { - f: &'a Foo<'b> - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs deleted file mode 100644 index 17564bcbf269f..0000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_region { - struct Foo<'a> { - x: &'a i32, - } - struct Bar<'a,'b> { - f: &'a Foo<'b> - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs deleted file mode 100644 index 33961de7d6a45..0000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod rev_variant_struct_type { - struct Foo { - x: fn(T) - } - struct Bar<'a,'b> { - f: &'a Foo<&'b i32> - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs deleted file mode 100644 index c5238086fc05d..0000000000000 --- a/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its -// arguments (like `'a`) outlive `'b`. -// -// Rule OutlivesNominalType from RFC 1214. - -//@ check-pass - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -mod variant_struct_type { - struct Foo { - x: T - } - struct Bar<'a,'b> { - f: &'a Foo<&'b i32> - } -} - -fn main() { } diff --git a/tests/ui/regions/regions-outlives-nominal-type.rs b/tests/ui/regions/regions-outlives-nominal-type.rs new file mode 100644 index 0000000000000..177d064042dd8 --- /dev/null +++ b/tests/ui/regions/regions-outlives-nominal-type.rs @@ -0,0 +1,80 @@ +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +//@ check-pass + +mod variant_enum_region { + struct Foo<'a> { + x: &'a i32, + } + enum Bar<'a, 'b> { + V(&'a Foo<'b>), + } +} + +mod rev_variant_enum_region { + struct Foo<'a> { + x: fn(&'a i32), + } + enum Bar<'a, 'b> { + V(&'a Foo<'b>), + } +} + +mod variant_enum_type { + struct Foo { + x: T, + } + enum Bar<'a, 'b> { + V(&'a Foo<&'b i32>), + } +} + +mod rev_variant_enum_type { + struct Foo { + x: fn(T), + } + enum Bar<'a, 'b> { + V(&'a Foo<&'b i32>), + } +} + +mod variant_struct_region { + struct Foo<'a> { + x: &'a i32, + } + struct Bar<'a, 'b> { + f: &'a Foo<'b>, + } +} + +mod rev_variant_struct_region { + struct Foo<'a> { + x: fn(&'a i32), + } + struct Bar<'a, 'b> { + f: &'a Foo<'b>, + } +} + +mod variant_struct_type { + struct Foo { + x: T, + } + struct Bar<'a, 'b> { + f: &'a Foo<&'b i32>, + } +} + +mod rev_variant_struct_type { + struct Foo { + x: fn(T), + } + struct Bar<'a, 'b> { + f: &'a Foo<&'b i32>, + } +} + +fn main() {} From a4d23841001ace656ed84df9792f257830f44fa3 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Wed, 18 Mar 2026 12:21:09 +0100 Subject: [PATCH 26/33] Move hashes into a separate json file --- src/bootstrap/src/core/build_steps/setup.rs | 66 ++++--------------- .../src/core/build_steps/setup/hashes.json | 53 +++++++++++++++ .../src/core/build_steps/setup/tests.rs | 10 ++- 3 files changed, 69 insertions(+), 60 deletions(-) create mode 100644 src/bootstrap/src/core/build_steps/setup/hashes.json diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index f4e6a20ec8497..1854637fc93ba 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -12,7 +12,10 @@ use std::io::Write; use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf}; use std::str::FromStr; use std::{fmt, fs, io}; +use std::collections::HashMap; +use std::sync::LazyLock; +use serde_derive::Deserialize; use sha2::Digest; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; @@ -529,7 +532,8 @@ undesirable, simply delete the `pre-push` file from .git/hooks." } /// Handles editor-specific setup differences -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Deserialize)] +#[serde(rename_all = "lowercase")] enum EditorKind { Emacs, Helix, @@ -588,59 +592,13 @@ Select which editor you would like to set up [default: None]: "; /// New entries should be appended whenever this is updated so we can detect /// outdated vs. user-modified settings files. fn hashes(&self) -> &'static [&'static str] { - match self { - EditorKind::Emacs => &[ - "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", - "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", - "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088", - "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", - "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", - "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1", - "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308", - "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938", - ], - EditorKind::Helix => &[ - "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", - "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", - "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", - "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", - "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1", - "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6", - "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6", - "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed", - ], - EditorKind::Vim | EditorKind::VsCode => &[ - "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", - "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", - "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", - "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", - "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", - "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", - "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", - "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", - "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", - "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", - "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", - "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", - "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", - "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", - "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", - "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798", - "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc", - "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd", - ], - EditorKind::Zed => &[ - "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", - "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909", - "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", - "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", - "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382", - "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f", - "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9", - "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568", - "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951", - ], - } + const ALL_HASHES: &str = include_str!("setup/hashes.json"); + static PARSED_HASHES: LazyLock>> = LazyLock::new(|| { + let mut map: HashMap<_, Vec<_>> = serde_json::from_str(ALL_HASHES).unwrap(); + map.insert(EditorKind::Vim, map.get(&EditorKind::VsCode).unwrap().clone()); + map + }); + &*PARSED_HASHES.get(self).unwrap() } fn settings_path(&self, config: &Config) -> PathBuf { diff --git a/src/bootstrap/src/core/build_steps/setup/hashes.json b/src/bootstrap/src/core/build_steps/setup/hashes.json new file mode 100644 index 0000000000000..be657b5772002 --- /dev/null +++ b/src/bootstrap/src/core/build_steps/setup/hashes.json @@ -0,0 +1,53 @@ +{ + "emacs": [ + "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", + "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", + "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088", + "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", + "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", + "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1", + "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308", + "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938" + ], + "helix": [ + "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", + "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", + "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", + "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", + "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1", + "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6", + "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6", + "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed" + ], + "vscode": [ + "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", + "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", + "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", + "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", + "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", + "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", + "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", + "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", + "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", + "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", + "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", + "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", + "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", + "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", + "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798", + "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc", + "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd" + ], + "zed": [ + "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", + "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909", + "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", + "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", + "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382", + "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f", + "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9", + "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568", + "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951" + ] +} diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs index e8f83ff75e404..6eafbb40b4674 100644 --- a/src/bootstrap/src/core/build_steps/setup/tests.rs +++ b/src/bootstrap/src/core/build_steps/setup/tests.rs @@ -8,13 +8,11 @@ fn check_matching_settings_hash() { for editor in EditorKind::ALL { let mut hasher = sha2::Sha256::new(); hasher.update(&editor.settings_template()); - let hash = hex_encode(hasher.finalize().as_slice()); + let actual = hex_encode(hasher.finalize().as_slice()); + let expected = *editor.hashes().last().unwrap(); assert_eq!( - &hash, - editor.hashes().last().unwrap(), - "Update `EditorKind::hashes()` with the new hash of `{}` for `EditorKind::{:?}`", - editor.settings_template(), - editor, + expected, actual, + "Update `setup/hashes.json` with the new hash of `{actual}` for `EditorKind::{editor:?}`", ); } } From 49bb371ca74904400330e065dd847b6b9390b2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 11 Mar 2026 16:39:03 +0000 Subject: [PATCH 27/33] When single impl can satisfy inference error, suggest type When encountering an inference error where a return type must be known, like when calling `Iterator::sum::()` without specifying `T`, look for all `T` that would satisfy `Sum`. If only one, suggest it. ``` error[E0283]: type annotations needed --> $DIR/cannot-infer-iterator-sum-return-type.rs:4:9 | LL | let sum = v | ^^^ ... LL | .sum(); // `sum::` needs `T` to be specified | --- type must be known at this point | = note: cannot satisfy `_: Sum` help: the trait `Sum` is implemented for `i32` --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL | = note: in this macro invocation note: required by a bound in `std::iter::Iterator::sum` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL = note: this error originates in the macro `integer_sum_product` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider giving `sum` an explicit type, where the type for type parameter `S` is specified | LL | let sum: i32 = v | +++++ ``` --- .../error_reporting/infer/need_type_info.rs | 64 ++++++++++++++++--- .../src/error_reporting/traits/ambiguity.rs | 27 +++++++- .../traits/fulfillment_errors.rs | 10 +++ .../const-generics/issues/issue-83249.stderr | 6 +- ...annot-infer-iterator-sum-return-type.fixed | 13 ++++ .../cannot-infer-iterator-sum-return-type.rs | 13 ++++ ...nnot-infer-iterator-sum-return-type.stderr | 26 ++++++++ 7 files changed, 145 insertions(+), 14 deletions(-) create mode 100644 tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed create mode 100644 tests/ui/inference/cannot-infer-iterator-sum-return-type.rs create mode 100644 tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 5cb8922574b61..7fcaea3a629f1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -158,6 +158,7 @@ impl UnderspecifiedArgKind { struct ClosureEraser<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, + depth: usize, } impl<'a, 'tcx> ClosureEraser<'a, 'tcx> { @@ -172,7 +173,8 @@ impl<'a, 'tcx> TypeFolder> for ClosureEraser<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind() { + self.depth += 1; + let ty = match ty.kind() { ty::Closure(_, args) => { // For a closure type, we turn it into a function pointer so that it gets rendered // as `fn(args) -> Ret`. @@ -233,9 +235,15 @@ impl<'a, 'tcx> TypeFolder> for ClosureEraser<'a, 'tcx> { // its type parameters. ty.super_fold_with(self) } - // We don't have an unknown type parameter anywhere, replace with `_`. + // We are in the top-level type, not one of its type parameters. Name it with its + // parameters replaced. + _ if self.depth == 1 => ty.super_fold_with(self), + // We don't have an unknown type parameter anywhere, and we are in a type parameter. + // Replace with `_`. _ => self.new_infer(), - } + }; + self.depth -= 1; + ty } fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { @@ -287,7 +295,7 @@ fn ty_to_string<'tcx>( let ty = infcx.resolve_vars_if_possible(ty); // We use `fn` ptr syntax for closures, but this only works when the closure does not capture // anything. We also remove all type parameters that are fully known to the type system. - let ty = ty.fold_with(&mut ClosureEraser { infcx }); + let ty = ty.fold_with(&mut ClosureEraser { infcx, depth: 0 }); match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in @@ -467,6 +475,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { term: Term<'tcx>, error_code: TypeAnnotationNeeded, should_label_span: bool, + ) -> Diag<'a> { + self.emit_inference_failure_err_with_type_hint( + body_def_id, + failure_span, + term, + error_code, + should_label_span, + None, + ) + } + + pub fn emit_inference_failure_err_with_type_hint( + &self, + body_def_id: LocalDefId, + failure_span: Span, + term: Term<'tcx>, + error_code: TypeAnnotationNeeded, + should_label_span: bool, + ty: Option>, ) -> Diag<'a> { let term = self.resolve_vars_if_possible(term); let arg_data = self @@ -479,7 +506,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; - let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term); + let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term, ty); if let Some(body) = self.tcx.hir_maybe_body_owned_by( self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(), ) { @@ -779,10 +806,20 @@ impl<'tcx> InferSourceKind<'tcx> { | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { ("closure", closure_as_fn_str(infcx, ty), long_ty_path) - } else if !ty.is_ty_or_numeric_infer() { - ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path) - } else { + } else if ty.is_ty_or_numeric_infer() + || ty.is_primitive() + || matches!( + ty.kind(), + ty::Adt(_, args) + if args.types().count() == 0 && args.consts().count() == 0 + ) + { + // `ty` is either `_`, a primitive type like `u32` or a type with no type or + // const parameters. We will not mention the type in the main inference error + // message. ("other", String::new(), long_ty_path) + } else { + ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path) } } // FIXME: We should be able to add some additional info here. @@ -815,6 +852,7 @@ struct FindInferSourceVisitor<'a, 'tcx> { typeck_results: &'a TypeckResults<'tcx>, target: Term<'tcx>, + ty: Option>, attempt: usize, infer_source_cost: usize, @@ -826,12 +864,14 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { tecx: &'a TypeErrCtxt<'a, 'tcx>, typeck_results: &'a TypeckResults<'tcx>, target: Term<'tcx>, + ty: Option>, ) -> Self { FindInferSourceVisitor { tecx, typeck_results, target, + ty, attempt: 0, infer_source_cost: usize::MAX, @@ -1213,7 +1253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) { intravisit::walk_local(self, local); - if let Some(ty) = self.opt_node_type(local.hir_id) { + if let Some(mut ty) = self.opt_node_type(local.hir_id) { if self.generic_arg_contains_target(ty.into()) { fn get_did( typeck_results: &TypeckResults<'_>, @@ -1241,7 +1281,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { _ => None, } } - + if let Some(t) = self.ty + && ty.has_infer() + { + ty = t; + } if let LocalSource::Normal = local.source && local.ty.is_none() { 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 7de8891196d85..7f5ed9ecb6d11 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -246,12 +246,37 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .find(|s| s.has_non_region_infer()); let mut err = if let Some(term) = term { - self.emit_inference_failure_err( + let candidates: Vec<_> = self + .tcx + .all_impls(trait_pred.def_id()) + .filter_map(|def_id| { + let imp = self.tcx.impl_trait_header(def_id); + if imp.polarity != ty::ImplPolarity::Positive + || !self.tcx.is_user_visible_dep(def_id.krate) + { + return None; + } + let imp = imp.trait_ref.skip_binder(); + if imp + .with_replaced_self_ty(self.tcx, trait_pred.skip_binder().self_ty()) + == trait_pred.skip_binder().trait_ref + { + Some(imp.self_ty()) + } else { + None + } + }) + .collect(); + self.emit_inference_failure_err_with_type_hint( obligation.cause.body_id, span, term, TypeAnnotationNeeded::E0283, true, + match &candidates[..] { + [candidate] => Some(*candidate), + _ => None, + }, ) } else { struct_span_code_err!( 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 d5383fd4d0831..6bf08170bcf7e 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 @@ -2251,6 +2251,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if candidates.is_empty() { return false; } + let mut specific_candidates = candidates.clone(); + specific_candidates.retain(|(tr, _)| { + tr.with_replaced_self_ty(self.tcx, trait_pred.skip_binder().self_ty()) + == trait_pred.skip_binder().trait_ref + }); + if !specific_candidates.is_empty() { + // We have found a subset of impls that fully satisfy the expected trait, only + // mention those types. + candidates = specific_candidates; + } if let &[(cand, def_id)] = &candidates[..] { if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id) && !self.tcx.features().enabled(sym::try_trait_v2) diff --git a/tests/ui/const-generics/issues/issue-83249.stderr b/tests/ui/const-generics/issues/issue-83249.stderr index 2668348613a40..0f00f70700f52 100644 --- a/tests/ui/const-generics/issues/issue-83249.stderr +++ b/tests/ui/const-generics/issues/issue-83249.stderr @@ -17,10 +17,10 @@ note: required by a bound in `foo` | LL | fn foo(_: [u8; T::N]) -> T { | ^^^ required by this bound in `foo` -help: consider giving this pattern a type +help: consider giving this pattern a type, where the type for type parameter `T` is specified | -LL | let _: /* Type */ = foo([0; 1]); - | ++++++++++++ +LL | let _: u8 = foo([0; 1]); + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed b/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed new file mode 100644 index 0000000000000..9a494391f0e4f --- /dev/null +++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed @@ -0,0 +1,13 @@ +//@ run-rustfix +fn main() { + let v = vec![1, 2]; + let sum: i32 = v //~ ERROR: type annotations needed + .iter() + .map(|val| *val) + .sum(); // `sum::` needs `T` to be specified + // In this case any integer would fit, but we resolve to `i32` because that's what `{integer}` + // got coerced to. If the user needs further hinting that they can change the integer type, that + // can come from other suggestions. (#100802) + let bool = sum > 0; + assert_eq!(bool, true); +} diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs b/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs new file mode 100644 index 0000000000000..013a2f9148586 --- /dev/null +++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs @@ -0,0 +1,13 @@ +//@ run-rustfix +fn main() { + let v = vec![1, 2]; + let sum = v //~ ERROR: type annotations needed + .iter() + .map(|val| *val) + .sum(); // `sum::` needs `T` to be specified + // In this case any integer would fit, but we resolve to `i32` because that's what `{integer}` + // got coerced to. If the user needs further hinting that they can change the integer type, that + // can come from other suggestions. (#100802) + let bool = sum > 0; + assert_eq!(bool, true); +} diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr b/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr new file mode 100644 index 0000000000000..594b6f0181db0 --- /dev/null +++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr @@ -0,0 +1,26 @@ +error[E0283]: type annotations needed + --> $DIR/cannot-infer-iterator-sum-return-type.rs:4:9 + | +LL | let sum = v + | ^^^ +... +LL | .sum(); // `sum::` needs `T` to be specified + | --- type must be known at this point + | + = note: the type must implement `Sum` +help: the trait `Sum` is implemented for `i32` + --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL + | + = note: in this macro invocation +note: required by a bound in `std::iter::Iterator::sum` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + = note: this error originates in the macro `integer_sum_product` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider giving `sum` an explicit type, where the type for type parameter `S` is specified + | +LL | let sum: i32 = v + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. From ca2139d3262232d6b15471783f503ffe125531f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 16 Mar 2026 22:38:16 +0000 Subject: [PATCH 28/33] Point at return type when it is the source of the type expectation When calling an fn that returns a return type as a returned expression, point at the return type to explain that it affects the expected type. ``` error[E0308]: mismatched types --> f56.rs:5:15 | 3 | fn main() { | - the call expression's return type is influenced by this return type 4 | let a = 0; 5 | ptr::read(&a) | --------- ^^ expected `*const ()`, found `&{integer}` | | | arguments to this function are incorrect | = note: expected raw pointer `*const ()` found reference `&{integer}` note: function defined here --> library/core/src/ptr/mod.rs:1681:21 | 1681 | pub const unsafe fn read(src: *const T) -> T { | ^^^^ ``` --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 41 ++++++++++++++++++- .../expectation-from-return-type.rs | 21 ++++++++++ .../expectation-from-return-type.stderr | 35 ++++++++++++++++ ...ransforming-option-ref-issue-127545.stderr | 6 +++ ...call-return-type-due-to-generic-arg.stderr | 3 ++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tests/ui/mismatched_types/expectation-from-return-type.rs create mode 100644 tests/ui/mismatched_types/expectation-from-return-type.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9faa75e18480d..f53259e91eec1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -11,7 +11,7 @@ use rustc_hir::attrs::DivergingBlockBehavior; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal}; +use rustc_hir::{Expr, ExprKind, FnRetTy, HirId, LangItem, Node, QPath, is_range_literal}; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants}; use rustc_index::IndexVec; @@ -1587,6 +1587,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); + if let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(def_id) + && let ty::Param(_) = + self.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output().kind() + && let parent = self.tcx.hir_get_parent_item(call_expr.hir_id).def_id + && let Some((output, body_id)) = match self.tcx.hir_node_by_def_id(parent) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn { sig, body, .. }, + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body)), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(sig, body), + .. + }) => Some((sig.decl.output, body)), + _ => None, + } + && let expr = self.tcx.hir_body(*body_id).value + && (expr.peel_blocks().span == call_expr.span + || matches!( + self.tcx.parent_hir_node(call_expr.hir_id), + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. }) + )) + { + err.span_label( + output.span(), + match output { + FnRetTy::DefaultReturn(_) => format!( + "this implicit `()` return type influences the call expression's return type" + ), + FnRetTy::Return(_) => { + "this return type influences the call expression's return type" + .to_string() + } + }, + ); + } } else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id) && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind { diff --git a/tests/ui/mismatched_types/expectation-from-return-type.rs b/tests/ui/mismatched_types/expectation-from-return-type.rs new file mode 100644 index 0000000000000..ffe3d929984df --- /dev/null +++ b/tests/ui/mismatched_types/expectation-from-return-type.rs @@ -0,0 +1,21 @@ +use std::ptr; + +fn main() { //~ NOTE: this implicit `()` return type influences the call expression's return type + let a = 0; + ptr::read(&a) + //~^ ERROR: mismatched types + //~| NOTE: expected `*const ()`, found `&{integer}` + //~| NOTE: arguments to this function are incorrect + //~| NOTE: expected raw pointer + //~| NOTE: function defined here +} + +fn foo() { //~ NOTE: this implicit `()` return type influences the call expression's return type + let a = 0; + return ptr::read(&a); + //~^ ERROR: mismatched types + //~| NOTE: expected `*const ()`, found `&{integer}` + //~| NOTE: arguments to this function are incorrect + //~| NOTE: expected raw pointer + //~| NOTE: function defined here +} diff --git a/tests/ui/mismatched_types/expectation-from-return-type.stderr b/tests/ui/mismatched_types/expectation-from-return-type.stderr new file mode 100644 index 0000000000000..3bd7a21f987fc --- /dev/null +++ b/tests/ui/mismatched_types/expectation-from-return-type.stderr @@ -0,0 +1,35 @@ +error[E0308]: mismatched types + --> $DIR/expectation-from-return-type.rs:5:15 + | +LL | fn main() { + | - this implicit `()` return type influences the call expression's return type +LL | let a = 0; +LL | ptr::read(&a) + | --------- ^^ expected `*const ()`, found `&{integer}` + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*const ()` + found reference `&{integer}` +note: function defined here + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + +error[E0308]: mismatched types + --> $DIR/expectation-from-return-type.rs:15:22 + | +LL | fn foo() { + | - this implicit `()` return type influences the call expression's return type +LL | let a = 0; +LL | return ptr::read(&a); + | --------- ^^ expected `*const ()`, found `&{integer}` + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*const ()` + found reference `&{integer}` +note: function defined here + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 9a18798db2139..6243a9a729a2f 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -16,6 +16,8 @@ LL | arg.map(|v| &**v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:9:19 | +LL | pub fn bar(arg: Option<&Vec>) -> &[i32] { + | ------ this return type influences the call expression's return type LL | arg.unwrap_or(&[]) | --------- ^^^ expected `&Vec`, found `&[_; 0]` | | @@ -41,6 +43,8 @@ LL + arg.map_or(&[], |v| v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:13:19 | +LL | pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { + | --------- this return type influences the call expression's return type LL | arg.unwrap_or(v) | --------- ^ expected `&Vec`, found `&[i32]` | | @@ -66,6 +70,8 @@ LL + arg.map_or(v, |v| v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:17:19 | +LL | pub fn convert_result(arg: Result<&Vec, ()>) -> &[i32] { + | ------ this return type influences the call expression's return type LL | arg.unwrap_or(&[]) | --------- ^^^ expected `&Vec`, found `&[_; 0]` | | diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr index 53920bc9e02ec..fd07d5b09aeb0 100644 --- a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr @@ -112,6 +112,9 @@ LL + let x: u16 = (S {}).method(0u16); error[E0308]: arguments to this function are incorrect --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5 | +LL | fn main() { + | - this implicit `()` return type influences the call expression's return type +... LL | function(0u32, 8u8) | ^^^^^^^^ ---- --- expected `bool`, found `u8` | | From 1098a9d032d96d4509f2f9c3a20a5f1959f40440 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Wed, 18 Mar 2026 13:35:58 +0100 Subject: [PATCH 29/33] Support `--bless`-ing editor hashes --- src/bootstrap/src/core/build_steps/setup.rs | 23 ++-- .../src/core/build_steps/setup/hashes.json | 122 ++++++++++-------- .../src/core/build_steps/setup/tests.rs | 40 +++++- 3 files changed, 119 insertions(+), 66 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 1854637fc93ba..85c23ac18e763 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -5,17 +5,17 @@ //! allows setting up things that cannot be simply captured inside the bootstrap.toml, in addition to //! leading people away from manually editing most of the bootstrap.toml values. +use std::collections::BTreeMap; use std::env::consts::EXE_SUFFIX; use std::fmt::Write as _; use std::fs::File; use std::io::Write; use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf}; use std::str::FromStr; -use std::{fmt, fs, io}; -use std::collections::HashMap; use std::sync::LazyLock; +use std::{fmt, fs, io}; -use serde_derive::Deserialize; +use serde_derive::{Deserialize, Serialize}; use sha2::Digest; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; @@ -532,7 +532,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." } /// Handles editor-specific setup differences -#[derive(Clone, Debug, Eq, PartialEq, Hash, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] enum EditorKind { Emacs, @@ -542,6 +542,13 @@ enum EditorKind { Zed, } +static PARSED_HASHES: LazyLock>> = LazyLock::new(|| { + const ALL_HASHES: &str = include_str!("setup/hashes.json"); + let mut map: BTreeMap<_, Vec<_>> = serde_json::from_str(ALL_HASHES).unwrap(); + map.insert(EditorKind::Vim, map.get(&EditorKind::VsCode).unwrap().clone()); + map +}); + impl EditorKind { // Used in `./tests.rs`. #[cfg(test)] @@ -592,13 +599,7 @@ Select which editor you would like to set up [default: None]: "; /// New entries should be appended whenever this is updated so we can detect /// outdated vs. user-modified settings files. fn hashes(&self) -> &'static [&'static str] { - const ALL_HASHES: &str = include_str!("setup/hashes.json"); - static PARSED_HASHES: LazyLock>> = LazyLock::new(|| { - let mut map: HashMap<_, Vec<_>> = serde_json::from_str(ALL_HASHES).unwrap(); - map.insert(EditorKind::Vim, map.get(&EditorKind::VsCode).unwrap().clone()); - map - }); - &*PARSED_HASHES.get(self).unwrap() + PARSED_HASHES.get(self).unwrap() } fn settings_path(&self, config: &Config) -> PathBuf { diff --git a/src/bootstrap/src/core/build_steps/setup/hashes.json b/src/bootstrap/src/core/build_steps/setup/hashes.json index be657b5772002..067c8fffe0d50 100644 --- a/src/bootstrap/src/core/build_steps/setup/hashes.json +++ b/src/bootstrap/src/core/build_steps/setup/hashes.json @@ -1,53 +1,73 @@ { - "emacs": [ - "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", - "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", - "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088", - "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", - "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", - "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1", - "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308", - "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938" - ], - "helix": [ - "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", - "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", - "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", - "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", - "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1", - "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6", - "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6", - "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed" - ], - "vscode": [ - "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", - "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", - "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", - "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", - "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", - "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", - "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", - "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", - "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", - "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", - "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", - "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", - "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", - "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", - "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", - "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798", - "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc", - "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd" - ], - "zed": [ - "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", - "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909", - "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", - "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", - "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382", - "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f", - "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9", - "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568", - "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951" - ] + "emacs": [ + "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", + "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", + "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088", + "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", + "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", + "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1", + "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308", + "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938" + ], + "helix": [ + "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", + "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", + "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", + "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", + "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1", + "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6", + "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6", + "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed" + ], + "vim": [ + "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", + "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", + "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", + "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", + "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", + "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", + "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", + "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", + "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", + "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", + "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", + "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", + "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", + "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", + "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798", + "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc", + "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd" + ], + "vscode": [ + "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", + "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922", + "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", + "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", + "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", + "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", + "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", + "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", + "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", + "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", + "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", + "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", + "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", + "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", + "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798", + "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc", + "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd" + ], + "zed": [ + "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", + "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909", + "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", + "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", + "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382", + "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f", + "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9", + "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568", + "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951" + ] } diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs index 6eafbb40b4674..57b5492866614 100644 --- a/src/bootstrap/src/core/build_steps/setup/tests.rs +++ b/src/bootstrap/src/core/build_steps/setup/tests.rs @@ -1,3 +1,8 @@ +use std::collections::BTreeMap; +use std::fs::File; +use std::io::Write; +use std::path::Path; + use sha2::Digest; use super::EditorKind; @@ -5,14 +10,41 @@ use crate::utils::helpers::hex_encode; #[test] fn check_matching_settings_hash() { + // Needs to be a btree so we serialize in a deterministic order. + let mut mismatched = BTreeMap::new(); + for editor in EditorKind::ALL { let mut hasher = sha2::Sha256::new(); hasher.update(&editor.settings_template()); let actual = hex_encode(hasher.finalize().as_slice()); let expected = *editor.hashes().last().unwrap(); - assert_eq!( - expected, actual, - "Update `setup/hashes.json` with the new hash of `{actual}` for `EditorKind::{editor:?}`", - ); + + if expected != actual { + mismatched.insert(editor, (expected, actual)); + } + } + + if mismatched.is_empty() { + return; + } + + if option_env!("INSTA_UPDATE").is_some_and(|s| s != "0") { + let mut updated = super::PARSED_HASHES.clone(); + for (editor, (_, actual)) in &mismatched { + *updated.get_mut(editor).unwrap().last_mut().unwrap() = actual; + } + let hash_path = + Path::new(env!("CARGO_MANIFEST_DIR")).join("src/core/build_steps/setup/hashes.json"); + let mut hash_file = File::create(hash_path).unwrap(); + serde_json::to_writer_pretty(&mut hash_file, &updated).unwrap(); + hash_file.write_all(b"\n").unwrap(); + } else { + for (editor, (expected, actual)) in &mismatched { + eprintln!("recorded hash did not match actual hash: {expected} != {actual}"); + eprintln!( + "Run `x test --bless -- hash`, or manually update `setup/hashes.json` with the new hash of `{actual}` for `EditorKind::{editor:?}`" + ); + } + panic!("mismatched hashes"); } } From ebb1f470caf9c364876618797040d6880df3fb2a Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 19 Mar 2026 01:08:01 -0400 Subject: [PATCH 30/33] Optimize 128-bit integer formatting The compiler is unaware of the restricted range of the input, so it is unable to optimize out the final division and modulus. By doing this manually, we get a nontrivial performance gain. --- library/core/src/fmt/num.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index d3d6495e75a2a..dfa27e32bc722 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -823,7 +823,7 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { let mut remain = n; // Format per four digits from the lookup table. - for quad_index in (0..4).rev() { + for quad_index in (1..4).rev() { // pull two pairs let quad = remain % 1_00_00; remain /= 1_00_00; @@ -834,6 +834,14 @@ fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { buf[quad_index * 4 + OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); buf[quad_index * 4 + OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); } + + // final two pairs + let pair1 = (remain / 100) as usize; + let pair2 = (remain % 100) as usize; + buf[OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]); + buf[OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]); + buf[OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); + buf[OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); } /// Euclidean division plus remainder with constant 1E16 basically consumes 16 From b2e8177455cad2c001a58d43a4dec6d896cea0ad Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 19 Mar 2026 15:59:16 +1100 Subject: [PATCH 31/33] Reorder `define_callbacks`. This is nitpicky, but the lack of a sensible order has been bugging me. - Within `mod $name`, put all the typedefs together. - After that: - First, types definitions and their impls. - Then the `TyCtxt*` impls, in a sensible order. - Likewise, put `TyCtxt::at` before the similar methods. - Also reflow some overly long lines. --- compiler/rustc_middle/src/query/plumbing.rs | 258 ++++++++++---------- 1 file changed, 133 insertions(+), 125 deletions(-) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index d4e7bb52be974..f4e1ead7c5859 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -201,6 +201,13 @@ pub struct TyCtxtEnsureDone<'tcx> { } impl<'tcx> TyCtxt<'tcx> { + /// Returns a transparent wrapper for `TyCtxt` which uses + /// `span` as the location of queries performed through it. + #[inline(always)] + pub fn at(self, span: Span) -> TyCtxtAt<'tcx> { + TyCtxtAt { tcx: self, span } + } + /// FIXME: `ensure_ok`'s effects are subtle. Is this comment fully accurate? /// /// Wrapper that calls queries in a special "ensure OK" mode, for callers @@ -258,13 +265,6 @@ impl<'tcx> TyCtxt<'tcx> { pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> { TyCtxtEnsureDone { tcx: self } } - - /// Returns a transparent wrapper for `TyCtxt` which uses - /// `span` as the location of queries performed through it. - #[inline(always)] - pub fn at(self, span: Span) -> TyCtxtAt<'tcx> { - TyCtxtAt { tcx: self, span } - } } macro_rules! query_helper_param_ty { @@ -323,6 +323,9 @@ macro_rules! define_callbacks { #[cfg(not($arena_cache))] pub type ProvidedValue<'tcx> = Value<'tcx>; + pub type Cache<'tcx> = + as $crate::query::QueryKey>::Cache>>; + /// This helper function takes a value returned by the query provider /// (or loaded from disk, or supplied by query feeding), allocates /// it in an arena if requested by the `arena_cache` modifier, and @@ -354,9 +357,6 @@ macro_rules! define_callbacks { erase::erase_val(value) } - pub type Cache<'tcx> = - as $crate::query::QueryKey>::Cache>>; - // Ensure that keys grow no larger than 88 bytes by accident. // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] @@ -390,116 +390,8 @@ macro_rules! define_callbacks { } )* - /// Holds per-query arenas for queries with the `arena_cache` modifier. - #[derive(Default)] - pub struct QueryArenas<'tcx> { - $( - // Use the `ArenaCached` helper trait to determine the arena's value type. - #[cfg($arena_cache)] - pub $name: TypedArena< - <$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated, - >, - )* - } - - impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) { - crate::query::inner::query_ensure_ok_or_done( - self.tcx, - &self.tcx.query_system.query_vtables.$name, - $crate::query::IntoQueryKey::into_query_key(key), - $crate::query::EnsureMode::Ok, - ) - } - )* - } - - // Only defined when the `ensure_result` modifier is present. - impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> { - $( - #[cfg($returns_error_guaranteed)] - $(#[$attr])* - #[inline(always)] - pub fn $name( - self, - key: query_helper_param_ty!($($K)*), - ) -> Result<(), rustc_errors::ErrorGuaranteed> { - crate::query::inner::query_ensure_result( - self.tcx, - &self.tcx.query_system.query_vtables.$name, - $crate::query::IntoQueryKey::into_query_key(key), - ) - } - )* - } - - impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) { - crate::query::inner::query_ensure_ok_or_done( - self.tcx, - &self.tcx.query_system.query_vtables.$name, - $crate::query::IntoQueryKey::into_query_key(key), - $crate::query::EnsureMode::Done, - ); - } - )* - } - - impl<'tcx> TyCtxt<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - #[must_use] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { - self.at(DUMMY_SP).$name(key) - } - )* - } - - impl<'tcx> $crate::query::TyCtxtAt<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { - use $crate::query::{erase, inner}; - - erase::restore_val::<$V>(inner::query_get_at( - self.tcx, - self.span, - &self.tcx.query_system.query_vtables.$name, - $crate::query::IntoQueryKey::into_query_key(key), - )) - } - )* - } - - $( - #[cfg($feedable)] - impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy> - TyCtxtFeed<'tcx, K> - { - $(#[$attr])* - #[inline(always)] - pub fn $name(self, value: $name::ProvidedValue<'tcx>) { - let key = self.key().into_query_key(); - let erased_value = $name::provided_to_erased(self.tcx, value); - $crate::query::inner::query_feed( - self.tcx, - &self.tcx.query_system.query_vtables.$name, - key, - erased_value, - ); - } - } - )* - - /// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a number. + /// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a + /// number. #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug)] pub enum TaggedQueryKey<'tcx> { @@ -528,7 +420,8 @@ macro_rules! define_callbacks { pub fn description(&self, tcx: TyCtxt<'tcx>) -> String { let (name, description) = ty::print::with_no_queries!(match self { $( - TaggedQueryKey::$name(key) => (stringify!($name), _description_fns::$name(tcx, *key)), + TaggedQueryKey::$name(key) => + (stringify!($name), _description_fns::$name(tcx, *key)), )* }); if tcx.sess.verbose_internals() { @@ -550,7 +443,8 @@ macro_rules! define_callbacks { } match self { $( - TaggedQueryKey::$name(key) => crate::query::QueryKey::default_span(key, tcx), + TaggedQueryKey::$name(key) => + crate::query::QueryKey::default_span(key, tcx), )* } } @@ -558,8 +452,13 @@ macro_rules! define_callbacks { pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option { // This is used to reduce code generation as it // can be reused for queries with the same key type. - fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option { - key.key_as_def_id().and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) + fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) + -> Option + { + key + .key_as_def_id() + .and_then(|def_id| def_id.as_local()) + .map(|def_id| tcx.def_kind(def_id)) } if let TaggedQueryKey::def_kind(..) = self { @@ -577,7 +476,19 @@ macro_rules! define_callbacks { /// Holds a `QueryVTable` for each query. pub struct QueryVTables<'tcx> { $( - pub $name: crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>, + pub $name: $crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>, + )* + } + + /// Holds per-query arenas for queries with the `arena_cache` modifier. + #[derive(Default)] + pub struct QueryArenas<'tcx> { + $( + // Use the `ArenaCached` helper trait to determine the arena's value type. + #[cfg($arena_cache)] + pub $name: TypedArena< + <$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated, + >, )* } @@ -637,6 +548,103 @@ macro_rules! define_callbacks { impl Clone for ExternProviders { fn clone(&self) -> Self { *self } } + + impl<'tcx> TyCtxt<'tcx> { + $( + $(#[$attr])* + #[inline(always)] + #[must_use] + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { + self.at(DUMMY_SP).$name(key) + } + )* + } + + impl<'tcx> $crate::query::TyCtxtAt<'tcx> { + $( + $(#[$attr])* + #[inline(always)] + pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { + use $crate::query::{erase, inner}; + + erase::restore_val::<$V>(inner::query_get_at( + self.tcx, + self.span, + &self.tcx.query_system.query_vtables.$name, + $crate::query::IntoQueryKey::into_query_key(key), + )) + } + )* + } + + impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> { + $( + $(#[$attr])* + #[inline(always)] + pub fn $name(self, key: query_helper_param_ty!($($K)*)) { + crate::query::inner::query_ensure_ok_or_done( + self.tcx, + &self.tcx.query_system.query_vtables.$name, + $crate::query::IntoQueryKey::into_query_key(key), + $crate::query::EnsureMode::Ok, + ) + } + )* + } + + // Only defined when the `ensure_result` modifier is present. + impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> { + $( + #[cfg($returns_error_guaranteed)] + $(#[$attr])* + #[inline(always)] + pub fn $name( + self, + key: query_helper_param_ty!($($K)*), + ) -> Result<(), rustc_errors::ErrorGuaranteed> { + crate::query::inner::query_ensure_result( + self.tcx, + &self.tcx.query_system.query_vtables.$name, + $crate::query::IntoQueryKey::into_query_key(key), + ) + } + )* + } + + impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> { + $( + $(#[$attr])* + #[inline(always)] + pub fn $name(self, key: query_helper_param_ty!($($K)*)) { + crate::query::inner::query_ensure_ok_or_done( + self.tcx, + &self.tcx.query_system.query_vtables.$name, + $crate::query::IntoQueryKey::into_query_key(key), + $crate::query::EnsureMode::Done, + ); + } + )* + } + + $( + #[cfg($feedable)] + impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy> + TyCtxtFeed<'tcx, K> + { + $(#[$attr])* + #[inline(always)] + pub fn $name(self, value: $name::ProvidedValue<'tcx>) { + let key = self.key().into_query_key(); + let erased_value = $name::provided_to_erased(self.tcx, value); + $crate::query::inner::query_feed( + self.tcx, + &self.tcx.query_system.query_vtables.$name, + key, + erased_value, + ); + } + } + )* }; } From 091d000b93fefc229775bb2905ec63e35a8c1490 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 19 Mar 2026 16:23:37 +1100 Subject: [PATCH 32/33] Minor `define_callbacks` tweaks. - Use `$crate` more consistently. - Add a couple of useful comments. - Remove some unnecessary local variables. --- compiler/rustc_middle/src/query/plumbing.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index f4e1ead7c5859..56a8f5e974aea 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -444,7 +444,7 @@ macro_rules! define_callbacks { match self { $( TaggedQueryKey::$name(key) => - crate::query::QueryKey::default_span(key, tcx), + $crate::query::QueryKey::default_span(key, tcx), )* } } @@ -452,7 +452,7 @@ macro_rules! define_callbacks { pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option { // This is used to reduce code generation as it // can be reused for queries with the same key type. - fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) + fn inner<'tcx>(key: &impl $crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option { key @@ -465,6 +465,7 @@ macro_rules! define_callbacks { // Try to avoid infinite recursion. return None } + match self { $( TaggedQueryKey::$name(key) => inner(key, tcx), @@ -582,7 +583,7 @@ macro_rules! define_callbacks { $(#[$attr])* #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { - crate::query::inner::query_ensure_ok_or_done( + $crate::query::inner::query_ensure_ok_or_done( self.tcx, &self.tcx.query_system.query_vtables.$name, $crate::query::IntoQueryKey::into_query_key(key), @@ -592,7 +593,7 @@ macro_rules! define_callbacks { )* } - // Only defined when the `ensure_result` modifier is present. + // Only defined when the `returns_error_guaranteed` modifier is present. impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> { $( #[cfg($returns_error_guaranteed)] @@ -602,7 +603,7 @@ macro_rules! define_callbacks { self, key: query_helper_param_ty!($($K)*), ) -> Result<(), rustc_errors::ErrorGuaranteed> { - crate::query::inner::query_ensure_result( + $crate::query::inner::query_ensure_result( self.tcx, &self.tcx.query_system.query_vtables.$name, $crate::query::IntoQueryKey::into_query_key(key), @@ -616,7 +617,7 @@ macro_rules! define_callbacks { $(#[$attr])* #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { - crate::query::inner::query_ensure_ok_or_done( + $crate::query::inner::query_ensure_ok_or_done( self.tcx, &self.tcx.query_system.query_vtables.$name, $crate::query::IntoQueryKey::into_query_key(key), @@ -627,6 +628,7 @@ macro_rules! define_callbacks { } $( + // Only defined when the `feedable` modifier is present. #[cfg($feedable)] impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy> TyCtxtFeed<'tcx, K> @@ -634,13 +636,11 @@ macro_rules! define_callbacks { $(#[$attr])* #[inline(always)] pub fn $name(self, value: $name::ProvidedValue<'tcx>) { - let key = self.key().into_query_key(); - let erased_value = $name::provided_to_erased(self.tcx, value); $crate::query::inner::query_feed( self.tcx, &self.tcx.query_system.query_vtables.$name, - key, - erased_value, + self.key().into_query_key(), + $name::provided_to_erased(self.tcx, value), ); } } From 7cec833020ed1a763a849ca1cd236412e0987e4f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 19 Mar 2026 16:54:06 +1100 Subject: [PATCH 33/33] Rename `query_helper_param_ty`. As `maybe_into_query_key`. Partly to use `key` instead of `param`, and also to make the link to the trait more obvious. --- compiler/rustc_middle/src/queries.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 4dd68db4f9135..b07b220865948 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -101,7 +101,7 @@ use crate::mir::mono::{ CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono, }; use crate::query::describe_as_module; -use crate::query::plumbing::{define_callbacks, query_helper_param_ty}; +use crate::query::plumbing::{define_callbacks, maybe_into_query_key}; use crate::traits::query::{ CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal, CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal, diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 56a8f5e974aea..4ef1b0adf581d 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -267,7 +267,7 @@ impl<'tcx> TyCtxt<'tcx> { } } -macro_rules! query_helper_param_ty { +macro_rules! maybe_into_query_key { (DefId) => { impl $crate::query::IntoQueryKey }; (LocalDefId) => { impl $crate::query::IntoQueryKey }; ($K:ty) => { $K }; @@ -276,7 +276,7 @@ macro_rules! query_helper_param_ty { macro_rules! define_callbacks { ( // You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that - // `query_helper_param_ty!` can match on specific type names. + // `maybe_into_query_key!` can match on specific type names. queries { $( $(#[$attr:meta])* @@ -555,7 +555,7 @@ macro_rules! define_callbacks { $(#[$attr])* #[inline(always)] #[must_use] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { + pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V { self.at(DUMMY_SP).$name(key) } )* @@ -565,7 +565,7 @@ macro_rules! define_callbacks { $( $(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V { + pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V { use $crate::query::{erase, inner}; erase::restore_val::<$V>(inner::query_get_at( @@ -582,7 +582,7 @@ macro_rules! define_callbacks { $( $(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) { + pub fn $name(self, key: maybe_into_query_key!($($K)*)) { $crate::query::inner::query_ensure_ok_or_done( self.tcx, &self.tcx.query_system.query_vtables.$name, @@ -601,7 +601,7 @@ macro_rules! define_callbacks { #[inline(always)] pub fn $name( self, - key: query_helper_param_ty!($($K)*), + key: maybe_into_query_key!($($K)*), ) -> Result<(), rustc_errors::ErrorGuaranteed> { $crate::query::inner::query_ensure_result( self.tcx, @@ -616,7 +616,7 @@ macro_rules! define_callbacks { $( $(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) { + pub fn $name(self, key: maybe_into_query_key!($($K)*)) { $crate::query::inner::query_ensure_ok_or_done( self.tcx, &self.tcx.query_system.query_vtables.$name, @@ -650,7 +650,7 @@ macro_rules! define_callbacks { // Re-export `macro_rules!` macros as normal items, so that they can be imported normally. pub(crate) use define_callbacks; -pub(crate) use query_helper_param_ty; +pub(crate) use maybe_into_query_key; #[cold] pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! {