From 964eb82b63f7c99f951e5b5f262dc8800f7bd6ec Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Thu, 29 May 2025 22:10:40 +0300 Subject: [PATCH 01/37] Stabilize `ip_from` --- library/core/src/net/ip_addr.rs | 12 ++++++------ library/coretests/tests/lib.rs | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index aaa68e8d7d1ad..1d1d184bb21ad 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -627,13 +627,13 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip_from)] /// use std::net::Ipv4Addr; /// /// let addr = Ipv4Addr::from_octets([13u8, 12u8, 11u8, 10u8]); /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); /// ``` - #[unstable(feature = "ip_from", issue = "131360")] + #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_octets(octets: [u8; 4]) -> Ipv4Addr { @@ -1460,7 +1460,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip_from)] /// use std::net::Ipv6Addr; /// /// let addr = Ipv6Addr::from_segments([ @@ -1475,7 +1474,8 @@ impl Ipv6Addr { /// addr /// ); /// ``` - #[unstable(feature = "ip_from", issue = "131360")] + #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_segments(segments: [u16; 8]) -> Ipv6Addr { @@ -2025,7 +2025,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip_from)] /// use std::net::Ipv6Addr; /// /// let addr = Ipv6Addr::from_octets([ @@ -2040,7 +2039,8 @@ impl Ipv6Addr { /// addr /// ); /// ``` - #[unstable(feature = "ip_from", issue = "131360")] + #[stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "ip_from", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_octets(octets: [u8; 16]) -> Ipv6Addr { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 693b14ef76209..b9c642461eadc 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -47,7 +47,6 @@ #![feature(hashmap_internals)] #![feature(int_roundings)] #![feature(ip)] -#![feature(ip_from)] #![feature(is_ascii_octdigit)] #![feature(isolate_most_least_significant_one)] #![feature(iter_advance_by)] From a067c6a3c6ac4db7652e1722acf2648ef65b0229 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sun, 1 Jun 2025 12:51:17 +0200 Subject: [PATCH 02/37] refactor `unreachable/expr_cast.rs` test --- tests/ui/reachable/expr_cast.rs | 15 +++++++-------- tests/ui/reachable/expr_cast.stderr | 26 ++++++++++++++------------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/tests/ui/reachable/expr_cast.rs b/tests/ui/reachable/expr_cast.rs index e8e477ea4f684..58ebe2a7b9fc9 100644 --- a/tests/ui/reachable/expr_cast.rs +++ b/tests/ui/reachable/expr_cast.rs @@ -1,13 +1,12 @@ -#![allow(unused_variables)] -#![allow(unused_assignments)] -#![allow(dead_code)] +//@ edition: 2024 #![deny(unreachable_code)] -#![feature(never_type, type_ascription)] fn a() { - // the cast is unreachable: - let x = {return} as !; //~ ERROR unreachable - //~| ERROR non-primitive cast + _ = {return} as u32; //~ error: unreachable } -fn main() { } +fn b() { + (return) as u32; //~ error: unreachable +} + +fn main() {} diff --git a/tests/ui/reachable/expr_cast.stderr b/tests/ui/reachable/expr_cast.stderr index 6643f1784a174..cf711d4436e00 100644 --- a/tests/ui/reachable/expr_cast.stderr +++ b/tests/ui/reachable/expr_cast.stderr @@ -1,24 +1,26 @@ error: unreachable expression - --> $DIR/expr_cast.rs:9:13 + --> $DIR/expr_cast.rs:5:9 | -LL | let x = {return} as !; - | ^------^^^^^^ - | || - | |any code following this expression is unreachable - | unreachable expression +LL | _ = {return} as u32; + | ^------^^^^^^^^ + | || + | |any code following this expression is unreachable + | unreachable expression | note: the lint level is defined here - --> $DIR/expr_cast.rs:4:9 + --> $DIR/expr_cast.rs:2:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ -error[E0605]: non-primitive cast: `()` as `!` - --> $DIR/expr_cast.rs:9:13 +error: unreachable expression + --> $DIR/expr_cast.rs:9:5 | -LL | let x = {return} as !; - | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object +LL | (return) as u32; + | --------^^^^^^^ + | | + | unreachable expression + | any code following this expression is unreachable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0605`. From d2e133d96a2a7b0063cfd514a35304e4908dcb6f Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sun, 1 Jun 2025 12:51:17 +0200 Subject: [PATCH 03/37] don't warn on explicit casts of never to any --- compiler/rustc_hir_typeck/src/expr.rs | 3 +++ tests/ui/reachable/expr_cast.rs | 13 ++++++++-- tests/ui/reachable/expr_cast.stderr | 26 ------------------- tests/ui/reachable/unreachable-try-pattern.rs | 2 +- .../reachable/unreachable-try-pattern.stderr | 11 ++++---- 5 files changed, 20 insertions(+), 35 deletions(-) delete mode 100644 tests/ui/reachable/expr_cast.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 454ec7ddcafbe..74136b5462824 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -290,6 +290,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ExprKind::Let(..) | ExprKind::Loop(..) | ExprKind::Match(..) => {} + // Do not warn on `as` casts from never to any, + // they are sometimes required to appeal typeck. + ExprKind::Cast(_, _) => {} // If `expr` is a result of desugaring the try block and is an ok-wrapped // diverging expression (e.g. it arose from desugaring of `try { return }`), // we skip issuing a warning because it is autogenerated code. diff --git a/tests/ui/reachable/expr_cast.rs b/tests/ui/reachable/expr_cast.rs index 58ebe2a7b9fc9..aa412c99b2e9b 100644 --- a/tests/ui/reachable/expr_cast.rs +++ b/tests/ui/reachable/expr_cast.rs @@ -1,12 +1,21 @@ +//@ check-pass //@ edition: 2024 +// +// Check that we don't warn on `as` casts of never to any as unreachable. +// While they *are* unreachable, sometimes they are required to appeal typeck. #![deny(unreachable_code)] fn a() { - _ = {return} as u32; //~ error: unreachable + _ = {return} as u32; } fn b() { - (return) as u32; //~ error: unreachable + (return) as u32; +} + +// example that needs an explicit never-to-any `as` cast +fn example() -> impl Iterator { + todo!() as std::iter::Empty<_> } fn main() {} diff --git a/tests/ui/reachable/expr_cast.stderr b/tests/ui/reachable/expr_cast.stderr deleted file mode 100644 index cf711d4436e00..0000000000000 --- a/tests/ui/reachable/expr_cast.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: unreachable expression - --> $DIR/expr_cast.rs:5:9 - | -LL | _ = {return} as u32; - | ^------^^^^^^^^ - | || - | |any code following this expression is unreachable - | unreachable expression - | -note: the lint level is defined here - --> $DIR/expr_cast.rs:2:9 - | -LL | #![deny(unreachable_code)] - | ^^^^^^^^^^^^^^^^ - -error: unreachable expression - --> $DIR/expr_cast.rs:9:5 - | -LL | (return) as u32; - | --------^^^^^^^ - | | - | unreachable expression - | any code following this expression is unreachable - -error: aborting due to 2 previous errors - diff --git a/tests/ui/reachable/unreachable-try-pattern.rs b/tests/ui/reachable/unreachable-try-pattern.rs index 22cbfb95af084..1358722e229ce 100644 --- a/tests/ui/reachable/unreachable-try-pattern.rs +++ b/tests/ui/reachable/unreachable-try-pattern.rs @@ -18,7 +18,7 @@ fn bar(x: Result) -> Result { fn foo(x: Result) -> Result { let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?; //~^ WARN unreachable pattern - //~| WARN unreachable expression + //~| WARN unreachable call Ok(y) } diff --git a/tests/ui/reachable/unreachable-try-pattern.stderr b/tests/ui/reachable/unreachable-try-pattern.stderr index 40b116131057c..468af427249c1 100644 --- a/tests/ui/reachable/unreachable-try-pattern.stderr +++ b/tests/ui/reachable/unreachable-try-pattern.stderr @@ -1,11 +1,10 @@ -warning: unreachable expression - --> $DIR/unreachable-try-pattern.rs:19:36 +warning: unreachable call + --> $DIR/unreachable-try-pattern.rs:19:33 | LL | let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?; - | -^^^^^^^ - | | - | unreachable expression - | any code following this expression is unreachable + | ^^ - any code following this expression is unreachable + | | + | unreachable call | note: the lint level is defined here --> $DIR/unreachable-try-pattern.rs:3:9 From 970ac40300bc75de9f5ef2edf77e93be5bd0769d Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sat, 2 Aug 2025 23:10:46 +0500 Subject: [PATCH 04/37] updated doc comment --- src/librustdoc/clean/types.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 89d5acb985b1b..cc3faa3d612a6 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1534,10 +1534,10 @@ impl Type { matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } }) } - /// Check if two types are "the same" for documentation purposes. + /// Check if this type is a subtype of another type for documentation purposes. /// /// This is different from `Eq`, because it knows that things like - /// `Placeholder` are possible matches for everything. + /// `Infer` and generics have special subtyping rules. /// /// This relation is not commutative when generics are involved: /// @@ -1548,8 +1548,8 @@ impl Type { /// let cache = Cache::new(false); /// let generic = Type::Generic(rustc_span::symbol::sym::Any); /// let unit = Type::Primitive(PrimitiveType::Unit); - /// assert!(!generic.is_same(&unit, &cache)); - /// assert!(unit.is_same(&generic, &cache)); + /// assert!(!generic.is_doc_subtype_of(&unit, &cache)); + /// assert!(unit.is_doc_subtype_of(&generic, &cache)); /// ``` /// /// An owned type is also the same as its borrowed variants (this is commutative), From 4e2d420ac5f23bb9853410098b4f686704c0a6c2 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 7 Aug 2025 10:57:51 +0200 Subject: [PATCH 05/37] avoid duplicate error string --- compiler/rustc_borrowck/src/diagnostics/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index b67dba3af96d2..995c953fda967 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -676,7 +676,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }); if let Some(span) = predicate_span { - err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); + err.span_note(span, fluent::borrowck_limitations_implies_static); } } From d62e8578c5dcf08a4b5766ea63ea921f68c9de99 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 7 Aug 2025 11:24:46 +0200 Subject: [PATCH 06/37] also consider HR bounds --- .../src/diagnostics/region_errors.rs | 20 ++++++++++++++++--- .../extended/lending_iterator.stderr | 6 ++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 2b74f1a48f731..cd03daad593a4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -215,7 +215,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { diag: &mut Diag<'_>, lower_bound: RegionVid, ) { - let mut suggestions = vec![]; let tcx = self.infcx.tcx; // find generic associated types in the given region 'lower_bound' @@ -239,7 +238,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // find higher-ranked trait bounds bounded to the generic associated types let mut hrtb_bounds = vec![]; - gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| { + gat_id_and_generics.iter().flatten().for_each(|&(gat_hir_id, generics)| { for pred in generics.predicates { let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) = pred.kind @@ -248,17 +247,32 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }; if bound_generic_params .iter() - .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id) + .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id) .is_some() { for bound in *bounds { hrtb_bounds.push(bound); } + } else { + for bound in *bounds { + if let Trait(trait_bound) = bound { + if trait_bound + .bound_generic_params + .iter() + .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id) + .is_some() + { + hrtb_bounds.push(bound); + return; + } + } + } } } }); debug!(?hrtb_bounds); + let mut suggestions = vec![]; hrtb_bounds.iter().for_each(|bound| { let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }) = bound else { return; diff --git a/tests/ui/generic-associated-types/extended/lending_iterator.stderr b/tests/ui/generic-associated-types/extended/lending_iterator.stderr index 84f5ed07bda59..dc349c6ceb93f 100644 --- a/tests/ui/generic-associated-types/extended/lending_iterator.stderr +++ b/tests/ui/generic-associated-types/extended/lending_iterator.stderr @@ -12,6 +12,12 @@ error: `Self` does not live long enough | LL | >::from_iter(self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/lending_iterator.rs:4:21 + | +LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors From a95a2ac476ef04ccf8cfabd35e6fcdb9569f053d Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 7 Aug 2025 11:30:24 +0200 Subject: [PATCH 07/37] rework `add_placeholder_from_predicate_note` --- .../rustc_borrowck/src/diagnostics/mod.rs | 58 ++++++++++++++++--- ...ation-not-general-enough-ice-133252.stderr | 6 -- .../bugs/hrtb-implied-1.stderr | 4 +- .../bugs/hrtb-implied-2.stderr | 6 +- .../bugs/hrtb-implied-3.stderr | 4 +- ...normalization-placeholder-leak.fail.stderr | 12 ++++ tests/ui/issues/issue-26217.stderr | 4 +- .../nll/local-outlives-static-via-hrtb.stderr | 8 +-- ...insensitive-scopes-issue-117146.nll.stderr | 4 +- ...sitive-scopes-issue-117146.polonius.stderr | 4 +- tests/ui/nll/type-test-universe.stderr | 4 +- .../reject_lifetime_extension.stderr | 4 +- 12 files changed, 84 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 995c953fda967..7d7d0abc3f4cb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -6,7 +6,9 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify}; use rustc_hir::def::{CtorKind, Namespace}; -use rustc_hir::{self as hir, CoroutineKind, LangItem}; +use rustc_hir::{ + self as hir, CoroutineKind, GenericBound, LangItem, WhereBoundPredicate, WherePredicateKind, +}; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin}; use rustc_infer::traits::SelectionError; @@ -658,25 +660,63 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// Add a note to region errors and borrow explanations when higher-ranked regions in predicates /// implicitly introduce an "outlives `'static`" constraint. + /// + /// This is very similar to `fn suggest_static_lifetime_for_gat_from_hrtb` which handles this + /// note for failed type tests instead of outlives errors. fn add_placeholder_from_predicate_note( &self, - err: &mut Diag<'_, G>, + diag: &mut Diag<'_, G>, path: &[OutlivesConstraint<'tcx>], ) { - let predicate_span = path.iter().find_map(|constraint| { + let tcx = self.infcx.tcx; + let Some((gat_hir_id, generics)) = path.iter().find_map(|constraint| { let outlived = constraint.sub; if let Some(origin) = self.regioncx.definitions.get(outlived) - && let NllRegionVariableOrigin::Placeholder(_) = origin.origin - && let ConstraintCategory::Predicate(span) = constraint.category + && let NllRegionVariableOrigin::Placeholder(placeholder) = origin.origin + && let Some(id) = placeholder.bound.kind.get_id() + && let Some(placeholder_id) = id.as_local() + && let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id) + && let Some(generics_impl) = + tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics() { - Some(span) + Some((gat_hir_id, generics_impl)) } else { None } - }); + }) else { + return; + }; - if let Some(span) = predicate_span { - err.span_note(span, fluent::borrowck_limitations_implies_static); + for pred in generics.predicates { + let WherePredicateKind::BoundPredicate(WhereBoundPredicate { + bound_generic_params, + bounds, + .. + }) = pred.kind + else { + continue; + }; + if bound_generic_params + .iter() + .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id) + .is_some() + { + diag.span_note(pred.span, fluent::borrowck_limitations_implies_static); + return; + } + for bound in bounds.iter() { + if let GenericBound::Trait(bound) = bound { + if bound + .bound_generic_params + .iter() + .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id) + .is_some() + { + diag.span_note(bound.span, fluent::borrowck_limitations_implies_static); + return; + } + } + } } } diff --git a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr index 4ec4d2138db60..5389226f7a7a4 100644 --- a/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr +++ b/tests/ui/borrowck/implementation-not-general-enough-ice-133252.stderr @@ -22,12 +22,6 @@ LL | force_send(async_load(¬_static)); ... LL | } | - `not_static` dropped here while still borrowed - | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/implementation-not-general-enough-ice-133252.rs:16:18 - | -LL | fn force_send(_: T) {} - | ^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr index 5dfc42bc8735a..9e925c33e581e 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr @@ -10,10 +10,10 @@ LL | } | - temporary value is freed at the end of this statement | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/hrtb-implied-1.rs:26:26 + --> $DIR/hrtb-implied-1.rs:26:5 | LL | for<'a> I::Item<'a>: Debug, - | ^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr index 9a1a09b29df9a..e28b4d7b9cac4 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr @@ -15,7 +15,11 @@ LL | let _next = iter2.next(); = note: requirement occurs because of a mutable reference to `Eat<&mut I, F>` = note: mutable references are invariant over their type parameter = help: see for more information about variance - = note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-implied-2.rs:31:8 + | +LL | F: FnMut(I::Item<'_>), + | ^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr index 77f363ee87db8..36197317b9560 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr @@ -12,10 +12,10 @@ LL | trivial_bound(iter); | argument requires that `'1` must outlive `'static` | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/hrtb-implied-3.rs:14:26 + --> $DIR/hrtb-implied-3.rs:14:5 | LL | for<'a> I::Item<'a>: Sized, - | ^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr b/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr index 8919919d04e5c..8ef77eed5ee3c 100644 --- a/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr +++ b/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr @@ -30,6 +30,12 @@ LL | fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {} | | | | | lifetime `'lt` defined here | requires that `'lt` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/normalization-placeholder-leak.rs:19:5 + | +LL | for<'x> T::Ty<'x>: Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: lifetime may not live long enough --> $DIR/normalization-placeholder-leak.rs:38:5 @@ -39,6 +45,12 @@ LL | fn test_alias<'lt, T: AnotherTrait>(_: Foo>) {} | | | | | lifetime `'lt` defined here | requires that `'lt` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/normalization-placeholder-leak.rs:19:5 + | +LL | for<'x> T::Ty<'x>: Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/issues/issue-26217.stderr b/tests/ui/issues/issue-26217.stderr index 0b153ad7490e0..dd7e645341aab 100644 --- a/tests/ui/issues/issue-26217.stderr +++ b/tests/ui/issues/issue-26217.stderr @@ -7,10 +7,10 @@ LL | foo::<&'a i32>(); | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/issue-26217.rs:1:30 + --> $DIR/issue-26217.rs:1:19 | LL | fn foo() where for<'a> T: 'a {} - | ^^ + | ^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.stderr b/tests/ui/nll/local-outlives-static-via-hrtb.stderr index a6b3328b5a294..6aa3fda45e019 100644 --- a/tests/ui/nll/local-outlives-static-via-hrtb.stderr +++ b/tests/ui/nll/local-outlives-static-via-hrtb.stderr @@ -13,10 +13,10 @@ LL | } | - `local` dropped here while still borrowed | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/local-outlives-static-via-hrtb.rs:15:53 + --> $DIR/local-outlives-static-via-hrtb.rs:15:42 | LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0597]: `local` does not live long enough --> $DIR/local-outlives-static-via-hrtb.rs:25:45 @@ -33,10 +33,10 @@ LL | } | - `local` dropped here while still borrowed | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/local-outlives-static-via-hrtb.rs:19:20 + --> $DIR/local-outlives-static-via-hrtb.rs:19:5 | LL | for<'a> &'a T: Reference, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 1d086c658dfcd..8ee45b472eaa5 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -14,10 +14,10 @@ LL | } | - `a` dropped here while still borrowed | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 + --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11 | LL | fn bad &()>(_: F) {} - | ^^^ + | ^^^^^^^^^^^^^^ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 1d086c658dfcd..8ee45b472eaa5 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -14,10 +14,10 @@ LL | } | - `a` dropped here while still borrowed | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/location-insensitive-scopes-issue-117146.rs:20:22 + --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11 | LL | fn bad &()>(_: F) {} - | ^^^ + | ^^^^^^^^^^^^^^ error: implementation of `Fn` is not general enough --> $DIR/location-insensitive-scopes-issue-117146.rs:13:5 diff --git a/tests/ui/nll/type-test-universe.stderr b/tests/ui/nll/type-test-universe.stderr index 31e17d64b8caf..bea18240c3526 100644 --- a/tests/ui/nll/type-test-universe.stderr +++ b/tests/ui/nll/type-test-universe.stderr @@ -13,10 +13,10 @@ LL | outlives_forall::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/type-test-universe.rs:6:16 + --> $DIR/type-test-universe.rs:6:5 | LL | for<'u> T: 'u, - | ^^ + | ^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/transmutability/references/reject_lifetime_extension.stderr b/tests/ui/transmutability/references/reject_lifetime_extension.stderr index a597041c6cac2..459e9a02aaa6e 100644 --- a/tests/ui/transmutability/references/reject_lifetime_extension.stderr +++ b/tests/ui/transmutability/references/reject_lifetime_extension.stderr @@ -68,10 +68,10 @@ LL | unsafe { extend_hrtb(src) } | argument requires that `'a` must outlive `'static` | note: due to current limitations in the borrow checker, this implies a `'static` lifetime - --> $DIR/reject_lifetime_extension.rs:85:25 + --> $DIR/reject_lifetime_extension.rs:85:9 | LL | for<'b> &'b u8: TransmuteFrom<&'a u8>, - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors From 5c716bdc8754a3d919396768fed2ec76110257cd Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 7 Aug 2025 12:09:48 +0200 Subject: [PATCH 08/37] add comment --- compiler/rustc_borrowck/src/diagnostics/mod.rs | 3 +++ compiler/rustc_borrowck/src/diagnostics/region_errors.rs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 7d7d0abc3f4cb..5642cdf87fded 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -687,6 +687,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { return; }; + // Look for the where-bound which introduces the placeholder. + // As we're using the HIR, we need to handle both `for<'a> T: Trait<'a>` + // and `T: for<'a> Trait`<'a>. for pred in generics.predicates { let WherePredicateKind::BoundPredicate(WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index cd03daad593a4..fe4e1b6011e62 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -236,7 +236,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .collect::>(); debug!(?gat_id_and_generics); - // find higher-ranked trait bounds bounded to the generic associated types + // Look for the where-bound which introduces the placeholder. + // As we're using the HIR, we need to handle both `for<'a> T: Trait<'a>` + // and `T: for<'a> Trait`<'a>. let mut hrtb_bounds = vec![]; gat_id_and_generics.iter().flatten().for_each(|&(gat_hir_id, generics)| { for pred in generics.predicates { From 3ebf611005370734ddf7ce22e41ac502e4fff59a Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 13 Aug 2025 14:08:53 +0200 Subject: [PATCH 09/37] it's not a borrow checker limitation :< --- compiler/rustc_borrowck/messages.ftl | 2 +- tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr | 2 +- tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr | 2 +- tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr | 2 +- .../generic-associated-types/collectivity-regression.stderr | 2 +- .../generic-associated-types/extended/lending_iterator.stderr | 2 +- .../ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr | 2 +- .../higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr | 2 +- .../implied-bounds/normalization-placeholder-leak.fail.stderr | 4 ++-- tests/ui/issues/issue-26217.stderr | 2 +- tests/ui/lifetimes/issue-105507.fixed | 4 ++-- tests/ui/lifetimes/issue-105507.rs | 4 ++-- tests/ui/lifetimes/issue-105507.stderr | 4 ++-- tests/ui/mismatched_types/closure-arg-type-mismatch.stderr | 2 +- tests/ui/nll/local-outlives-static-via-hrtb.stderr | 4 ++-- .../location-insensitive-scopes-issue-117146.nll.stderr | 2 +- .../location-insensitive-scopes-issue-117146.polonius.stderr | 2 +- tests/ui/nll/type-test-universe.stderr | 2 +- .../references/reject_lifetime_extension.stderr | 2 +- 19 files changed, 24 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 33b80c4b03d6f..f59e106c7ac3c 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -90,7 +90,7 @@ borrowck_lifetime_constraints_error = lifetime may not live long enough borrowck_limitations_implies_static = - due to current limitations in the borrow checker, this implies a `'static` lifetime + due to a current limitation of the type system, this implies a `'static` lifetime borrowck_move_closure_suggestion = consider adding 'move' keyword before the nested closure diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr index 9e925c33e581e..8bb72833e301c 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-1.stderr @@ -9,7 +9,7 @@ LL | print_items::>(windows); LL | } | - temporary value is freed at the end of this statement | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/hrtb-implied-1.rs:26:5 | LL | for<'a> I::Item<'a>: Debug, diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr index e28b4d7b9cac4..1a397f6cdb21a 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-2.stderr @@ -15,7 +15,7 @@ LL | let _next = iter2.next(); = note: requirement occurs because of a mutable reference to `Eat<&mut I, F>` = note: mutable references are invariant over their type parameter = help: see for more information about variance -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/hrtb-implied-2.rs:31:8 | LL | F: FnMut(I::Item<'_>), diff --git a/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr b/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr index 36197317b9560..aaafcb3b7afb4 100644 --- a/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr +++ b/tests/ui/generic-associated-types/bugs/hrtb-implied-3.stderr @@ -11,7 +11,7 @@ LL | trivial_bound(iter); | `iter` escapes the function body here | argument requires that `'1` must outlive `'static` | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/hrtb-implied-3.rs:14:5 | LL | for<'a> I::Item<'a>: Sized, diff --git a/tests/ui/generic-associated-types/collectivity-regression.stderr b/tests/ui/generic-associated-types/collectivity-regression.stderr index 1c081ac644afa..31349c8eb270c 100644 --- a/tests/ui/generic-associated-types/collectivity-regression.stderr +++ b/tests/ui/generic-associated-types/collectivity-regression.stderr @@ -7,7 +7,7 @@ LL | | let _x = x; LL | | }; | |_____^ | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/collectivity-regression.rs:11:16 | LL | for<'a> T: Get = ()>, diff --git a/tests/ui/generic-associated-types/extended/lending_iterator.stderr b/tests/ui/generic-associated-types/extended/lending_iterator.stderr index dc349c6ceb93f..7af95dc96a10a 100644 --- a/tests/ui/generic-associated-types/extended/lending_iterator.stderr +++ b/tests/ui/generic-associated-types/extended/lending_iterator.stderr @@ -13,7 +13,7 @@ error: `Self` does not live long enough LL | >::from_iter(self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/lending_iterator.rs:4:21 | LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr index 1c077a9b906cd..697e85dc8c394 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-just-for-static.stderr @@ -15,7 +15,7 @@ LL | fn give_some<'a>() { LL | want_hrtb::<&'a u32>() | ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/hrtb-just-for-static.rs:9:15 | LL | where T : for<'a> Foo<&'a isize> diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr index 727b9e6bec8e6..327c0faa48287 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-perfect-forwarding.stderr @@ -47,7 +47,7 @@ LL | fn foo_hrtb_bar_not<'b, T>(mut t: T) LL | foo_hrtb_bar_not(&mut t); | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/hrtb-perfect-forwarding.rs:37:8 | LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>, diff --git a/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr b/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr index 8ef77eed5ee3c..be8b44b1bde6c 100644 --- a/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr +++ b/tests/ui/implied-bounds/normalization-placeholder-leak.fail.stderr @@ -31,7 +31,7 @@ LL | fn test_lifetime<'lt, T: Trait>(_: Foo<&'lt u8>) {} | | lifetime `'lt` defined here | requires that `'lt` must outlive `'static` | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/normalization-placeholder-leak.rs:19:5 | LL | for<'x> T::Ty<'x>: Sized; @@ -46,7 +46,7 @@ LL | fn test_alias<'lt, T: AnotherTrait>(_: Foo>) {} | | lifetime `'lt` defined here | requires that `'lt` must outlive `'static` | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/normalization-placeholder-leak.rs:19:5 | LL | for<'x> T::Ty<'x>: Sized; diff --git a/tests/ui/issues/issue-26217.stderr b/tests/ui/issues/issue-26217.stderr index dd7e645341aab..a875056781955 100644 --- a/tests/ui/issues/issue-26217.stderr +++ b/tests/ui/issues/issue-26217.stderr @@ -6,7 +6,7 @@ LL | fn bar<'a>() { LL | foo::<&'a i32>(); | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/issue-26217.rs:1:19 | LL | fn foo() where for<'a> T: 'a {} diff --git a/tests/ui/lifetimes/issue-105507.fixed b/tests/ui/lifetimes/issue-105507.fixed index 177da01b154b3..46d4f14a2457e 100644 --- a/tests/ui/lifetimes/issue-105507.fixed +++ b/tests/ui/lifetimes/issue-105507.fixed @@ -25,8 +25,8 @@ impl ProjectedMyTrait for T where T: Project, for<'a> T::Projected<'a>: MyTrait, - //~^ NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime - //~| NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime + //~^ NOTE due to a current limitation of the type system, this implies a `'static` lifetime + //~| NOTE due to a current limitation of the type system, this implies a `'static` lifetime {} fn require_trait(_: T) {} diff --git a/tests/ui/lifetimes/issue-105507.rs b/tests/ui/lifetimes/issue-105507.rs index 858fa19a0295b..f1721fee5b4ad 100644 --- a/tests/ui/lifetimes/issue-105507.rs +++ b/tests/ui/lifetimes/issue-105507.rs @@ -25,8 +25,8 @@ impl ProjectedMyTrait for T where T: Project, for<'a> T::Projected<'a>: MyTrait, - //~^ NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime - //~| NOTE due to current limitations in the borrow checker, this implies a `'static` lifetime + //~^ NOTE due to a current limitation of the type system, this implies a `'static` lifetime + //~| NOTE due to a current limitation of the type system, this implies a `'static` lifetime {} fn require_trait(_: T) {} diff --git a/tests/ui/lifetimes/issue-105507.stderr b/tests/ui/lifetimes/issue-105507.stderr index 44d3a7eb9a420..7fccba7cc4468 100644 --- a/tests/ui/lifetimes/issue-105507.stderr +++ b/tests/ui/lifetimes/issue-105507.stderr @@ -4,7 +4,7 @@ error: `T` does not live long enough LL | require_trait(wrap); | ^^^^^^^^^^^^^^^^^^^ | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/issue-105507.rs:27:35 | LL | for<'a> T::Projected<'a>: MyTrait, @@ -20,7 +20,7 @@ error: `U` does not live long enough LL | require_trait(wrap1); | ^^^^^^^^^^^^^^^^^^^^ | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/issue-105507.rs:27:35 | LL | for<'a> T::Projected<'a>: MyTrait, diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr index abc5d150a3f9c..62e872639671b 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -57,7 +57,7 @@ LL | baz(f); = note: requirement occurs because of a mutable pointer to `&u32` = note: mutable pointers are invariant over their type parameter = help: see for more information about variance -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/closure-arg-type-mismatch.rs:8:11 | LL | fn baz(_: F) {} diff --git a/tests/ui/nll/local-outlives-static-via-hrtb.stderr b/tests/ui/nll/local-outlives-static-via-hrtb.stderr index 6aa3fda45e019..a98f11ce51363 100644 --- a/tests/ui/nll/local-outlives-static-via-hrtb.stderr +++ b/tests/ui/nll/local-outlives-static-via-hrtb.stderr @@ -12,7 +12,7 @@ LL | assert_static_via_hrtb_with_assoc_type(&&local); LL | } | - `local` dropped here while still borrowed | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/local-outlives-static-via-hrtb.rs:15:42 | LL | fn assert_static_via_hrtb(_: G) where for<'a> G: Outlives<'a> {} @@ -32,7 +32,7 @@ LL | assert_static_via_hrtb_with_assoc_type(&&local); LL | } | - `local` dropped here while still borrowed | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/local-outlives-static-via-hrtb.rs:19:5 | LL | for<'a> &'a T: Reference, diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr index 8ee45b472eaa5..6e47b8e59f5c6 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.nll.stderr @@ -13,7 +13,7 @@ LL | let b = |_| &a; LL | } | - `a` dropped here while still borrowed | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11 | LL | fn bad &()>(_: F) {} diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr index 8ee45b472eaa5..6e47b8e59f5c6 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.polonius.stderr @@ -13,7 +13,7 @@ LL | let b = |_| &a; LL | } | - `a` dropped here while still borrowed | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/location-insensitive-scopes-issue-117146.rs:20:11 | LL | fn bad &()>(_: F) {} diff --git a/tests/ui/nll/type-test-universe.stderr b/tests/ui/nll/type-test-universe.stderr index bea18240c3526..54b48c1597bdf 100644 --- a/tests/ui/nll/type-test-universe.stderr +++ b/tests/ui/nll/type-test-universe.stderr @@ -12,7 +12,7 @@ LL | fn test2<'a>() { LL | outlives_forall::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/type-test-universe.rs:6:5 | LL | for<'u> T: 'u, diff --git a/tests/ui/transmutability/references/reject_lifetime_extension.stderr b/tests/ui/transmutability/references/reject_lifetime_extension.stderr index 459e9a02aaa6e..b97029841453f 100644 --- a/tests/ui/transmutability/references/reject_lifetime_extension.stderr +++ b/tests/ui/transmutability/references/reject_lifetime_extension.stderr @@ -67,7 +67,7 @@ LL | unsafe { extend_hrtb(src) } | `src` escapes the function body here | argument requires that `'a` must outlive `'static` | -note: due to current limitations in the borrow checker, this implies a `'static` lifetime +note: due to a current limitation of the type system, this implies a `'static` lifetime --> $DIR/reject_lifetime_extension.rs:85:9 | LL | for<'b> &'b u8: TransmuteFrom<&'a u8>, From c64c6d85e12d227869014c42abde50aaf935bc87 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Aug 2025 22:34:35 +1000 Subject: [PATCH 10/37] Use `LLVMSetTailCallKind` --- compiler/rustc_codegen_llvm/src/builder.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 ++- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 26 ------------------- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 917d07e3c61bf..2983927ca1c83 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1453,7 +1453,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { instance: Option>, ) { let call = self.call(llty, fn_attrs, Some(fn_abi), llfn, args, funclet, instance); - llvm::LLVMRustSetTailCallKind(call, llvm::TailCallKind::MustTail); + llvm::LLVMSetTailCallKind(call, llvm::TailCallKind::MustTail); match &fn_abi.ret.mode { PassMode::Ignore | PassMode::Indirect { .. } => self.ret_void(), diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ad3c3d5932eef..439626263e9ca 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -97,6 +97,7 @@ pub(crate) enum ModuleFlagMergeBehavior { // Consts for the LLVM CallConv type, pre-cast to usize. +/// Must match the layout of `LLVMTailCallKind`. #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] #[allow(dead_code)] @@ -1197,7 +1198,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); - pub(crate) safe fn LLVMRustSetTailCallKind(CallInst: &Value, Kind: TailCallKind); + pub(crate) safe fn LLVMSetTailCallKind(CallInst: &Value, kind: TailCallKind); // Operations on attributes pub(crate) fn LLVMCreateStringAttribute( diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index cd4f80f808c65..7cc50d00a63ca 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1993,29 +1993,3 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) { MD.NoHWAddress = true; GV.setSanitizerMetadata(MD); } - -enum class LLVMRustTailCallKind { - None = 0, - Tail = 1, - MustTail = 2, - NoTail = 3 -}; - -extern "C" void LLVMRustSetTailCallKind(LLVMValueRef Call, - LLVMRustTailCallKind Kind) { - CallInst *CI = unwrap(Call); - switch (Kind) { - case LLVMRustTailCallKind::None: - CI->setTailCallKind(CallInst::TCK_None); - break; - case LLVMRustTailCallKind::Tail: - CI->setTailCallKind(CallInst::TCK_Tail); - break; - case LLVMRustTailCallKind::MustTail: - CI->setTailCallKind(CallInst::TCK_MustTail); - break; - case LLVMRustTailCallKind::NoTail: - CI->setTailCallKind(CallInst::TCK_NoTail); - break; - } -} From 51bccdd1ab0802dd5a55bd06e956c8d547bdec2d Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sun, 10 Aug 2025 09:44:39 +0200 Subject: [PATCH 11/37] Port `#[custom_mir(..)]` to the new attribute system --- .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/prototype.rs | 140 ++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 + compiler/rustc_errors/src/diagnostic_impls.rs | 23 +++ .../rustc_hir/src/attrs/data_structures.rs | 19 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_middle/src/mir/mod.rs | 42 ------ .../rustc_mir_build/src/builder/custom/mod.rs | 65 ++++---- compiler/rustc_mir_build/src/builder/mod.rs | 9 +- .../rustc_mir_build/src/check_unsafety.rs | 5 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 10 +- compiler/rustc_passes/messages.ftl | 10 ++ compiler/rustc_passes/src/check_attr.rs | 51 ++++++- compiler/rustc_passes/src/errors.rs | 23 +++ compiler/rustc_span/src/symbol.rs | 8 + 15 files changed, 318 insertions(+), 91 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/prototype.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index ed5d1d92b8caf..3d6e26a24b8e4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -43,6 +43,7 @@ pub(crate) mod no_implicit_prelude; pub(crate) mod non_exhaustive; pub(crate) mod path; pub(crate) mod proc_macro_attrs; +pub(crate) mod prototype; pub(crate) mod repr; pub(crate) mod rustc_internal; pub(crate) mod semantics; diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs new file mode 100644 index 0000000000000..fb1e47298b4cc --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -0,0 +1,140 @@ +//! Attributes that are only used on function prototypes. + +use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; +use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase}; +use rustc_span::{Span, Symbol, sym}; + +use super::{AttributeOrder, OnDuplicate}; +use crate::attributes::SingleAttributeParser; +use crate::context::{AcceptContext, AllowedTargets, MaybeWarn, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct CustomMirParser; + +impl SingleAttributeParser for CustomMirParser { + const PATH: &[rustc_span::Symbol] = &[sym::custom_mir]; + + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[MaybeWarn::Allow(Target::Fn)]); + + const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span); + return None; + }; + + let mut dialect = None; + let mut phase = None; + let mut failed = false; + + for item in list.mixed() { + let Some(meta_item) = item.meta_item() else { + cx.expected_name_value(item.span(), None); + failed = true; + break; + }; + + if let Some(arg) = meta_item.word_is(sym::dialect) { + extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed); + } else if let Some(arg) = meta_item.word_is(sym::phase) { + extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed); + } else if let Some(word) = meta_item.path().word() { + let word = word.to_string(); + cx.unknown_key(meta_item.span(), word, &["dialect", "phase"]); + failed = true; + } else { + cx.expected_name_value(meta_item.span(), None); + failed = true; + }; + } + + let dialect = parse_dialect(cx, dialect, &mut failed); + let phase = parse_phase(cx, phase, &mut failed); + + if failed { + return None; + } + + Some(AttributeKind::CustomMir(dialect, phase, cx.attr_span)) + } +} + +fn extract_value( + cx: &mut AcceptContext<'_, '_, S>, + key: Symbol, + arg: &ArgParser<'_>, + span: Span, + out_val: &mut Option<(Symbol, Span)>, + failed: &mut bool, +) { + if out_val.is_some() { + cx.duplicate_key(span, key); + *failed = true; + return; + } + + let Some(val) = arg.name_value() else { + cx.expected_single_argument(arg.span().unwrap_or(span)); + *failed = true; + return; + }; + + let Some(value_sym) = val.value_as_str() else { + cx.expected_string_literal(val.value_span, Some(val.value_as_lit())); + *failed = true; + return; + }; + + *out_val = Some((value_sym, val.value_span)); +} + +fn parse_dialect( + cx: &mut AcceptContext<'_, '_, S>, + dialect: Option<(Symbol, Span)>, + failed: &mut bool, +) -> Option<(MirDialect, Span)> { + let (dialect, span) = dialect?; + + let dialect = match dialect { + sym::analysis => MirDialect::Analysis, + sym::built => MirDialect::Built, + sym::runtime => MirDialect::Runtime, + + _ => { + cx.expected_specific_argument(span, vec!["analysis", "built", "runtime"]); + *failed = true; + return None; + } + }; + + Some((dialect, span)) +} + +fn parse_phase( + cx: &mut AcceptContext<'_, '_, S>, + phase: Option<(Symbol, Span)>, + failed: &mut bool, +) -> Option<(MirPhase, Span)> { + let (phase, span) = phase?; + + let phase = match phase { + sym::initial => MirPhase::Initial, + sym::post_cleanup => MirPhase::PostCleanup, + sym::optimized => MirPhase::Optimized, + + _ => { + cx.expected_specific_argument(span, vec!["initial", "post-cleanup", "optimized"]); + *failed = true; + return None; + } + }; + + Some((phase, span)) +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index bebe3350c4e0d..d1d1ea43b2f29 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -46,6 +46,7 @@ use crate::attributes::path::PathParser as PathAttributeParser; use crate::attributes::proc_macro_attrs::{ ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser, }; +use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, @@ -167,6 +168,7 @@ attribute_parsers!( // tidy-alphabetical-start Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index eca5806fac520..698b6b8d50404 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -9,6 +9,7 @@ use rustc_abi::TargetDataLayoutErrors; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast_pretty::pprust; use rustc_hir::RustcVersion; +use rustc_hir::attrs::{MirDialect, MirPhase}; use rustc_macros::Subdiagnostic; use rustc_span::edition::Edition; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol}; @@ -312,6 +313,28 @@ impl IntoDiagArg for ExprPrecedence { } } +impl IntoDiagArg for MirDialect { + fn into_diag_arg(self, _path: &mut Option) -> DiagArgValue { + let arg = match self { + MirDialect::Analysis => "analysis", + MirDialect::Built => "built", + MirDialect::Runtime => "runtime", + }; + DiagArgValue::Str(Cow::Borrowed(arg)) + } +} + +impl IntoDiagArg for MirPhase { + fn into_diag_arg(self, _path: &mut Option) -> DiagArgValue { + let arg = match self { + MirPhase::Initial => "initial", + MirPhase::PostCleanup => "post-cleanup", + MirPhase::Optimized => "optimized", + }; + DiagArgValue::Str(Cow::Borrowed(arg)) + } +} + #[derive(Clone)] pub struct DiagSymbolList(Vec); diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 510fc83297829..31715955ed341 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -205,6 +205,22 @@ pub enum Linkage { WeakODR, } +#[derive(Clone, Copy, Decodable, Debug, Encodable, PartialEq)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum MirDialect { + Analysis, + Built, + Runtime, +} + +#[derive(Clone, Copy, Decodable, Debug, Encodable, PartialEq)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum MirPhase { + Initial, + PostCleanup, + Optimized, +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -324,6 +340,9 @@ pub enum AttributeKind { /// Represents `#[coverage(..)]`. Coverage(Span, CoverageAttrKind), + /// Represents `#[custom_mir]`. + CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span), + ///Represents `#[rustc_deny_explicit_impl]`. DenyExplicitImpl(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 84a975523f2c8..defabdccc023a 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -31,6 +31,7 @@ impl AttributeKind { ConstTrait(..) => No, Coroutine(..) => No, Coverage(..) => No, + CustomMir(_, _, _) => Yes, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, DoNotImplementViaObject(..) => No, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c55c7fc6002c7..c977e5329c292 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -115,48 +115,6 @@ impl MirPhase { MirPhase::Runtime(runtime_phase) => (3, 1 + runtime_phase as usize), } } - - /// Parses a `MirPhase` from a pair of strings. Panics if this isn't possible for any reason. - pub fn parse(dialect: String, phase: Option) -> Self { - match &*dialect.to_ascii_lowercase() { - "built" => { - assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR"); - MirPhase::Built - } - "analysis" => Self::Analysis(AnalysisPhase::parse(phase)), - "runtime" => Self::Runtime(RuntimePhase::parse(phase)), - _ => bug!("Unknown MIR dialect: '{}'", dialect), - } - } -} - -impl AnalysisPhase { - pub fn parse(phase: Option) -> Self { - let Some(phase) = phase else { - return Self::Initial; - }; - - match &*phase.to_ascii_lowercase() { - "initial" => Self::Initial, - "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup, - _ => bug!("Unknown analysis phase: '{}'", phase), - } - } -} - -impl RuntimePhase { - pub fn parse(phase: Option) -> Self { - let Some(phase) = phase else { - return Self::Initial; - }; - - match &*phase.to_ascii_lowercase() { - "initial" => Self::Initial, - "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup, - "optimized" => Self::Optimized, - _ => bug!("Unknown runtime phase: '{}'", phase), - } - } } /// Where a specific `mir::Body` comes from. diff --git a/compiler/rustc_mir_build/src/builder/custom/mod.rs b/compiler/rustc_mir_build/src/builder/custom/mod.rs index 902a6e7f115be..792ad6d782cf3 100644 --- a/compiler/rustc_mir_build/src/builder/custom/mod.rs +++ b/compiler/rustc_mir_build/src/builder/custom/mod.rs @@ -19,10 +19,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{Attribute, HirId}; +use rustc_hir::{HirId, attrs}; use rustc_index::{IndexSlice, IndexVec}; +use rustc_middle::bug; use rustc_middle::mir::*; -use rustc_middle::span_bug; use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; @@ -39,7 +39,8 @@ pub(super) fn build_custom_mir<'tcx>( return_ty: Ty<'tcx>, return_ty_span: Span, span: Span, - attr: &Attribute, + dialect: Option, + phase: Option, ) -> Body<'tcx> { let mut body = Body { basic_blocks: BasicBlocks::new(IndexVec::new()), @@ -72,7 +73,7 @@ pub(super) fn build_custom_mir<'tcx>( inlined_parent_scope: None, local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }), }); - body.injection_phase = Some(parse_attribute(attr)); + body.injection_phase = Some(parse_attribute(dialect, phase)); let mut pctxt = ParseCtxt { tcx, @@ -98,40 +99,38 @@ pub(super) fn build_custom_mir<'tcx>( body } -fn parse_attribute(attr: &Attribute) -> MirPhase { - let meta_items = attr.meta_item_list().unwrap(); - let mut dialect: Option = None; - let mut phase: Option = None; - - // Not handling errors properly for this internal attribute; will just abort on errors. - for nested in meta_items { - let name = nested.name().unwrap(); - let value = nested.value_str().unwrap().as_str().to_string(); - match name.as_str() { - "dialect" => { - assert!(dialect.is_none()); - dialect = Some(value); - } - "phase" => { - assert!(phase.is_none()); - phase = Some(value); - } - other => { - span_bug!( - nested.span(), - "Unexpected key while parsing custom_mir attribute: '{}'", - other - ); - } - } - } - +/// Turns the arguments passed to `#[custom_mir(..)]` into a proper +/// [`MirPhase`]. Panics if this isn't possible for any reason. +fn parse_attribute(dialect: Option, phase: Option) -> MirPhase { let Some(dialect) = dialect else { + // Caught during attribute checking. assert!(phase.is_none()); return MirPhase::Built; }; - MirPhase::parse(dialect, phase) + match dialect { + attrs::MirDialect::Built => { + // Caught during attribute checking. + assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR"); + MirPhase::Built + } + attrs::MirDialect::Analysis => match phase { + None | Some(attrs::MirPhase::Initial) => MirPhase::Analysis(AnalysisPhase::Initial), + + Some(attrs::MirPhase::PostCleanup) => MirPhase::Analysis(AnalysisPhase::PostCleanup), + + Some(attrs::MirPhase::Optimized) => { + // Caught during attribute checking. + bug!("`optimized` dialect is not compatible with the `analysis` dialect") + } + }, + + attrs::MirDialect::Runtime => match phase { + None | Some(attrs::MirPhase::Initial) => MirPhase::Runtime(RuntimePhase::Initial), + Some(attrs::MirPhase::PostCleanup) => MirPhase::Runtime(RuntimePhase::PostCleanup), + Some(attrs::MirPhase::Optimized) => MirPhase::Runtime(RuntimePhase::Optimized), + }, + } } struct ParseCtxt<'a, 'tcx> { diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 855cd2f3bc0a6..9570760f94319 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -11,9 +11,10 @@ use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_errors::ErrorGuaranteed; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId, ItemLocalId, Node}; +use rustc_hir::{self as hir, BindingMode, ByRef, HirId, ItemLocalId, Node, find_attr}; use rustc_index::bit_set::GrowableBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -479,8 +480,7 @@ fn construct_fn<'tcx>( ty => span_bug!(span_with_body, "unexpected type of body: {ty:?}"), }; - if let Some(custom_mir_attr) = - tcx.hir_attrs(fn_id).iter().find(|attr| attr.has_name(sym::custom_mir)) + if let Some((dialect, phase)) = find_attr!(tcx.hir_attrs(fn_id), AttributeKind::CustomMir(dialect, phase, _) => (dialect, phase)) { return custom::build_custom_mir( tcx, @@ -492,7 +492,8 @@ fn construct_fn<'tcx>( return_ty, return_ty_span, span_with_body, - custom_mir_attr, + dialect.as_ref().map(|(d, _)| *d), + phase.as_ref().map(|(p, _)| *p), ); } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0b6b36640e92b..cdab785e84263 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -5,8 +5,9 @@ use std::ops::Bound; use rustc_ast::AsmMacro; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::DiagArgValue; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability}; +use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::mir::BorrowKind; use rustc_middle::span_bug; @@ -1157,7 +1158,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { // Closures and inline consts are handled by their owner, if it has a body assert!(!tcx.is_typeck_child(def.to_def_id())); // Also, don't safety check custom MIR - if tcx.has_attr(def, sym::custom_mir) { + if find_attr!(tcx.get_all_attrs(def), AttributeKind::CustomMir(..) => ()).is_some() { return; } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 24d4136c64237..9657c4dc839d6 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -4,11 +4,11 @@ use rustc_data_structures::steal::Steal; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_hir::HirId; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; +use rustc_hir::{self as hir, HirId, find_attr}; use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::thir::*; @@ -111,10 +111,8 @@ impl<'tcx> ThirBuildCx<'tcx> { typeck_results, rvalue_scopes: &typeck_results.rvalue_scopes, body_owner: def.to_def_id(), - apply_adjustments: tcx - .hir_attrs(hir_id) - .iter() - .all(|attr| !attr.has_name(rustc_span::sym::custom_mir)), + apply_adjustments: + !find_attr!(tcx.hir_attrs(hir_id), AttributeKind::CustomMir(..) => ()).is_some(), } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 7481b0ea96018..f7a5ba8194b11 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -74,6 +74,16 @@ passes_const_stable_not_stable = attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` .label = attribute specified here +passes_custom_mir_incompatible_dialect_and_phase = + The {$dialect} dialect is not compatible with the {$phase} phase + .dialect_span = this dialect... + .phase_span = ... is not compatible with this phase + +passes_custom_mir_phase_requires_dialect = + `dialect` key required + .phase_span = `phase` argument requires a `dialect` argument + + passes_dead_codes = { $multiple -> *[true] multiple {$descr}s are diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0e28c51e981f8..3c329d2070089 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -18,7 +18,7 @@ use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, }; -use rustc_hir::attrs::{AttributeKind, InlineAttr, ReprAttr}; +use rustc_hir::attrs::{AttributeKind, InlineAttr, MirDialect, MirPhase, ReprAttr}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; @@ -197,6 +197,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::MustUse { span, .. }) => { self.check_must_use(hir_id, *span, target) } + &Attribute::Parsed(AttributeKind::CustomMir(dialect, phase, attr_span)) => { + self.check_custom_mir(dialect, phase, attr_span) + } Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -248,7 +251,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::Coroutine(..) | AttributeKind::Linkage(..), ) => { /* do nothing */ } - Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -331,8 +333,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::panic_handler | sym::lang | sym::needs_allocator - | sym::default_lib_allocator - | sym::custom_mir, + | sym::default_lib_allocator, .. ] => {} [name, rest@..] => { @@ -2113,6 +2114,48 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span }); }; } + + fn check_custom_mir( + &self, + dialect: Option<(MirDialect, Span)>, + phase: Option<(MirPhase, Span)>, + attr_span: Span, + ) { + let Some((dialect, dialect_span)) = dialect else { + if let Some((_, phase_span)) = phase { + self.dcx() + .emit_err(errors::CustomMirPhaseRequiresDialect { attr_span, phase_span }); + } + return; + }; + + match dialect { + MirDialect::Analysis => { + if let Some((MirPhase::Optimized, phase_span)) = phase { + self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase { + dialect, + phase: MirPhase::Optimized, + attr_span, + dialect_span, + phase_span, + }); + } + } + + MirDialect::Built => { + if let Some((phase, phase_span)) = phase { + self.dcx().emit_err(errors::CustomMirIncompatibleDialectAndPhase { + dialect, + phase, + attr_span, + dialect_span, + phase_span, + }); + } + } + MirDialect::Runtime => {} + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c5d5155d0e5a5..f8ecf10714a47 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -7,6 +7,7 @@ use rustc_errors::{ MultiSpan, Subdiagnostic, }; use rustc_hir::Target; +use rustc_hir::attrs::{MirDialect, MirPhase}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{MainDefinition, Ty}; use rustc_span::{DUMMY_SP, Span, Symbol}; @@ -1570,3 +1571,25 @@ pub(crate) struct ReprAlignShouldBeAlign { pub span: Span, pub item: &'static str, } + +#[derive(Diagnostic)] +#[diag(passes_custom_mir_phase_requires_dialect)] +pub(crate) struct CustomMirPhaseRequiresDialect { + #[primary_span] + pub attr_span: Span, + #[label] + pub phase_span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_custom_mir_incompatible_dialect_and_phase)] +pub(crate) struct CustomMirIncompatibleDialectAndPhase { + pub dialect: MirDialect, + pub phase: MirPhase, + #[primary_span] + pub attr_span: Span, + #[label] + pub dialect_span: Span, + #[label] + pub phase_span: Span, +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 416ce27367e5e..12bb216b8d821 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -446,6 +446,7 @@ symbols! { altivec, alu32, always, + analysis, and, and_then, anon, @@ -587,6 +588,7 @@ symbols! { btreemap_contains_key, btreemap_insert, btreeset_iter, + built, builtin_syntax, c, c_dash_variadic, @@ -851,6 +853,7 @@ symbols! { destructuring_assignment, diagnostic, diagnostic_namespace, + dialect, direct, discriminant_kind, discriminant_type, @@ -1207,6 +1210,7 @@ symbols! { infer_static_outlives_requirements, inherent_associated_types, inherit, + initial, inlateout, inline, inline_const, @@ -1542,6 +1546,7 @@ symbols! { opt_out_copy, optimize, optimize_attribute, + optimized, optin_builtin_traits, option, option_env, @@ -1623,6 +1628,7 @@ symbols! { pattern_types, permissions_from_mode, phantom_data, + phase, pic, pie, pin, @@ -1639,6 +1645,7 @@ symbols! { poll, poll_next, position, + post_cleanup: "post-cleanup", post_dash_lto: "post-lto", postfix_match, powerpc_target_feature, @@ -1802,6 +1809,7 @@ symbols! { roundf128, rt, rtm_target_feature, + runtime, rust, rust_2015, rust_2018, From 4d62bf1634aad793631517559fe4d9e3e072a2bd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:21:18 +0000 Subject: [PATCH 12/37] All weak lang items have an explicit link name and vice versa --- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a36a772bc9719..7fa3719838779 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -6,7 +6,6 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr}; use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, UsedBy}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, @@ -520,14 +519,12 @@ fn handle_lang_items( // strippable by the linker. // // Additionally weak lang items have predetermined symbol names. - if let Some(lang_item) = lang_item { - if WEAK_LANG_ITEMS.contains(&lang_item) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; - } - if let Some(link_name) = lang_item.link_name() { - codegen_fn_attrs.export_name = Some(link_name); - codegen_fn_attrs.link_name = Some(link_name); - } + if let Some(lang_item) = lang_item + && let Some(link_name) = lang_item.link_name() + { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; + codegen_fn_attrs.export_name = Some(link_name); + codegen_fn_attrs.link_name = Some(link_name); } // error when using no_mangle on a lang item item From f3ef465ffb5cd3da61176ac67e7051eb55b62095 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:27:29 +0000 Subject: [PATCH 13/37] Combining no_mangle and rustc_std_internal_symbol is not allowed --- compiler/rustc_symbol_mangling/src/lib.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index f3c96f641902e..96a501fb0ea5e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -193,13 +193,12 @@ fn compute_symbol_name<'tcx>( // defining crate. // Weak lang items automatically get #[rustc_std_internal_symbol] // applied by the code computing the CodegenFnAttrs. - // We are mangling all #[rustc_std_internal_symbol] items that don't - // also have #[no_mangle] as a combination of the rustc version and the - // unmangled linkage name. This is to ensure that if we link against a - // staticlib compiled by a different rustc version, we don't get symbol - // conflicts or even UB due to a different implementation/ABI. Rust - // staticlibs currently export all symbols, including those that are - // hidden in cdylibs. + // We are mangling all #[rustc_std_internal_symbol] items as a + // combination of the rustc version and the unmangled linkage name. + // This is to ensure that if we link against a staticlib compiled by a + // different rustc version, we don't get symbol conflicts or even UB + // due to a different implementation/ABI. Rust staticlibs currently + // export all symbols, including those that are hidden in cdylibs. // We are using the v0 symbol mangling scheme here as we need to be // consistent across all crates and in some contexts the legacy symbol // mangling scheme can't be used. For example both the GCC backend and @@ -211,11 +210,7 @@ fn compute_symbol_name<'tcx>( if let Some(name) = attrs.export_name { name } else { tcx.item_name(def_id) } }; - if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - return name.to_string(); - } else { return v0::mangle_internal_symbol(tcx, name.as_str()); - } } let wasm_import_module_exception_force_mangling = { From e193b5342b170f9e3cc6e7ee3bd863652f1244a2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Aug 2025 22:51:10 +1000 Subject: [PATCH 14/37] Use `LLVMGetTypeKind` --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 16 +++--- compiler/rustc_codegen_llvm/src/type_.rs | 2 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 54 ------------------- 3 files changed, 11 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 439626263e9ca..8265b0114ce95 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -333,10 +333,15 @@ impl RealPredicate { } } -/// LLVMTypeKind -#[derive(Copy, Clone, PartialEq, Debug)] +/// Must match the layout of `LLVMTypeKind`. +/// +/// Use [`RawEnum`] for values of `LLVMTypeKind` returned from LLVM, +/// to avoid risk of UB if LLVM adds new enum values. +/// +/// All of LLVM's variants should be declared here, even if no Rust-side code refers +/// to them, because unknown variants will cause [`RawEnum::to_rust`] to panic. +#[derive(Copy, Clone, PartialEq, Debug, TryFromU32)] #[repr(C)] -#[expect(dead_code, reason = "Some variants are unused, but are kept to match LLVM-C")] pub(crate) enum TypeKind { Void = 0, Half = 1, @@ -1047,6 +1052,8 @@ unsafe extern "C" { CanThrow: llvm::Bool, ) -> &'ll Value; + pub(crate) safe fn LLVMGetTypeKind(Ty: &Type) -> RawEnum; + // Operations on integer types pub(crate) fn LLVMInt1TypeInContext(C: &Context) -> &Type; pub(crate) fn LLVMInt8TypeInContext(C: &Context) -> &Type; @@ -1842,9 +1849,6 @@ unsafe extern "C" { // Create and destroy contexts. pub(crate) fn LLVMRustContextCreate(shouldDiscardNames: bool) -> &'static mut Context; - /// See llvm::LLVMTypeKind::getTypeID. - pub(crate) fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind; - // Operations on all values pub(crate) fn LLVMRustGlobalAddMetadata<'a>( Val: &'a Value, diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 893655031388c..f02d16baf94e7 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -204,7 +204,7 @@ impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { } fn type_kind(&self, ty: &'ll Type) -> TypeKind { - unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() } + llvm::LLVMGetTypeKind(ty).to_rust().to_generic() } fn type_ptr(&self) -> &'ll Type { diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 7cc50d00a63ca..e4fe1fc2e429f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1460,60 +1460,6 @@ LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef DI) { return toRust((DiagnosticKind)unwrap(DI)->getKind()); } -// This is kept distinct from LLVMGetTypeKind, because when -// a new type kind is added, the Rust-side enum must be -// updated or UB will result. -extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { - switch (unwrap(Ty)->getTypeID()) { - case Type::VoidTyID: - return LLVMVoidTypeKind; - case Type::HalfTyID: - return LLVMHalfTypeKind; - case Type::FloatTyID: - return LLVMFloatTypeKind; - case Type::DoubleTyID: - return LLVMDoubleTypeKind; - case Type::X86_FP80TyID: - return LLVMX86_FP80TypeKind; - case Type::FP128TyID: - return LLVMFP128TypeKind; - case Type::PPC_FP128TyID: - return LLVMPPC_FP128TypeKind; - case Type::LabelTyID: - return LLVMLabelTypeKind; - case Type::MetadataTyID: - return LLVMMetadataTypeKind; - case Type::IntegerTyID: - return LLVMIntegerTypeKind; - case Type::FunctionTyID: - return LLVMFunctionTypeKind; - case Type::StructTyID: - return LLVMStructTypeKind; - case Type::ArrayTyID: - return LLVMArrayTypeKind; - case Type::PointerTyID: - return LLVMPointerTypeKind; - case Type::FixedVectorTyID: - return LLVMVectorTypeKind; - case Type::TokenTyID: - return LLVMTokenTypeKind; - case Type::ScalableVectorTyID: - return LLVMScalableVectorTypeKind; - case Type::BFloatTyID: - return LLVMBFloatTypeKind; - case Type::X86_AMXTyID: - return LLVMX86_AMXTypeKind; - default: { - std::string error; - auto stream = llvm::raw_string_ostream(error); - stream << "Rust does not support the TypeID: " << unwrap(Ty)->getTypeID() - << " for the type: " << *unwrap(Ty); - stream.flush(); - report_fatal_error(error.c_str()); - } - } -} - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI, From 460519a7f509756d07dcf187e671a11fde7b3fca Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:37:24 +0000 Subject: [PATCH 15/37] Merge link_name and export_name --- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- compiler/rustc_codegen_ssa/src/base.rs | 2 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 17 ++++++---- compiler/rustc_lint/src/foreign_modules.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 2 +- .../src/middle/codegen_fn_attrs.rs | 17 ++++------ compiler/rustc_symbol_mangling/src/lib.rs | 33 +++++++------------ src/tools/miri/src/shims/foreign_items.rs | 2 +- 8 files changed, 33 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index c548f4675834f..35cc013b8527d 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -513,7 +513,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", module)); let name = - codegen_fn_attrs.link_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id())); + codegen_fn_attrs.symbol_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id())); let name = name.as_str(); to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name)); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b4556ced0b3fb..883212cd07a90 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -857,7 +857,7 @@ pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( instance: Instance<'tcx>, ) -> bool { fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name { + if let Some(name) = tcx.codegen_fn_attrs(def_id).symbol_name { name.as_str().starts_with("llvm.") } else { false diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 7fa3719838779..136b8591f83d0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -189,7 +189,7 @@ fn process_builtin_attrs( match p { AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, AttributeKind::ExportName { name, .. } => { - codegen_fn_attrs.export_name = Some(*name) + codegen_fn_attrs.symbol_name = Some(*name) } AttributeKind::Inline(inline, span) => { codegen_fn_attrs.inline = *inline; @@ -197,7 +197,13 @@ fn process_builtin_attrs( } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), - AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), + AttributeKind::LinkName { name, .. } => { + // FIXME Remove check for foreign functions once #[link_name] on non-foreign + // functions is a hard error + if tcx.is_foreign_item(did) { + codegen_fn_attrs.symbol_name = Some(*name); + } + } AttributeKind::LinkOrdinal { ordinal, span } => { codegen_fn_attrs.link_ordinal = Some(*ordinal); interesting_spans.link_ordinal = Some(*span); @@ -417,7 +423,7 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way // both for exports and imports through foreign items. This is handled further, // during symbol mangling logic. - } else if codegen_fn_attrs.link_name.is_some() { + } else if codegen_fn_attrs.symbol_name.is_some() { // * This can be overridden with the `#[link_name]` attribute } else { // NOTE: there's one more exception that we cannot apply here. On wasm, @@ -472,7 +478,7 @@ fn check_result( } // error when specifying link_name together with link_ordinal - if let Some(_) = codegen_fn_attrs.link_name + if let Some(_) = codegen_fn_attrs.symbol_name && let Some(_) = codegen_fn_attrs.link_ordinal { let msg = "cannot use `#[link_name]` with `#[link_ordinal]`"; @@ -523,8 +529,7 @@ fn handle_lang_items( && let Some(link_name) = lang_item.link_name() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; - codegen_fn_attrs.export_name = Some(link_name); - codegen_fn_attrs.link_name = Some(link_name); + codegen_fn_attrs.symbol_name = Some(link_name); } // error when using no_mangle on a lang item item diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 759e6c927b828..3267e70f1de26 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -179,7 +179,7 @@ impl ClashingExternDeclarations { /// symbol's name. fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName { if let Some((overridden_link_name, overridden_link_name_span)) = - tcx.codegen_fn_attrs(fi).link_name.map(|overridden_link_name| { + tcx.codegen_fn_attrs(fi).symbol_name.map(|overridden_link_name| { // FIXME: Instead of searching through the attributes again to get span // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 958e314efabb4..63f1b51df1c6b 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -701,7 +701,7 @@ impl<'tcx> Collector<'tcx> { .link_ordinal .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord))); - let name = codegen_fn_attrs.link_name.unwrap_or_else(|| self.tcx.item_name(item)); + let name = codegen_fn_attrs.symbol_name.unwrap_or_else(|| self.tcx.item_name(item)); if self.tcx.sess.target.binary_format == BinaryFormat::Elf { let name = name.as_str(); diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 2852c4cbd34c7..b3a26f3b8eff0 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -36,14 +36,10 @@ pub struct CodegenFnAttrs { pub inline: InlineAttr, /// Parsed representation of the `#[optimize]` attribute pub optimize: OptimizeAttr, - /// The `#[export_name = "..."]` attribute, indicating a custom symbol a - /// function should be exported under - pub export_name: Option, - /// The `#[link_name = "..."]` attribute, indicating a custom symbol an - /// imported function should be imported as. Note that `export_name` - /// probably isn't set when this is set, this is for foreign items while - /// `#[export_name]` is for Rust-defined functions. - pub link_name: Option, + /// The name this function will be imported/exported under. This can be set + /// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute + /// depending on if this is a function definition or foreign function. + pub symbol_name: Option, /// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an /// imported function has in the dynamic library. Note that this must not /// be set when `link_name` is set. This is for foreign items with the @@ -170,8 +166,7 @@ impl CodegenFnAttrs { flags: CodegenFnAttrFlags::empty(), inline: InlineAttr::None, optimize: OptimizeAttr::Default, - export_name: None, - link_name: None, + symbol_name: None, link_ordinal: None, target_features: vec![], safe_target_features: false, @@ -200,7 +195,7 @@ impl CodegenFnAttrs { self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) - || self.export_name.is_some() + || self.symbol_name.is_some() || match self.linkage { // These are private, so make sure we don't try to consider // them external. diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 96a501fb0ea5e..d97ee95652530 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -204,13 +204,9 @@ fn compute_symbol_name<'tcx>( // mangling scheme can't be used. For example both the GCC backend and // Rust-for-Linux don't support some of the characters used by the // legacy symbol mangling scheme. - let name = if tcx.is_foreign_item(def_id) { - if let Some(name) = attrs.link_name { name } else { tcx.item_name(def_id) } - } else { - if let Some(name) = attrs.export_name { name } else { tcx.item_name(def_id) } - }; + let name = if let Some(name) = attrs.symbol_name { name } else { tcx.item_name(def_id) }; - return v0::mangle_internal_symbol(tcx, name.as_str()); + return v0::mangle_internal_symbol(tcx, name.as_str()); } let wasm_import_module_exception_force_mangling = { @@ -235,23 +231,16 @@ fn compute_symbol_name<'tcx>( && tcx.wasm_import_module_map(LOCAL_CRATE).contains_key(&def_id.into()) }; - if let Some(name) = attrs.link_name - && !wasm_import_module_exception_force_mangling - { - // Use provided name - return name.to_string(); - } - - if let Some(name) = attrs.export_name { - // Use provided name - return name.to_string(); - } + if !wasm_import_module_exception_force_mangling { + if let Some(name) = attrs.symbol_name { + // Use provided name + return name.to_string(); + } - if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) - && !wasm_import_module_exception_force_mangling - { - // Don't mangle - return tcx.item_name(def_id).to_string(); + if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + // Don't mangle + return tcx.item_name(def_id).to_string(); + } } // If we're dealing with an instance of a function that's inlined from diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 21545b680299c..23b1d0c4f6ecf 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(()); } // Skip over items without an explicitly defined symbol name. - if !(attrs.export_name.is_some() + if !(attrs.symbol_name.is_some() || attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)) { From f94a0d0ca406002e41d3b69aa5ec5a7f5a8e7fa6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:48:43 +0000 Subject: [PATCH 16/37] Remove unused feature gate --- compiler/rustc_builtin_macros/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 7bc448a9acb8b..66e9befa255b0 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -8,7 +8,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(autodiff)] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] From 1d00627966f6fd477ae6d7e855749c16cd00202b Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 15 Aug 2025 16:14:39 +0200 Subject: [PATCH 17/37] add static glibc to the nix dev shell this fixes `tests/ui/process/nofile-limit.rs` which fails to link on nixos for me without this change --- src/tools/nix-dev-shell/shell.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix index 0adbacf7e8d56..ad33b121f979a 100644 --- a/src/tools/nix-dev-shell/shell.nix +++ b/src/tools/nix-dev-shell/shell.nix @@ -14,6 +14,7 @@ pkgs.mkShell { packages = [ pkgs.git pkgs.nix + pkgs.glibc.static x # Get the runtime deps of the x wrapper ] ++ lists.flatten (attrsets.attrValues env); From ef3bb6fb0b7d7095f1a988835486daba4552ed89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 16:26:07 +0200 Subject: [PATCH 18/37] Do not strip binaries in bootstrap everytime if they are unchanged --- src/bootstrap/src/core/build_steps/compile.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d860cafa1c0fd..842393a10fe6b 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -12,6 +12,7 @@ use std::ffi::OsStr; use std::io::BufReader; use std::io::prelude::*; use std::path::{Path, PathBuf}; +use std::time::SystemTime; use std::{env, fs, str}; use serde_derive::Deserialize; @@ -2578,7 +2579,17 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) } let previous_mtime = t!(t!(path.metadata()).modified()); - command("strip").arg("--strip-debug").arg(path).run_capture(builder); + let stamp = BuildStamp::new(path.parent().unwrap()) + .with_prefix(path.file_name().unwrap().to_str().unwrap()) + .with_prefix("strip") + .add_stamp(previous_mtime.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos()); + + // Running strip can be relatively expensive (~1s on librustc_driver.so), so we don't rerun it + // if the file is unchanged. + if !stamp.is_up_to_date() { + command("strip").arg("--strip-debug").arg(path).run_capture(builder); + } + t!(stamp.write()); let file = t!(fs::File::open(path)); From 9fab380839c2ab1cede5a04e078267f1740a9939 Mon Sep 17 00:00:00 2001 From: Alan Urmancheev <108410815+alurm@users.noreply.github.com> Date: Sat, 16 Aug 2025 02:30:18 +0400 Subject: [PATCH 19/37] Fix typo in doc for library/std/src/fs.rs#set_permissions "privalage" -> "privilege" --- library/std/src/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index a220a3f56e9a8..d4a584f4d14ff 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3119,7 +3119,7 @@ pub fn read_dir>(path: P) -> io::Result { /// On UNIX-like systems, this function will update the permission bits /// of the file pointed to by the symlink. /// -/// Note that this behavior can lead to privalage escalation vulnerabilities, +/// Note that this behavior can lead to privilege escalation vulnerabilities, /// where the ability to create a symlink in one directory allows you to /// cause the permissions of another file or directory to be modified. /// From 5107ac92bbd6f9acd4adeef00ffeca02a4e73d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 17:13:21 +0200 Subject: [PATCH 20/37] Do not call `fs::remove_file` in `cp_link_filtered_recurse` The target is removed by `copy_link` too, so no need to duplicate the syscall. --- src/bootstrap/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 706a3cbb2109b..55e74f9e4d996 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1862,7 +1862,6 @@ impl Build { self.create_dir(&dst); self.cp_link_filtered_recurse(&path, &dst, &relative, filter); } else { - let _ = fs::remove_file(&dst); self.copy_link(&path, &dst, FileType::Regular); } } From cdea62dc445363e6030beae2019f5d123ba3f0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 17:49:08 +0200 Subject: [PATCH 21/37] Optimize `copy_src_dirs` --- src/bootstrap/src/core/build_steps/dist.rs | 81 +++++++++++----------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 414f4464d1edf..133e6f894afd8 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -916,6 +916,12 @@ fn copy_src_dirs( exclude_dirs: &[&str], dst_dir: &Path, ) { + // The src directories should be relative to `base`, we depend on them not being absolute + // paths below. + for src_dir in src_dirs { + assert!(Path::new(src_dir).is_relative()); + } + // Iterating, filtering and copying a large number of directories can be quite slow. // Avoid doing it in dry run (and thus also tests). if builder.config.dry_run() { @@ -923,6 +929,7 @@ fn copy_src_dirs( } fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool { + // The paths are relative, e.g. `llvm-project/...`. let spath = match path.to_str() { Some(path) => path, None => return false, @@ -930,65 +937,53 @@ fn copy_src_dirs( if spath.ends_with('~') || spath.ends_with(".pyc") { return false; } + // Normalize slashes + let spath = spath.replace("\\", "/"); - const LLVM_PROJECTS: &[&str] = &[ + static LLVM_PROJECTS: &[&str] = &[ "llvm-project/clang", - "llvm-project\\clang", "llvm-project/libunwind", - "llvm-project\\libunwind", "llvm-project/lld", - "llvm-project\\lld", "llvm-project/lldb", - "llvm-project\\lldb", "llvm-project/llvm", - "llvm-project\\llvm", "llvm-project/compiler-rt", - "llvm-project\\compiler-rt", "llvm-project/cmake", - "llvm-project\\cmake", "llvm-project/runtimes", - "llvm-project\\runtimes", "llvm-project/third-party", - "llvm-project\\third-party", ]; - if spath.contains("llvm-project") - && !spath.ends_with("llvm-project") - && !LLVM_PROJECTS.iter().any(|path| spath.contains(path)) - { - return false; - } + if spath.starts_with("llvm-project") && spath != "llvm-project" { + if !LLVM_PROJECTS.iter().any(|path| spath.starts_with(path)) { + return false; + } - // Keep only these third party libraries - const LLVM_THIRD_PARTY: &[&str] = - &["llvm-project/third-party/siphash", "llvm-project\\third-party\\siphash"]; - if (spath.starts_with("llvm-project/third-party") - || spath.starts_with("llvm-project\\third-party")) - && !(spath.ends_with("llvm-project/third-party") - || spath.ends_with("llvm-project\\third-party")) - && !LLVM_THIRD_PARTY.iter().any(|path| spath.contains(path)) - { - return false; - } + // Keep siphash third-party dependency + if spath.starts_with("llvm-project/third-party") + && spath != "llvm-project/third-party" + && !spath.starts_with("llvm-project/third-party/siphash") + { + return false; + } - const LLVM_TEST: &[&str] = &["llvm-project/llvm/test", "llvm-project\\llvm\\test"]; - if LLVM_TEST.iter().any(|path| spath.contains(path)) - && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s")) - { - return false; + if spath.starts_with("llvm-project/llvm/test") + && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s")) + { + return false; + } } // Cargo tests use some files like `.gitignore` that we would otherwise exclude. - const CARGO_TESTS: &[&str] = &["tools/cargo/tests", "tools\\cargo\\tests"]; - if CARGO_TESTS.iter().any(|path| spath.contains(path)) { + if spath.starts_with("tools/cargo/tests") { return true; } - let full_path = Path::new(dir).join(path); - if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) { - return false; + if !exclude_dirs.is_empty() { + let full_path = Path::new(dir).join(path); + if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) { + return false; + } } - let excludes = [ + static EXCLUDES: &[&str] = &[ "CVS", "RCS", "SCCS", @@ -1011,7 +1006,15 @@ fn copy_src_dirs( ".hgrags", "_darcs", ]; - !path.iter().map(|s| s.to_str().unwrap()).any(|s| excludes.contains(&s)) + + // We want to check if any component of `path` doesn't contain the strings in `EXCLUDES`. + // However, since we traverse directories top-down in `Builder::cp_link_filtered`, + // it is enough to always check only the last component: + // - If the path is a file, we will iterate to it and then check it's filename + // - If the path is a dir, if it's dir name contains an excluded string, we will not even + // recurse into it. + let last_component = path.iter().next_back().map(|s| s.to_str().unwrap()).unwrap(); + !EXCLUDES.contains(&last_component) } // Copy the directories using our filter From e8f90b12fcb51f00ba41a86ddd3f1d511d013514 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 16 Aug 2025 09:44:39 +0200 Subject: [PATCH 22/37] Don't show foreign types as an allowed target if the feature is not enabled --- compiler/rustc_attr_parsing/src/context.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index bebe3350c4e0d..a61ca70059fbf 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -1060,6 +1060,9 @@ pub(crate) fn allowed_targets_applied( if !features.stmt_expr_attributes() { allowed_targets.retain(|t| !matches!(t, Target::Expression | Target::Statement)); } + if !features.extern_types() { + allowed_targets.retain(|t| !matches!(t, Target::ForeignTy)); + } } // We define groups of "similar" targets. From a69ba29a0f94fe77249906d478a3ae91506fdfb7 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 16 Aug 2025 09:44:43 +0200 Subject: [PATCH 23/37] Fix deprecation attribute on foreign statics & types --- compiler/rustc_attr_parsing/src/attributes/deprecation.rs | 2 ++ tests/ui/deprecation/deprecation-sanity.rs | 5 +++++ tests/ui/deprecation/deprecation-sanity.stderr | 2 +- tests/ui/where-clauses/unsupported_attribute.stderr | 4 ++-- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 8101c91460f26..d3a61f3a6535d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -54,6 +54,8 @@ impl SingleAttributeParser for DeprecationParser { Allow(Target::TyAlias), Allow(Target::Use), Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + Allow(Target::ForeignTy), Allow(Target::Field), Allow(Target::Trait), Allow(Target::AssocTy), diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs index 9698a37602503..45ee91741e5a1 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -42,4 +42,9 @@ impl Default for X { } } +unsafe extern "C" { + #[deprecated] + static FOO: std::ffi::c_int; +} + fn main() { } diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 1d44215731df4..57af76d8f2492 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -177,7 +177,7 @@ LL | #[deprecated = "hello"] | ^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates = note: `#[deny(useless_deprecated)]` on by default error: aborting due to 10 previous errors diff --git a/tests/ui/where-clauses/unsupported_attribute.stderr b/tests/ui/where-clauses/unsupported_attribute.stderr index 411c895ed8736..cdd6e82b98d4d 100644 --- a/tests/ui/where-clauses/unsupported_attribute.stderr +++ b/tests/ui/where-clauses/unsupported_attribute.stderr @@ -64,7 +64,7 @@ error: `#[deprecated]` attribute cannot be used on where predicates LL | #[deprecated] T: Trait, | ^^^^^^^^^^^^^ | - = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates error: `#[deprecated]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:25:5 @@ -72,7 +72,7 @@ error: `#[deprecated]` attribute cannot be used on where predicates LL | #[deprecated] 'a: 'static, | ^^^^^^^^^^^^^ | - = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates error: `#[automatically_derived]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:26:5 From e906a59ebb5111d065d74c0127647dd380e25dc5 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 16 Aug 2025 11:41:51 +0200 Subject: [PATCH 24/37] Fix `unicode_data.rs` mention message --- triagebot.toml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 2f31a30019bce..e55f2abce7f10 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1003,11 +1003,12 @@ cc = ["@calebzulawski", "@programmerjake"] [mentions."library/core/src/unicode/unicode_data.rs"] message = """ -`library/core/src/unicode/unicode_data.rs` is generated by -`src/tools/unicode-table-generator` via `./x run -src/tools/unicode-table-generator`. If you want to modify `unicode_data.rs`, -please modify the tool then regenerate the library source file with the tool -instead of editing the library source file manually. +`library/core/src/unicode/unicode_data.rs` is generated by the \ +`src/tools/unicode-table-generator` tool. + +If you want to modify `unicode_data.rs`, please modify the tool then regenerate the library \ +source file via `./x run src/tools/unicode-table-generator` instead of editing \ +`unicode_data.rs` manually. """ [mentions."src/librustdoc/html/static"] From 34509759350225fcbd198d99738e6fdfcbdf7e17 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 16 Aug 2025 21:41:39 +0800 Subject: [PATCH 25/37] remove `should_render` in `PrintAttribute` derive --- compiler/rustc_macros/src/print_attribute.rs | 60 +++++++------------- 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs index 9023520c75043..0114e0dfde0db 100644 --- a/compiler/rustc_macros/src/print_attribute.rs +++ b/compiler/rustc_macros/src/print_attribute.rs @@ -4,7 +4,7 @@ use syn::spanned::Spanned; use syn::{Data, Fields, Ident}; use synstructure::Structure; -fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, TokenStream) { +fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream) { let string_name = name.to_string(); let mut disps = vec![quote! {let mut __printed_anything = false;}]; @@ -43,7 +43,6 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok #(#disps)* __p.word("}"); }, - quote! { true }, ) } Fields::Unnamed(fields_unnamed) => { @@ -76,10 +75,9 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok #(#disps)* __p.pclose(); }, - quote! { true }, ) } - Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }, quote! { true }), + Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }), } } @@ -89,51 +87,33 @@ pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream { }; // Must be applied to an enum type. - let (code, printed) = match &input.ast().data { + let code = match &input.ast().data { Data::Enum(e) => { - let (arms, printed) = e + let arms = e .variants .iter() .map(|x| { let ident = &x.ident; - let (pat, code, printed) = print_fields(ident, &x.fields); + let (pat, code) = print_fields(ident, &x.fields); - ( - quote! { - Self::#ident #pat => {#code} - }, - quote! { - Self::#ident #pat => {#printed} - }, - ) + quote! { + Self::#ident #pat => {#code} + } }) - .unzip::<_, _, Vec<_>, Vec<_>>(); + .collect::>(); - ( - quote! { - match self { - #(#arms)* - } - }, - quote! { - match self { - #(#printed)* - } - }, - ) + quote! { + match self { + #(#arms)* + } + } } Data::Struct(s) => { - let (pat, code, printed) = print_fields(&input.ast().ident, &s.fields); - ( - quote! { - let Self #pat = self; - #code - }, - quote! { - let Self #pat = self; - #printed - }, - ) + let (pat, code) = print_fields(&input.ast().ident, &s.fields); + quote! { + let Self #pat = self; + #code + } } Data::Union(u) => { return span_error(u.union_token.span(), "can't derive PrintAttribute on unions"); @@ -144,7 +124,7 @@ pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream { input.gen_impl(quote! { #[allow(unused)] gen impl PrintAttribute for @Self { - fn should_render(&self) -> bool { #printed } + fn should_render(&self) -> bool { true } fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code } } }) From e31fed054bc19845b04ee0be50c1254174e87ad0 Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 6 Aug 2025 17:21:25 -0500 Subject: [PATCH 26/37] run spellcheck as a tidy extra check in ci --- compiler/rustc_next_trait_solver/src/canonicalizer.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- library/std/src/sync/nonpoison/mutex.rs | 2 +- library/std/src/sync/poison/mutex.rs | 2 +- src/ci/docker/host-x86_64/tidy/Dockerfile | 2 +- src/librustdoc/html/static/js/main.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 1bc35e599c706..3e1f48610ffc0 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -27,7 +27,7 @@ enum CanonicalizeInputKind { ParamEnv, /// When canonicalizing predicates, we don't keep `'static`. If we're /// currently outside of the trait solver and canonicalize the root goal - /// during HIR typeck, we replace each occurance of a region with a + /// during HIR typeck, we replace each occurrence of a region with a /// unique region variable. See the comment on `InferCtxt::in_hir_typeck` /// for more details. Predicate { is_hir_typeck_root_goal: bool }, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5200f9340e115..679e663f88614 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4270,7 +4270,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if path.len() == 2 && let [segment] = prefix_path { - // Delay to check whether methond name is an associated function or not + // Delay to check whether method name is an associated function or not // ``` // let foo = Foo {}; // foo::bar(); // possibly suggest to foo.bar(); diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index b6861c78f001d..fd1e671d7a3d3 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -100,7 +100,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex, } -/// A [`MutexGuard`] is not `Send` to maximize platform portablity. +/// A [`MutexGuard`] is not `Send` to maximize platform portability. /// /// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to /// release mutex locks on the same thread they were acquired. diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 6205c4fa4ca4b..720c212c65cf7 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -279,7 +279,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { poison: poison::Guard, } -/// A [`MutexGuard`] is not `Send` to maximize platform portablity. +/// A [`MutexGuard`] is not `Send` to maximize platform portability. /// /// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to /// release mutex locks on the same thread they were acquired. diff --git a/src/ci/docker/host-x86_64/tidy/Dockerfile b/src/ci/docker/host-x86_64/tidy/Dockerfile index ee1ae5410ee81..c8558689d3ba9 100644 --- a/src/ci/docker/host-x86_64/tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/tidy/Dockerfile @@ -45,4 +45,4 @@ RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)' # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \ - src/tools/tidy tidyselftest --extra-checks=py,cpp,js + src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 8e3d07b3a1c28..21d154edf5d2a 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1529,7 +1529,7 @@ function preLoadCss(cssUrl) { ["⏎", "Go to active search result"], ["+", "Expand all sections"], ["-", "Collapse all sections"], - // for the sake of brevity, we don't say "inherint impl blocks", + // for the sake of brevity, we don't say "inherit impl blocks", // although that would be more correct, // since trait impl blocks are collapsed by - ["_", "Collapse all sections, including impl blocks"], From 6c1533901788a1e40fc4a9f9b712ad70d7c17a22 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 16 Aug 2025 16:21:23 +0000 Subject: [PATCH 27/37] Simplify decode_span. --- .../rustc_middle/src/query/on_disk_cache.rs | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index a7ac34428986e..546791135ba61 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -645,34 +645,29 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { let parent = Option::::decode(self); let tag: u8 = Decodable::decode(self); - if tag == TAG_PARTIAL_SPAN { - return Span::new(BytePos(0), BytePos(0), ctxt, parent); - } else if tag == TAG_RELATIVE_SPAN { - let dlo = u32::decode(self); - let dto = u32::decode(self); - - let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); - let span = Span::new( - enclosing.lo + BytePos::from_u32(dlo), - enclosing.lo + BytePos::from_u32(dto), - ctxt, - parent, - ); - - return span; - } else { - debug_assert_eq!(tag, TAG_FULL_SPAN); - } - - let file_lo_index = SourceFileIndex::decode(self); - let line_lo = usize::decode(self); - let col_lo = RelativeBytePos::decode(self); - let len = BytePos::decode(self); - - let file_lo = self.file_index_to_file(file_lo_index); - let lo = file_lo.lines()[line_lo - 1] + col_lo; - let lo = file_lo.absolute_position(lo); - let hi = lo + len; + let (lo, hi) = match tag { + TAG_PARTIAL_SPAN => (BytePos(0), BytePos(0)), + TAG_RELATIVE_SPAN => { + let dlo = u32::decode(self); + let dto = u32::decode(self); + + let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); + (enclosing.lo + BytePos::from_u32(dlo), enclosing.lo + BytePos::from_u32(dto)) + } + TAG_FULL_SPAN => { + let file_lo_index = SourceFileIndex::decode(self); + let line_lo = usize::decode(self); + let col_lo = RelativeBytePos::decode(self); + let len = BytePos::decode(self); + + let file_lo = self.file_index_to_file(file_lo_index); + let lo = file_lo.lines()[line_lo - 1] + col_lo; + let lo = file_lo.absolute_position(lo); + let hi = lo + len; + (lo, hi) + } + _ => unreachable!(), + }; Span::new(lo, hi, ctxt, parent) } From a84373085e184460c3cbaefaad0339723af4944e Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 16 Aug 2025 16:23:21 +0000 Subject: [PATCH 28/37] Simplify span_data_to_lines_and_cols. --- .../rustc_span/src/caching_source_map_view.rs | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index a887b50ec1ebe..41cfaa3ee34e5 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -123,27 +123,25 @@ impl<'sm> CachingSourceMapView<'sm> { if lo_cache_idx != -1 && hi_cache_idx != -1 { // Cache hit for span lo and hi. Check if they belong to the same file. - let result = { - let lo = &self.line_cache[lo_cache_idx as usize]; - let hi = &self.line_cache[hi_cache_idx as usize]; + let lo_file_index = self.line_cache[lo_cache_idx as usize].file_index; + let hi_file_index = self.line_cache[hi_cache_idx as usize].file_index; - if lo.file_index != hi.file_index { - return None; - } - - ( - lo.file.stable_id, - lo.line_number, - span_data.lo - lo.line.start, - hi.line_number, - span_data.hi - hi.line.start, - ) - }; + if lo_file_index != hi_file_index { + return None; + } self.line_cache[lo_cache_idx as usize].touch(self.time_stamp); self.line_cache[hi_cache_idx as usize].touch(self.time_stamp); - return Some(result); + let lo = &self.line_cache[lo_cache_idx as usize]; + let hi = &self.line_cache[hi_cache_idx as usize]; + return Some(( + lo.file.stable_id, + lo.line_number, + span_data.lo - lo.line.start, + hi.line_number, + span_data.hi - hi.line.start, + )); } // No cache hit or cache hit for only one of span lo and hi. From 1cb4fd7dd12be93465a55d56622c52002e3b050b Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 8 Aug 2025 13:18:53 -0500 Subject: [PATCH 29/37] tidy now installs typos-cli as-needed via cargo --- compiler/rustc_resolve/src/imports.rs | 6 +-- library/std/src/sys/mod.rs | 2 +- src/tools/tidy/src/extra_checks/mod.rs | 37 ++++----------- src/tools/tidy/src/lib.rs | 66 ++++++++++++++++++++++++++ src/tools/tidy/src/main.rs | 1 + 5 files changed, 80 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7c93fdb88ee44..2ecabb33763cc 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -866,7 +866,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } ImportKind::Glob { .. } => { // FIXME: Use mutable resolver directly as a hack, this should be an output of - // specualtive resolution. + // speculative resolution. self.get_mut_unchecked().resolve_glob_import(import); return 0; } @@ -903,7 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); // FIXME: Use mutable resolver directly as a hack, this should be an output of - // specualtive resolution. + // speculative resolution. this.get_mut_unchecked().define_binding_local( parent, target, @@ -917,7 +917,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if target.name != kw::Underscore { let key = BindingKey::new(target, ns); // FIXME: Use mutable resolver directly as a hack, this should be an output of - // specualtive resolution. + // speculative resolution. this.get_mut_unchecked().update_local_resolution( parent, key, diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 8ec0a0e33023f..6324c1a232af4 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -1,7 +1,7 @@ #![allow(unsafe_op_in_unsafe_fn)] /// The configure builtins provides runtime support compiler-builtin features -/// which require dynamic intialization to work as expected, e.g. aarch64 +/// which require dynamic initialization to work as expected, e.g. aarch64 /// outline-atomics. mod configure_builtins; diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index f90f716cd9501..604b5d1e37c70 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -41,7 +41,6 @@ const RUFF_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "ruff.toml const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"]; const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"]; -// this must be kept in sync with with .github/workflows/spellcheck.yml const SPELLCHECK_DIRS: &[&str] = &["compiler", "library", "src/bootstrap", "src/librustdoc"]; pub fn check( @@ -51,6 +50,7 @@ pub fn check( librustdoc_path: &Path, tools_path: &Path, npm: &Path, + cargo: &Path, bless: bool, extra_checks: Option<&str>, pos_args: &[String], @@ -63,6 +63,7 @@ pub fn check( librustdoc_path, tools_path, npm, + cargo, bless, extra_checks, pos_args, @@ -78,6 +79,7 @@ fn check_impl( librustdoc_path: &Path, tools_path: &Path, npm: &Path, + cargo: &Path, bless: bool, extra_checks: Option<&str>, pos_args: &[String], @@ -293,7 +295,7 @@ fn check_impl( } else { eprintln!("spellcheck files"); } - spellcheck_runner(&args)?; + spellcheck_runner(&outdir, &cargo, &args)?; } if js_lint || js_typecheck { @@ -576,33 +578,12 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } } -/// Check that spellchecker is installed then run it at the given path -fn spellcheck_runner(args: &[&str]) -> Result<(), Error> { - // sync version with .github/workflows/spellcheck.yml - let expected_version = "typos-cli 1.34.0"; - match Command::new("typos").arg("--version").output() { - Ok(o) => { - let stdout = String::from_utf8_lossy(&o.stdout); - if stdout.trim() != expected_version { - return Err(Error::Version { - program: "typos", - required: expected_version, - installed: stdout.trim().to_string(), - }); - } - } - Err(e) if e.kind() == io::ErrorKind::NotFound => { - return Err(Error::MissingReq( - "typos", - "spellcheck file checks", - // sync version with .github/workflows/spellcheck.yml - Some("install tool via `cargo install typos-cli@1.34.0`".to_owned()), - )); - } - Err(e) => return Err(e.into()), - } +/// Ensure that spellchecker is installed then run it at the given path +fn spellcheck_runner(outdir: &Path, cargo: &Path, args: &[&str]) -> Result<(), Error> { + let bin_path = + crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.34.0")?; - let status = Command::new("typos").args(args).status()?; + let status = Command::new(bin_path).args(args).status()?; if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) } } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 4ea9d051ddb5e..37713cbf75e9b 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -4,7 +4,9 @@ //! to be used by tools. use std::ffi::OsStr; +use std::path::{Path, PathBuf}; use std::process::Command; +use std::{env, io}; use build_helper::ci::CiEnv; use build_helper::git::{GitConfig, get_closest_upstream_commit}; @@ -180,6 +182,70 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool { !v.is_empty() } +/// If the given executable is installed with the given version, use that, +/// otherwise install via cargo. +pub fn ensure_version_or_cargo_install( + build_dir: &Path, + cargo: &Path, + pkg_name: &str, + bin_name: &str, + version: &str, +) -> io::Result { + // ignore the process exit code here and instead just let the version number check fail. + // we also importantly don't return if the program wasn't installed, + // instead we want to continue to the fallback. + 'ck: { + // FIXME: rewrite as if-let chain once this crate is 2024 edition. + let Ok(output) = Command::new(bin_name).arg("--version").output() else { + break 'ck; + }; + let Ok(s) = str::from_utf8(&output.stdout) else { + break 'ck; + }; + let Some(v) = s.trim().split_whitespace().last() else { + break 'ck; + }; + if v == version { + return Ok(PathBuf::from(bin_name)); + } + } + + let tool_root_dir = build_dir.join("misc-tools"); + let tool_bin_dir = tool_root_dir.join("bin"); + eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); + // use --force to ensure that if the required version is bumped, we update it. + // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. + // modify PATH so that cargo doesn't print a warning telling the user to modify the path. + let cargo_exit_code = Command::new(cargo) + .args(["install", "--locked", "--force", "--quiet"]) + .arg("--root") + .arg(&tool_root_dir) + .arg("--target-dir") + .arg(tool_root_dir.join("target")) + .arg(format!("{pkg_name}@{version}")) + .env( + "PATH", + env::join_paths( + env::split_paths(&env::var("PATH").unwrap()) + .chain(std::iter::once(tool_bin_dir.clone())), + ) + .expect("build dir contains invalid char"), + ) + .env("RUSTFLAGS", "-Copt-level=0") + .spawn()? + .wait()?; + if !cargo_exit_code.success() { + return Err(io::Error::other("cargo install failed")); + } + let bin_path = tool_bin_dir.join(bin_name); + assert!( + matches!(bin_path.try_exists(), Ok(true)), + "cargo install did not produce the expected binary" + ); + eprintln!("finished building tool {bin_name}"); + Ok(bin_path) +} + pub mod alphabetical; pub mod bins; pub mod debug_artifacts; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index cd2567ddb64bf..bfe30258915ea 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -184,6 +184,7 @@ fn main() { &librustdoc_path, &tools_path, &npm, + &cargo, bless, extra_checks, pos_args From 6a51eef11b0d43bc7a0f0e20142649fe2783d9f3 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 9 Aug 2025 11:32:24 -0500 Subject: [PATCH 30/37] tidy: run typos check in src root, not current dir --- src/tools/tidy/src/extra_checks/mod.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 604b5d1e37c70..d44fc3999f77f 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -295,7 +295,7 @@ fn check_impl( } else { eprintln!("spellcheck files"); } - spellcheck_runner(&outdir, &cargo, &args)?; + spellcheck_runner(root_path, &outdir, &cargo, &args)?; } if js_lint || js_typecheck { @@ -579,12 +579,25 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { } /// Ensure that spellchecker is installed then run it at the given path -fn spellcheck_runner(outdir: &Path, cargo: &Path, args: &[&str]) -> Result<(), Error> { +fn spellcheck_runner( + src_root: &Path, + outdir: &Path, + cargo: &Path, + args: &[&str], +) -> Result<(), Error> { let bin_path = crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.34.0")?; - let status = Command::new(bin_path).args(args).status()?; - if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) } + match Command::new(bin_path).current_dir(src_root).args(args).status() { + Ok(status) => { + if status.success() { + Ok(()) + } else { + Err(Error::FailedCheck("typos")) + } + } + Err(err) => Err(Error::Generic(format!("failed to run typos tool: {err:?}"))), + } } /// Check git for tracked files matching an extension From d73e6b46e7a9af6488b13a016515403ee44a3e08 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 8 Aug 2025 15:17:25 -0500 Subject: [PATCH 31/37] tidy: add better error reporting for if typos can't be run --- src/tools/tidy/src/extra_checks/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index d44fc3999f77f..31169ec596775 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -587,7 +587,6 @@ fn spellcheck_runner( ) -> Result<(), Error> { let bin_path = crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.34.0")?; - match Command::new(bin_path).current_dir(src_root).args(args).status() { Ok(status) => { if status.success() { From 0d797d23cfbe26d50b5405c72b5a791b6dc58b3d Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 16 Aug 2025 10:04:28 -0500 Subject: [PATCH 32/37] typos: allow moreso --- typos.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/typos.toml b/typos.toml index 317aafc861565..b0ff48f8fa28b 100644 --- a/typos.toml +++ b/typos.toml @@ -33,6 +33,7 @@ misformed = "misformed" targetting = "targetting" publically = "publically" clonable = "clonable" +moreso = "moreso" # this can be valid word, depends on dictionary edition #matcheable = "matcheable" From 2050a3b297d8878f232d28d48aa1a3a12d1616ee Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 16 Aug 2025 10:34:55 -0500 Subject: [PATCH 33/37] std: fix more typos --- library/std/src/sys/pal/uefi/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index df5611b2dddc1..748178659412f 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -188,7 +188,7 @@ pub(crate) mod system_time_internal { Duration::new(epoch, t.nanosecond) } - /// This algorithm is a modifed version of the one described in the post: + /// This algorithm is a modified version of the one described in the post: /// https://howardhinnant.github.io/date_algorithms.html#clive_from_days /// /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX @@ -197,7 +197,7 @@ pub(crate) mod system_time_internal { // Check timzone validity assert!(timezone <= 1440 && timezone >= -1440); - // FIXME(#126043): use checked_sub_signed once stablized + // FIXME(#126043): use checked_sub_signed once stabilized let secs = dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap(); From 80d32344f3dba453f7bd8f14086f215c23ba1bde Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 13 Aug 2025 17:26:16 +0200 Subject: [PATCH 34/37] Fix bug where `rustdoc-js` tester would not pick the right `search.js` file if there is more than one --- src/tools/rustdoc-js/tester.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 0baa179e16b2d..ff6b039896cc9 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -409,6 +409,24 @@ async function runChecks(testFile, doSearch, parseQuery, getCorrections) { return res; } +function mostRecentMatch(staticFiles, regex) { + const matchingEntries = fs.readdirSync(staticFiles) + .filter(f => f.match(regex)) + .map(f => { + const stats = fs.statSync(path.join(staticFiles, f)); + return { + path: f, + time: stats.mtimeMs, + }; + }); + if (matchingEntries.length === 0) { + throw "No static file matching regex"; + } + // We sort entries in descending order. + matchingEntries.sort((a, b) => b.time - a.time); + return matchingEntries[0].path; +} + /** * Load searchNNN.js and search-indexNNN.js. * @@ -452,7 +470,7 @@ function loadSearchJS(doc_folder, resource_suffix) { }; const staticFiles = path.join(doc_folder, "static.files"); - const searchJs = fs.readdirSync(staticFiles).find(f => f.match(/search.*\.js$/)); + const searchJs = mostRecentMatch(staticFiles, /search.*\.js$/); const searchModule = require(path.join(staticFiles, searchJs)); searchModule.initSearch(searchIndex.searchIndex); const docSearch = searchModule.docSearch; From 826ebde3a797736f0e96c1a01ee738436f735cd5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 16 Aug 2025 23:57:15 +0200 Subject: [PATCH 35/37] Strenghten rustdoc js tester file macthing regex --- src/tools/rustdoc-js/tester.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index ff6b039896cc9..b88c95d81bca1 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -470,7 +470,7 @@ function loadSearchJS(doc_folder, resource_suffix) { }; const staticFiles = path.join(doc_folder, "static.files"); - const searchJs = mostRecentMatch(staticFiles, /search.*\.js$/); + const searchJs = mostRecentMatch(staticFiles, /search-[0-9a-f]{8}.*\.js$/); const searchModule = require(path.join(staticFiles, searchJs)); searchModule.initSearch(searchIndex.searchIndex); const docSearch = searchModule.docSearch; From 8792010768cff60d202b3608e6918be3199aeae2 Mon Sep 17 00:00:00 2001 From: Sebastien Marie Date: Sat, 16 Aug 2025 20:11:52 +0200 Subject: [PATCH 36/37] Rust build fails on OpenBSD after using file_lock feature PR 130999 added the file_lock feature, but doesn't included OpenBSD in the supported targets (Tier 3 platform), leading to a compilation error ("try_lock() not supported"). --- library/std/src/sys/fs/unix.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index b310db2dac485..4643ced9ad818 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1263,6 +1263,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", ))] pub fn lock(&self) -> io::Result<()> { @@ -1275,6 +1276,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", )))] pub fn lock(&self) -> io::Result<()> { @@ -1286,6 +1288,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", ))] pub fn lock_shared(&self) -> io::Result<()> { @@ -1298,6 +1301,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", )))] pub fn lock_shared(&self) -> io::Result<()> { @@ -1309,6 +1313,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", ))] pub fn try_lock(&self) -> Result<(), TryLockError> { @@ -1329,6 +1334,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", )))] pub fn try_lock(&self) -> Result<(), TryLockError> { @@ -1343,6 +1349,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", ))] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { @@ -1363,6 +1370,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", )))] pub fn try_lock_shared(&self) -> Result<(), TryLockError> { @@ -1377,6 +1385,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", ))] pub fn unlock(&self) -> io::Result<()> { @@ -1389,6 +1398,7 @@ impl File { target_os = "fuchsia", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", target_vendor = "apple", )))] pub fn unlock(&self) -> io::Result<()> { From cbfa17a9935809f8145c8083bef5f2203820c44a Mon Sep 17 00:00:00 2001 From: Samuel Moelius <35515885+smoelius@users.noreply.github.com> Date: Sun, 17 Aug 2025 12:55:04 -0400 Subject: [PATCH 37/37] Reorder `lto` options from most to least optimizing --- src/doc/rustc/src/codegen-options/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 07eafdf4c4c62..445b10188e3f8 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -375,12 +375,12 @@ linking time. It takes one of the following values: * `y`, `yes`, `on`, `true`, `fat`, or no value: perform "fat" LTO which attempts to perform optimizations across all crates within the dependency graph. -* `n`, `no`, `off`, `false`: disables LTO. * `thin`: perform ["thin" LTO](http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html). This is similar to "fat", but takes substantially less time to run while still achieving performance gains similar to "fat". For larger projects like the Rust compiler, ThinLTO can even result in better performance than fat LTO. +* `n`, `no`, `off`, `false`: disables LTO. If `-C lto` is not specified, then the compiler will attempt to perform "thin local LTO" which performs "thin" LTO on the local crate only across its