From b5a4e5d73fb7fd47caa1b22ffe8527c13f895c21 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 4 Aug 2025 01:24:22 +0500 Subject: [PATCH 01/17] remove gates --- library/alloc/src/collections/btree/map/entry.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index ea8fa363c3805..b16aad0bb03dd 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -275,7 +275,6 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// # Examples /// /// ``` - /// #![feature(btree_entry_insert)] /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); @@ -284,7 +283,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// assert_eq!(entry.key(), &"poneyland"); /// ``` #[inline] - #[unstable(feature = "btree_entry_insert", issue = "65225")] + #[stable(feature = "btree_entry_insert", since = "CURRENT_RUSTC_VERSION")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { match self { Occupied(mut entry) => { @@ -383,7 +382,6 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { /// # Examples /// /// ``` - /// #![feature(btree_entry_insert)] /// use std::collections::BTreeMap; /// use std::collections::btree_map::Entry; /// @@ -395,7 +393,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { /// } /// assert_eq!(map["poneyland"], 37); /// ``` - #[unstable(feature = "btree_entry_insert", issue = "65225")] + #[stable(feature = "btree_entry_insert", since = "CURRENT_RUSTC_VERSION")] pub fn insert_entry(mut self, value: V) -> OccupiedEntry<'a, K, V, A> { let handle = match self.handle { None => { From 9fd57df6397b0e2b0cd4db32884ed5e5443c7906 Mon Sep 17 00:00:00 2001 From: dianne Date: Tue, 12 Aug 2025 23:55:29 -0700 Subject: [PATCH 02/17] add tests, some with incorrect lifetime extension behavior --- .../format-args-temporary-scopes.e2024.stderr | 15 +++ .../borrowck/format-args-temporary-scopes.rs | 20 +++ .../ui/drop/super-let-tail-expr-drop-order.rs | 122 ++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr create mode 100644 tests/ui/borrowck/format-args-temporary-scopes.rs create mode 100644 tests/ui/drop/super-let-tail-expr-drop-order.rs diff --git a/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr b/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr new file mode 100644 index 0000000000000..923c929a68d60 --- /dev/null +++ b/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr @@ -0,0 +1,15 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/format-args-temporary-scopes.rs:13:25 + | +LL | println!("{:?}", { &temp() }); + | ---^^^^^--- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/format-args-temporary-scopes.rs b/tests/ui/borrowck/format-args-temporary-scopes.rs new file mode 100644 index 0000000000000..e6223d7c55183 --- /dev/null +++ b/tests/ui/borrowck/format-args-temporary-scopes.rs @@ -0,0 +1,20 @@ +//! Test for #145784 as it relates to format arguments: arguments to macros such as `println!` +//! should obey normal temporary scoping rules. +//@ revisions: e2021 e2024 +//@ [e2021] check-pass +//@ [e2021] edition: 2021 +//@ [e2024] edition: 2024 + +fn temp() {} + +fn main() { + // In Rust 2024, block tail expressions are temporary scopes, so the result of `temp()` is + // dropped after evaluating `&temp()`. + println!("{:?}", { &temp() }); + //[e2024]~^ ERROR: temporary value dropped while borrowed [E0716] + + // In Rust 1.89, `format_args!` extended the lifetime of all extending expressions in its + // arguments when provided with two or more arguments. This caused the result of `temp()` to + // outlive the result of the block, making this compile. + println!("{:?}{:?}", { &temp() }, ()); +} diff --git a/tests/ui/drop/super-let-tail-expr-drop-order.rs b/tests/ui/drop/super-let-tail-expr-drop-order.rs new file mode 100644 index 0000000000000..5aa17bba21f1b --- /dev/null +++ b/tests/ui/drop/super-let-tail-expr-drop-order.rs @@ -0,0 +1,122 @@ +//! Test for #145784: the argument to `pin!` should be treated as an extending expression if and +//! only if the whole `pin!` invocation is an extending expression. Likewise, since `pin!` is +//! implemented in terms of `super let`, test the same for `super let` initializers. Since the +//! argument to `pin!` and the initializer of `super let` are not temporary drop scopes, this only +//! affects lifetimes in two cases: +//! +//! - Block tail expressions in Rust 2024, which are both extending expressions and temporary drop +//! scopes; treating them as extending expressions within a non-extending `pin!` resulted in borrow +//! expression operands living past the end of the block. +//! +//! - Nested `super let` statements, which can have their binding and temporary lifetimes extended +//! when the block they're in is an extending expression. +//! +//! For more information on extending expressions, see +//! https://doc.rust-lang.org/reference/destructors.html#extending-based-on-expressions +//! +//! For tests that `super let` initializers aren't temporary drop scopes, and tests for +//! lifetime-extended `super let`, see tests/ui/borrowck/super-let-lifetime-and-drop.rs +//@ run-pass +//@ revisions: e2021 e2024 +//@ [e2021] edition: 2021 +//@ [e2024] edition: 2024 + +#![feature(super_let)] + +use std::cell::RefCell; +use std::pin::pin; + +fn main() { + // Test block arguments to `pin!` in non-extending expressions. + // In Rust 2021, block tail expressions aren't temporary drop scopes, so their temporaries + // should outlive the `pin!` invocation. + // In Rust 2024, block tail expressions are temporary drop scopes, so their temporaries should + // be dropped after evaluating the tail expression within the `pin!` invocation. + // By nesting two `pin!` calls, this ensures non-extended `pin!` doesn't extend an inner `pin!`. + assert_drop_order(1..=3, |o| { + #[cfg(e2021)] + ( + pin!(( + pin!({ &o.log(3) as *const LogDrop<'_> }), + drop(o.log(1)), + )), + drop(o.log(2)), + ); + #[cfg(e2024)] + ( + pin!(( + pin!({ &o.log(3) as *const LogDrop<'_> }), + drop(o.log(1)), + )), + drop(o.log(2)), + ); + }); + + // The same holds for `super let` initializers in non-extending expressions. + assert_drop_order(1..=4, |o| { + #[cfg(e2021)] + ( + { + super let _ = { + super let _ = { &o.log(4) as *const LogDrop<'_> }; + drop(o.log(1)) + }; + drop(o.log(2)) + }, + drop(o.log(3)), + ); + #[cfg(e2024)] + ( + { + super let _ = { + super let _ = { &o.log(4) as *const LogDrop<'_> }; + drop(o.log(1)) + }; + drop(o.log(2)) + }, + drop(o.log(3)), + ); + }); + + // Within an extending expression, the argument to `pin!` is also an extending expression, + // allowing borrow operands in block tail expressions to have extended lifetimes. + assert_drop_order(1..=2, |o| { + let _ = pin!({ &o.log(2) as *const LogDrop<'_> }); + drop(o.log(1)); + }); + + // The same holds for `super let` initializers in extending expressions. + assert_drop_order(1..=2, |o| { + let _ = { super let _ = { &o.log(2) as *const LogDrop<'_> }; }; + drop(o.log(1)); + }); +} + +// # Test scaffolding... + +struct DropOrder(RefCell>); +struct LogDrop<'o>(&'o DropOrder, u64); + +impl DropOrder { + fn log(&self, n: u64) -> LogDrop<'_> { + LogDrop(self, n) + } +} + +impl<'o> Drop for LogDrop<'o> { + fn drop(&mut self) { + self.0.0.borrow_mut().push(self.1); + } +} + +#[track_caller] +fn assert_drop_order( + ex: impl IntoIterator, + f: impl Fn(&DropOrder), +) { + let order = DropOrder(RefCell::new(Vec::new())); + f(&order); + let order = order.0.into_inner(); + let expected: Vec = ex.into_iter().collect(); + assert_eq!(order, expected); +} From 0976d6ccac3d71befb58ceefd3109864f0eb210d Mon Sep 17 00:00:00 2001 From: dianne Date: Sun, 24 Aug 2025 22:48:00 -0700 Subject: [PATCH 03/17] don't extend non-extended `super let` initializers' block tail temps --- .../rustc_hir_analysis/src/check/region.rs | 24 +++++++++++++++---- .../format-args-temporary-scopes.e2024.stderr | 14 ++++++++++- .../borrowck/format-args-temporary-scopes.rs | 1 + .../ui/drop/super-let-tail-expr-drop-order.rs | 14 +++++------ 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index f5770b7312ddf..58521697b387f 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -467,8 +467,12 @@ fn resolve_local<'tcx>( // A, but the inner rvalues `a()` and `b()` have an extended lifetime // due to rule C. - if let_kind == LetKind::Super { - if let Some(scope) = visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) { + let extend_initializer = match let_kind { + LetKind::Regular => true, + LetKind::Super + if let Some(scope) = + visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) => + { // This expression was lifetime-extended by a parent let binding. E.g. // // let a = { @@ -481,7 +485,10 @@ fn resolve_local<'tcx>( // Processing of `let a` will have already decided to extend the lifetime of this // `super let` to its own var_scope. We use that scope. visitor.cx.var_parent = scope; - } else { + // Extend temporaries to live in the same scope as the parent `let`'s bindings. + true + } + LetKind::Super => { // This `super let` is not subject to lifetime extension from a parent let binding. E.g. // // identity({ super let x = temp(); &x }).method(); @@ -497,10 +504,17 @@ fn resolve_local<'tcx>( } visitor.cx.var_parent = parent; } + // Don't lifetime-extend child `super let`s or block tail expressions' temporaries in + // the initializer when this `super let` is not itself extended by a parent `let` + // (#145784). Block tail expressions are temporary drop scopes in Editions 2024 and + // later, their temps shouldn't outlive the block in e.g. `f(pin!({ &temp() }))`. + false } - } + }; - if let Some(expr) = init { + if let Some(expr) = init + && extend_initializer + { record_rvalue_scope_if_borrow_expr(visitor, expr, visitor.cx.var_parent); if let Some(pat) = pat { diff --git a/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr b/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr index 923c929a68d60..506fc6e0965f7 100644 --- a/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr +++ b/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr @@ -10,6 +10,18 @@ LL | println!("{:?}", { &temp() }); | = note: consider using a `let` binding to create a longer lived value -error: aborting due to 1 previous error +error[E0716]: temporary value dropped while borrowed + --> $DIR/format-args-temporary-scopes.rs:19:29 + | +LL | println!("{:?}{:?}", { &temp() }, ()); + | ---^^^^^--- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/format-args-temporary-scopes.rs b/tests/ui/borrowck/format-args-temporary-scopes.rs index e6223d7c55183..2641058accb31 100644 --- a/tests/ui/borrowck/format-args-temporary-scopes.rs +++ b/tests/ui/borrowck/format-args-temporary-scopes.rs @@ -17,4 +17,5 @@ fn main() { // arguments when provided with two or more arguments. This caused the result of `temp()` to // outlive the result of the block, making this compile. println!("{:?}{:?}", { &temp() }, ()); + //[e2024]~^ ERROR: temporary value dropped while borrowed [E0716] } diff --git a/tests/ui/drop/super-let-tail-expr-drop-order.rs b/tests/ui/drop/super-let-tail-expr-drop-order.rs index 5aa17bba21f1b..8ec9296ed4f1d 100644 --- a/tests/ui/drop/super-let-tail-expr-drop-order.rs +++ b/tests/ui/drop/super-let-tail-expr-drop-order.rs @@ -45,10 +45,10 @@ fn main() { #[cfg(e2024)] ( pin!(( - pin!({ &o.log(3) as *const LogDrop<'_> }), - drop(o.log(1)), + pin!({ &o.log(1) as *const LogDrop<'_> }), + drop(o.log(2)), )), - drop(o.log(2)), + drop(o.log(3)), ); }); @@ -69,12 +69,12 @@ fn main() { ( { super let _ = { - super let _ = { &o.log(4) as *const LogDrop<'_> }; - drop(o.log(1)) + super let _ = { &o.log(1) as *const LogDrop<'_> }; + drop(o.log(2)) }; - drop(o.log(2)) + drop(o.log(3)) }, - drop(o.log(3)), + drop(o.log(4)), ); }); From d5b5a4a0e11d92a963578d15a9f693e1538caf3f Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 25 Aug 2025 04:52:52 -0700 Subject: [PATCH 04/17] additional tests Co-authored-by: Travis Cross --- .../ui/drop/super-let-tail-expr-drop-order.rs | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/ui/drop/super-let-tail-expr-drop-order.rs b/tests/ui/drop/super-let-tail-expr-drop-order.rs index 8ec9296ed4f1d..5b2ecfbb3200c 100644 --- a/tests/ui/drop/super-let-tail-expr-drop-order.rs +++ b/tests/ui/drop/super-let-tail-expr-drop-order.rs @@ -22,10 +22,13 @@ //@ [e2024] edition: 2024 #![feature(super_let)] +#![allow(unused_braces)] use std::cell::RefCell; use std::pin::pin; +fn f(_: LogDrop<'_>, x: T) -> T { x } + fn main() { // Test block arguments to `pin!` in non-extending expressions. // In Rust 2021, block tail expressions aren't temporary drop scopes, so their temporaries @@ -90,6 +93,73 @@ fn main() { let _ = { super let _ = { &o.log(2) as *const LogDrop<'_> }; }; drop(o.log(1)); }); + + // We have extending borrow expressions within an extending block + // expression (within an extending borrow expression) within a + // non-extending expresion within the initializer expression. + #[cfg(e2021)] + { + // These two should be the same. + assert_drop_order(1..=3, |e| { + let _v = f(e.log(1), &{ &raw const *&e.log(2) }); + drop(e.log(3)); + }); + assert_drop_order(1..=3, |e| { + let _v = f(e.log(1), { + super let v = &{ &raw const *&e.log(2) }; + v + }); + drop(e.log(3)); + }); + } + #[cfg(e2024)] + { + // These two should be the same. + assert_drop_order(1..=3, |e| { + let _v = f(e.log(2), &{ &raw const *&e.log(1) }); + drop(e.log(3)); + }); + assert_drop_order(1..=3, |e| { + let _v = f(e.log(2), { + super let v = &{ &raw const *&e.log(1) }; + v + }); + drop(e.log(3)); + }); + } + + // We have extending borrow expressions within a non-extending + // expression within the initializer expression. + // + // These two should be the same. + assert_drop_order(1..=3, |e| { + let _v = f(e.log(1), &&raw const *&e.log(2)); + drop(e.log(3)); + }); + assert_drop_order(1..=3, |e| { + let _v = f(e.log(1), { + super let v = &&raw const *&e.log(2); + v + }); + drop(e.log(3)); + }); + + // We have extending borrow expressions within an extending block + // expression (within an extending borrow expression) within the + // initializer expression. + // + // These two should be the same. + assert_drop_order(1..=2, |e| { + let _v = &{ &raw const *&e.log(2) }; + drop(e.log(1)); + }); + assert_drop_order(1..=2, |e| { + let _v = { + super let v = &{ &raw const *&e.log(2) }; + v + }; + drop(e.log(1)); + }); } // # Test scaffolding... From 9405e76431374e25077b374ed0cd9c920a1c0f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 15 Sep 2025 02:53:29 -0700 Subject: [PATCH 05/17] Detect attempt to use var-args in closure ``` error: unexpected `...` --> $DIR/varargs-in-closure-isnt-supported.rs:5:20 | LL | let mut lol = |...| (); | ^^^ not a valid pattern | = note: C-variadic type `...` is not allowed here ``` --- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 4 ++- compiler/rustc_parse/src/parser/pat.rs | 27 +++++++++++++------ .../varargs-in-closure-isnt-supported.rs | 11 ++++++++ .../varargs-in-closure-isnt-supported.stderr | 22 +++++++++++++++ 5 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 tests/ui/closures/varargs-in-closure-isnt-supported.rs create mode 100644 tests/ui/closures/varargs-in-closure-isnt-supported.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 72cd75f6d8943..6d9521c7d2be0 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -189,6 +189,7 @@ parse_dotdotdot = unexpected token: `...` parse_dotdotdot_rest_pattern = unexpected `...` .label = not a valid pattern .suggestion = for a rest pattern, use `..` instead of `...` + .note = C-variadic type `...` is not allowed here parse_double_colon_in_bound = expected `:` followed by trait or lifetime .suggestion = use single colon diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 00ca5acd84d51..2b107fe35d592 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2723,7 +2723,9 @@ pub(crate) struct DotDotDotRestPattern { #[label] pub span: Span, #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] - pub suggestion: Span, + pub suggestion: Option, + #[note] + pub var_args: Option<()>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index c4d30b3d32832..fda19d62bc774 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -756,7 +756,7 @@ impl<'a> Parser<'a> { self.bump(); // `..` PatKind::Rest } else if self.check(exp!(DotDotDot)) && !self.is_pat_range_end_start(1) { - self.recover_dotdotdot_rest_pat(lo) + self.recover_dotdotdot_rest_pat(lo, expected) } else if let Some(form) = self.parse_range_end() { self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`. } else if self.eat(exp!(Bang)) { @@ -886,16 +886,27 @@ impl<'a> Parser<'a> { /// Recover from a typoed `...` pattern that was encountered /// Ref: Issue #70388 - fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind { + fn recover_dotdotdot_rest_pat(&mut self, lo: Span, expected: Option) -> PatKind { // A typoed rest pattern `...`. self.bump(); // `...` - // The user probably mistook `...` for a rest pattern `..`. - self.dcx().emit_err(DotDotDotRestPattern { - span: lo, - suggestion: lo.with_lo(lo.hi() - BytePos(1)), - }); - PatKind::Rest + if let Some(Expected::ParameterName) = expected { + // We have `...` in a closure argument, likely meant to be var-arg, which aren't + // supported in closures (#146489). + PatKind::Err(self.dcx().emit_err(DotDotDotRestPattern { + span: lo, + suggestion: None, + var_args: Some(()), + })) + } else { + // The user probably mistook `...` for a rest pattern `..`. + self.dcx().emit_err(DotDotDotRestPattern { + span: lo, + suggestion: Some(lo.with_lo(lo.hi() - BytePos(1))), + var_args: None, + }); + PatKind::Rest + } } /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`. diff --git a/tests/ui/closures/varargs-in-closure-isnt-supported.rs b/tests/ui/closures/varargs-in-closure-isnt-supported.rs new file mode 100644 index 0000000000000..5dff69194f90e --- /dev/null +++ b/tests/ui/closures/varargs-in-closure-isnt-supported.rs @@ -0,0 +1,11 @@ +// var-args are not supported in closures, ensure we don't misdirect people (#146489) +#![feature(c_variadic)] + +unsafe extern "C" fn thats_not_a_pattern(mut ap: ...) -> u32 { + let mut lol = |...| (); //~ ERROR: unexpected `...` + unsafe { ap.arg::() } //~^ NOTE: C-variadic type `...` is not allowed here + //~| ERROR: type annotations needed + //~| NOTE: not a valid pattern +} + +fn main() {} diff --git a/tests/ui/closures/varargs-in-closure-isnt-supported.stderr b/tests/ui/closures/varargs-in-closure-isnt-supported.stderr new file mode 100644 index 0000000000000..4f66ff59af127 --- /dev/null +++ b/tests/ui/closures/varargs-in-closure-isnt-supported.stderr @@ -0,0 +1,22 @@ +error: unexpected `...` + --> $DIR/varargs-in-closure-isnt-supported.rs:5:20 + | +LL | let mut lol = |...| (); + | ^^^ not a valid pattern + | + = note: C-variadic type `...` is not allowed here + +error[E0282]: type annotations needed + --> $DIR/varargs-in-closure-isnt-supported.rs:5:20 + | +LL | let mut lol = |...| (); + | ^^^ + | +help: consider giving this closure parameter an explicit type + | +LL | let mut lol = |...: /* Type */| (); + | ++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. From 0e290e4228e90720b4b3e263f95250db7046cdd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 15 Sep 2025 03:06:16 -0700 Subject: [PATCH 06/17] Silence inference error on `PatKind::Err` --- .../src/error_reporting/infer/need_type_info.rs | 10 ++++++++-- .../closures/varargs-in-closure-isnt-supported.rs | 1 - .../varargs-in-closure-isnt-supported.stderr | 14 +------------- 3 files changed, 9 insertions(+), 16 deletions(-) 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 edab530590b2a..94772be16be20 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 @@ -4,7 +4,7 @@ use std::path::PathBuf; use rustc_errors::codes::*; use rustc_errors::{Diag, IntoDiagArg}; -use rustc_hir as hir; +use rustc_hir::{self as hir, PatKind}; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; @@ -512,7 +512,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { type_name: ty_to_string(self, ty, def_id), }); } - InferSourceKind::ClosureArg { insert_span, ty } => { + InferSourceKind::ClosureArg { insert_span, ty, .. } => { infer_subdiags.push(SourceKindSubdiag::LetLike { span: insert_span, name: String::new(), @@ -652,6 +652,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }), }; *err.long_ty_path() = long_ty_path; + if let InferSourceKind::ClosureArg { kind: PatKind::Err(_), .. } = kind { + // We will have already emitted an error about this pattern. + err.downgrade_to_delayed_bug(); + } err } } @@ -673,6 +677,7 @@ enum InferSourceKind<'tcx> { ClosureArg { insert_span: Span, ty: Ty<'tcx>, + kind: PatKind<'tcx>, }, GenericArg { insert_span: Span, @@ -1197,6 +1202,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { kind: InferSourceKind::ClosureArg { insert_span: param.pat.span.shrink_to_hi(), ty: param_ty, + kind: param.pat.kind, }, }) } diff --git a/tests/ui/closures/varargs-in-closure-isnt-supported.rs b/tests/ui/closures/varargs-in-closure-isnt-supported.rs index 5dff69194f90e..4de78bef14d30 100644 --- a/tests/ui/closures/varargs-in-closure-isnt-supported.rs +++ b/tests/ui/closures/varargs-in-closure-isnt-supported.rs @@ -4,7 +4,6 @@ unsafe extern "C" fn thats_not_a_pattern(mut ap: ...) -> u32 { let mut lol = |...| (); //~ ERROR: unexpected `...` unsafe { ap.arg::() } //~^ NOTE: C-variadic type `...` is not allowed here - //~| ERROR: type annotations needed //~| NOTE: not a valid pattern } diff --git a/tests/ui/closures/varargs-in-closure-isnt-supported.stderr b/tests/ui/closures/varargs-in-closure-isnt-supported.stderr index 4f66ff59af127..a645741a52771 100644 --- a/tests/ui/closures/varargs-in-closure-isnt-supported.stderr +++ b/tests/ui/closures/varargs-in-closure-isnt-supported.stderr @@ -6,17 +6,5 @@ LL | let mut lol = |...| (); | = note: C-variadic type `...` is not allowed here -error[E0282]: type annotations needed - --> $DIR/varargs-in-closure-isnt-supported.rs:5:20 - | -LL | let mut lol = |...| (); - | ^^^ - | -help: consider giving this closure parameter an explicit type - | -LL | let mut lol = |...: /* Type */| (); - | ++++++++++++ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0282`. From a84c8deb1f61e020e026e1fa53bc613426da8fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 15 Sep 2025 03:10:27 -0700 Subject: [PATCH 07/17] Fix existing test --- tests/ui/c-variadic/no-closure.rs | 3 +-- tests/ui/c-variadic/no-closure.stderr | 18 +++--------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/tests/ui/c-variadic/no-closure.rs b/tests/ui/c-variadic/no-closure.rs index c0b77786e8b4a..a5b791fbca800 100644 --- a/tests/ui/c-variadic/no-closure.rs +++ b/tests/ui/c-variadic/no-closure.rs @@ -8,8 +8,7 @@ const F: extern "C" fn(...) = |_: ...| {}; fn foo() { let f = |...| {}; - //~^ ERROR: `..` patterns are not allowed here - //~| ERROR: unexpected `...` + //~^ ERROR: unexpected `...` let f = |_: ...| {}; //~^ ERROR C-variadic type `...` may not be nested inside another type diff --git a/tests/ui/c-variadic/no-closure.stderr b/tests/ui/c-variadic/no-closure.stderr index 77bd106bb9519..ad635a29ab486 100644 --- a/tests/ui/c-variadic/no-closure.stderr +++ b/tests/ui/c-variadic/no-closure.stderr @@ -10,26 +10,14 @@ error: unexpected `...` LL | let f = |...| {}; | ^^^ not a valid pattern | -help: for a rest pattern, use `..` instead of `...` - | -LL - let f = |...| {}; -LL + let f = |..| {}; - | + = note: C-variadic type `...` is not allowed here error[E0743]: C-variadic type `...` may not be nested inside another type - --> $DIR/no-closure.rs:14:17 + --> $DIR/no-closure.rs:13:17 | LL | let f = |_: ...| {}; | ^^^ -error: `..` patterns are not allowed here - --> $DIR/no-closure.rs:10:14 - | -LL | let f = |...| {}; - | ^^^ - | - = note: only allowed in tuple, tuple struct, and slice patterns - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0743`. From 53b58b3afdc1d3b069c8b73230abf68878196f75 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Mon, 15 Sep 2025 14:31:43 +0200 Subject: [PATCH 08/17] tests/run-make: Update list of statically linked musl targets All of the tier 3 targets in the list now link dynamically by default (except mips64el-unknown-linux-muslabi64, I overlooked that one). Adjust the list of targets expected to link statically accordingly. Signed-off-by: Jens Reidel --- tests/run-make/musl-default-linking/rmake.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/run-make/musl-default-linking/rmake.rs b/tests/run-make/musl-default-linking/rmake.rs index 7bb54e2739c9d..1b30c538b5e30 100644 --- a/tests/run-make/musl-default-linking/rmake.rs +++ b/tests/run-make/musl-default-linking/rmake.rs @@ -4,7 +4,7 @@ use run_make_support::{rustc, serde_json}; // Per https://github.com/rust-lang/compiler-team/issues/422, // we should be trying to move these targets to dynamically link // musl libc by default. -//@ needs-llvm-components: aarch64 arm mips powerpc riscv systemz x86 +//@ needs-llvm-components: aarch64 arm mips powerpc x86 static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[ "aarch64-unknown-linux-musl", "arm-unknown-linux-musleabi", @@ -14,16 +14,8 @@ static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[ "armv7-unknown-linux-musleabihf", "i586-unknown-linux-musl", "i686-unknown-linux-musl", - "mips64-unknown-linux-musl", - "mips64-unknown-linux-muslabi64", "mips64el-unknown-linux-muslabi64", - "powerpc-unknown-linux-musl", - "powerpc-unknown-linux-muslspe", - "powerpc64-unknown-linux-musl", "powerpc64le-unknown-linux-musl", - "riscv32gc-unknown-linux-musl", - "s390x-unknown-linux-musl", - "thumbv7neon-unknown-linux-musleabihf", "x86_64-unknown-linux-musl", ]; From fa7e474f9ca755ac102debcf6cd0ce77313ee0bf Mon Sep 17 00:00:00 2001 From: ash Date: Mon, 15 Sep 2025 13:55:20 -0600 Subject: [PATCH 09/17] remove FIXME from `has_significant_drop`, replaced with checking non_region_infer --- compiler/rustc_middle/src/ty/util.rs | 9 +-------- tests/ui/type-inference/has_sigdrop.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 tests/ui/type-inference/has_sigdrop.rs diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 029586a9c554c..b79b67c5927b0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1359,6 +1359,7 @@ impl<'tcx> Ty<'tcx> { /// 2229 drop reorder migration analysis. #[inline] pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + assert!(!self.has_non_region_infer()); // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1371,14 +1372,6 @@ impl<'tcx> Ty<'tcx> { _ => self, }; - // FIXME(#86868): We should be canonicalizing, or else moving this to a method of inference - // context, or *something* like that, but for now just avoid passing inference - // variables to queries that can't cope with them. Instead, conservatively - // return "true" (may change drop order). - if query_ty.has_infer() { - return true; - } - // This doesn't depend on regions, so try to minimize distinct // query keys used. let erased = tcx.normalize_erasing_regions(typing_env, query_ty); diff --git a/tests/ui/type-inference/has_sigdrop.rs b/tests/ui/type-inference/has_sigdrop.rs new file mode 100644 index 0000000000000..c3d835cfe16f8 --- /dev/null +++ b/tests/ui/type-inference/has_sigdrop.rs @@ -0,0 +1,18 @@ +//@ run-pass +// Inference, canonicalization, and significant drops should work nicely together. +// Related issue: #86868 + +#[clippy::has_significant_drop] +struct DropGuy {} + +fn creator() -> DropGuy { + DropGuy {} +} + +fn dropper() { + let _ = creator(); +} + +fn main() { + dropper(); +} From d66fb4910fb7e87b7e17477ae147854adf76b0dd Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 5 Sep 2025 21:35:58 -0500 Subject: [PATCH 10/17] Suggest removing Box::new --- .../src/fn_ctxt/suggestions.rs | 22 +++++++++++++++++++ tests/ui/coercion/coerce-block-tail.stderr | 7 +++--- .../ui/coercion/coerce-box-new-to-unboxed.rs | 4 ++++ .../coercion/coerce-box-new-to-unboxed.stderr | 19 ++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/ui/coercion/coerce-box-new-to-unboxed.rs create mode 100644 tests/ui/coercion/coerce-box-new-to-unboxed.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index aca3840712e79..a12bc05793439 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2955,6 +2955,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let deref_kind = if checked_ty.is_box() { + // detect Box::new(..) + if let ExprKind::Call(box_new, [_]) = expr.kind + && let ExprKind::Path(qpath) = &box_new.kind + && let Res::Def(DefKind::AssocFn, fn_id) = + self.typeck_results.borrow().qpath_res(qpath, box_new.hir_id) + && let Some(impl_id) = self.tcx.inherent_impl_of_assoc(fn_id) + && self.tcx.type_of(impl_id).skip_binder().is_box() + && self.tcx.item_name(fn_id) == sym::new + { + let l_paren = self.tcx.sess.source_map().next_point(box_new.span); + let r_paren = self.tcx.sess.source_map().end_point(expr.span); + return Some(( + vec![ + (box_new.span.to(l_paren), String::new()), + (r_paren, String::new()), + ], + "consider removing the Box".to_string(), + Applicability::MachineApplicable, + false, + false, + )); + } "unboxing the value" } else if checked_ty.is_ref() { "dereferencing the borrow" diff --git a/tests/ui/coercion/coerce-block-tail.stderr b/tests/ui/coercion/coerce-block-tail.stderr index 1301f3b7813ed..b358401b7062b 100644 --- a/tests/ui/coercion/coerce-block-tail.stderr +++ b/tests/ui/coercion/coerce-block-tail.stderr @@ -6,10 +6,11 @@ LL | let _: &i32 = & { Box::new(1i32) }; | = note: expected type `i32` found struct `Box` -help: consider unboxing the value +help: consider removing the Box + | +LL - let _: &i32 = & { Box::new(1i32) }; +LL + let _: &i32 = & { 1i32 }; | -LL | let _: &i32 = & { *Box::new(1i32) }; - | + error: aborting due to 1 previous error diff --git a/tests/ui/coercion/coerce-box-new-to-unboxed.rs b/tests/ui/coercion/coerce-box-new-to-unboxed.rs new file mode 100644 index 0000000000000..63ff0fc4e2381 --- /dev/null +++ b/tests/ui/coercion/coerce-box-new-to-unboxed.rs @@ -0,0 +1,4 @@ +fn main() { + let _: String = Box::new(String::new()); + //~^ ERROR mismatched types +} diff --git a/tests/ui/coercion/coerce-box-new-to-unboxed.stderr b/tests/ui/coercion/coerce-box-new-to-unboxed.stderr new file mode 100644 index 0000000000000..bdd962686e4b4 --- /dev/null +++ b/tests/ui/coercion/coerce-box-new-to-unboxed.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/coerce-box-new-to-unboxed.rs:2:21 + | +LL | let _: String = Box::new(String::new()); + | ------ ^^^^^^^^^^^^^^^^^^^^^^^ expected `String`, found `Box` + | | + | expected due to this + | + = note: expected struct `String` + found struct `Box` +help: consider removing the Box + | +LL - let _: String = Box::new(String::new()); +LL + let _: String = String::new(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From c89b6a955c9e16c7c96714cea7945945caadcc79 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 10 Sep 2025 12:40:29 +0000 Subject: [PATCH 11/17] Iterator repeat: no infinite loop for `last` and `count` --- library/core/src/iter/sources/repeat.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index c4f5a483e5c2a..4bcd5b16aea6a 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -9,7 +9,7 @@ use crate::num::NonZero; /// [`Iterator::take()`], in order to make them finite. /// /// Use [`str::repeat()`] instead of this function if you just want to repeat -/// a char/string `n`th times. +/// a char/string `n` times. /// /// If the element type of the iterator you need does not implement `Clone`, /// or if you do not want to keep the repeated element in memory, you can @@ -98,11 +98,12 @@ impl Iterator for Repeat { } fn last(self) -> Option { - loop {} + Some(self.element) } + #[track_caller] fn count(self) -> usize { - loop {} + panic!("iterator is infinite"); } } From dfbaf7e898ad5bdad9655bf21ebadeae55117733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 24 Aug 2025 11:19:51 +0200 Subject: [PATCH 12/17] port `#[rustc_coherence_is_core]` to the new attribute parsing infrastructure --- .../rustc_attr_parsing/src/attributes/crate_level.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/attributes/traits.rs | 8 -------- compiler/rustc_attr_parsing/src/context.rs | 12 ++++++------ compiler/rustc_hir/src/attrs/data_structures.rs | 6 +++--- compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 2 +- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- 7 files changed, 21 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 4611de4445997..0a340cd5e9330 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -174,3 +174,12 @@ impl NoArgsAttributeParser for NoStdParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd; } + +pub(crate) struct RustcCoherenceIsCoreParser; + +impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { + const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore; +} diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index c756bce96e28f..ced3bcad2293a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -149,14 +149,6 @@ impl NoArgsAttributeParser for AllowIncoherentImplParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl; } -pub(crate) struct CoherenceIsCoreParser; -impl NoArgsAttributeParser for CoherenceIsCoreParser { - const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore; -} - pub(crate) struct FundamentalParser; impl NoArgsAttributeParser for FundamentalParser { const PATH: &[Symbol] = &[sym::fundamental]; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d7998048be5af..55b7ca05ef47e 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -26,7 +26,7 @@ use crate::attributes::codegen_attrs::{ use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser, - RecursionLimitParser, TypeLengthLimitParser, + RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser, }; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::dummy::DummyParser; @@ -61,10 +61,10 @@ use crate::attributes::stability::{ }; use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser}; use crate::attributes::traits::{ - AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser, - DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, - ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, - TypeConstParser, UnsafeSpecializationMarkerParser, + AllowIncoherentImplParser, CoinductiveParser, ConstTraitParser, DenyExplicitImplParser, + DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser, + PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser, + UnsafeSpecializationMarkerParser, }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; @@ -204,7 +204,6 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, Single>, Single>, Single>, @@ -232,6 +231,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index ea11a99efbc35..b56027b8b7adc 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -444,9 +444,6 @@ pub enum AttributeKind { span: Span, }, - /// Represents `#[rustc_coherence_is_core]`. - CoherenceIsCore, - /// Represents `#[rustc_coinductive]`. Coinductive(Span), @@ -633,6 +630,9 @@ pub enum AttributeKind { /// Represents `#[rustc_builtin_macro]`. RustcBuiltinMacro { builtin_name: Option, helper_attrs: ThinVec, span: Span }, + /// Represents `#[rustc_coherence_is_core]` + RustcCoherenceIsCore(Span), + /// Represents `#[rustc_layout_scalar_valid_range_end]`. RustcLayoutScalarValidRangeEnd(Box, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 55521c1585402..c5005010f528e 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -26,7 +26,6 @@ impl AttributeKind { AsPtr(..) => Yes, AutomaticallyDerived(..) => Yes, BodyStability { .. } => No, - CoherenceIsCore => No, Coinductive(..) => No, Cold(..) => No, Confusables { .. } => Yes, @@ -82,6 +81,7 @@ impl AttributeKind { RecursionLimit { .. } => No, Repr { .. } => No, RustcBuiltinMacro { .. } => Yes, + RustcCoherenceIsCore(..) => No, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcObjectLifetimeDefault => No, diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 4370816d38e5f..430cd329408f5 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -370,7 +370,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn hir_rustc_coherence_is_core(self) -> bool { - find_attr!(self.hir_krate_attrs(), AttributeKind::CoherenceIsCore) + find_attr!(self.hir_krate_attrs(), AttributeKind::RustcCoherenceIsCore(..)) } pub fn hir_get_module(self, module: LocalModDefId) -> (&'tcx Mod<'tcx>, Span, HirId) { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2562d2e0b83c5..ff38d6b7e208f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -246,7 +246,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::Repr { .. } | AttributeKind::Cold(..) | AttributeKind::ExportName { .. } - | AttributeKind::CoherenceIsCore | AttributeKind::Fundamental | AttributeKind::Optimize(..) | AttributeKind::LinkSection { .. } @@ -276,6 +275,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::PatternComplexityLimit { .. } | AttributeKind::NoCore { .. } | AttributeKind::NoStd { .. } + | AttributeKind::RustcCoherenceIsCore(..) ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); From c916e8886b3a1c6f32daf467c1c3d8316e35a6df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 16 Sep 2025 11:08:43 -0700 Subject: [PATCH 13/17] fmt --- .../src/error_reporting/infer/need_type_info.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 94772be16be20..75283dc4ffaa6 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 @@ -4,11 +4,12 @@ use std::path::PathBuf; use rustc_errors::codes::*; use rustc_errors::{Diag, IntoDiagArg}; -use rustc_hir::{self as hir, PatKind}; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource}; +use rustc_hir::{ + self as hir, Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource, PatKind, +}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; From ed85f9846da9abfad09bb5732bc18d6c39fbc9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 16 Sep 2025 11:21:29 -0700 Subject: [PATCH 14/17] remove redundant test --- tests/ui/closures/varargs-in-closure-isnt-supported.rs | 10 ---------- .../closures/varargs-in-closure-isnt-supported.stderr | 10 ---------- 2 files changed, 20 deletions(-) delete mode 100644 tests/ui/closures/varargs-in-closure-isnt-supported.rs delete mode 100644 tests/ui/closures/varargs-in-closure-isnt-supported.stderr diff --git a/tests/ui/closures/varargs-in-closure-isnt-supported.rs b/tests/ui/closures/varargs-in-closure-isnt-supported.rs deleted file mode 100644 index 4de78bef14d30..0000000000000 --- a/tests/ui/closures/varargs-in-closure-isnt-supported.rs +++ /dev/null @@ -1,10 +0,0 @@ -// var-args are not supported in closures, ensure we don't misdirect people (#146489) -#![feature(c_variadic)] - -unsafe extern "C" fn thats_not_a_pattern(mut ap: ...) -> u32 { - let mut lol = |...| (); //~ ERROR: unexpected `...` - unsafe { ap.arg::() } //~^ NOTE: C-variadic type `...` is not allowed here - //~| NOTE: not a valid pattern -} - -fn main() {} diff --git a/tests/ui/closures/varargs-in-closure-isnt-supported.stderr b/tests/ui/closures/varargs-in-closure-isnt-supported.stderr deleted file mode 100644 index a645741a52771..0000000000000 --- a/tests/ui/closures/varargs-in-closure-isnt-supported.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unexpected `...` - --> $DIR/varargs-in-closure-isnt-supported.rs:5:20 - | -LL | let mut lol = |...| (); - | ^^^ not a valid pattern - | - = note: C-variadic type `...` is not allowed here - -error: aborting due to 1 previous error - From 8306a2f02e6c56447ff05b19b4b73c5c861e34fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 16 Sep 2025 11:24:51 -0700 Subject: [PATCH 15/17] Reword note --- compiler/rustc_parse/messages.ftl | 2 +- tests/ui/c-variadic/no-closure.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 6d9521c7d2be0..3a4c9348b3275 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -189,7 +189,7 @@ parse_dotdotdot = unexpected token: `...` parse_dotdotdot_rest_pattern = unexpected `...` .label = not a valid pattern .suggestion = for a rest pattern, use `..` instead of `...` - .note = C-variadic type `...` is not allowed here + .note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list parse_double_colon_in_bound = expected `:` followed by trait or lifetime .suggestion = use single colon diff --git a/tests/ui/c-variadic/no-closure.stderr b/tests/ui/c-variadic/no-closure.stderr index ad635a29ab486..4b553c215979a 100644 --- a/tests/ui/c-variadic/no-closure.stderr +++ b/tests/ui/c-variadic/no-closure.stderr @@ -10,7 +10,7 @@ error: unexpected `...` LL | let f = |...| {}; | ^^^ not a valid pattern | - = note: C-variadic type `...` is not allowed here + = note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error[E0743]: C-variadic type `...` may not be nested inside another type --> $DIR/no-closure.rs:13:17 From e9270e3cba3da56d4d83ed74f648e53b041cb263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 16 Sep 2025 11:38:08 -0700 Subject: [PATCH 16/17] Detect top-level `...` in argument type When writing something like the expression `|_: ...| {}`, we now detect the `...` during parsing explicitly instead of relying on the detection in `parse_ty_common` so that we don't talk about "nested `...` are not supported". ``` error: unexpected `...` --> $DIR/no-closure.rs:6:35 | LL | const F: extern "C" fn(...) = |_: ...| {}; | ^^^ | = note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list ``` --- compiler/rustc_parse/messages.ftl | 3 +++ compiler/rustc_parse/src/errors.rs | 8 ++++++++ compiler/rustc_parse/src/parser/ty.rs | 13 +++++++++++-- tests/ui/c-variadic/no-closure.rs | 8 ++++++-- tests/ui/c-variadic/no-closure.stderr | 13 ++++++++----- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 3a4c9348b3275..f83cf645f829d 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -191,6 +191,9 @@ parse_dotdotdot_rest_pattern = unexpected `...` .suggestion = for a rest pattern, use `..` instead of `...` .note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list +parse_dotdotdot_rest_type = unexpected `...` + .note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list + parse_double_colon_in_bound = expected `:` followed by trait or lifetime .suggestion = use single colon diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 2b107fe35d592..1abeee6fe433e 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3032,6 +3032,14 @@ pub(crate) struct NestedCVariadicType { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_dotdotdot_rest_type)] +#[note] +pub(crate) struct InvalidCVariadicType { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_invalid_dyn_keyword)] #[help] diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 23aaafac934ee..65347496599d7 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -15,8 +15,8 @@ use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use crate::errors::{ self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg, - HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, - NestedCVariadicType, ReturnTypesUseThinArrow, + HelpUseLatestEdition, InvalidCVariadicType, InvalidDynKeyword, LifetimeAfterMut, + NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; use crate::parser::{FnContext, FnParseMode}; @@ -106,6 +106,15 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, Box> { + if self.token == token::DotDotDot { + // We special case this so that we don't talk about "nested C-variadics" in types. + // We still pass in `AllowCVariadic::No` so that `parse_ty_common` can complain about + // things like `Vec<...>`. + let span = self.token.span; + self.bump(); + let kind = TyKind::Err(self.dcx().emit_err(InvalidCVariadicType { span })); + return Ok(self.mk_ty(span, kind)); + } // Make sure deeply nested types don't overflow the stack. ensure_sufficient_stack(|| { self.parse_ty_common( diff --git a/tests/ui/c-variadic/no-closure.rs b/tests/ui/c-variadic/no-closure.rs index a5b791fbca800..830ed962a8c4a 100644 --- a/tests/ui/c-variadic/no-closure.rs +++ b/tests/ui/c-variadic/no-closure.rs @@ -4,13 +4,17 @@ // Check that `...` in closures is rejected. const F: extern "C" fn(...) = |_: ...| {}; -//~^ ERROR C-variadic type `...` may not be nested inside another type +//~^ ERROR: unexpected `...` +//~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list fn foo() { let f = |...| {}; //~^ ERROR: unexpected `...` + //~| NOTE: not a valid pattern + //~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list let f = |_: ...| {}; - //~^ ERROR C-variadic type `...` may not be nested inside another type + //~^ ERROR: unexpected `...` + //~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list f(1i64) } diff --git a/tests/ui/c-variadic/no-closure.stderr b/tests/ui/c-variadic/no-closure.stderr index 4b553c215979a..0946c4632e6e4 100644 --- a/tests/ui/c-variadic/no-closure.stderr +++ b/tests/ui/c-variadic/no-closure.stderr @@ -1,23 +1,26 @@ -error[E0743]: C-variadic type `...` may not be nested inside another type +error: unexpected `...` --> $DIR/no-closure.rs:6:35 | LL | const F: extern "C" fn(...) = |_: ...| {}; | ^^^ + | + = note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error: unexpected `...` - --> $DIR/no-closure.rs:10:14 + --> $DIR/no-closure.rs:11:14 | LL | let f = |...| {}; | ^^^ not a valid pattern | = note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list -error[E0743]: C-variadic type `...` may not be nested inside another type - --> $DIR/no-closure.rs:13:17 +error: unexpected `...` + --> $DIR/no-closure.rs:16:17 | LL | let f = |_: ...| {}; | ^^^ + | + = note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0743`. From d81872a97145f35766b9885d6d88e8077d0eaf59 Mon Sep 17 00:00:00 2001 From: T Date: Fri, 12 Sep 2025 01:53:11 +0000 Subject: [PATCH 17/17] add Readme.md to tidy update Readme add info about githooks and bootstrap.toml add info about config and remove linting specific files add link to rustc-dev-guide --- src/doc/rustc-dev-guide/src/tests/intro.md | 4 +- src/tools/tidy/Readme.md | 112 +++++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/tools/tidy/Readme.md diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md index b90c16d602c31..4fa63b83b17fb 100644 --- a/src/doc/rustc-dev-guide/src/tests/intro.md +++ b/src/doc/rustc-dev-guide/src/tests/intro.md @@ -70,10 +70,12 @@ package tests: Tidy is a custom tool used for validating source code style and formatting conventions, such as rejecting long lines. There is more information in the -[section on coding conventions](../conventions.md#formatting). +[section on coding conventions](../conventions.md#formatting) or the [Tidy Readme]. > Examples: `./x test tidy` +[Tidy Readme]: https://github.com/rust-lang/rust/blob/master/src/tools/tidy/Readme.md + ### Formatting diff --git a/src/tools/tidy/Readme.md b/src/tools/tidy/Readme.md new file mode 100644 index 0000000000000..fc9dc6350e92d --- /dev/null +++ b/src/tools/tidy/Readme.md @@ -0,0 +1,112 @@ +# Tidy +Tidy is the Rust project's custom internal linter and a crucial part of our testing and continuous integration (CI) infrastructure. It is designed to enforce a consistent style and formatting across the entire codebase, but its role extends beyond simple linting. Tidy also helps with infrastructure, policy, and documentation, ensuring the project remains organized, functional, and... tidy. + +This document will cover how to use tidy, the specific checks tidy performs, and using tidy directives to manage its behavior. By understanding and utilizing tidy, you can help us maintain the high standards of the Rust project. +## Tidy Checks +### Style and Code Quality +These lints focus on enforcing consistent formatting, style, and general code health. +* [`alphabetical`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/alphabetical/index.html): Checks that lists are sorted alphabetically +* [`style`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/style/index.html): Check to enforce various stylistic guidelines on the Rust codebase. +* [`filenames`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/filenames/index.html): Check to prevent invalid characters in file names. +* [`pal`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/pal/index.html): Check to enforce rules about platform-specific code in std. +* [`target_policy`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/target_policy/index.html): Check for target tier policy compliance. +* [`error_codes`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/error_codes/index.html): Check to ensure error codes are properly documented and tested. + +### Infrastructure +These checks focus on the integrity of the project's dependencies, internal tools, and documentation. +* [`bins`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/bins/index.html): Prevent stray binaries from being checked into the source tree. +* [`fluent_alphabetical`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_alphabetical/index.html) / [`fluent_period`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_period/index.html) / [`fluent_used`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_used/index.html): Various checks related to [Fluent](https://github.com/projectfluent) for localization and natural language translation. +* [`deps`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/deps/index.html) / [`extdeps`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/extdeps/index.html): Check for valid licenses and sources for external dependencies. +* [`gcc_submodule`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/gcc_submodule/index.html): Check that the `src/gcc` submodule version is valid. +* [`triagebot`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/triagebot/index.html): Check to ensure paths mentioned in `triagebot.toml` exist in the project. +* [`x_version`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/x_version/index.html): Validates the current version of the `x` tool. + +* [`edition`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/edition/index.html) / [`features`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/features/index.html): Check for a valid Rust edition and proper ordering of unstable features. +* [`rustdoc_css_themes`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_css_themes/index.html) / [`rustdoc_templates`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_templates/index.html): Verify that Rust documentation templates and themes are correct. +* [`unstable_book`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unstable_book/index.html): Synchronizes the unstable book with unstable features. +### Testing +These checks ensure that tests are correctly structured, cleaned up, and free of common errors. +* [`tests_placement`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/tests_placement/index.html) / [`unit_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unit_tests/index.html): Verify that tests are located in the correct directories and are not using improper attributes. +* [`known_bug`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/known_bug/index.html) / [`unknown_revision`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unknown_revision/index.html): Ensure that test directives and annotations are used correctly. +* [`debug_artifacts`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/debug_artifacts/index.html) / [`mir_opt_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/mir_opt_tests/index.html): Prevent unnecessary artifacts and stale files in test directories. +* [`tests_revision_unpaired_stdout_stderr`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/tests_revision_unpaired_stdout_stderr/index.html) / [`ui_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/ui_tests/index.html): Check for unpaired or stray test output files. +* [`target_specific_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/target_specific_tests/index.html): Check to ensure that all target specific tests (those that require a --target flag) also require the pre-requisite LLVM components to run. +* [`rustdoc_gui_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_gui_tests/index.html): Checks that rustdoc gui tests start with a small description +* [`rustdoc_json`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_json/index.html): Verify that `FORMAT_VERSION` is in sync with `rust-json-types`. +## Using Tidy + +Tidy is used in a number of different ways. +* Every time `./x test` is used tidy will run automatically. + +* On every pull request, tidy will run automatically during CI checks. +* Optionally, with the use of git-hooks, tidy can run locally on every push. This can be setup with `./x setup`. See the [rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/building/suggested.html#installing-a-pre-push-hook) for more information. + +You can run tidy manually with: + +`./x test tidy` + +To first run the relevant formatter and then run tidy you can add `--bless`. + +`./x test tidy --bless` +### Extra Checks +[`extra_checks`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/extra_checks/index.html) are optional checks primarily focused on other file types and programming languages. + +Example usage: + +`./x test tidy --extra-checks=py,cpp,js,spellcheck` + +All options for `--extra-checks`: +* `cpp`, `cpp:fmt` +* `py`, `py:lint`, `py:fmt` +* `js`, `js:lint`, `js:fmt`, `js:typecheck` +* `shell`, `shell:lint` +* `spellcheck` + +Default values for tidy's `extra-checks` can be set in `bootstrap.toml`. For example, `build.tidy-extra-checks = "js,py"`. + +Any argument without a suffix (eg. `py` or `js`) will include all possible checks. For example, `--extra-checks=js` is the same as `extra-checks=js:lint,js:fmt,js:typecheck`. + +Any argument can be prefixed with `auto:` to only run if relevant files are modified (eg. `--extra-checks=auto:py`). + +A specific configuration file or folder can be passed to tidy after a double dash (`--extra-checks=py -- foo.py`) + +## Tidy Directives + +Tidy directives are special comments that help tidy operate. + +Tidy directives can be used in the following types of comments: +* `// ` +* `# ` +* `/* {...} */` +* `` + +You might find yourself needing to ignore a specific tidy style check and can do so with: +* `ignore-tidy-cr` +* `ignore-tidy-undocumented-unsafe` +* `ignore-tidy-tab` +* `ignore-tidy-linelength` +* `ignore-tidy-filelength` + +* `ignore-tidy-end-whitespace` +* `ignore-tidy-trailing-newlines` +* `ignore-tidy-leading-newlines` +* `ignore-tidy-copyright` +* `ignore-tidy-dbg` +* `ignore-tidy-odd-backticks` +* `ignore-tidy-todo` + +Some checks, like `alphabetical`, require a tidy directive to use: +``` +// tidy-alphabetical-start +fn aaa() {} +fn eee() {} +fn z() {} +// tidy-alphabetical-end +``` +While not exactly a tidy directive, // TODO will fail tidy and make sure you can't merge a PR with unfinished work. + +### Test Specific Directives + +`target-specific-tests` can be ignored with `// ignore-tidy-target-specific-tests` + +Tidy's `unknown_revision` check can be suppressed by adding the revision name to `//@ unused-revision-names:{revision}` or with `//@ unused-revision-names:*`.