From 01795b14f07910223e12240128510f48ff110629 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 27 Feb 2025 11:57:05 +0100 Subject: [PATCH 01/42] change definitely non-productive cycles to error --- .../src/solve/eval_ctxt/mod.rs | 51 +++++- .../src/solve/inspect/build.rs | 2 +- .../rustc_next_trait_solver/src/solve/mod.rs | 4 +- .../src/solve/project_goals.rs | 3 +- .../src/solve/search_graph.rs | 12 +- .../src/solve/fulfill/derive_errors.rs | 2 +- .../rustc_type_ir/src/search_graph/mod.rs | 162 ++++++++++++------ compiler/rustc_type_ir/src/solve/mod.rs | 19 +- tests/ui/associated-type-bounds/hrtb.rs | 3 + .../supertrait-defines-ty.rs | 3 + .../inherent-impls-overflow.next.stderr | 7 +- .../inherent-impls-overflow.rs | 2 +- .../trait_ref_is_knowable-norm-overflow.rs | 8 +- ...trait_ref_is_knowable-norm-overflow.stderr | 16 +- .../cyclic-normalization-to-error-nalgebra.rs | 21 +++ .../recursive-self-normalization-2.rs | 7 +- .../recursive-self-normalization-2.stderr | 54 +----- .../overflow/recursive-self-normalization.rs | 7 +- .../recursive-self-normalization.stderr | 54 +----- 19 files changed, 233 insertions(+), 204 deletions(-) create mode 100644 tests/ui/traits/next-solver/cycles/cyclic-normalization-to-error-nalgebra.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index b0bbec489471d..e48ee71c858c4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -271,12 +271,39 @@ where /// and will need to clearly document it in the rustc-dev-guide before /// stabilization. pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind { - match (self.current_goal_kind, source) { - (_, GoalSource::NormalizeGoal(step_kind)) => step_kind, - (CurrentGoalKind::CoinductiveTrait, GoalSource::ImplWhereBound) => { - PathKind::Coinductive + match source { + // We treat these goals as unknown for now. It is likely that most miscellaneous + // nested goals will be converted to an inductive variant in the future. + // + // Having unknown cycles is always the safer option, as changing that to either + // succeed or hard error is backwards compatible. If we incorrectly treat a cycle + // as inductive even though it should not be, it may be unsound during coherence and + // fixing it may cause inference breakage or introduce ambiguity. + GoalSource::Misc => PathKind::Unknown, + GoalSource::NormalizeGoal(path_kind) => path_kind, + GoalSource::ImplWhereBound => { + // We currently only consider a cycle coinductive if it steps + // into a where-clause of a coinductive trait. + // + // We probably want to make all traits coinductive in the future, + // so we treat cycles involving their where-clauses as ambiguous. + if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind { + PathKind::Coinductive + } else { + PathKind::Unknown + } } - _ => PathKind::Inductive, + // Relating types is always unproductive. If we were to map proof trees to + // corecursive functions as explained in #136824, relating types never + // introduces a constructor which could cause the recursion to be guarded. + GoalSource::TypeRelating => PathKind::Inductive, + // Instantiating a higher ranked goal can never cause the recursion to be + // guarded and is therefore unproductive. + GoalSource::InstantiateHigherRanked => PathKind::Inductive, + // These goal sources are likely unproductive and can be changed to + // `PathKind::Inductive`. Keeping them as unknown until we're confident + // about this and have an example where it is necessary. + GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown, } } @@ -606,7 +633,7 @@ where let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw( GoalEvaluationKind::Nested, - GoalSource::Misc, + GoalSource::TypeRelating, unconstrained_goal, )?; // Add the nested goals from normalization to our own nested goals. @@ -683,7 +710,7 @@ where pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal>) { goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new( self, - GoalSource::Misc, + GoalSource::TypeRelating, goal.param_env, )); self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal); @@ -939,7 +966,15 @@ where rhs: T, ) -> Result<(), NoSolution> { let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?; - self.add_goals(GoalSource::Misc, goals); + if cfg!(debug_assertions) { + for g in goals.iter() { + match g.predicate.kind().skip_binder() { + ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {} + p => unreachable!("unexpected nested goal in `relate`: {p:?}"), + } + } + } + self.add_goals(GoalSource::TypeRelating, goals); Ok(()) } diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 1607fbb1b6a7b..6a8e0790f7cb4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -421,7 +421,7 @@ impl, I: Interner> ProofTreeBuilder { self.add_goal( delegate, max_input_universe, - GoalSource::Misc, + GoalSource::TypeRelating, goal.with(delegate.cx(), goal.predicate), ); } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 1fa35b60304cf..199f0c7512e1b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -313,7 +313,9 @@ where ty::AliasRelationDirection::Equate, ), ); - self.add_goal(GoalSource::Misc, alias_relate_goal); + // We normalize the self type to be able to relate it with + // types from candidates. + self.add_goal(GoalSource::TypeRelating, alias_relate_goal); self.try_evaluate_added_goals()?; Ok(self.resolve_vars_if_possible(normalized_term)) } else { diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs index d945288007174..944d5f0e042d7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -24,7 +24,8 @@ where ty::AliasRelationDirection::Equate, ), ); - self.add_goal(GoalSource::Misc, goal); + // A projection goal holds if the alias is equal to the expected term. + self.add_goal(GoalSource::TypeRelating, goal); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 67eb442d2cce7..aa1206cd6b730 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use rustc_type_ir::Interner; use rustc_type_ir::search_graph::{self, PathKind}; -use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult}; +use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult}; use super::inspect::ProofTreeBuilder; use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints}; @@ -47,7 +47,8 @@ where ) -> QueryResult { match kind { PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes), - PathKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)), + PathKind::Unknown => response_no_constraints(cx, input, Certainty::overflow(false)), + PathKind::Inductive => Err(NoSolution), } } @@ -57,12 +58,7 @@ where input: CanonicalInput, result: QueryResult, ) -> bool { - match kind { - PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes) == result, - PathKind::Inductive => { - response_no_constraints(cx, input, Certainty::overflow(false)) == result - } - } + Self::initial_provisional_result(cx, kind, input) == result } fn on_stack_overflow( diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 4f177df89e230..352ac7c1a4e6f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -440,7 +440,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { match (child_mode, nested_goal.source()) { ( ChildMode::Trait(_) | ChildMode::Host(_), - GoalSource::Misc | GoalSource::NormalizeGoal(_), + GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_), ) => { continue; } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 18e84db5d686c..1950fab35be38 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -13,6 +13,7 @@ /// behavior as long as the resulting behavior is still correct. use std::cmp::Ordering; use std::collections::BTreeMap; +use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; @@ -20,7 +21,7 @@ use std::marker::PhantomData; use derive_where::derive_where; use rustc_index::{Idx, IndexVec}; #[cfg(feature = "nightly")] -use rustc_macros::HashStable_NoContext; +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use tracing::debug; use crate::data_structures::HashMap; @@ -111,21 +112,32 @@ pub trait Delegate { /// In the initial iteration of a cycle, we do not yet have a provisional /// result. In the case we return an initial provisional result depending /// on the kind of cycle. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum PathKind { - Coinductive, + /// A path consisting of only inductive/unproductive steps. Inductive, + /// A path which is not be coinductive right now but we may want + /// to change of them to be so in the future. We return an ambiguous + /// result in this case to prevent people from relying on this. + Unknown, + /// A path with at least one coinductive step. Such cycles hold. + Coinductive, } + impl PathKind { /// Returns the path kind when merging `self` with `rest`. /// /// Given an inductive path `self` and a coinductive path `rest`, /// the path `self -> rest` would be coinductive. + /// + /// This operation represents an ordering and would be equivalent + /// to `max(self, rest)`. fn extend(self, rest: PathKind) -> PathKind { - match self { - PathKind::Coinductive => PathKind::Coinductive, - PathKind::Inductive => rest, + match (self, rest) { + (PathKind::Coinductive, _) | (_, PathKind::Coinductive) => PathKind::Coinductive, + (PathKind::Unknown, _) | (_, PathKind::Unknown) => PathKind::Unknown, + (PathKind::Inductive, PathKind::Inductive) => PathKind::Inductive, } } } @@ -159,9 +171,6 @@ impl UsageKind { } } } - fn and_merge(&mut self, other: impl Into) { - *self = self.merge(other); - } } /// For each goal we track whether the paths from this goal @@ -297,7 +306,7 @@ impl CycleHeads { let path_from_entry = match step_kind { PathKind::Coinductive => AllPathsToHeadCoinductive::Yes, - PathKind::Inductive => path_from_entry, + PathKind::Unknown | PathKind::Inductive => path_from_entry, }; self.insert(head, path_from_entry); @@ -305,6 +314,63 @@ impl CycleHeads { } } +bitflags::bitflags! { + /// Tracks how nested goals have been accessed. This is necessary to disable + /// global cache entries if computing them would otherwise result in a cycle or + /// access a provisional cache entry. + #[derive(Debug, Clone, Copy)] + pub struct PathsToNested: u8 { + /// The initial value when adding a goal to its own nested goals. + const EMPTY = 1 << 0; + const INDUCTIVE = 1 << 1; + const UNKNOWN = 1 << 2; + const COINDUCTIVE = 1 << 3; + } +} +impl From for PathsToNested { + fn from(path: PathKind) -> PathsToNested { + match path { + PathKind::Inductive => PathsToNested::INDUCTIVE, + PathKind::Unknown => PathsToNested::UNKNOWN, + PathKind::Coinductive => PathsToNested::COINDUCTIVE, + } + } +} +impl PathsToNested { + /// The implementation of this function is kind of ugly. We check whether + /// there currently exist 'weaker' paths in the set, if so we upgrade these + /// paths to at least `path`. + #[must_use] + fn extend_with(mut self, path: PathKind) -> Self { + match path { + PathKind::Inductive => { + if self.intersects(PathsToNested::EMPTY) { + self.remove(PathsToNested::EMPTY); + self.insert(PathsToNested::INDUCTIVE); + } + } + PathKind::Unknown => { + if self.intersects(PathsToNested::EMPTY | PathsToNested::INDUCTIVE) { + self.remove(PathsToNested::EMPTY | PathsToNested::INDUCTIVE); + self.insert(PathsToNested::UNKNOWN); + } + } + PathKind::Coinductive => { + if self.intersects( + PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN, + ) { + self.remove( + PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN, + ); + self.insert(PathsToNested::COINDUCTIVE); + } + } + } + + self + } +} + /// The nested goals of each stack entry and the path from the /// stack entry to that nested goal. /// @@ -322,15 +388,18 @@ impl CycleHeads { /// results from a the cycle BAB depending on the cycle root. #[derive_where(Debug, Default, Clone; X: Cx)] struct NestedGoals { - nested_goals: HashMap, + nested_goals: HashMap, } impl NestedGoals { fn is_empty(&self) -> bool { self.nested_goals.is_empty() } - fn insert(&mut self, input: X::Input, path_from_entry: UsageKind) { - self.nested_goals.entry(input).or_insert(path_from_entry).and_merge(path_from_entry); + fn insert(&mut self, input: X::Input, paths_to_nested: PathsToNested) { + match self.nested_goals.entry(input) { + Entry::Occupied(mut entry) => *entry.get_mut() |= paths_to_nested, + Entry::Vacant(entry) => drop(entry.insert(paths_to_nested)), + } } /// Adds the nested goals of a nested goal, given that the path `step_kind` from this goal @@ -341,18 +410,15 @@ impl NestedGoals { /// the same as for the child. fn extend_from_child(&mut self, step_kind: PathKind, nested_goals: &NestedGoals) { #[allow(rustc::potential_query_instability)] - for (input, path_from_entry) in nested_goals.iter() { - let path_from_entry = match step_kind { - PathKind::Coinductive => UsageKind::Single(PathKind::Coinductive), - PathKind::Inductive => path_from_entry, - }; - self.insert(input, path_from_entry); + for (input, paths_to_nested) in nested_goals.iter() { + let paths_to_nested = paths_to_nested.extend_with(step_kind); + self.insert(input, paths_to_nested); } } #[cfg_attr(feature = "nightly", rustc_lint_query_instability)] #[allow(rustc::potential_query_instability)] - fn iter(&self) -> impl Iterator { + fn iter(&self) -> impl Iterator + '_ { self.nested_goals.iter().map(|(i, p)| (*i, *p)) } @@ -490,7 +556,7 @@ impl, X: Cx> SearchGraph { // goals as this change may cause them to now depend on additional // goals, resulting in new cycles. See the dev-guide for examples. if parent_depends_on_cycle { - parent.nested_goals.insert(parent.input, UsageKind::Single(PathKind::Inductive)) + parent.nested_goals.insert(parent.input, PathsToNested::EMPTY); } } } @@ -666,7 +732,7 @@ impl, X: Cx> SearchGraph { // // We must therefore not use the global cache entry for `B` in that case. // See tests/ui/traits/next-solver/cycles/hidden-by-overflow.rs - last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Inductive)); + last.nested_goals.insert(last.input, PathsToNested::EMPTY); } debug!("encountered stack overflow"); @@ -749,16 +815,11 @@ impl, X: Cx> SearchGraph { // We now care about the path from the next highest cycle head to the // provisional cache entry. - match path_from_head { - PathKind::Coinductive => {} - PathKind::Inductive => { - *path_from_head = Self::cycle_path_kind( - &self.stack, - stack_entry.step_kind_from_parent, - head, - ) - } - } + *path_from_head = path_from_head.extend(Self::cycle_path_kind( + &self.stack, + stack_entry.step_kind_from_parent, + head, + )); // Mutate the result of the provisional cache entry in case we did // not reach a fixpoint. *result = mutate_result(input, *result); @@ -858,7 +919,7 @@ impl, X: Cx> SearchGraph { for &ProvisionalCacheEntry { encountered_overflow, ref heads, - path_from_head, + path_from_head: head_to_provisional, result: _, } in entries.iter() { @@ -870,24 +931,19 @@ impl, X: Cx> SearchGraph { // A provisional cache entry only applies if the path from its highest head // matches the path when encountering the goal. + // + // We check if any of the paths taken while computing the global goal + // would end up with an applicable provisional cache entry. let head = heads.highest_cycle_head(); - let full_path = match Self::cycle_path_kind(stack, step_kind_from_parent, head) { - PathKind::Coinductive => UsageKind::Single(PathKind::Coinductive), - PathKind::Inductive => path_from_global_entry, - }; - - match (full_path, path_from_head) { - (UsageKind::Mixed, _) - | (UsageKind::Single(PathKind::Coinductive), PathKind::Coinductive) - | (UsageKind::Single(PathKind::Inductive), PathKind::Inductive) => { - debug!( - ?full_path, - ?path_from_head, - "cache entry not applicable due to matching paths" - ); - return false; - } - _ => debug!(?full_path, ?path_from_head, "paths don't match"), + let head_to_curr = Self::cycle_path_kind(stack, step_kind_from_parent, head); + let full_paths = path_from_global_entry.extend_with(head_to_curr); + if full_paths.contains(head_to_provisional.into()) { + debug!( + ?full_paths, + ?head_to_provisional, + "cache entry not applicable due to matching paths" + ); + return false; } } } @@ -986,8 +1042,8 @@ impl, X: Cx> SearchGraph { let last = &mut self.stack[last_index]; last.reached_depth = last.reached_depth.max(next_index); - last.nested_goals.insert(input, UsageKind::Single(step_kind_from_parent)); - last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Inductive)); + last.nested_goals.insert(input, step_kind_from_parent.into()); + last.nested_goals.insert(last.input, PathsToNested::EMPTY); if last_index != head { last.heads.insert(head, step_kind_from_parent); } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index b93668b5111ba..8848640510c79 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -58,20 +58,24 @@ impl Goal { /// Why a specific goal has to be proven. /// /// This is necessary as we treat nested goals different depending on -/// their source. This is currently mostly used by proof tree visitors -/// but will be used by cycle handling in the future. +/// their source. This is used to decide whether a cycle is coinductive. +/// See the documentation of `EvalCtxt::step_kind_for_source` for more details +/// about this. +/// +/// It is also used by proof tree visitors, e.g. for diagnostics purposes. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GoalSource { Misc, - /// We're proving a where-bound of an impl. + /// A nested goal required to prove that types are equal/subtypes. + /// This is always an unproductive step. /// - /// FIXME(-Znext-solver=coinductive): Explain how and why this - /// changes whether cycles are coinductive. + /// This is also used for all `NormalizesTo` goals as we they are used + /// to relate types in `AliasRelate`. + TypeRelating, + /// We're proving a where-bound of an impl. ImplWhereBound, /// Const conditions that need to hold for `~const` alias bounds to hold. - /// - /// FIXME(-Znext-solver=coinductive): Are these even coinductive? AliasBoundConstCondition, /// Instantiating a higher-ranked goal and re-proving it. InstantiateHigherRanked, @@ -79,7 +83,6 @@ pub enum GoalSource { /// This is used in two places: projecting to an opaque whose hidden type /// is already registered in the opaque type storage, and for rigid projections. AliasWellFormed, - /// In case normalizing aliases in nested goals cycles, eagerly normalizing these /// aliases in the context of the parent may incorrectly change the cycle kind. /// Normalizing aliases in goals therefore tracks the original path kind for this diff --git a/tests/ui/associated-type-bounds/hrtb.rs b/tests/ui/associated-type-bounds/hrtb.rs index 1bf574f2e6518..8ff7faec3a0f0 100644 --- a/tests/ui/associated-type-bounds/hrtb.rs +++ b/tests/ui/associated-type-bounds/hrtb.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) trait A<'a> {} trait B<'b> {} diff --git a/tests/ui/associated-type-bounds/supertrait-defines-ty.rs b/tests/ui/associated-type-bounds/supertrait-defines-ty.rs index ed1c1fa6f039a..1c09ff3d3fb86 100644 --- a/tests/ui/associated-type-bounds/supertrait-defines-ty.rs +++ b/tests/ui/associated-type-bounds/supertrait-defines-ty.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) // Make sure that we don't look into associated type bounds when looking for // supertraits that define an associated type. Fixes #76593. diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr index 192b5eebdaac8..4f1d339bc999d 100644 --- a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr +++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr @@ -1,8 +1,8 @@ -error[E0275]: overflow evaluating the requirement `Loop == _` +error[E0271]: type mismatch resolving `Loop normalizes-to _` --> $DIR/inherent-impls-overflow.rs:10:6 | LL | impl Loop {} - | ^^^^ + | ^^^^ types differ error: type parameter `T` is only used recursively --> $DIR/inherent-impls-overflow.rs:14:24 @@ -36,4 +36,5 @@ LL | impl Poly0<()> {} error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0275`. +Some errors have detailed explanations: E0271, E0275. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.rs b/tests/ui/lazy-type-alias/inherent-impls-overflow.rs index 1397695a3fe41..0d5ec7d153073 100644 --- a/tests/ui/lazy-type-alias/inherent-impls-overflow.rs +++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.rs @@ -9,7 +9,7 @@ type Loop = Loop; //[current]~ ERROR overflow normalizing the type alias `Loop` impl Loop {} //[current]~^ ERROR overflow normalizing the type alias `Loop` -//[next]~^^ ERROR overflow evaluating the requirement `Loop == _` +//[next]~^^ ERROR type mismatch resolving `Loop normalizes-to _` type Poly0 = Poly1<(T,)>; //[current]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>` diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs index 3238f02836283..28fd66cd1694a 100644 --- a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs @@ -6,9 +6,11 @@ trait Overflow { type Assoc; } -impl Overflow for T { - type Assoc = ::Assoc; - //~^ ERROR: overflow +impl Overflow for T +where + (T,): Overflow +{ + type Assoc = <(T,) as Overflow>::Assoc; } diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr index 294fa0d7613c5..34a45e9363069 100644 --- a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr @@ -1,19 +1,15 @@ -error[E0275]: overflow evaluating the requirement `::Assoc == _` - --> $DIR/trait_ref_is_knowable-norm-overflow.rs:10:18 - | -LL | type Assoc = ::Assoc; - | ^^^^^^^^^^^^^^^^^^^^^^ - error[E0119]: conflicting implementations of trait `Trait` - --> $DIR/trait_ref_is_knowable-norm-overflow.rs:18:1 + --> $DIR/trait_ref_is_knowable-norm-overflow.rs:20:1 | LL | impl Trait for T {} | ------------------------- first implementation here LL | struct LocalTy; LL | impl Trait for ::Assoc {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + | + = note: overflow evaluating the requirement `_ == ::Assoc` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`trait_ref_is_knowable_norm_overflow`) -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0119, E0275. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/cycles/cyclic-normalization-to-error-nalgebra.rs b/tests/ui/traits/next-solver/cycles/cyclic-normalization-to-error-nalgebra.rs new file mode 100644 index 0000000000000..ec478aa02b770 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cyclic-normalization-to-error-nalgebra.rs @@ -0,0 +1,21 @@ +// Regression test for trait-system-refactor-initiative#114. +// +// We previously treated the cycle when trying to use the +// `>::Output: DimMin` where-bound when +// normalizing `>::Output` as ambiguous, causing +// this to error. + +//@ check-pass +//@ compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver + +pub trait DimMin { + type Output; +} +pub fn repro, C>() +where + >::Output: DimMin>::Output>, +{ +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs index 0f01a453b332e..94a9484ecdcf1 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs @@ -13,12 +13,7 @@ fn needs_bar() {} fn test::Assoc2> + Foo2::Assoc1>>() { needs_bar::(); - //~^ ERROR overflow evaluating the requirement `::Assoc1 == _` - //~| ERROR overflow evaluating the requirement `::Assoc1 == _` - //~| ERROR overflow evaluating the requirement `::Assoc1 == _` - //~| ERROR overflow evaluating the requirement `::Assoc1 == _` - //~| ERROR overflow evaluating the requirement `::Assoc1: Sized` - //~| ERROR overflow evaluating the requirement `::Assoc1: Bar` + //~^ ERROR the trait bound `::Assoc1: Bar` is not satisfied } fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr index 2b0e57966fe7b..6f5111a6193ca 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr @@ -1,59 +1,19 @@ -error[E0275]: overflow evaluating the requirement `::Assoc1 == _` +error[E0277]: the trait bound `::Assoc1: Bar` is not satisfied --> $DIR/recursive-self-normalization-2.rs:15:17 | LL | needs_bar::(); - | ^^^^^^^^^ - -error[E0275]: overflow evaluating the requirement `::Assoc1: Bar` - --> $DIR/recursive-self-normalization-2.rs:15:17 - | -LL | needs_bar::(); - | ^^^^^^^^^ + | ^^^^^^^^^ the trait `Bar` is not implemented for `::Assoc1` | note: required by a bound in `needs_bar` --> $DIR/recursive-self-normalization-2.rs:12:17 | LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` - -error[E0275]: overflow evaluating the requirement `::Assoc1: Sized` - --> $DIR/recursive-self-normalization-2.rs:15:17 - | -LL | needs_bar::(); - | ^^^^^^^^^ - | -note: required by an implicit `Sized` bound in `needs_bar` - --> $DIR/recursive-self-normalization-2.rs:12:14 - | -LL | fn needs_bar() {} - | ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar` -help: consider relaxing the implicit `Sized` restriction - | -LL | fn needs_bar() {} - | ++++++++ - -error[E0275]: overflow evaluating the requirement `::Assoc1 == _` - --> $DIR/recursive-self-normalization-2.rs:15:5 - | -LL | needs_bar::(); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error[E0275]: overflow evaluating the requirement `::Assoc1 == _` - --> $DIR/recursive-self-normalization-2.rs:15:5 - | -LL | needs_bar::(); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0275]: overflow evaluating the requirement `::Assoc1 == _` - --> $DIR/recursive-self-normalization-2.rs:15:17 - | -LL | needs_bar::(); - | ^^^^^^^^^ +help: consider further restricting the associated type | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +LL | fn test::Assoc2> + Foo2::Assoc1>>() where ::Assoc1: Bar { + | ++++++++++++++++++++++++++++++ -error: aborting due to 6 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs index f435b48737e23..f441ac499f99c 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs @@ -9,12 +9,7 @@ fn needs_bar() {} fn test::Assoc>>() { needs_bar::(); - //~^ ERROR overflow evaluating the requirement `::Assoc == _` - //~| ERROR overflow evaluating the requirement `::Assoc == _` - //~| ERROR overflow evaluating the requirement `::Assoc == _` - //~| ERROR overflow evaluating the requirement `::Assoc == _` - //~| ERROR overflow evaluating the requirement `::Assoc: Sized` - //~| ERROR overflow evaluating the requirement `::Assoc: Bar` + //~^ ERROR the trait bound `::Assoc: Bar` is not satisfied } fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr index af8504dcaeeea..c551823468741 100644 --- a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr @@ -1,59 +1,19 @@ -error[E0275]: overflow evaluating the requirement `::Assoc == _` +error[E0277]: the trait bound `::Assoc: Bar` is not satisfied --> $DIR/recursive-self-normalization.rs:11:17 | LL | needs_bar::(); - | ^^^^^^^^ - -error[E0275]: overflow evaluating the requirement `::Assoc: Bar` - --> $DIR/recursive-self-normalization.rs:11:17 - | -LL | needs_bar::(); - | ^^^^^^^^ + | ^^^^^^^^ the trait `Bar` is not implemented for `::Assoc` | note: required by a bound in `needs_bar` --> $DIR/recursive-self-normalization.rs:8:17 | LL | fn needs_bar() {} | ^^^ required by this bound in `needs_bar` - -error[E0275]: overflow evaluating the requirement `::Assoc: Sized` - --> $DIR/recursive-self-normalization.rs:11:17 - | -LL | needs_bar::(); - | ^^^^^^^^ - | -note: required by an implicit `Sized` bound in `needs_bar` - --> $DIR/recursive-self-normalization.rs:8:14 - | -LL | fn needs_bar() {} - | ^ required by the implicit `Sized` requirement on this type parameter in `needs_bar` -help: consider relaxing the implicit `Sized` restriction - | -LL | fn needs_bar() {} - | ++++++++ - -error[E0275]: overflow evaluating the requirement `::Assoc == _` - --> $DIR/recursive-self-normalization.rs:11:5 - | -LL | needs_bar::(); - | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0275]: overflow evaluating the requirement `::Assoc == _` - --> $DIR/recursive-self-normalization.rs:11:5 - | -LL | needs_bar::(); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0275]: overflow evaluating the requirement `::Assoc == _` - --> $DIR/recursive-self-normalization.rs:11:17 - | -LL | needs_bar::(); - | ^^^^^^^^ +help: consider further restricting the associated type | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +LL | fn test::Assoc>>() where ::Assoc: Bar { + | ++++++++++++++++++++++++++++ -error: aborting due to 6 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0277`. From 18809a2b123752d904a9487117665115b404a513 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 28 Feb 2025 13:11:25 +0100 Subject: [PATCH 02/42] keep inductive cycles as ambig in coherence --- .../src/solve/search_graph.rs | 20 ++++++++++++++++-- .../rustc_type_ir/src/search_graph/mod.rs | 5 ++++- .../cycles/unproductive-in-coherence.rs | 21 +++++++++++++++++++ .../cycles/unproductive-in-coherence.stderr | 11 ++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs create mode 100644 tests/ui/traits/next-solver/cycles/unproductive-in-coherence.stderr diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index aa1206cd6b730..eba496fa22659 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,9 +1,9 @@ use std::convert::Infallible; use std::marker::PhantomData; -use rustc_type_ir::Interner; use rustc_type_ir::search_graph::{self, PathKind}; use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult}; +use rustc_type_ir::{Interner, TypingMode}; use super::inspect::ProofTreeBuilder; use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints}; @@ -48,7 +48,23 @@ where match kind { PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes), PathKind::Unknown => response_no_constraints(cx, input, Certainty::overflow(false)), - PathKind::Inductive => Err(NoSolution), + // Even though we know these cycles to be unproductive, we still return + // overflow during coherence. This is both as we are not 100% confident in + // the implementation yet and any incorrect errors would be unsound there. + // The affected cases are also fairly artificial and not necessarily desirable + // so keeping this as ambiguity is fine for now. + // + // See `tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs` for an + // example where this would matter. We likely should change these cycles to `NoSolution` + // even in coherence once this is a bit more settled. + PathKind::Inductive => match input.typing_mode { + TypingMode::Coherence => { + response_no_constraints(cx, input, Certainty::overflow(false)) + } + TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => Err(NoSolution), + }, } } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 1950fab35be38..9ae8392805779 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -115,7 +115,10 @@ pub trait Delegate { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum PathKind { - /// A path consisting of only inductive/unproductive steps. + /// A path consisting of only inductive/unproductive steps. Their initial + /// provisional result is `Err(NoSolution)`. We currently treat them as + /// `PathKind::Unknown` during coherence until we're fully confident in + /// our approach. Inductive, /// A path which is not be coinductive right now but we may want /// to change of them to be so in the future. We return an ambiguous diff --git a/tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs b/tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs new file mode 100644 index 0000000000000..46dd6adf66225 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs @@ -0,0 +1,21 @@ +// If we treat known inductive cycles as errors, this test compiles +// as normalizing `Overflow::Assoc` fails. +// +// As coherence already uses the new solver on stable, this change +// would require an FCP. + +trait Trait { + type Assoc; +} + +struct Overflow; +impl Trait for Overflow { + type Assoc = ::Assoc; +} + +trait Overlap {} +impl Overlap, U> for T {} +impl Overlap for Overflow {} +//~^ ERROR conflicting implementations of trait `Overlap<::Assoc, _>` for type `Overflow` + +fn main() {} diff --git a/tests/ui/traits/next-solver/cycles/unproductive-in-coherence.stderr b/tests/ui/traits/next-solver/cycles/unproductive-in-coherence.stderr new file mode 100644 index 0000000000000..6605a28d54771 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/unproductive-in-coherence.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Overlap<::Assoc, _>` for type `Overflow` + --> $DIR/unproductive-in-coherence.rs:18:1 + | +LL | impl Overlap, U> for T {} + | ----------------------------------------------------- first implementation here +LL | impl Overlap for Overflow {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Overflow` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. From 36efaf8437fd3926868293c87fa6cffc6f309bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 5 Mar 2025 10:54:11 +0100 Subject: [PATCH 03/42] normalize away `-Wlinker-messages` wrappers from `rust-lld` rmake test --- tests/run-make/rust-lld/rmake.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-make/rust-lld/rmake.rs b/tests/run-make/rust-lld/rmake.rs index e5ae943538842..35f716c24c71a 100644 --- a/tests/run-make/rust-lld/rmake.rs +++ b/tests/run-make/rust-lld/rmake.rs @@ -60,7 +60,8 @@ fn main() { } fn find_lld_version_in_logs(stderr: String) -> bool { - let lld_version_re = - Regex::new(r"^warning: linker std(out|err): LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); + // Strip the `-Wlinker-messages` wrappers prefixing the linker output. + let stderr = Regex::new(r"warning: linker std(out|err):").unwrap().replace_all(&stderr, ""); + let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); stderr.lines().any(|line| lld_version_re.is_match(line.trim())) } From b2de19e8acb938eb1c6c4e59f8a06655b299f6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 25 Feb 2025 13:43:25 +0100 Subject: [PATCH 04/42] Update bootstrap to edition 2024 --- src/bootstrap/Cargo.toml | 2 +- src/bootstrap/src/bin/sccache-plus-cl.rs | 9 +++- src/bootstrap/src/core/build_steps/format.rs | 2 +- src/bootstrap/src/utils/cc_detect/tests.rs | 56 +++++++++++++------- src/bootstrap/src/utils/helpers.rs | 2 +- src/bootstrap/src/utils/job.rs | 4 +- 6 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 2c1d85b01e6af..2ea2596088fd5 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bootstrap" version = "0.0.0" -edition = "2021" +edition = "2024" build = "build.rs" default-run = "bootstrap" diff --git a/src/bootstrap/src/bin/sccache-plus-cl.rs b/src/bootstrap/src/bin/sccache-plus-cl.rs index 6e87d4222e863..c161d69d5f73b 100644 --- a/src/bootstrap/src/bin/sccache-plus-cl.rs +++ b/src/bootstrap/src/bin/sccache-plus-cl.rs @@ -4,8 +4,13 @@ use std::process::{self, Command}; fn main() { let target = env::var("SCCACHE_TARGET").unwrap(); // Locate the actual compiler that we're invoking - env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); - env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); + + // SAFETY: we're in main, there are no other threads + unsafe { + env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); + env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); + } + let mut cfg = cc::Build::new(); cfg.cargo_metadata(false) .out_dir("/") diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index c7eafadee2df3..9817e47baa101 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -27,7 +27,7 @@ fn rustfmt( rustfmt: &Path, paths: &[PathBuf], check: bool, -) -> impl FnMut(bool) -> RustfmtStatus { +) -> impl FnMut(bool) -> RustfmtStatus + use<> { let mut cmd = Command::new(rustfmt); // Avoid the submodule config paths from coming into play. We only allow a single global config // for the workspace for now. diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index 006dfe7e5d7b3..c97529cbe9eb4 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -9,20 +9,24 @@ use crate::{Build, Config, Flags}; fn test_cc2ar_env_specific() { let triple = "x86_64-unknown-linux-gnu"; let key = "AR_x86_64_unknown_linux_gnu"; - env::set_var(key, "custom-ar"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::set_var(key, "custom-ar") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); let result = cc2ar(cc, target, default_ar); - env::remove_var(key); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var(key) }; assert_eq!(result, Some(PathBuf::from("custom-ar"))); } #[test] fn test_cc2ar_musl() { let triple = "x86_64-unknown-linux-musl"; - env::remove_var("AR_x86_64_unknown_linux_musl"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_linux_musl") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -33,8 +37,10 @@ fn test_cc2ar_musl() { #[test] fn test_cc2ar_openbsd() { let triple = "x86_64-unknown-openbsd"; - env::remove_var("AR_x86_64_unknown_openbsd"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_openbsd") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/cc"); let default_ar = PathBuf::from("default-ar"); @@ -45,8 +51,10 @@ fn test_cc2ar_openbsd() { #[test] fn test_cc2ar_vxworks() { let triple = "armv7-wrs-vxworks"; - env::remove_var("AR_armv7_wrs_vxworks"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_armv7_wrs_vxworks") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -57,8 +65,10 @@ fn test_cc2ar_vxworks() { #[test] fn test_cc2ar_nto_i586() { let triple = "i586-unknown-nto-something"; - env::remove_var("AR_i586_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_i586_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -69,8 +79,10 @@ fn test_cc2ar_nto_i586() { #[test] fn test_cc2ar_nto_aarch64() { let triple = "aarch64-unknown-nto-something"; - env::remove_var("AR_aarch64_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_aarch64_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -81,8 +93,10 @@ fn test_cc2ar_nto_aarch64() { #[test] fn test_cc2ar_nto_x86_64() { let triple = "x86_64-unknown-nto-something"; - env::remove_var("AR_x86_64_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -94,8 +108,10 @@ fn test_cc2ar_nto_x86_64() { #[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")] fn test_cc2ar_nto_unknown() { let triple = "powerpc-unknown-nto-something"; - env::remove_var("AR_powerpc_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_powerpc_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -177,7 +193,8 @@ fn test_default_compiler_wasi() { let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); let target = TargetSelection::from_user("wasm32-wasi"); let wasi_sdk = PathBuf::from("/wasi-sdk"); - env::set_var("WASI_SDK_PATH", &wasi_sdk); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::set_var("WASI_SDK_PATH", &wasi_sdk) }; let mut cfg = cc::Build::new(); if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) { let expected = { @@ -190,7 +207,10 @@ fn test_default_compiler_wasi() { "default_compiler should return a compiler path for wasi target when WASI_SDK_PATH is set" ); } - env::remove_var("WASI_SDK_PATH"); + // SAFETY: bootstrap tests run on a single thread + unsafe { + env::remove_var("WASI_SDK_PATH"); + } } #[test] diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 7ad308cd06728..89d93a29acbca 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -286,7 +286,7 @@ pub fn output(cmd: &mut Command) -> String { /// to finish and then return its output. This allows the spawned process /// to do work without immediately blocking bootstrap. #[track_caller] -pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String { +pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String + use<> { let child = match cmd.stderr(Stdio::inherit()).stdout(Stdio::piped()).spawn() { Ok(child) => child, Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index a60e889fd576c..99fc3e2dc7b55 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -7,7 +7,9 @@ pub unsafe fn setup(_build: &mut crate::Build) {} #[cfg(all(unix, not(target_os = "haiku")))] pub unsafe fn setup(build: &mut crate::Build) { if build.config.low_priority { - libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + unsafe { + libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + } } } From 6a38322d2608a480b38da6efd926627950bc0537 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 5 Mar 2025 14:43:36 +0000 Subject: [PATCH 05/42] Rename print_something to should_render --- .../rustc_attr_data_structures/src/lib.rs | 40 +++++++++++-------- compiler/rustc_macros/src/print_attribute.rs | 10 ++--- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index be00d1c10e0c4..16ff4183ef5f6 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -34,13 +34,17 @@ pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStabl /// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the /// representation much. pub trait PrintAttribute { - fn print_something(&self) -> bool; + /// Whether or not this will render as something meaningful, or if it's skipped + /// (which will force the containing struct to also skip printing a comma + /// and the field name). + fn should_render(&self) -> bool; + fn print_attribute(&self, p: &mut Printer); } impl PrintAttribute for &T { - fn print_something(&self) -> bool { - T::print_something(self) + fn should_render(&self) -> bool { + T::should_render(self) } fn print_attribute(&self, p: &mut Printer) { @@ -48,9 +52,10 @@ impl PrintAttribute for &T { } } impl PrintAttribute for Option { - fn print_something(&self) -> bool { - self.as_ref().is_some_and(|x| x.print_something()) + fn should_render(&self) -> bool { + self.as_ref().is_some_and(|x| x.should_render()) } + fn print_attribute(&self, p: &mut Printer) { if let Some(i) = self { T::print_attribute(i, p) @@ -58,9 +63,10 @@ impl PrintAttribute for Option { } } impl PrintAttribute for ThinVec { - fn print_something(&self) -> bool { - self.is_empty() || self[0].print_something() + fn should_render(&self) -> bool { + self.is_empty() || self[0].should_render() } + fn print_attribute(&self, p: &mut Printer) { let mut last_printed = false; p.word("["); @@ -69,7 +75,7 @@ impl PrintAttribute for ThinVec { p.word_space(","); } i.print_attribute(p); - last_printed = i.print_something(); + last_printed = i.should_render(); } p.word("]"); } @@ -77,7 +83,7 @@ impl PrintAttribute for ThinVec { macro_rules! print_skip { ($($t: ty),* $(,)?) => {$( impl PrintAttribute for $t { - fn print_something(&self) -> bool { false } + fn should_render(&self) -> bool { false } fn print_attribute(&self, _: &mut Printer) { } })* }; @@ -86,7 +92,7 @@ macro_rules! print_skip { macro_rules! print_disp { ($($t: ty),* $(,)?) => {$( impl PrintAttribute for $t { - fn print_something(&self) -> bool { true } + fn should_render(&self) -> bool { true } fn print_attribute(&self, p: &mut Printer) { p.word(format!("{}", self)); } @@ -96,7 +102,7 @@ macro_rules! print_disp { macro_rules! print_debug { ($($t: ty),* $(,)?) => {$( impl PrintAttribute for $t { - fn print_something(&self) -> bool { true } + fn should_render(&self) -> bool { true } fn print_attribute(&self, p: &mut Printer) { p.word(format!("{:?}", self)); } @@ -105,29 +111,29 @@ macro_rules! print_debug { } macro_rules! print_tup { - (num_print_something $($ts: ident)*) => { 0 $(+ $ts.print_something() as usize)* }; + (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* }; () => {}; ($t: ident $($ts: ident)*) => { #[allow(non_snake_case, unused)] impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) { - fn print_something(&self) -> bool { + fn should_render(&self) -> bool { let ($t, $($ts),*) = self; - print_tup!(num_print_something $t $($ts)*) != 0 + print_tup!(num_should_render $t $($ts)*) != 0 } fn print_attribute(&self, p: &mut Printer) { let ($t, $($ts),*) = self; - let parens = print_tup!(num_print_something $t $($ts)*) > 1; + let parens = print_tup!(num_should_render $t $($ts)*) > 1; if parens { p.word("("); } - let mut printed_anything = $t.print_something(); + let mut printed_anything = $t.should_render(); $t.print_attribute(p); $( - if printed_anything && $ts.print_something() { + if $ts.should_render() { p.word_space(","); printed_anything = true; } diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs index 3c6e30b851bf7..fe78fb15cb95a 100644 --- a/compiler/rustc_macros/src/print_attribute.rs +++ b/compiler/rustc_macros/src/print_attribute.rs @@ -16,7 +16,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok let name = field.ident.as_ref().unwrap(); let string_name = name.to_string(); disps.push(quote! { - if __printed_anything && #name.print_something() { + if __printed_anything && #name.should_render() { __p.word_space(","); __printed_anything = true; } @@ -31,7 +31,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok quote! { {#(#field_names),*} }, quote! { __p.word(#string_name); - if true #(&& !#field_names.print_something())* { + if true #(&& !#field_names.should_render())* { return; } @@ -48,7 +48,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok for idx in 0..fields_unnamed.unnamed.len() { let name = format_ident!("f{idx}"); disps.push(quote! { - if __printed_anything && #name.print_something() { + if __printed_anything && #name.should_render() { __p.word_space(","); __printed_anything = true; } @@ -62,7 +62,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok quote! { __p.word(#string_name); - if true #(&& !#field_names.print_something())* { + if true #(&& !#field_names.should_render())* { return; } @@ -138,7 +138,7 @@ pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream { input.gen_impl(quote! { #[allow(unused)] gen impl PrintAttribute for @Self { - fn print_something(&self) -> bool { #printed } + fn should_render(&self) -> bool { #printed } fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code } } }) From 279377f87aa1871e1011366b6cf997cfa24e3d65 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 5 Mar 2025 15:20:16 +0000 Subject: [PATCH 06/42] Fix pretty printing of parsed attrs in hir_pretty --- .../rustc_attr_data_structures/src/lib.rs | 12 ++++++----- compiler/rustc_hir_pretty/src/lib.rs | 4 ++-- compiler/rustc_macros/src/print_attribute.rs | 21 ++++++++++++------- tests/pretty/hir-pretty-attr.pp | 2 +- .../rustdoc-json/enums/discriminant/struct.rs | 2 +- .../rustdoc-json/enums/discriminant/tuple.rs | 2 +- tests/ui/unpretty/deprecated-attr.rs | 2 -- tests/ui/unpretty/deprecated-attr.stdout | 21 ++++++++----------- 8 files changed, 34 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index 16ff4183ef5f6..bbd3308809c33 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -125,7 +125,7 @@ macro_rules! print_tup { let ($t, $($ts),*) = self; let parens = print_tup!(num_should_render $t $($ts)*) > 1; if parens { - p.word("("); + p.popen(); } let mut printed_anything = $t.should_render(); @@ -134,14 +134,16 @@ macro_rules! print_tup { $( if $ts.should_render() { - p.word_space(","); + if printed_anything { + p.word_space(","); + } printed_anything = true; } $ts.print_attribute(p); )* if parens { - p.word(")"); + p.pclose(); } } } @@ -152,8 +154,8 @@ macro_rules! print_tup { print_tup!(A B C D E F G H); print_skip!(Span, ()); -print_disp!(Symbol, u16, bool, NonZero); -print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); +print_disp!(u16, bool, NonZero); +print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); /// Finds attributes in sequences of attributes by pattern matching. /// diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 0e3721126fb33..2769b5343a05d 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -117,9 +117,9 @@ impl<'a> State<'a> { self.hardbreak() } hir::Attribute::Parsed(pa) => { - self.word("#[attr=\""); + self.word("#[attr = "); pa.print_attribute(self); - self.word("\")]"); + self.word("]"); self.hardbreak() } } diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs index fe78fb15cb95a..42d94e72ee942 100644 --- a/compiler/rustc_macros/src/print_attribute.rs +++ b/compiler/rustc_macros/src/print_attribute.rs @@ -16,12 +16,14 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok let name = field.ident.as_ref().unwrap(); let string_name = name.to_string(); disps.push(quote! { - if __printed_anything && #name.should_render() { - __p.word_space(","); + if #name.should_render() { + if __printed_anything { + __p.word_space(","); + } + __p.word(#string_name); + __p.word_space(":"); __printed_anything = true; } - __p.word(#string_name); - __p.word_space(":"); #name.print_attribute(__p); }); field_names.push(name); @@ -35,6 +37,7 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok return; } + __p.nbsp(); __p.word("{"); #(#disps)* __p.word("}"); @@ -48,8 +51,10 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok for idx in 0..fields_unnamed.unnamed.len() { let name = format_ident!("f{idx}"); disps.push(quote! { - if __printed_anything && #name.should_render() { - __p.word_space(","); + if #name.should_render() { + if __printed_anything { + __p.word_space(","); + } __printed_anything = true; } #name.print_attribute(__p); @@ -66,9 +71,9 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok return; } - __p.word("("); + __p.popen(); #(#disps)* - __p.word(")"); + __p.pclose(); }, quote! { true }, ) diff --git a/tests/pretty/hir-pretty-attr.pp b/tests/pretty/hir-pretty-attr.pp index 586810b004662..d8cc8c424ca5f 100644 --- a/tests/pretty/hir-pretty-attr.pp +++ b/tests/pretty/hir-pretty-attr.pp @@ -6,6 +6,6 @@ //@ pretty-mode:hir //@ pp-exact:hir-pretty-attr.pp -#[attr="Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])")] +#[attr = Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])] struct Example { } diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index 82437f5ef03bb..f2bed77902b03 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,5 +1,5 @@ #[repr(i32)] -//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr=\"Repr([ReprInt(SignedInt(I32))])\")]\n"]' +//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' pub enum Foo { //@ is "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null //@ count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index 25bba07e8f796..201c1cdc88e7e 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,5 +1,5 @@ #[repr(u32)] -//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr=\"Repr([ReprInt(UnsignedInt(U32))])\")]\n"]' +//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(U32))])]\n"]' pub enum Foo { //@ is "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null //@ count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 diff --git a/tests/ui/unpretty/deprecated-attr.rs b/tests/ui/unpretty/deprecated-attr.rs index 24a32d8a9acf9..dda362a595e24 100644 --- a/tests/ui/unpretty/deprecated-attr.rs +++ b/tests/ui/unpretty/deprecated-attr.rs @@ -1,8 +1,6 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass -// FIXME(jdonszelmann): the pretty printing output for deprecated (and possibly more attrs) is -// slightly broken. #[deprecated] pub struct PlainDeprecated; diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index 675351351a0c6..42de7b4533e51 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -5,24 +5,21 @@ extern crate std; //@ compile-flags: -Zunpretty=hir //@ check-pass -// FIXME(jdonszelmann): the pretty printing output for deprecated (and possibly more attrs) is -// slightly broken. -#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote: -suggestion: }span: }")] +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] struct PlainDeprecated; -#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote: -here's why this is deprecatedsuggestion: }span: }")] +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note: +"here's why this is deprecated"}}] struct DirectNote; -#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote: -here's why this is deprecatedsuggestion: }span: }")] +#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note: +"here's why this is deprecated"}}] struct ExplicitNote; -#[attr="Deprecation{deprecation: Deprecation{since: NonStandard(1.2.3)note: -here's why this is deprecatedsuggestion: }span: }")] +#[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), +note: "here's why this is deprecated"}}] struct SinceAndNote; -#[attr="Deprecation{deprecation: Deprecation{since: NonStandard(1.2.3)note: -here's why this is deprecatedsuggestion: }span: }")] +#[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), +note: "here's why this is deprecated"}}] struct FlippedOrder; From f525b173edd08cf68f025a5b2db38b665887771d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 10 Mar 2025 02:31:16 +0000 Subject: [PATCH 07/42] Remove AdtFlags::IS_ANONYMOUS and Copy/Clone condition for anonymous ADT --- compiler/rustc_middle/src/ty/adt.rs | 8 -------- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_trait_selection/src/traits/select/mod.rs | 9 --------- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 3585f28b4a550..c1dc6a894cae5 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -53,8 +53,6 @@ bitflags::bitflags! { const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; /// Indicates whether the type is `UnsafeCell`. const IS_UNSAFE_CELL = 1 << 9; - /// Indicates whether the type is anonymous. - const IS_ANONYMOUS = 1 << 10; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -402,12 +400,6 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } - /// Returns `true` if this is an anonymous adt - #[inline] - pub fn is_anonymous(self) -> bool { - self.flags().contains(AdtFlags::IS_ANONYMOUS) - } - /// Returns `true` if this type has a destructor. pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool { self.destructor(tcx).is_some() diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c5509c0a6087e..97cfe5946af15 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1151,7 +1151,7 @@ pub struct VariantDef { /// `DefId` that identifies the variant's constructor. /// If this variant is a struct variant, then this is `None`. pub ctor: Option<(CtorKind, DefId)>, - /// Variant or struct name, maybe empty for anonymous adt (struct or union). + /// Variant or struct name. pub name: Symbol, /// Discriminant of this variant. pub discr: VariantDiscr, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 0a54b8468fe3c..e1adabbeaa662 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2231,15 +2231,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - // `Copy` and `Clone` are automatically implemented for an anonymous adt - // if all of its fields are `Copy` and `Clone` - ty::Adt(adt, args) if adt.is_anonymous() => { - // (*) binder moved here - Where(obligation.predicate.rebind( - adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect(), - )) - } - ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { // Fallback to whatever user-defined impls exist in this case. None From b827087a41869d4ad01398eefa7b491e2c68b1e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Mar 2025 08:33:53 +0100 Subject: [PATCH 08/42] add tracking issue for unqualified_local_imports --- compiler/rustc_feature/src/unstable.rs | 2 +- .../feature-gates/feature-gate-unqualified-local-imports.stderr | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 7741f6668c382..3c61bfd1c93f5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -240,7 +240,7 @@ declare_features! ( /// Added for testing unstable lints; perma-unstable. (internal, test_unstable_lint, "1.60.0", None), /// Helps with formatting for `group_imports = "StdExternalCrate"`. - (unstable, unqualified_local_imports, "1.83.0", None), + (unstable, unqualified_local_imports, "1.83.0", Some(138299)), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. (unstable, with_negative_coherence, "1.60.0", None), diff --git a/tests/ui/feature-gates/feature-gate-unqualified-local-imports.stderr b/tests/ui/feature-gates/feature-gate-unqualified-local-imports.stderr index bc8edd847cc0f..30e36acb871a4 100644 --- a/tests/ui/feature-gates/feature-gate-unqualified-local-imports.stderr +++ b/tests/ui/feature-gates/feature-gate-unqualified-local-imports.stderr @@ -5,6 +5,7 @@ LL | #![allow(unqualified_local_imports)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `unqualified_local_imports` lint is unstable + = note: see issue #138299 for more information = help: add `#![feature(unqualified_local_imports)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: `#[warn(unknown_lints)]` on by default From 02bb2d4410d4db07c40bed308f8ba0d2af28d069 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Tue, 4 Mar 2025 14:31:03 +0000 Subject: [PATCH 09/42] Disable CFI for weakly linked syscalls Currently, when enabling CFI via -Zsanitizer=cfi and executing e.g. std::sys::random::getrandom, we can observe a CFI violation. This is the case for all consumers of the std::sys::pal::weak::weak macro, as it is defining weak functions which don't show up in LLVM IR metadata. CFI fails for all these functions. Similar to other such cases in https://github.com/rust-lang/rust/issues/115199, this change stops emitting the CFI typecheck for consumers of the macro via the \#[no_sanitize(cfi)] attribute. --- library/std/src/sys/fs/unix.rs | 12 ++++++++++++ library/std/src/sys/pal/unix/fd.rs | 1 + library/std/src/sys/pal/unix/process/process_unix.rs | 1 + library/std/src/sys/pal/unix/thread.rs | 1 + library/std/src/sys/pal/unix/time.rs | 9 +++++++++ library/std/src/sys/pal/unix/weak.rs | 3 +++ 6 files changed, 27 insertions(+) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 914971934bfb0..d95735978c199 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1454,6 +1454,18 @@ impl File { Ok(()) } + #[cfg_attr( + any( + target_os = "android", + all( + target_os = "linux", + target_env = "gnu", + target_pointer_width = "32", + not(target_arch = "riscv32") + ) + ), + no_sanitize(cfi) + )] pub fn set_times(&self, times: FileTimes) -> io::Result<()> { #[cfg(not(any( target_os = "redox", diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 2fc33bdfefbf5..6da329288f746 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -251,6 +251,7 @@ impl FileDesc { } #[cfg(all(target_os = "android", target_pointer_width = "32"))] + #[no_sanitize(cfi)] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 25d9e9353320f..6d3680d231e6b 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -434,6 +434,7 @@ impl Command { target_os = "nto", target_vendor = "apple", ))] + #[cfg_attr(target_os = "linux", no_sanitize(cfi))] fn posix_spawn( &mut self, stdio: &ChildPipes, diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 11f6998cac118..33db8e6939a4d 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -188,6 +188,7 @@ impl Thread { } #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] + #[no_sanitize(cfi)] pub fn set_name(name: &CStr) { weak! { fn pthread_setname_np( diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 0271626380c5f..fc60c307f34e1 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -96,6 +96,15 @@ impl Timespec { } } + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_pointer_width = "32", + not(target_arch = "riscv32") + ), + no_sanitize(cfi) + )] pub fn now(clock: libc::clockid_t) -> Timespec { use crate::mem::MaybeUninit; use crate::sys::cvt; diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index 7ec4787f1eab7..9a718b71f4696 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -144,6 +144,9 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + // FIXME: Rust currently omits weak function definitions + // and its metadata from LLVM IR. + #[no_sanitize(cfi)] unsafe fn $name($($arg_name: $t),*) -> $ret { weak! { fn $name($($t),*) -> $ret } From e5dc1e378619b11b296a953ca08abb2cdf38f9e0 Mon Sep 17 00:00:00 2001 From: Bastian Kersting Date: Mon, 10 Mar 2025 08:59:24 +0000 Subject: [PATCH 10/42] Add comments for #[no_sanitize(cfi)] in stdlib --- library/std/src/sys/fs/unix.rs | 2 ++ library/std/src/sys/pal/unix/fd.rs | 2 ++ library/std/src/sys/pal/unix/process/process_unix.rs | 2 ++ library/std/src/sys/pal/unix/thread.rs | 2 ++ library/std/src/sys/pal/unix/time.rs | 2 ++ library/std/src/sys/pal/unix/weak.rs | 2 +- 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index d95735978c199..d944bc9c9a2a0 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1454,6 +1454,8 @@ impl File { Ok(()) } + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. #[cfg_attr( any( target_os = "android", diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 6da329288f746..a08c7ccec2da3 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -251,6 +251,8 @@ impl FileDesc { } #[cfg(all(target_os = "android", target_pointer_width = "32"))] + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. #[no_sanitize(cfi)] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index 6d3680d231e6b..be9a7e919905f 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -434,6 +434,8 @@ impl Command { target_os = "nto", target_vendor = "apple", ))] + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. #[cfg_attr(target_os = "linux", no_sanitize(cfi))] fn posix_spawn( &mut self, diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 33db8e6939a4d..abe8d3fbf681e 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -188,6 +188,8 @@ impl Thread { } #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. #[no_sanitize(cfi)] pub fn set_name(name: &CStr) { weak! { diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index fc60c307f34e1..c0a3044660b7e 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -96,6 +96,8 @@ impl Timespec { } } + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. #[cfg_attr( all( target_os = "linux", diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index 9a718b71f4696..ce3f66a83748b 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -144,7 +144,7 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( - // FIXME: Rust currently omits weak function definitions + // FIXME(#115199): Rust currently omits weak function definitions // and its metadata from LLVM IR. #[no_sanitize(cfi)] unsafe fn $name($($arg_name: $t),*) -> $ret { From fb9ce0297682a0c54fe374800c2a41cc666d9580 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 12 Feb 2025 16:59:13 +0100 Subject: [PATCH 11/42] Limit formatting width and precision to 16 bits. --- compiler/rustc_ast/src/format.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 11 +++++ compiler/rustc_ast_lowering/src/format.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 18 ++++---- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/fmt/float.rs | 12 ++--- library/core/src/fmt/mod.rs | 51 ++++++++++++---------- library/core/src/fmt/rt.rs | 13 ++++-- library/core/src/time.rs | 3 +- library/coretests/tests/num/flt2dec/mod.rs | 2 +- 10 files changed, 69 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index b93846c1fe6f3..b611ddea1d9f1 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -266,7 +266,7 @@ pub enum FormatAlignment { #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` - Literal(usize), + Literal(u16), /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. Argument(FormatArgPosition), } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index acf35b75e4df3..0f175ea615f6e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2152,6 +2152,17 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(sp, hir::ExprKind::Lit(lit)) } + pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> { + let lit = self.arena.alloc(hir::Lit { + span: sp, + node: ast::LitKind::Int( + u128::from(value).into(), + ast::LitIntType::Unsigned(ast::UintTy::U16), + ), + }); + self.expr(sp, hir::ExprKind::Lit(lit)) + } + pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Char(value) }); self.expr(sp, hir::ExprKind::Lit(lit)) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 07b94dbc2aebd..faa47274f96ce 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -292,7 +292,7 @@ fn make_count<'hir>( hir::LangItem::FormatCount, sym::Is, )); - let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]); + let value = ctx.arena.alloc_from_iter([ctx.expr_u16(sp, *n)]); ctx.expr_call_mut(sp, count_is, value) } Some(FormatCount::Argument(arg)) => { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 287bd8678da25..5b8a2fe52d3f5 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -189,7 +189,7 @@ pub enum DebugHex { #[derive(Copy, Clone, Debug, PartialEq)] pub enum Count<'a> { /// The count is specified explicitly. - CountIs(usize), + CountIs(u16), /// The count is specified by the argument with the given name. CountIsName(&'a str, InnerSpan), /// The count is specified by the argument at the given index. @@ -564,7 +564,7 @@ impl<'a> Parser<'a> { /// consuming a macro argument, `None` if it's the case. fn position(&mut self) -> Option> { if let Some(i) = self.integer() { - Some(ArgumentIs(i)) + Some(ArgumentIs(i.into())) } else { match self.cur.peek() { Some(&(lo, c)) if rustc_lexer::is_id_start(c) => { @@ -770,7 +770,7 @@ impl<'a> Parser<'a> { /// width. fn count(&mut self, start: usize) -> Count<'a> { if let Some(i) = self.integer() { - if self.consume('$') { CountIsParam(i) } else { CountIs(i) } + if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) } } else { let tmp = self.cur.clone(); let word = self.word(); @@ -821,15 +821,15 @@ impl<'a> Parser<'a> { word } - fn integer(&mut self) -> Option { - let mut cur: usize = 0; + fn integer(&mut self) -> Option { + let mut cur: u16 = 0; let mut found = false; let mut overflow = false; let start = self.current_pos(); while let Some(&(_, c)) = self.cur.peek() { if let Some(i) = c.to_digit(10) { let (tmp, mul_overflow) = cur.overflowing_mul(10); - let (tmp, add_overflow) = tmp.overflowing_add(i as usize); + let (tmp, add_overflow) = tmp.overflowing_add(i as u16); if mul_overflow || add_overflow { overflow = true; } @@ -846,11 +846,11 @@ impl<'a> Parser<'a> { let overflowed_int = &self.input[start..end]; self.err( format!( - "integer `{}` does not fit into the type `usize` whose range is `0..={}`", + "integer `{}` does not fit into the type `u16` whose range is `0..={}`", overflowed_int, - usize::MAX + u16::MAX ), - "integer out of range for `usize`", + "integer out of range for `u16`", self.span(start, end), ); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9e7f5047eb30c..8b701de34545c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1016,6 +1016,7 @@ symbols! { from_residual, from_size_align_unchecked, from_str_method, + from_u16, from_usize, from_yeet, fs_create_dir, diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 3f10158193d76..4a43c12be9aaa 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -29,7 +29,7 @@ fn float_to_decimal_common_exact( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, ) -> Result where T: flt2dec::DecodableFloat, @@ -40,7 +40,7 @@ where flt2dec::strategy::grisu::format_exact, *num, sign, - precision, + precision.into(), &mut buf, &mut parts, ); @@ -55,7 +55,7 @@ fn float_to_decimal_common_shortest( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, ) -> Result where T: flt2dec::DecodableFloat, @@ -68,7 +68,7 @@ where flt2dec::strategy::grisu::format_shortest, *num, sign, - precision, + precision.into(), &mut buf, &mut parts, ); @@ -101,7 +101,7 @@ fn float_to_exponential_common_exact( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, upper: bool, ) -> Result where @@ -113,7 +113,7 @@ where flt2dec::strategy::grisu::format_exact, *num, sign, - precision, + precision.into(), upper, &mut buf, &mut parts, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 3f60bb067d6e6..e0dc632df7051 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -294,8 +294,8 @@ pub struct FormattingOptions { flags: u32, fill: char, align: Option, - width: Option, - precision: Option, + width: Option, + precision: Option, } impl FormattingOptions { @@ -389,7 +389,7 @@ impl FormattingOptions { /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn width(&mut self, width: Option) -> &mut Self { + pub fn width(&mut self, width: Option) -> &mut Self { self.width = width; self } @@ -403,7 +403,7 @@ impl FormattingOptions { /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn precision(&mut self, precision: Option) -> &mut Self { + pub fn precision(&mut self, precision: Option) -> &mut Self { self.precision = precision; self } @@ -455,12 +455,12 @@ impl FormattingOptions { } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn get_width(&self) -> Option { + pub const fn get_width(&self) -> Option { self.width } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn get_precision(&self) -> Option { + pub const fn get_precision(&self) -> Option { self.precision } /// Returns the current precision. @@ -1499,15 +1499,18 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume unsafe { value.fmt(fmt) } } -unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { +unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { match *cnt { + #[cfg(bootstrap)] + rt::Count::Is(n) => Some(n as u16), + #[cfg(not(bootstrap))] rt::Count::Is(n) => Some(n), rt::Count::Implied => None, rt::Count::Param(i) => { debug_assert!(i < args.len()); // SAFETY: cnt and args come from the same Arguments, // which guarantees this index is always within bounds. - unsafe { args.get_unchecked(i).as_usize() } + unsafe { args.get_unchecked(i).as_u16() } } } } @@ -1516,11 +1519,11 @@ unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option #[must_use = "don't forget to write the post padding"] pub(crate) struct PostPadding { fill: char, - padding: usize, + padding: u16, } impl PostPadding { - fn new(fill: char, padding: usize) -> PostPadding { + fn new(fill: char, padding: u16) -> PostPadding { PostPadding { fill, padding } } @@ -1634,7 +1637,7 @@ impl<'a> Formatter<'a> { } // Check if we're over the minimum width, if so then we can also // just write the bytes. - Some(min) if width >= min => { + Some(min) if width >= usize::from(min) => { write_prefix(self, sign, prefix)?; self.buf.write_str(buf) } @@ -1645,7 +1648,7 @@ impl<'a> Formatter<'a> { let old_align = crate::mem::replace(&mut self.options.align, Some(Alignment::Right)); write_prefix(self, sign, prefix)?; - let post_padding = self.padding(min - width, Alignment::Right)?; + let post_padding = self.padding(min - width as u16, Alignment::Right)?; self.buf.write_str(buf)?; post_padding.write(self)?; self.options.fill = old_fill; @@ -1654,7 +1657,7 @@ impl<'a> Formatter<'a> { } // Otherwise, the sign and prefix goes after the padding Some(min) => { - let post_padding = self.padding(min - width, Alignment::Right)?; + let post_padding = self.padding(min - width as u16, Alignment::Right)?; write_prefix(self, sign, prefix)?; self.buf.write_str(buf)?; post_padding.write(self) @@ -1702,14 +1705,14 @@ impl<'a> Formatter<'a> { // string being formatted. let (s, char_count) = if let Some(max_char_count) = self.options.precision { let mut iter = s.char_indices(); - let remaining = match iter.advance_by(max_char_count) { + let remaining = match iter.advance_by(usize::from(max_char_count)) { Ok(()) => 0, Err(remaining) => remaining.get(), }; // SAFETY: The offset of `.char_indices()` is guaranteed to be // in-bounds and between character boundaries. let truncated = unsafe { s.get_unchecked(..iter.offset()) }; - (truncated, max_char_count - remaining) + (truncated, usize::from(max_char_count) - remaining) } else { // Use the optimized char counting algorithm for the full string. (s, s.chars().count()) @@ -1717,11 +1720,11 @@ impl<'a> Formatter<'a> { // The `width` field is more of a minimum width parameter at this point. if let Some(width) = self.options.width - && char_count < width + && char_count < usize::from(width) { // If we're under the minimum width, then fill up the minimum width // with the specified string + some alignment. - let post_padding = self.padding(width - char_count, Alignment::Left)?; + let post_padding = self.padding(width - char_count as u16, Alignment::Left)?; self.buf.write_str(s)?; post_padding.write(self) } else { @@ -1737,7 +1740,7 @@ impl<'a> Formatter<'a> { /// thing that is being padded. pub(crate) fn padding( &mut self, - padding: usize, + padding: u16, default: Alignment, ) -> result::Result { let align = self.align().unwrap_or(default); @@ -1777,19 +1780,19 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; - width = width.saturating_sub(sign.len()); + width = width.saturating_sub(sign.len() as u16); self.options.fill = '0'; self.options.align = Some(Alignment::Right); } // remaining parts go through the ordinary padding process. let len = formatted.len(); - let ret = if width <= len { + let ret = if usize::from(width) <= len { // no padding // SAFETY: Per the precondition. unsafe { self.write_formatted_parts(&formatted) } } else { - let post_padding = self.padding(width - len, Alignment::Right)?; + let post_padding = self.padding(width - len as u16, Alignment::Right)?; // SAFETY: Per the precondition. unsafe { self.write_formatted_parts(&formatted)?; @@ -2021,7 +2024,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.options.width + self.options.width.map(|x| x as usize) } /// Returns the optionally specified precision for numeric types. @@ -2052,7 +2055,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.options.precision + self.options.precision.map(|x| x as usize) } /// Determines if the `+` flag was specified. @@ -2792,7 +2795,7 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); if f.options.width.is_none() { - f.options.width = Some((usize::BITS / 4) as usize + 2); + f.options.width = Some((usize::BITS / 4) as u16 + 2); } } f.options.flags |= 1 << (rt::Flag::Alternate as u32); diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 85d089a079082..cb908adc1cbaf 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -47,7 +47,11 @@ pub enum Alignment { #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value + #[cfg(bootstrap)] Is(usize), + /// Specified with a literal number, stores the value + #[cfg(not(bootstrap))] + Is(u16), /// Specified using `$` and `*` syntaxes, stores the index into `args` Param(usize), /// Not specified @@ -74,7 +78,7 @@ enum ArgumentType<'a> { formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result, _lifetime: PhantomData<&'a ()>, }, - Count(usize), + Count(u16), } /// This struct represents a generic "argument" which is taken by format_args!(). @@ -151,7 +155,10 @@ impl Argument<'_> { } #[inline] pub const fn from_usize(x: &usize) -> Argument<'_> { - Argument { ty: ArgumentType::Count(*x) } + if *x > u16::MAX as usize { + panic!("Formatting argument out of range"); + }; + Argument { ty: ArgumentType::Count(*x as u16) } } /// Format this placeholder argument. @@ -181,7 +188,7 @@ impl Argument<'_> { } #[inline] - pub(super) const fn as_usize(&self) -> Option { + pub(super) const fn as_u16(&self) -> Option { match self.ty { ArgumentType::Count(count) => Some(count), ArgumentType::Placeholder { .. } => None, diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 8b211b442eab6..37b5c1076fa2a 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1377,7 +1377,8 @@ impl fmt::Debug for Duration { } else { // We need to add padding. Use the `Formatter::padding` helper function. let default_align = fmt::Alignment::Left; - let post_padding = f.padding(requested_w - actual_w, default_align)?; + let post_padding = + f.padding((requested_w - actual_w) as u16, default_align)?; emit_without_padding(f)?; post_padding.write(f) } diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs index 6041923117c2a..6e74cc91c5b27 100644 --- a/library/coretests/tests/num/flt2dec/mod.rs +++ b/library/coretests/tests/num/flt2dec/mod.rs @@ -577,7 +577,7 @@ where } // very large output - assert_eq!(to_string(f, 1.1, Minus, 80000), format!("1.1{:0>79999}", "")); + assert_eq!(to_string(f, 1.1, Minus, 50000), format!("1.1{:0>49999}", "")); } pub fn to_shortest_exp_str_test(mut f_: F) From 4374d5461e9a4041dcbd7413c79fced0bec333fc Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 12 Feb 2025 17:33:05 +0100 Subject: [PATCH 12/42] Update tests. --- library/coretests/tests/num/flt2dec/mod.rs | 28 +-- ...nential_common.GVN.32bit.panic-abort.diff} | 45 ++++- ...ential_common.GVN.32bit.panic-unwind.diff} | 45 ++++- ...onential_common.GVN.64bit.panic-abort.diff | 180 ++++++++++++++++++ ...nential_common.GVN.64bit.panic-unwind.diff | 180 ++++++++++++++++++ tests/mir-opt/funky_arms.rs | 1 + 6 files changed, 459 insertions(+), 20 deletions(-) rename tests/mir-opt/{funky_arms.float_to_exponential_common.GVN.panic-abort.diff => funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff} (73%) rename tests/mir-opt/{funky_arms.float_to_exponential_common.GVN.panic-unwind.diff => funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff} (73%) create mode 100644 tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff create mode 100644 tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs index 6e74cc91c5b27..c64bb0a30720a 100644 --- a/library/coretests/tests/num/flt2dec/mod.rs +++ b/library/coretests/tests/num/flt2dec/mod.rs @@ -914,22 +914,22 @@ where ); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", "")); + assert_eq!(to_string(f, 0.0, Minus, 50000, false), format!("0.{:0>49999}e0", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 50000, false), format!("1.{:0>49999}e1", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 50000, false), format!("1.{:0>49999}e0", "")); assert_eq!( - to_string(f, 1.0e-1, Minus, 80000, false), + to_string(f, 1.0e-1, Minus, 50000, false), format!( - "1.000000000000000055511151231257827021181583404541015625{:0>79945}\ + "1.000000000000000055511151231257827021181583404541015625{:0>49945}\ e-1", "" ) ); assert_eq!( - to_string(f, 1.0e-20, Minus, 80000, false), + to_string(f, 1.0e-20, Minus, 50000, false), format!( "9.999999999999999451532714542095716517295037027873924471077157760\ - 66783064379706047475337982177734375{:0>79901}e-21", + 66783064379706047475337982177734375{:0>49901}e-21", "" ) ); @@ -1150,18 +1150,18 @@ where ); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000), format!("0.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000), format!("10.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000), format!("1.{:0>80000}", "")); + assert_eq!(to_string(f, 0.0, Minus, 50000), format!("0.{:0>50000}", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 50000), format!("10.{:0>50000}", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 50000), format!("1.{:0>50000}", "")); assert_eq!( - to_string(f, 1.0e-1, Minus, 80000), - format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "") + to_string(f, 1.0e-1, Minus, 50000), + format!("0.1000000000000000055511151231257827021181583404541015625{:0>49945}", "") ); assert_eq!( - to_string(f, 1.0e-20, Minus, 80000), + to_string(f, 1.0e-20, Minus, 50000), format!( "0.0000000000000000000099999999999999994515327145420957165172950370\ - 2787392447107715776066783064379706047475337982177734375{:0>79881}", + 2787392447107715776066783064379706047475337982177734375{:0>49881}", "" ) ); diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff similarity index 73% rename from tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff rename to tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff index a1be927e1c04a..45fc7365d8d6c 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-abort.diff @@ -29,6 +29,16 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { + let mut _22: std::option::Option; + scope 6 (inlined Option::::map::::precision::{closure#0}}>) { + let mut _23: isize; + let _24: u16; + let mut _25: usize; + scope 7 { + scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { + } + } + } } } } @@ -65,9 +75,12 @@ bb3: { StorageLive(_6); - _6 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); - _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; + StorageLive(_24); + StorageLive(_22); + _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); + StorageLive(_23); + _23 = discriminant(_22); + switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; } bb4: { @@ -135,7 +148,33 @@ } bb9: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_24); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + } + + bb10: { unreachable; } + + bb11: { + _6 = const Option::::None; + goto -> bb9; + } + + bb12: { + _24 = move ((_22 as Some).0: u16); + StorageLive(_25); + _25 = copy _24 as usize (IntToInt); + _6 = Option::::Some(move _25); + StorageDead(_25); + goto -> bb9; + } + } + + ALLOC0 (size: 8, align: 4) { + 00 00 00 00 __ __ __ __ │ ....░░░░ } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff similarity index 73% rename from tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff rename to tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff index 87ab71feb2faa..578d2c2194b0e 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.32bit.panic-unwind.diff @@ -29,6 +29,16 @@ debug precision => _8; let _8: usize; scope 5 (inlined Formatter::<'_>::precision) { + let mut _22: std::option::Option; + scope 6 (inlined Option::::map::::precision::{closure#0}}>) { + let mut _23: isize; + let _24: u16; + let mut _25: usize; + scope 7 { + scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { + } + } + } } } } @@ -65,9 +75,12 @@ bb3: { StorageLive(_6); - _6 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); - _7 = discriminant(_6); - switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb9]; + StorageLive(_24); + StorageLive(_22); + _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); + StorageLive(_23); + _23 = discriminant(_22); + switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; } bb4: { @@ -135,7 +148,33 @@ } bb9: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_24); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + } + + bb10: { unreachable; } + + bb11: { + _6 = const Option::::None; + goto -> bb9; + } + + bb12: { + _24 = move ((_22 as Some).0: u16); + StorageLive(_25); + _25 = copy _24 as usize (IntToInt); + _6 = Option::::Some(move _25); + StorageDead(_25); + goto -> bb9; + } + } + + ALLOC0 (size: 8, align: 4) { + 00 00 00 00 __ __ __ __ │ ....░░░░ } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff new file mode 100644 index 0000000000000..5f0f7d6cc74fb --- /dev/null +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-abort.diff @@ -0,0 +1,180 @@ +- // MIR for `float_to_exponential_common` before GVN ++ // MIR for `float_to_exponential_common` after GVN + + fn float_to_exponential_common(_1: &mut Formatter<'_>, _2: &T, _3: bool) -> Result<(), std::fmt::Error> { + debug fmt => _1; + debug num => _2; + debug upper => _3; + let mut _0: std::result::Result<(), std::fmt::Error>; + let _4: bool; + let mut _6: std::option::Option; + let mut _7: isize; + let mut _9: &mut std::fmt::Formatter<'_>; + let mut _10: &T; + let mut _11: core::num::flt2dec::Sign; + let mut _12: u32; + let mut _13: u32; + let mut _14: usize; + let mut _15: bool; + let mut _16: &mut std::fmt::Formatter<'_>; + let mut _17: &T; + let mut _18: core::num::flt2dec::Sign; + let mut _19: bool; + scope 1 { + debug force_sign => _4; + let _5: core::num::flt2dec::Sign; + scope 2 { + debug sign => _5; + scope 3 { + debug precision => _8; + let _8: usize; + scope 5 (inlined Formatter::<'_>::precision) { + let mut _22: std::option::Option; + scope 6 (inlined Option::::map::::precision::{closure#0}}>) { + let mut _23: isize; + let _24: u16; + let mut _25: usize; + scope 7 { + scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { + } + } + } + } + } + } + } + scope 4 (inlined Formatter::<'_>::sign_plus) { + let mut _20: u32; + let mut _21: u32; + } + + bb0: { + StorageLive(_4); + StorageLive(_20); + StorageLive(_21); + _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _20 = BitAnd(move _21, const 1_u32); + StorageDead(_21); + _4 = Ne(move _20, const 0_u32); + StorageDead(_20); + StorageLive(_5); + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { +- _5 = MinusPlus; ++ _5 = const MinusPlus; + goto -> bb3; + } + + bb2: { +- _5 = core::num::flt2dec::Sign::Minus; ++ _5 = const core::num::flt2dec::Sign::Minus; + goto -> bb3; + } + + bb3: { + StorageLive(_6); + StorageLive(_24); + StorageLive(_22); + _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); + StorageLive(_23); + _23 = discriminant(_22); + switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + } + + bb4: { +- StorageLive(_8); ++ nop; + _8 = copy ((_6 as Some).0: usize); + StorageLive(_9); + _9 = copy _1; + StorageLive(_10); + _10 = copy _2; + StorageLive(_11); + _11 = copy _5; + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + _14 = copy _8; +- _13 = move _14 as u32 (IntToInt); ++ _13 = copy _8 as u32 (IntToInt); + StorageDead(_14); + _12 = Add(move _13, const 1_u32); + StorageDead(_13); + StorageLive(_15); + _15 = copy _3; +- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind unreachable]; ++ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _11, move _12, copy _3) -> [return: bb5, unwind unreachable]; + } + + bb5: { + StorageDead(_15); + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); +- StorageDead(_8); ++ nop; + goto -> bb8; + } + + bb6: { + StorageLive(_16); + _16 = copy _1; + StorageLive(_17); + _17 = copy _2; + StorageLive(_18); + _18 = copy _5; + StorageLive(_19); + _19 = copy _3; +- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind unreachable]; ++ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _18, copy _3) -> [return: bb7, unwind unreachable]; + } + + bb7: { + StorageDead(_19); + StorageDead(_18); + StorageDead(_17); + StorageDead(_16); + goto -> bb8; + } + + bb8: { + StorageDead(_5); + StorageDead(_4); + StorageDead(_6); + return; + } + + bb9: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_24); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + } + + bb10: { + unreachable; + } + + bb11: { + _6 = const Option::::None; + goto -> bb9; + } + + bb12: { + _24 = move ((_22 as Some).0: u16); + StorageLive(_25); + _25 = copy _24 as usize (IntToInt); + _6 = Option::::Some(move _25); + StorageDead(_25); + goto -> bb9; + } + } + + ALLOC0 (size: 16, align: 8) { + 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ + } + diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff new file mode 100644 index 0000000000000..10cc46a8b8285 --- /dev/null +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.64bit.panic-unwind.diff @@ -0,0 +1,180 @@ +- // MIR for `float_to_exponential_common` before GVN ++ // MIR for `float_to_exponential_common` after GVN + + fn float_to_exponential_common(_1: &mut Formatter<'_>, _2: &T, _3: bool) -> Result<(), std::fmt::Error> { + debug fmt => _1; + debug num => _2; + debug upper => _3; + let mut _0: std::result::Result<(), std::fmt::Error>; + let _4: bool; + let mut _6: std::option::Option; + let mut _7: isize; + let mut _9: &mut std::fmt::Formatter<'_>; + let mut _10: &T; + let mut _11: core::num::flt2dec::Sign; + let mut _12: u32; + let mut _13: u32; + let mut _14: usize; + let mut _15: bool; + let mut _16: &mut std::fmt::Formatter<'_>; + let mut _17: &T; + let mut _18: core::num::flt2dec::Sign; + let mut _19: bool; + scope 1 { + debug force_sign => _4; + let _5: core::num::flt2dec::Sign; + scope 2 { + debug sign => _5; + scope 3 { + debug precision => _8; + let _8: usize; + scope 5 (inlined Formatter::<'_>::precision) { + let mut _22: std::option::Option; + scope 6 (inlined Option::::map::::precision::{closure#0}}>) { + let mut _23: isize; + let _24: u16; + let mut _25: usize; + scope 7 { + scope 8 (inlined Formatter::<'_>::precision::{closure#0}) { + } + } + } + } + } + } + } + scope 4 (inlined Formatter::<'_>::sign_plus) { + let mut _20: u32; + let mut _21: u32; + } + + bb0: { + StorageLive(_4); + StorageLive(_20); + StorageLive(_21); + _21 = copy (((*_1).0: std::fmt::FormattingOptions).0: u32); + _20 = BitAnd(move _21, const 1_u32); + StorageDead(_21); + _4 = Ne(move _20, const 0_u32); + StorageDead(_20); + StorageLive(_5); + switchInt(copy _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { +- _5 = MinusPlus; ++ _5 = const MinusPlus; + goto -> bb3; + } + + bb2: { +- _5 = core::num::flt2dec::Sign::Minus; ++ _5 = const core::num::flt2dec::Sign::Minus; + goto -> bb3; + } + + bb3: { + StorageLive(_6); + StorageLive(_24); + StorageLive(_22); + _22 = copy (((*_1).0: std::fmt::FormattingOptions).4: std::option::Option); + StorageLive(_23); + _23 = discriminant(_22); + switchInt(move _23) -> [0: bb11, 1: bb12, otherwise: bb10]; + } + + bb4: { +- StorageLive(_8); ++ nop; + _8 = copy ((_6 as Some).0: usize); + StorageLive(_9); + _9 = copy _1; + StorageLive(_10); + _10 = copy _2; + StorageLive(_11); + _11 = copy _5; + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + _14 = copy _8; +- _13 = move _14 as u32 (IntToInt); ++ _13 = copy _8 as u32 (IntToInt); + StorageDead(_14); + _12 = Add(move _13, const 1_u32); + StorageDead(_13); + StorageLive(_15); + _15 = copy _3; +- _0 = float_to_exponential_common_exact::(move _9, move _10, move _11, move _12, move _15) -> [return: bb5, unwind continue]; ++ _0 = float_to_exponential_common_exact::(copy _1, copy _2, move _11, move _12, copy _3) -> [return: bb5, unwind continue]; + } + + bb5: { + StorageDead(_15); + StorageDead(_12); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); +- StorageDead(_8); ++ nop; + goto -> bb8; + } + + bb6: { + StorageLive(_16); + _16 = copy _1; + StorageLive(_17); + _17 = copy _2; + StorageLive(_18); + _18 = copy _5; + StorageLive(_19); + _19 = copy _3; +- _0 = float_to_exponential_common_shortest::(move _16, move _17, move _18, move _19) -> [return: bb7, unwind continue]; ++ _0 = float_to_exponential_common_shortest::(copy _1, copy _2, move _18, copy _3) -> [return: bb7, unwind continue]; + } + + bb7: { + StorageDead(_19); + StorageDead(_18); + StorageDead(_17); + StorageDead(_16); + goto -> bb8; + } + + bb8: { + StorageDead(_5); + StorageDead(_4); + StorageDead(_6); + return; + } + + bb9: { + StorageDead(_23); + StorageDead(_22); + StorageDead(_24); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, 0: bb6, otherwise: bb10]; + } + + bb10: { + unreachable; + } + + bb11: { + _6 = const Option::::None; + goto -> bb9; + } + + bb12: { + _24 = move ((_22 as Some).0: u16); + StorageLive(_25); + _25 = copy _24 as usize (IntToInt); + _6 = Option::::Some(move _25); + StorageDead(_25); + goto -> bb9; + } + } + + ALLOC0 (size: 16, align: 8) { + 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ + } + diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs index fc3691049eb4a..403a22ebed320 100644 --- a/tests/mir-opt/funky_arms.rs +++ b/tests/mir-opt/funky_arms.rs @@ -1,5 +1,6 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// EMIT_MIR_FOR_EACH_BIT_WIDTH #![feature(flt2dec)] From ce512c2e4d0dc72f0b7cd17896c2c4e4ea8acfe5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 12 Feb 2025 18:17:28 +0100 Subject: [PATCH 13/42] Fix rust-analyzer for 16-bit fmt width and precision. --- src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index 28c824fd31d73..24badc52f25ac 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -137,7 +137,7 @@ pub enum FormatAlignment { #[derive(Clone, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` - Literal(usize), + Literal(u16), /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. Argument(FormatArgPosition), } From 7677567e54285312c133b135821409f8cf3fa636 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 28 Feb 2025 12:49:20 +0100 Subject: [PATCH 14/42] Remove unnecessary semicolon. --- library/core/src/fmt/rt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index cb908adc1cbaf..a45875ba57c34 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -157,7 +157,7 @@ impl Argument<'_> { pub const fn from_usize(x: &usize) -> Argument<'_> { if *x > u16::MAX as usize { panic!("Formatting argument out of range"); - }; + } Argument { ty: ArgumentType::Count(*x as u16) } } From 2647cf17e75346ed50042a1ebe28aa3137a5544e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 28 Feb 2025 12:49:28 +0100 Subject: [PATCH 15/42] Add #[track_caller] to from_usize. --- library/core/src/fmt/rt.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index a45875ba57c34..080fc6ddfc9b8 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -154,6 +154,7 @@ impl Argument<'_> { Self::new(x, UpperExp::fmt) } #[inline] + #[track_caller] pub const fn from_usize(x: &usize) -> Argument<'_> { if *x > u16::MAX as usize { panic!("Formatting argument out of range"); From 7ca7675b7857c10851f0b2a18b44b52abaab607c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 27 Feb 2025 17:45:53 +0100 Subject: [PATCH 16/42] Make all keys explicit in citool Just to avoid surprises, the amount of used keys is not large. --- src/ci/citool/src/main.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 52e7638d98bdf..346d7f7cf6621 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -33,9 +33,12 @@ struct Job { /// Should the job be only executed on a specific channel? #[serde(default)] only_on_channel: Option, - /// Rest of attributes that will be passed through to GitHub actions - #[serde(flatten)] - extra_keys: BTreeMap, + /// Do not cancel the whole workflow if this job fails. + #[serde(default)] + continue_on_error: Option, + /// Free additional disk space in the job, by removing unused packages. + #[serde(default)] + free_disk: Option, } impl Job { @@ -105,8 +108,10 @@ struct GithubActionsJob { full_name: String, os: String, env: BTreeMap, - #[serde(flatten)] - extra_keys: BTreeMap, + #[serde(skip_serializing_if = "Option::is_none")] + continue_on_error: Option, + #[serde(skip_serializing_if = "Option::is_none")] + free_disk: Option, } /// Type of workflow that is being executed on CI @@ -240,7 +245,8 @@ fn calculate_jobs( full_name, os: job.os, env, - extra_keys: yaml_map_to_json(&job.extra_keys), + free_disk: job.free_disk, + continue_on_error: job.continue_on_error, } }) .collect(); From 112f7b01a1b25035cd8b288d6936c6be48a3d845 Mon Sep 17 00:00:00 2001 From: morine0122 Date: Sun, 2 Mar 2025 18:06:06 +0900 Subject: [PATCH 17/42] make precise capturing args in rustdoc Json typed --- compiler/rustc_hir/src/hir.rs | 11 +++++--- compiler/rustc_hir_analysis/src/collect.rs | 11 +++++--- compiler/rustc_metadata/src/rmeta/mod.rs | 3 ++- compiler/rustc_middle/src/query/mod.rs | 4 +-- compiler/rustc_middle/src/ty/parameterized.rs | 2 ++ src/librustdoc/clean/mod.rs | 27 +++++++++++++++++-- src/librustdoc/clean/types.rs | 17 +++++++++++- src/librustdoc/html/format.rs | 2 +- src/librustdoc/json/conversions.rs | 13 ++++++++- src/rustdoc-json-types/lib.rs | 20 ++++++++++++-- .../impl-trait-precise-capturing.rs | 6 ++--- 11 files changed, 96 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 928455ace8562..69327ca3c0083 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3368,13 +3368,16 @@ pub struct OpaqueTy<'hir> { pub span: Span, } -#[derive(Debug, Clone, Copy, HashStable_Generic)] -pub enum PreciseCapturingArg<'hir> { - Lifetime(&'hir Lifetime), +#[derive(Debug, Clone, Copy, HashStable_Generic, Encodable, Decodable)] +pub enum PreciseCapturingArgKind { + Lifetime(T), /// Non-lifetime argument (type or const) - Param(PreciseCapturingNonLifetimeArg), + Param(U), } +pub type PreciseCapturingArg<'hir> = + PreciseCapturingArgKind<&'hir Lifetime, PreciseCapturingNonLifetimeArg>; + impl PreciseCapturingArg<'_> { pub fn hir_id(self) -> HirId { match self { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 49523912b14d3..33921547bbb4f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -28,7 +28,7 @@ use rustc_errors::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt, walk_generics}; -use rustc_hir::{self as hir, GenericParamKind, HirId, Node}; +use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; @@ -1792,7 +1792,7 @@ fn opaque_ty_origin<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> hir::OpaqueT fn rendered_precise_capturing_args<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> Option<&'tcx [Symbol]> { +) -> Option<&'tcx [PreciseCapturingArgKind]> { if let Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) = tcx.opt_rpitit_info(def_id.to_def_id()) { @@ -1801,7 +1801,12 @@ fn rendered_precise_capturing_args<'tcx>( tcx.hir_node_by_def_id(def_id).expect_opaque_ty().bounds.iter().find_map(|bound| match bound { hir::GenericBound::Use(args, ..) => { - Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name()))) + Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| match arg { + PreciseCapturingArgKind::Lifetime(_) => { + PreciseCapturingArgKind::Lifetime(arg.name()) + } + PreciseCapturingArgKind::Param(_) => PreciseCapturingArgKind::Param(arg.name()), + }))) } _ => None, }) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 7b34e605c5307..5536c93f84a43 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -10,6 +10,7 @@ use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; +use rustc_hir::PreciseCapturingArgKind; use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; @@ -440,7 +441,7 @@ define_tables! { coerce_unsized_info: Table>, mir_const_qualif: Table>, rendered_const: Table>, - rendered_precise_capturing_args: Table>, + rendered_precise_capturing_args: Table>>, asyncness: Table, fn_arg_names: Table>, coroutine_kind: Table, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3ad9201dd6f8e..86719766eacc1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -25,7 +25,7 @@ use rustc_hir::def_id::{ CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId, }; use rustc_hir::lang_items::{LangItem, LanguageItems}; -use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate}; +use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate}; use rustc_index::IndexVec; use rustc_lint_defs::LintId; use rustc_macros::rustc_queries; @@ -1430,7 +1430,7 @@ rustc_queries! { } /// Gets the rendered precise capturing args for an opaque for use in rustdoc. - query rendered_precise_capturing_args(def_id: DefId) -> Option<&'tcx [Symbol]> { + query rendered_precise_capturing_args(def_id: DefId) -> Option<&'tcx [PreciseCapturingArgKind]> { desc { |tcx| "rendering precise capturing args for `{}`", tcx.def_path_str(def_id) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 8eaf0a58f7086..1b495a85a5fbd 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::DefIndex; use rustc_index::{Idx, IndexVec}; +use rustc_span::Symbol; use crate::ty; @@ -96,6 +97,7 @@ trivially_parameterized_over_tcx! { rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, rustc_hir::OpaqueTyOrigin, + rustc_hir::PreciseCapturingArgKind, rustc_index::bit_set::DenseBitSet, rustc_index::bit_set::FiniteBitSet, rustc_session::cstore::ForeignModule, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 97ff4c2ef4096..c0e37179e95ec 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -231,7 +231,7 @@ fn clean_generic_bound<'tcx>( GenericBound::TraitBound(clean_poly_trait_ref(t, cx), t.modifiers) } hir::GenericBound::Use(args, ..) => { - GenericBound::Use(args.iter().map(|arg| arg.name()).collect()) + GenericBound::Use(args.iter().map(|arg| clean_precise_capturing_arg(arg, cx)).collect()) } }) } @@ -286,6 +286,18 @@ fn clean_lifetime(lifetime: &hir::Lifetime, cx: &DocContext<'_>) -> Lifetime { Lifetime(lifetime.ident.name) } +pub(crate) fn clean_precise_capturing_arg( + arg: &hir::PreciseCapturingArg<'_>, + cx: &DocContext<'_>, +) -> PreciseCapturingArg { + match arg { + hir::PreciseCapturingArg::Lifetime(lt) => { + PreciseCapturingArg::Lifetime(clean_lifetime(lt, cx)) + } + hir::PreciseCapturingArg::Param(param) => PreciseCapturingArg::Param(param.ident.name), + } +} + pub(crate) fn clean_const<'tcx>( constant: &hir::ConstArg<'tcx>, _cx: &mut DocContext<'tcx>, @@ -2364,7 +2376,18 @@ fn clean_middle_opaque_bounds<'tcx>( } if let Some(args) = cx.tcx.rendered_precise_capturing_args(impl_trait_def_id) { - bounds.push(GenericBound::Use(args.to_vec())); + bounds.push(GenericBound::Use( + args.iter() + .map(|arg| match arg { + hir::PreciseCapturingArgKind::Lifetime(lt) => { + PreciseCapturingArg::Lifetime(Lifetime(*lt)) + } + hir::PreciseCapturingArgKind::Param(param) => { + PreciseCapturingArg::Param(*param) + } + }) + .collect(), + )); } ImplTrait(bounds) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9e9cd52883491..228d9108e4eb6 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1240,7 +1240,7 @@ pub(crate) enum GenericBound { TraitBound(PolyTrait, hir::TraitBoundModifiers), Outlives(Lifetime), /// `use<'a, T>` precise-capturing bound syntax - Use(Vec), + Use(Vec), } impl GenericBound { @@ -1304,6 +1304,21 @@ impl Lifetime { } } +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub(crate) enum PreciseCapturingArg { + Lifetime(Lifetime), + Param(Symbol), +} + +impl PreciseCapturingArg { + pub(crate) fn name(self) -> Symbol { + match self { + PreciseCapturingArg::Lifetime(lt) => lt.0, + PreciseCapturingArg::Param(param) => param, + } + } +} + #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec, bound_params: Vec }, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 8b8439a253527..e93b9eb272a47 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -283,7 +283,7 @@ impl clean::GenericBound { } else { f.write_str("use<")?; } - args.iter().joined(", ", f)?; + args.iter().map(|arg| arg.name()).joined(", ", f)?; if f.alternate() { f.write_str(">") } else { f.write_str(">") } } }) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 9606ba76991a7..d65c13b2b6313 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -548,7 +548,18 @@ impl FromClean for GenericBound { } } Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), - Use(args) => GenericBound::Use(args.into_iter().map(|arg| arg.to_string()).collect()), + Use(args) => GenericBound::Use( + args.iter() + .map(|arg| match arg { + clean::PreciseCapturingArg::Lifetime(lt) => { + PreciseCapturingArg::Lifetime(convert_lifetime(*lt)) + } + clean::PreciseCapturingArg::Param(param) => { + PreciseCapturingArg::Param(param.to_string()) + } + }) + .collect(), + ), } } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 8f6496e9626c8..8ec7cffe06620 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 40; +pub const FORMAT_VERSION: u32 = 41; /// The root of the emitted JSON blob. /// @@ -909,7 +909,7 @@ pub enum GenericBound { /// ``` Outlives(String), /// `use<'a, T>` precise-capturing bound syntax - Use(Vec), + Use(Vec), } /// A set of modifiers applied to a trait. @@ -927,6 +927,22 @@ pub enum TraitBoundModifier { MaybeConst, } +/// One precise capturing argument. See [the rust reference](https://doc.rust-lang.org/reference/types/impl-trait.html#precise-capturing). +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum PreciseCapturingArg { + /// A lifetime. + /// ```rust + /// pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} + /// // ^^ + Lifetime(String), + /// A type or constant parameter. + /// ```rust + /// pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} + /// // ^ ^ + Param(String), +} + /// Either a type or a constant, usually stored as the right-hand side of an equation in places like /// [`AssocItemConstraint`] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/tests/rustdoc-json/impl-trait-precise-capturing.rs b/tests/rustdoc-json/impl-trait-precise-capturing.rs index 52252560e6fda..06be95099b4d5 100644 --- a/tests/rustdoc-json/impl-trait-precise-capturing.rs +++ b/tests/rustdoc-json/impl-trait-precise-capturing.rs @@ -1,4 +1,4 @@ -//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[0]" \"\'a\" -//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[1]" \"T\" -//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[2]" \"N\" +//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[0].lifetime" \"\'a\" +//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[1].param" \"T\" +//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[2].param" \"N\" pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} From 0412507c52d074e20dc47501078d24c4ab51294f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 10 Mar 2025 13:14:50 +0100 Subject: [PATCH 18/42] Move job handling to a separate module --- src/ci/citool/src/jobs.rs | 233 +++++++++++++++++++++++++++++ src/ci/citool/src/main.rs | 237 +----------------------------- src/ci/citool/src/merge_report.rs | 2 +- 3 files changed, 242 insertions(+), 230 deletions(-) create mode 100644 src/ci/citool/src/jobs.rs diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs new file mode 100644 index 0000000000000..8103e9b934460 --- /dev/null +++ b/src/ci/citool/src/jobs.rs @@ -0,0 +1,233 @@ +use crate::{GitHubContext, utils}; +use serde_yaml::Value; +use std::collections::BTreeMap; +use std::path::Path; + +use serde_yaml::Value; + +use crate::GitHubContext; + +/// Representation of a job loaded from the `src/ci/github-actions/jobs.yml` file. +#[derive(serde::Deserialize, Debug, Clone)] +pub struct Job { + /// Name of the job, e.g. mingw-check + pub name: String, + /// GitHub runner on which the job should be executed + pub os: String, + pub env: BTreeMap, + /// Should the job be only executed on a specific channel? + #[serde(default)] + pub only_on_channel: Option, + /// Do not cancel the whole workflow if this job fails. + #[serde(default)] + pub continue_on_error: Option, + /// Free additional disk space in the job, by removing unused packages. + #[serde(default)] + pub free_disk: Option, +} + +impl Job { + /// By default, the Docker image of a job is based on its name. + /// However, it can be overridden by its IMAGE environment variable. + pub fn image(&self) -> String { + self.env + .get("IMAGE") + .map(|v| v.as_str().expect("IMAGE value should be a string").to_string()) + .unwrap_or_else(|| self.name.clone()) + } + + fn is_linux(&self) -> bool { + self.os.contains("ubuntu") + } +} + +#[derive(serde::Deserialize, Debug)] +struct JobEnvironments { + #[serde(rename = "pr")] + pr_env: BTreeMap, + #[serde(rename = "try")] + try_env: BTreeMap, + #[serde(rename = "auto")] + auto_env: BTreeMap, +} + +#[derive(serde::Deserialize, Debug)] +pub struct JobDatabase { + #[serde(rename = "pr")] + pub pr_jobs: Vec, + #[serde(rename = "try")] + pub try_jobs: Vec, + #[serde(rename = "auto")] + pub auto_jobs: Vec, + + /// Shared environments for the individual run types. + envs: JobEnvironments, +} + +impl JobDatabase { + fn find_auto_job_by_name(&self, name: &str) -> Option { + self.auto_jobs.iter().find(|j| j.name == name).cloned() + } +} + +pub fn load_job_db(path: &Path) -> anyhow::Result { + let db = utils::read_to_string(path)?; + let mut db: Value = serde_yaml::from_str(&db)?; + + // We need to expand merge keys (<<), because serde_yaml can't deal with them + // `apply_merge` only applies the merge once, so do it a few times to unwrap nested merges. + db.apply_merge()?; + db.apply_merge()?; + + let db: JobDatabase = serde_yaml::from_value(db)?; + Ok(db) +} + +/// Representation of a job outputted to a GitHub Actions workflow. +#[derive(serde::Serialize, Debug)] +struct GithubActionsJob { + /// The main identifier of the job, used by CI scripts to determine what should be executed. + name: String, + /// Helper label displayed in GitHub Actions interface, containing the job name and a run type + /// prefix (PR/try/auto). + full_name: String, + os: String, + env: BTreeMap, + #[serde(skip_serializing_if = "Option::is_none")] + continue_on_error: Option, + #[serde(skip_serializing_if = "Option::is_none")] + free_disk: Option, +} + +/// Skip CI jobs that are not supposed to be executed on the given `channel`. +fn skip_jobs(jobs: Vec, channel: &str) -> Vec { + jobs.into_iter() + .filter(|job| { + job.only_on_channel.is_none() || job.only_on_channel.as_deref() == Some(channel) + }) + .collect() +} + +/// Type of workflow that is being executed on CI +#[derive(Debug)] +pub enum RunType { + /// Workflows that run after a push to a PR branch + PullRequest, + /// Try run started with @bors try + TryJob { custom_jobs: Option> }, + /// Merge attempt workflow + AutoJob, +} + +/// Maximum number of custom try jobs that can be requested in a single +/// `@bors try` request. +const MAX_TRY_JOBS_COUNT: usize = 20; + +fn calculate_jobs( + run_type: &RunType, + db: &JobDatabase, + channel: &str, +) -> anyhow::Result> { + let (jobs, prefix, base_env) = match run_type { + RunType::PullRequest => (db.pr_jobs.clone(), "PR", &db.envs.pr_env), + RunType::TryJob { custom_jobs } => { + let jobs = if let Some(custom_jobs) = custom_jobs { + if custom_jobs.len() > MAX_TRY_JOBS_COUNT { + return Err(anyhow::anyhow!( + "It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs", + custom_jobs.len() + )); + } + + let mut jobs = vec![]; + let mut unknown_jobs = vec![]; + for custom_job in custom_jobs { + if let Some(job) = db.find_auto_job_by_name(custom_job) { + jobs.push(job); + } else { + unknown_jobs.push(custom_job.clone()); + } + } + if !unknown_jobs.is_empty() { + return Err(anyhow::anyhow!( + "Custom job(s) `{}` not found in auto jobs", + unknown_jobs.join(", ") + )); + } + jobs + } else { + db.try_jobs.clone() + }; + (jobs, "try", &db.envs.try_env) + } + RunType::AutoJob => (db.auto_jobs.clone(), "auto", &db.envs.auto_env), + }; + let jobs = skip_jobs(jobs, channel); + let jobs = jobs + .into_iter() + .map(|job| { + let mut env: BTreeMap = crate::yaml_map_to_json(base_env); + env.extend(crate::yaml_map_to_json(&job.env)); + let full_name = format!("{prefix} - {}", job.name); + + GithubActionsJob { + name: job.name, + full_name, + os: job.os, + env, + continue_on_error: job.continue_on_error, + free_disk: job.free_disk, + } + }) + .collect(); + + Ok(jobs) +} + +pub fn calculate_job_matrix( + db: JobDatabase, + gh_ctx: GitHubContext, + channel: &str, +) -> anyhow::Result<()> { + let run_type = gh_ctx.get_run_type().ok_or_else(|| { + anyhow::anyhow!("Cannot determine the type of workflow that is being executed") + })?; + eprintln!("Run type: {run_type:?}"); + + let jobs = calculate_jobs(&run_type, &db, channel)?; + if jobs.is_empty() { + return Err(anyhow::anyhow!("Computed job list is empty")); + } + + let run_type = match run_type { + RunType::PullRequest => "pr", + RunType::TryJob { .. } => "try", + RunType::AutoJob => "auto", + }; + + eprintln!("Output"); + eprintln!("jobs={jobs:?}"); + eprintln!("run_type={run_type}"); + println!("jobs={}", serde_json::to_string(&jobs)?); + println!("run_type={run_type}"); + + Ok(()) +} + +pub fn find_linux_job<'a>(jobs: &'a [Job], name: &str) -> anyhow::Result<&'a Job> { + let Some(job) = jobs.iter().find(|j| j.name == name) else { + let available_jobs: Vec<&Job> = jobs.iter().filter(|j| j.is_linux()).collect(); + let mut available_jobs = + available_jobs.iter().map(|j| j.name.to_string()).collect::>(); + available_jobs.sort(); + return Err(anyhow::anyhow!( + "Job {name} not found. The following jobs are available:\n{}", + available_jobs.join(", ") + )); + }; + if !job.is_linux() { + return Err(anyhow::anyhow!("Only Linux jobs can be executed locally")); + } + + Ok(job) +} diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 346d7f7cf6621..8765922d089a7 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -1,5 +1,6 @@ mod cpu_usage; mod datadog; +mod jobs; mod merge_report; mod metrics; mod utils; @@ -10,10 +11,12 @@ use std::process::Command; use anyhow::Context; use clap::Parser; +use jobs::JobDatabase; use serde_yaml::Value; use crate::cpu_usage::load_cpu_usage; use crate::datadog::upload_datadog_metric; +use crate::jobs::RunType; use crate::merge_report::post_merge_report; use crate::metrics::postprocess_metrics; use crate::utils::load_env_var; @@ -22,109 +25,6 @@ const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); const JOBS_YML_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../github-actions/jobs.yml"); -/// Representation of a job loaded from the `src/ci/github-actions/jobs.yml` file. -#[derive(serde::Deserialize, Debug, Clone)] -struct Job { - /// Name of the job, e.g. mingw-check - name: String, - /// GitHub runner on which the job should be executed - os: String, - env: BTreeMap, - /// Should the job be only executed on a specific channel? - #[serde(default)] - only_on_channel: Option, - /// Do not cancel the whole workflow if this job fails. - #[serde(default)] - continue_on_error: Option, - /// Free additional disk space in the job, by removing unused packages. - #[serde(default)] - free_disk: Option, -} - -impl Job { - fn is_linux(&self) -> bool { - self.os.contains("ubuntu") - } - - /// By default, the Docker image of a job is based on its name. - /// However, it can be overridden by its IMAGE environment variable. - fn image(&self) -> String { - self.env - .get("IMAGE") - .map(|v| v.as_str().expect("IMAGE value should be a string").to_string()) - .unwrap_or_else(|| self.name.clone()) - } -} - -#[derive(serde::Deserialize, Debug)] -struct JobEnvironments { - #[serde(rename = "pr")] - pr_env: BTreeMap, - #[serde(rename = "try")] - try_env: BTreeMap, - #[serde(rename = "auto")] - auto_env: BTreeMap, -} - -#[derive(serde::Deserialize, Debug)] -struct JobDatabase { - #[serde(rename = "pr")] - pr_jobs: Vec, - #[serde(rename = "try")] - try_jobs: Vec, - #[serde(rename = "auto")] - auto_jobs: Vec, - - /// Shared environments for the individual run types. - envs: JobEnvironments, -} - -impl JobDatabase { - fn find_auto_job_by_name(&self, name: &str) -> Option { - self.auto_jobs.iter().find(|j| j.name == name).cloned() - } -} - -fn load_job_db(path: &Path) -> anyhow::Result { - let db = utils::read_to_string(path)?; - let mut db: Value = serde_yaml::from_str(&db)?; - - // We need to expand merge keys (<<), because serde_yaml can't deal with them - // `apply_merge` only applies the merge once, so do it a few times to unwrap nested merges. - db.apply_merge()?; - db.apply_merge()?; - - let db: JobDatabase = serde_yaml::from_value(db)?; - Ok(db) -} - -/// Representation of a job outputted to a GitHub Actions workflow. -#[derive(serde::Serialize, Debug)] -struct GithubActionsJob { - /// The main identifier of the job, used by CI scripts to determine what should be executed. - name: String, - /// Helper label displayed in GitHub Actions interface, containing the job name and a run type - /// prefix (PR/try/auto). - full_name: String, - os: String, - env: BTreeMap, - #[serde(skip_serializing_if = "Option::is_none")] - continue_on_error: Option, - #[serde(skip_serializing_if = "Option::is_none")] - free_disk: Option, -} - -/// Type of workflow that is being executed on CI -#[derive(Debug)] -enum RunType { - /// Workflows that run after a push to a PR branch - PullRequest, - /// Try run started with @bors try - TryJob { custom_jobs: Option> }, - /// Merge attempt workflow - AutoJob, -} - struct GitHubContext { event_name: String, branch_ref: String, @@ -169,15 +69,6 @@ fn load_github_ctx() -> anyhow::Result { Ok(GitHubContext { event_name, branch_ref: load_env_var("GITHUB_REF")?, commit_message }) } -/// Skip CI jobs that are not supposed to be executed on the given `channel`. -fn skip_jobs(jobs: Vec, channel: &str) -> Vec { - jobs.into_iter() - .filter(|job| { - job.only_on_channel.is_none() || job.only_on_channel.as_deref() == Some(channel) - }) - .collect() -} - fn yaml_map_to_json(map: &BTreeMap) -> BTreeMap { map.into_iter() .map(|(key, value)| { @@ -189,125 +80,13 @@ fn yaml_map_to_json(map: &BTreeMap) -> BTreeMap anyhow::Result> { - let (jobs, prefix, base_env) = match run_type { - RunType::PullRequest => (db.pr_jobs.clone(), "PR", &db.envs.pr_env), - RunType::TryJob { custom_jobs } => { - let jobs = if let Some(custom_jobs) = custom_jobs { - if custom_jobs.len() > MAX_TRY_JOBS_COUNT { - return Err(anyhow::anyhow!( - "It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs", - custom_jobs.len() - )); - } - - let mut jobs = vec![]; - let mut unknown_jobs = vec![]; - for custom_job in custom_jobs { - if let Some(job) = db.find_auto_job_by_name(custom_job) { - jobs.push(job); - } else { - unknown_jobs.push(custom_job.clone()); - } - } - if !unknown_jobs.is_empty() { - return Err(anyhow::anyhow!( - "Custom job(s) `{}` not found in auto jobs", - unknown_jobs.join(", ") - )); - } - jobs - } else { - db.try_jobs.clone() - }; - (jobs, "try", &db.envs.try_env) - } - RunType::AutoJob => (db.auto_jobs.clone(), "auto", &db.envs.auto_env), - }; - let jobs = skip_jobs(jobs, channel); - let jobs = jobs - .into_iter() - .map(|job| { - let mut env: BTreeMap = yaml_map_to_json(base_env); - env.extend(yaml_map_to_json(&job.env)); - let full_name = format!("{prefix} - {}", job.name); - - GithubActionsJob { - name: job.name, - full_name, - os: job.os, - env, - free_disk: job.free_disk, - continue_on_error: job.continue_on_error, - } - }) - .collect(); - - Ok(jobs) -} - -fn calculate_job_matrix( - db: JobDatabase, - gh_ctx: GitHubContext, - channel: &str, -) -> anyhow::Result<()> { - let run_type = gh_ctx.get_run_type().ok_or_else(|| { - anyhow::anyhow!("Cannot determine the type of workflow that is being executed") - })?; - eprintln!("Run type: {run_type:?}"); - - let jobs = calculate_jobs(&run_type, &db, channel)?; - if jobs.is_empty() { - return Err(anyhow::anyhow!("Computed job list is empty")); - } - - let run_type = match run_type { - RunType::PullRequest => "pr", - RunType::TryJob { .. } => "try", - RunType::AutoJob => "auto", - }; - - eprintln!("Output"); - eprintln!("jobs={jobs:?}"); - eprintln!("run_type={run_type}"); - println!("jobs={}", serde_json::to_string(&jobs)?); - println!("run_type={run_type}"); - - Ok(()) -} - -fn find_linux_job<'a>(jobs: &'a [Job], name: &str) -> anyhow::Result<&'a Job> { - let Some(job) = jobs.iter().find(|j| j.name == name) else { - let available_jobs: Vec<&Job> = jobs.iter().filter(|j| j.is_linux()).collect(); - let mut available_jobs = - available_jobs.iter().map(|j| j.name.to_string()).collect::>(); - available_jobs.sort(); - return Err(anyhow::anyhow!( - "Job {name} not found. The following jobs are available:\n{}", - available_jobs.join(", ") - )); - }; - if !job.is_linux() { - return Err(anyhow::anyhow!("Only Linux jobs can be executed locally")); - } - - Ok(job) -} - fn run_workflow_locally(db: JobDatabase, job_type: JobType, name: String) -> anyhow::Result<()> { let jobs = match job_type { JobType::Auto => &db.auto_jobs, JobType::PR => &db.pr_jobs, }; - let job = find_linux_job(jobs, &name).with_context(|| format!("Cannot find job {name}"))?; + let job = + jobs::find_linux_job(jobs, &name).with_context(|| format!("Cannot find job {name}"))?; let mut custom_env: BTreeMap = BTreeMap::new(); // Replicate src/ci/scripts/setup-environment.sh @@ -391,7 +170,7 @@ enum Args { } #[derive(clap::ValueEnum, Clone)] -enum JobType { +pub enum JobType { /// Merge attempt ("auto") job Auto, /// Pull request job @@ -401,7 +180,7 @@ enum JobType { fn main() -> anyhow::Result<()> { let args = Args::parse(); let default_jobs_file = Path::new(JOBS_YML_PATH); - let load_db = |jobs_path| load_job_db(jobs_path).context("Cannot load jobs.yml"); + let load_db = |jobs_path| jobs::load_job_db(jobs_path).context("Cannot load jobs.yml"); match args { Args::CalculateJobMatrix { jobs_file } => { @@ -413,7 +192,7 @@ fn main() -> anyhow::Result<()> { .trim() .to_string(); - calculate_job_matrix(load_db(jobs_path)?, gh_ctx, &channel) + jobs::calculate_job_matrix(load_db(jobs_path)?, gh_ctx, &channel) .context("Failed to calculate job matrix")?; } Args::RunJobLocally { job_type, name } => { diff --git a/src/ci/citool/src/merge_report.rs b/src/ci/citool/src/merge_report.rs index 5dd662280f0f3..17e42d49286fe 100644 --- a/src/ci/citool/src/merge_report.rs +++ b/src/ci/citool/src/merge_report.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use anyhow::Context; use build_helper::metrics::{JsonRoot, TestOutcome}; -use crate::JobDatabase; +use crate::jobs::JobDatabase; use crate::metrics::get_test_suites; type Sha = String; From 2ce0205735afce776f402eb96f85759906959473 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 10 Mar 2025 13:57:23 +0100 Subject: [PATCH 19/42] Share implementation of expr_u{16,32,size}. --- compiler/rustc_ast_lowering/src/expr.rs | 29 +++++++------------------ 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0f175ea615f6e..5bb6704dde45a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2130,37 +2130,24 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]))) } - pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> { let lit = self.arena.alloc(hir::Lit { span: sp, - node: ast::LitKind::Int( - (value as u128).into(), - ast::LitIntType::Unsigned(ast::UintTy::Usize), - ), + node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)), }); self.expr(sp, hir::ExprKind::Lit(lit)) } + pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + self.expr_uint(sp, ast::UintTy::Usize, value as u128) + } + pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { - span: sp, - node: ast::LitKind::Int( - u128::from(value).into(), - ast::LitIntType::Unsigned(ast::UintTy::U32), - ), - }); - self.expr(sp, hir::ExprKind::Lit(lit)) + self.expr_uint(sp, ast::UintTy::U32, value as u128) } pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { - span: sp, - node: ast::LitKind::Int( - u128::from(value).into(), - ast::LitIntType::Unsigned(ast::UintTy::U16), - ), - }); - self.expr(sp, hir::ExprKind::Lit(lit)) + self.expr_uint(sp, ast::UintTy::U16, value as u128) } pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { From 3326a9fd2733799deb74011ae9eda4c7d5c0b7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 10 Mar 2025 13:32:58 +0100 Subject: [PATCH 20/42] Allow using glob aliases for custom try jobs --- src/ci/citool/Cargo.lock | 7 ++++ src/ci/citool/Cargo.toml | 1 + src/ci/citool/src/jobs.rs | 59 ++++++++++++++++-------------- src/ci/citool/src/jobs/tests.rs | 64 +++++++++++++++++++++++++++++++++ src/ci/citool/src/main.rs | 19 +++++----- 5 files changed, 116 insertions(+), 34 deletions(-) create mode 100644 src/ci/citool/src/jobs/tests.rs diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock index 46343a7b86e8a..c061ec6ebdcee 100644 --- a/src/ci/citool/Cargo.lock +++ b/src/ci/citool/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "build_helper", "clap", "csv", + "glob-match", "insta", "serde", "serde_json", @@ -308,6 +309,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "glob-match" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" + [[package]] name = "hashbrown" version = "0.15.2" diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index c486f2977a1cb..dde09224afe84 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" anyhow = "1" clap = { version = "4.5", features = ["derive"] } csv = "1" +glob-match = "0.2" serde = { version = "1", features = ["derive"] } serde_yaml = "0.9" serde_json = "1" diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index 8103e9b934460..d161d17ebe646 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -1,7 +1,7 @@ -use crate::{GitHubContext, utils}; -use serde_yaml::Value; +#[cfg(test)] +mod tests; + use std::collections::BTreeMap; -use std::path::Path; use serde_yaml::Value; @@ -65,13 +65,19 @@ pub struct JobDatabase { } impl JobDatabase { - fn find_auto_job_by_name(&self, name: &str) -> Option { - self.auto_jobs.iter().find(|j| j.name == name).cloned() + /// Find `auto` jobs that correspond to the passed `pattern`. + /// Patterns are matched using the glob syntax. + /// For example `dist-*` matches all jobs starting with `dist-`. + fn find_auto_jobs_by_pattern(&self, pattern: &str) -> Vec { + self.auto_jobs + .iter() + .filter(|j| glob_match::glob_match(pattern, &j.name)) + .cloned() + .collect() } } -pub fn load_job_db(path: &Path) -> anyhow::Result { - let db = utils::read_to_string(path)?; +pub fn load_job_db(db: &str) -> anyhow::Result { let mut db: Value = serde_yaml::from_str(&db)?; // We need to expand merge keys (<<), because serde_yaml can't deal with them @@ -114,7 +120,7 @@ pub enum RunType { /// Workflows that run after a push to a PR branch PullRequest, /// Try run started with @bors try - TryJob { custom_jobs: Option> }, + TryJob { job_patterns: Option> }, /// Merge attempt workflow AutoJob, } @@ -130,28 +136,29 @@ fn calculate_jobs( ) -> anyhow::Result> { let (jobs, prefix, base_env) = match run_type { RunType::PullRequest => (db.pr_jobs.clone(), "PR", &db.envs.pr_env), - RunType::TryJob { custom_jobs } => { - let jobs = if let Some(custom_jobs) = custom_jobs { - if custom_jobs.len() > MAX_TRY_JOBS_COUNT { - return Err(anyhow::anyhow!( - "It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs", - custom_jobs.len() - )); - } - - let mut jobs = vec![]; - let mut unknown_jobs = vec![]; - for custom_job in custom_jobs { - if let Some(job) = db.find_auto_job_by_name(custom_job) { - jobs.push(job); + RunType::TryJob { job_patterns } => { + let jobs = if let Some(patterns) = job_patterns { + let mut jobs: Vec = vec![]; + let mut unknown_patterns = vec![]; + for pattern in patterns { + let matched_jobs = db.find_auto_jobs_by_pattern(pattern); + if matched_jobs.is_empty() { + unknown_patterns.push(pattern.clone()); } else { - unknown_jobs.push(custom_job.clone()); + jobs.extend(matched_jobs); } } - if !unknown_jobs.is_empty() { + if !unknown_patterns.is_empty() { + return Err(anyhow::anyhow!( + "Patterns `{}` did not match any auto jobs", + unknown_patterns.join(", ") + )); + } + if jobs.len() > MAX_TRY_JOBS_COUNT { return Err(anyhow::anyhow!( - "Custom job(s) `{}` not found in auto jobs", - unknown_jobs.join(", ") + "It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs expanded from {} pattern(s)", + jobs.len(), + patterns.len() )); } jobs diff --git a/src/ci/citool/src/jobs/tests.rs b/src/ci/citool/src/jobs/tests.rs new file mode 100644 index 0000000000000..a489656fa5dc7 --- /dev/null +++ b/src/ci/citool/src/jobs/tests.rs @@ -0,0 +1,64 @@ +use crate::jobs::{JobDatabase, load_job_db}; + +#[test] +fn lookup_job_pattern() { + let db = load_job_db( + r#" +envs: + pr: + try: + auto: + +pr: +try: +auto: + - name: dist-a + os: ubuntu + env: {} + - name: dist-a-alt + os: ubuntu + env: {} + - name: dist-b + os: ubuntu + env: {} + - name: dist-b-alt + os: ubuntu + env: {} + - name: test-a + os: ubuntu + env: {} + - name: test-a-alt + os: ubuntu + env: {} + - name: test-i686 + os: ubuntu + env: {} + - name: dist-i686 + os: ubuntu + env: {} + - name: test-msvc-i686-1 + os: ubuntu + env: {} + - name: test-msvc-i686-2 + os: ubuntu + env: {} +"#, + ) + .unwrap(); + check_pattern(&db, "dist-*", &["dist-a", "dist-a-alt", "dist-b", "dist-b-alt", "dist-i686"]); + check_pattern(&db, "*-alt", &["dist-a-alt", "dist-b-alt", "test-a-alt"]); + check_pattern(&db, "dist*-alt", &["dist-a-alt", "dist-b-alt"]); + check_pattern( + &db, + "*i686*", + &["test-i686", "dist-i686", "test-msvc-i686-1", "test-msvc-i686-2"], + ); +} + +#[track_caller] +fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) { + let jobs = + db.find_auto_jobs_by_pattern(pattern).into_iter().map(|j| j.name).collect::>(); + + assert_eq!(jobs, expected); +} diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 8765922d089a7..2a4be061e4ec9 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -35,21 +35,21 @@ impl GitHubContext { fn get_run_type(&self) -> Option { match (self.event_name.as_str(), self.branch_ref.as_str()) { ("pull_request", _) => Some(RunType::PullRequest), - ("push", "refs/heads/try-perf") => Some(RunType::TryJob { custom_jobs: None }), + ("push", "refs/heads/try-perf") => Some(RunType::TryJob { job_patterns: None }), ("push", "refs/heads/try" | "refs/heads/automation/bors/try") => { - let custom_jobs = self.get_custom_jobs(); - let custom_jobs = if !custom_jobs.is_empty() { Some(custom_jobs) } else { None }; - Some(RunType::TryJob { custom_jobs }) + let patterns = self.get_try_job_patterns(); + let patterns = if !patterns.is_empty() { Some(patterns) } else { None }; + Some(RunType::TryJob { job_patterns: patterns }) } ("push", "refs/heads/auto") => Some(RunType::AutoJob), _ => None, } } - /// Tries to parse names of specific CI jobs that should be executed in the form of - /// try-job: + /// Tries to parse patterns of CI jobs that should be executed in the form of + /// try-job: /// from the commit message of the passed GitHub context. - fn get_custom_jobs(&self) -> Vec { + fn get_try_job_patterns(&self) -> Vec { if let Some(ref msg) = self.commit_message { msg.lines() .filter_map(|line| line.trim().strip_prefix("try-job: ")) @@ -180,7 +180,10 @@ pub enum JobType { fn main() -> anyhow::Result<()> { let args = Args::parse(); let default_jobs_file = Path::new(JOBS_YML_PATH); - let load_db = |jobs_path| jobs::load_job_db(jobs_path).context("Cannot load jobs.yml"); + let load_db = |jobs_path| { + let db = utils::read_to_string(jobs_path)?; + Ok::<_, anyhow::Error>(jobs::load_job_db(&db).context("Cannot load jobs.yml")?) + }; match args { Args::CalculateJobMatrix { jobs_file } => { From 06d86cd60c59d4fb7b0df30248a0c50fbd96b14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 10 Mar 2025 13:35:50 +0100 Subject: [PATCH 21/42] Modify try-job documentation --- src/doc/rustc-dev-guide/src/tests/ci.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index ae6adb678af14..7fd4c16972248 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -134,15 +134,17 @@ There are several use-cases for try builds: the [dist-x86_64-linux] CI job. - Run a specific CI job (e.g. Windows tests) on a PR, to quickly test if it passes the test suite executed by that job. You can select which CI jobs will - be executed in the try build by adding up to 10 lines containing `try-job: - ` to the PR description. All such specified jobs will be executed + be executed in the try build by adding lines containing `try-job: + ` to the PR description. All such specified jobs will be executed in the try build once the `@bors try` command is used on the PR. If no try jobs are specified in this way, the jobs defined in the `try` section of - [`jobs.yml`] will be executed by default. + [`jobs.yml`] will be executed by default. Each pattern can either be an exact + name of a job or a glob pattern that matches multiple jobs, for example + `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. > **Using `try-job` PR description directives** > -> 1. Identify which set of try-jobs (max 10) you would like to exercise. You can +> 1. Identify which set of try-jobs you would like to exercise. You can > find the name of the CI jobs in [`jobs.yml`]. > > 2. Amend PR description to include (usually at the end of the PR description) @@ -153,9 +155,10 @@ There are several use-cases for try builds: > > try-job: x86_64-msvc > try-job: test-various +> try-job: *-alt > ``` > -> Each `try-job` directive must be on its own line. +> Each `try-job` pattern must be on its own line. > > 3. Run the prescribed try jobs with `@bors try`. As aforementioned, this > requires the user to either (1) have `try` permissions or (2) be delegated From dfef1a7b5ab07617d3c5a595f3764bdcc01ef23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 10 Mar 2025 13:56:42 +0100 Subject: [PATCH 22/42] Handle backticks in try job patterns --- src/ci/citool/src/main.rs | 11 ++++++++-- src/doc/rustc-dev-guide/src/tests/ci.md | 27 +++++++++++++++---------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 2a4be061e4ec9..cd690ebeb0625 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -46,13 +46,20 @@ impl GitHubContext { } } - /// Tries to parse patterns of CI jobs that should be executed in the form of + /// Tries to parse patterns of CI jobs that should be executed + /// from the commit message of the passed GitHub context + /// + /// They can be specified in the form of /// try-job: - /// from the commit message of the passed GitHub context. + /// or + /// try-job: `` + /// (to avoid GitHub rendering the glob patterns as Markdown) fn get_try_job_patterns(&self) -> Vec { if let Some(ref msg) = self.commit_message { msg.lines() .filter_map(|line| line.trim().strip_prefix("try-job: ")) + // Strip backticks if present + .map(|l| l.trim_matches('`')) .map(|l| l.trim().to_string()) .collect() } else { diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 7fd4c16972248..0c0f750a45d72 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -133,29 +133,34 @@ There are several use-cases for try builds: Again, a working compiler build is needed for this, which can be produced by the [dist-x86_64-linux] CI job. - Run a specific CI job (e.g. Windows tests) on a PR, to quickly test if it - passes the test suite executed by that job. You can select which CI jobs will - be executed in the try build by adding lines containing `try-job: - ` to the PR description. All such specified jobs will be executed - in the try build once the `@bors try` command is used on the PR. If no try - jobs are specified in this way, the jobs defined in the `try` section of - [`jobs.yml`] will be executed by default. Each pattern can either be an exact - name of a job or a glob pattern that matches multiple jobs, for example - `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. + passes the test suite executed by that job. + +You can select which CI jobs will +be executed in the try build by adding lines containing `try-job: +` to the PR description. All such specified jobs will be executed +in the try build once the `@bors try` command is used on the PR. If no try +jobs are specified in this way, the jobs defined in the `try` section of +[`jobs.yml`] will be executed by default. + +Each pattern can either be an exact name of a job or a glob pattern that matches multiple jobs, +for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. When using +glob patterns, you might want to wrap them in backticks (`` ` ``) to avoid GitHub rendering +the pattern as Markdown. > **Using `try-job` PR description directives** > > 1. Identify which set of try-jobs you would like to exercise. You can > find the name of the CI jobs in [`jobs.yml`]. > -> 2. Amend PR description to include (usually at the end of the PR description) -> e.g. +> 2. Amend PR description to include a set of patterns (usually at the end +> of the PR description), for example: > > ```text > This PR fixes #123456. > > try-job: x86_64-msvc > try-job: test-various -> try-job: *-alt +> try-job: `*-alt` > ``` > > Each `try-job` pattern must be on its own line. From 16c08f61139df87e07bbb37a9c7bccc5e62d0490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 10 Mar 2025 14:03:36 +0100 Subject: [PATCH 23/42] Ignore job duplicates --- src/ci/citool/src/jobs.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs index d161d17ebe646..45a188fb234a1 100644 --- a/src/ci/citool/src/jobs.rs +++ b/src/ci/citool/src/jobs.rs @@ -145,7 +145,11 @@ fn calculate_jobs( if matched_jobs.is_empty() { unknown_patterns.push(pattern.clone()); } else { - jobs.extend(matched_jobs); + for job in matched_jobs { + if !jobs.iter().any(|j| j.name == job.name) { + jobs.push(job); + } + } } } if !unknown_patterns.is_empty() { From bf58a3521f8e5fb0fa693e77ce9ef7e5e3c4a915 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sun, 9 Mar 2025 01:36:51 +0300 Subject: [PATCH 24/42] stabilize `ci_rustc_if_unchanged_logic` test for local environments Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/tests.rs | 10 ++++++++-- src/bootstrap/src/core/config/config.rs | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 63a1bbc24f16e..1f96ac729e2a3 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -261,8 +261,14 @@ fn ci_rustc_if_unchanged_logic() { // Make sure "if-unchanged" logic doesn't try to use CI rustc while there are changes // in compiler and/or library. if config.download_rustc_commit.is_some() { - let has_changes = - config.last_modified_commit(&["compiler", "library"], "download-rustc", true).is_none(); + let mut paths = vec!["compiler"]; + + // Handle library tree the same way as in `Config::download_ci_rustc_commit`. + if build_helper::ci::CiEnv::is_ci() { + paths.push("library"); + } + + let has_changes = config.last_modified_commit(&paths, "download-rustc", true).is_none(); assert!( !has_changes, diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index ac24da9f86b25..09dc9dfbc04ad 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2985,6 +2985,9 @@ impl Config { // these changes to speed up the build process for library developers. This provides consistent // functionality for library developers between `download-rustc=true` and `download-rustc="if-unchanged"` // options. + // + // If you update "library" logic here, update `builder::tests::ci_rustc_if_unchanged_logic` test + // logic accordingly. if !CiEnv::is_ci() { allowed_paths.push(":!library"); } From 32e0ce2fe6863439f2d3b81c443787ffd5283f63 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 10 Mar 2025 18:15:27 +0300 Subject: [PATCH 25/42] remove rls support from bootstrap Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/check.rs | 1 - src/bootstrap/src/core/build_steps/clippy.rs | 1 - src/bootstrap/src/core/build_steps/dist.rs | 43 -------------------- src/bootstrap/src/core/build_steps/setup.rs | 4 +- src/bootstrap/src/core/build_steps/tool.rs | 2 - src/bootstrap/src/core/builder/mod.rs | 4 -- src/bootstrap/src/lib.rs | 2 +- src/bootstrap/src/utils/tarball.rs | 3 -- 8 files changed, 2 insertions(+), 58 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 18aa3119842ce..e67bc62a60352 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -454,7 +454,6 @@ tool_check_step!(Rustdoc { path: "src/tools/rustdoc", alt_path: "src/librustdoc" tool_check_step!(Clippy { path: "src/tools/clippy" }); tool_check_step!(Miri { path: "src/tools/miri" }); tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri" }); -tool_check_step!(Rls { path: "src/tools/rls" }); tool_check_step!(Rustfmt { path: "src/tools/rustfmt" }); tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools" }); tool_check_step!(TestFloatParse { path: "src/etc/test-float-parse" }); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index fe8c89f7a5394..d3ab215d1b527 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -346,7 +346,6 @@ lint_any!( OptDist, "src/tools/opt-dist", "opt-dist"; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; RemoteTestServer, "src/tools/remote-test-server", "remote-test-server"; - Rls, "src/tools/rls", "rls"; RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer"; Rustdoc, "src/librustdoc", "clippy"; Rustfmt, "src/tools/rustfmt", "rustfmt"; diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index ec0edeab9968c..c393eb55c6244 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1157,48 +1157,6 @@ impl Step for Cargo { } } -#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] -pub struct Rls { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for Rls { - type Output = Option; - const ONLY_HOSTS: bool = true; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let default = should_build_extended_tool(run.builder, "rls"); - run.alias("rls").default_condition(default) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rls { - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.build, - run.target, - ), - target: run.target, - }); - } - - fn run(self, builder: &Builder<'_>) -> Option { - let compiler = self.compiler; - let target = self.target; - - let rls = builder.ensure(tool::Rls { compiler, target }); - - let mut tarball = Tarball::new(builder, "rls", &target.triple); - tarball.set_overlay(OverlayKind::Rls); - tarball.is_preview(true); - tarball.add_file(rls.tool_path, "bin", 0o755); - tarball.add_legal_and_readme_to("share/doc/rls"); - Some(tarball.generate()) - } -} - #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, @@ -1528,7 +1486,6 @@ impl Step for Extended { add_component!("rust-json-docs" => JsonDocs { host: target }); add_component!("cargo" => Cargo { compiler, target }); add_component!("rustfmt" => Rustfmt { compiler, target }); - add_component!("rls" => Rls { compiler, target }); add_component!("rust-analyzer" => RustAnalyzer { compiler, target }); add_component!("llvm-components" => LlvmTools { target }); add_component!("clippy" => Clippy { compiler, target }); diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index f25dfaab0f115..e198a8dd6a5be 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -85,9 +85,7 @@ impl FromStr for Profile { "lib" | "library" => Ok(Profile::Library), "compiler" => Ok(Profile::Compiler), "maintainer" | "dist" | "user" => Ok(Profile::Dist), - "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => { - Ok(Profile::Tools) - } + "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" => Ok(Profile::Tools), "none" => Ok(Profile::None), "llvm" | "codegen" => Err("the \"llvm\" and \"codegen\" profiles have been removed,\ use \"compiler\" instead which has the same functionality" diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index e0cf2c121390b..016f09cb2a8ec 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -228,7 +228,6 @@ pub fn prepare_tool_cargo( let mut features = extra_features.to_vec(); if builder.build.config.cargo_native_static { if path.ends_with("cargo") - || path.ends_with("rls") || path.ends_with("clippy") || path.ends_with("miri") || path.ends_with("rustfmt") @@ -1231,7 +1230,6 @@ tool_extended!(CargoMiri { stable: false, add_bins_to_sysroot: ["cargo-miri"] }); -tool_extended!(Rls { path: "src/tools/rls", tool_name: "rls", stable: true }); tool_extended!(Rustfmt { path: "src/tools/rustfmt", tool_name: "rustfmt", diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 8e1cecfcd18bc..0b49751f73cb1 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -895,7 +895,6 @@ impl<'a> Builder<'a> { tool::RemoteTestClient, tool::RustInstaller, tool::Cargo, - tool::Rls, tool::RustAnalyzer, tool::RustAnalyzerProcMacroSrv, tool::Rustdoc, @@ -938,7 +937,6 @@ impl<'a> Builder<'a> { clippy::OptDist, clippy::RemoteTestClient, clippy::RemoteTestServer, - clippy::Rls, clippy::RustAnalyzer, clippy::Rustdoc, clippy::Rustfmt, @@ -956,7 +954,6 @@ impl<'a> Builder<'a> { check::Miri, check::CargoMiri, check::MiroptTestTools, - check::Rls, check::Rustfmt, check::RustAnalyzer, check::TestFloatParse, @@ -1071,7 +1068,6 @@ impl<'a> Builder<'a> { dist::Analysis, dist::Src, dist::Cargo, - dist::Rls, dist::RustAnalyzer, dist::Rustfmt, dist::Clippy, diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 994ccabf0eb3f..fc4084378389e 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -253,7 +253,7 @@ pub enum Mode { /// Build a tool which uses the locally built rustc and the target std, /// placing the output in the "stageN-tools" directory. This is used for /// anything that needs a fully functional rustc, such as rustdoc, clippy, - /// cargo, rls, rustfmt, miri, etc. + /// cargo, rustfmt, miri, etc. ToolRustc, } diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 843ea65e83862..f1678bacc9769 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -22,7 +22,6 @@ pub(crate) enum OverlayKind { Clippy, Miri, Rustfmt, - Rls, RustAnalyzer, RustcCodegenCranelift, LlvmBitcodeLinker, @@ -56,7 +55,6 @@ impl OverlayKind { "src/tools/rustfmt/LICENSE-APACHE", "src/tools/rustfmt/LICENSE-MIT", ], - OverlayKind::Rls => &["src/tools/rls/README.md", "LICENSE-APACHE", "LICENSE-MIT"], OverlayKind::RustAnalyzer => &[ "src/tools/rust-analyzer/README.md", "src/tools/rust-analyzer/LICENSE-APACHE", @@ -90,7 +88,6 @@ impl OverlayKind { OverlayKind::Rustfmt => { builder.rustfmt_info.version(builder, &builder.release_num("rustfmt")) } - OverlayKind::Rls => builder.release(&builder.release_num("rls")), OverlayKind::RustAnalyzer => builder .rust_analyzer_info .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")), From 733cbb594deafbfedcf5c4a188c720baf756b0ab Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 10 Mar 2025 18:18:11 +0300 Subject: [PATCH 26/42] remove rls specific parts from tidy and build-manifest Signed-off-by: onur-ozkan --- src/tools/build-manifest/src/main.rs | 2 -- src/tools/build-manifest/src/versions.rs | 3 --- src/tools/tidy/src/walk.rs | 2 -- 3 files changed, 7 deletions(-) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index dfc8f3bc7e0db..741d7e3fa16c1 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -386,7 +386,6 @@ impl Builder { // NOTE: this profile is effectively deprecated; do not add new components to it. let mut complete = default; complete.extend([ - Rls, RustAnalyzer, RustSrc, LlvmTools, @@ -475,7 +474,6 @@ impl Builder { // but might be marked as unavailable if they weren't built. PkgType::Clippy | PkgType::Miri - | PkgType::Rls | PkgType::RustAnalyzer | PkgType::Rustfmt | PkgType::LlvmTools diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs index 495cab582eb07..6ef8a0e83de3f 100644 --- a/src/tools/build-manifest/src/versions.rs +++ b/src/tools/build-manifest/src/versions.rs @@ -51,7 +51,6 @@ pkg_type! { Cargo = "cargo", HtmlDocs = "rust-docs", RustAnalysis = "rust-analysis", - Rls = "rls"; preview = true, RustAnalyzer = "rust-analyzer"; preview = true, Clippy = "clippy"; preview = true, Rustfmt = "rustfmt"; preview = true, @@ -77,7 +76,6 @@ impl PkgType { fn should_use_rust_version(&self) -> bool { match self { PkgType::Cargo => false, - PkgType::Rls => false, PkgType::RustAnalyzer => false, PkgType::Clippy => false, PkgType::Rustfmt => false, @@ -118,7 +116,6 @@ impl PkgType { HtmlDocs => HOSTS, JsonDocs => HOSTS, RustSrc => &["*"], - Rls => HOSTS, RustAnalyzer => HOSTS, Clippy => HOSTS, Miri => HOSTS, diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index edf7658d25fdc..08ee5c16c122f 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -32,8 +32,6 @@ pub fn filter_dirs(path: &Path) -> bool { "src/doc/rustc-dev-guide", "src/doc/reference", "src/gcc", - // Filter RLS output directories - "target/rls", "src/bootstrap/target", "vendor", ]; From 91f8a400d846db5774d43e8b483d8613feb82a27 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 10 Mar 2025 18:19:03 +0300 Subject: [PATCH 27/42] remove rls source from the repository Signed-off-by: onur-ozkan --- Cargo.lock | 7 --- Cargo.toml | 1 - src/tools/rls/Cargo.toml | 8 --- src/tools/rls/README.md | 6 --- src/tools/rls/src/main.rs | 102 -------------------------------------- 5 files changed, 124 deletions(-) delete mode 100644 src/tools/rls/Cargo.toml delete mode 100644 src/tools/rls/README.md delete mode 100644 src/tools/rls/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index ecd26d6199c90..44e3cf5b70698 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3044,13 +3044,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rls" -version = "2.0.0" -dependencies = [ - "serde_json", -] - [[package]] name = "run_make_support" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index e2d032e080660..80b18a5dd4617 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ members = [ "src/tools/remote-test-server", "src/tools/rust-installer", "src/tools/rustdoc", - "src/tools/rls", "src/tools/rustfmt", "src/tools/miri", "src/tools/miri/cargo-miri", diff --git a/src/tools/rls/Cargo.toml b/src/tools/rls/Cargo.toml deleted file mode 100644 index b7aa659c25a94..0000000000000 --- a/src/tools/rls/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "rls" -version = "2.0.0" -edition = "2021" -license = "Apache-2.0/MIT" - -[dependencies] -serde_json = "1.0.83" diff --git a/src/tools/rls/README.md b/src/tools/rls/README.md deleted file mode 100644 index 43c331c413f5c..0000000000000 --- a/src/tools/rls/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# RLS Stub - -RLS has been replaced with [rust-analyzer](https://rust-analyzer.github.io/). - -This directory contains a stub which replaces RLS with a simple LSP server -which only displays an alert to the user that RLS is no longer available. diff --git a/src/tools/rls/src/main.rs b/src/tools/rls/src/main.rs deleted file mode 100644 index 3a95b47cd4dc4..0000000000000 --- a/src/tools/rls/src/main.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! RLS stub. -//! -//! This is a small stub that replaces RLS to alert the user that RLS is no -//! longer available. - -use std::error::Error; -use std::io::{BufRead, Write}; - -use serde_json::Value; - -const ALERT_MSG: &str = "\ -RLS is no longer available as of Rust 1.65. -Consider migrating to rust-analyzer instead. -See https://rust-analyzer.github.io/ for installation instructions. -"; - -fn main() { - if let Err(e) = run() { - eprintln!("error: {e}"); - std::process::exit(1); - } -} - -struct Message { - method: Option, -} - -fn run() -> Result<(), Box> { - let mut stdin = std::io::stdin().lock(); - let mut stdout = std::io::stdout().lock(); - - let init = read_message(&mut stdin)?; - if init.method.as_deref() != Some("initialize") { - return Err(format!("expected initialize, got {:?}", init.method).into()); - } - // No response, the LSP specification says that `showMessageRequest` may - // be posted before during this phase. - - // message_type 1 is "Error" - let alert = serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "method": "window/showMessageRequest", - "params": { - "message_type": "1", - "message": ALERT_MSG - } - }); - write_message_raw(&mut stdout, serde_json::to_string(&alert).unwrap())?; - - loop { - let message = read_message(&mut stdin)?; - if message.method.as_deref() == Some("shutdown") { - std::process::exit(0); - } - } -} - -fn read_message_raw(reader: &mut R) -> Result> { - let mut content_length: usize = 0; - - // Read headers. - loop { - let mut line = String::new(); - reader.read_line(&mut line)?; - if line.is_empty() { - return Err("remote disconnected".into()); - } - if line == "\r\n" { - break; - } - if line.to_lowercase().starts_with("content-length:") { - let value = &line[15..].trim(); - content_length = usize::from_str_radix(value, 10)?; - } - } - if content_length == 0 { - return Err("no content-length".into()); - } - - let mut buffer = vec![0; content_length]; - reader.read_exact(&mut buffer)?; - let content = String::from_utf8(buffer)?; - - Ok(content) -} - -fn read_message(reader: &mut R) -> Result> { - let m = read_message_raw(reader)?; - match serde_json::from_str::(&m) { - Ok(message) => Ok(Message { - method: message.get("method").and_then(|value| value.as_str().map(String::from)), - }), - Err(e) => Err(format!("failed to parse message {m}\n{e}").into()), - } -} - -fn write_message_raw(mut writer: W, output: String) -> Result<(), Box> { - write!(writer, "Content-Length: {}\r\n\r\n{}", output.len(), output)?; - writer.flush()?; - Ok(()) -} From a657aebd310f394bf4124758492825970f2358c2 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 10 Mar 2025 18:19:56 +0300 Subject: [PATCH 28/42] add change entry for rls removal Signed-off-by: onur-ozkan --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 425ffdccad57f..48d375794b207 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -370,4 +370,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "The rust.description option has moved to build.description and rust.description is now deprecated.", }, + ChangeInfo { + change_id: 126856, + severity: ChangeSeverity::Warning, + summary: "Removed `src/tools/rls` tool as it was deprecated long time ago.", + }, ]; From 5d4ff50f49220ebdf894421999ecee3deeaa7938 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 10 Mar 2025 18:01:15 +0100 Subject: [PATCH 29/42] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 4a01a9182496f..81a976a237f84 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 4a01a9182496f807aaa5f72d93a25ce18bcbe105 +Subproject commit 81a976a237f84b8392c4ce1bd5fd076eb757a2eb diff --git a/src/doc/edition-guide b/src/doc/edition-guide index daa4b763cd848..1e27e5e6d5133 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit daa4b763cd848f986813b5cf8069e1649f7147af +Subproject commit 1e27e5e6d5133ae4612f5cc195c15fc8d51b1c9c diff --git a/src/doc/nomicon b/src/doc/nomicon index 8f5c7322b65d0..b4448fa406a6d 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8f5c7322b65d079aa5b242eb10d89a98e12471e1 +Subproject commit b4448fa406a6dccde62d1e2f34f70fc51814cdcc diff --git a/src/doc/reference b/src/doc/reference index 615b4cec60c26..dda31c85f2ef2 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 615b4cec60c269cfc105d511c93287620032d5b0 +Subproject commit dda31c85f2ef2e5d2f0f2f643c9231690a30a626 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 66543bbc5b7db..6f69823c28ae8 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 66543bbc5b7dbd4e679092c07ae06ba6c73fd912 +Subproject commit 6f69823c28ae8d929d6c815181c73d3e99ef16d3 From dcf6137b5cb16c5ed569fd0a17517cbaed48e604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Mon, 10 Mar 2025 19:03:51 +0100 Subject: [PATCH 30/42] use next_back() instead of last() on DoubleEndedIterator --- compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs | 2 +- compiler/rustc_parse/src/parser/diagnostics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index ace5e34b38249..fa061c806180f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1520,7 +1520,7 @@ fn generics_args_err_extend<'a>( }) .collect(); if args.len() > 1 - && let Some(span) = args.into_iter().last() + && let Some(span) = args.into_iter().next_back() { err.note( "generic arguments are not allowed on both an enum and its variant's path \ diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index bb227a58cf19d..716ababb00802 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2107,7 +2107,7 @@ impl<'a> Parser<'a> { ast::GenericBound::Trait(poly) => Some(poly), _ => None, }) - .last() + .next_back() { err.span_suggestion_verbose( poly.span.shrink_to_hi(), From e337d87e965d2562544a2d45f6eeef503c1271d5 Mon Sep 17 00:00:00 2001 From: David Tenty Date: Fri, 7 Mar 2025 00:43:04 -0500 Subject: [PATCH 31/42] Add powerpc64le maintainers --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 +- .../powerpc64le-unknown-linux-gnu.md | 47 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index b1d7e5421c1b4..2f86021a4859d 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -72,6 +72,7 @@ - [powerpc-unknown-linux-gnuspe](platform-support/powerpc-unknown-linux-gnuspe.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [powerpc64le-unknown-linux-gnu](platform-support/powerpc64le-unknown-linux-gnu.md) - [powerpc64le-unknown-linux-musl](platform-support/powerpc64le-unknown-linux-musl.md) - [riscv32e\*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) - [riscv32i\*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 84440a5ab78b0..bdecc23e1f39a 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -96,7 +96,7 @@ target | notes [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) -`powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17) +[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17) [`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19, musl 1.2.3) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) diff --git a/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md new file mode 100644 index 0000000000000..6cb34b2a777a5 --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md @@ -0,0 +1,47 @@ +# `powerpc64le-unknown-linux-gnu` + +**Tier: 2** + +Target for 64-bit little endian PowerPC Linux programs + +## Target maintainers + +- David Tenty `daltenty@ibm.com`, https://github.com/daltenty +- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr + +## Requirements + +Building the target itself requires a 64-bit little endian PowerPC compiler that is supported by `cc-rs`. + +## Building the target + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["powerpc64le-unknown-linux-gnu"] +``` + +Make sure your C compiler is included in `$PATH`, then add it to the `config.toml`: + +```toml +[target.powerpc64le-unknown-linux-gnu] +cc = "powerpc64le-linux-gnu-gcc" +cxx = "powerpc64le-linux-gnu-g++" +ar = "powerpc64le-linux-gnu-ar" +linker = "powerpc64le-linux-gnu-gcc" +``` + +## Building Rust programs + +This target is distributed through `rustup`, and requires no special +configuration. + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +This target can be tested as normal with `x.py` on a 64-bit little endian +PowerPC host or via QEMU emulation. From d75c9733f4ff9f6a45566952e8f330f6c50bcb80 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 12:02:17 -0500 Subject: [PATCH 32/42] main.js: insertAfter needs non-root referenceNode --- src/librustdoc/html/static/js/main.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index edfcc1291b976..cde3909603f51 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -121,12 +121,9 @@ function getNakedUrl() { * doesn't have a parent node. * * @param {HTMLElement} newNode - * @param {HTMLElement} referenceNode + * @param {HTMLElement & { parentNode: HTMLElement }} referenceNode */ function insertAfter(newNode, referenceNode) { - // You're not allowed to pass an element with no parent. - // I dunno how to make TS's typechecker see that. - // @ts-expect-error referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } From 93161f5c14dd4f85c174ab446542063a25f6b2da Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 13:01:07 -0500 Subject: [PATCH 33/42] main.js: don't set mouseMovedAfterSearch, as it is never read --- src/librustdoc/html/static/js/main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index cde3909603f51..bcfc2c6fabd1b 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -322,7 +322,6 @@ function preLoadCss(cssUrl) { search = window.searchState.outputElement(); } switchDisplayedElement(search); - // @ts-expect-error window.searchState.mouseMovedAfterSearch = false; document.title = window.searchState.title; }, From cf7f3cf42417e9898d067536445fdee62d3d6663 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 13:24:33 -0500 Subject: [PATCH 34/42] main.js: give type signatures to a few helper functions --- src/librustdoc/html/static/js/main.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index bcfc2c6fabd1b..9e98131a00725 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -322,7 +322,6 @@ function preLoadCss(cssUrl) { search = window.searchState.outputElement(); } switchDisplayedElement(search); - window.searchState.mouseMovedAfterSearch = false; document.title = window.searchState.title; }, removeQueryParameters: () => { @@ -499,17 +498,22 @@ function preLoadCss(cssUrl) { handleHashes(ev); } - // @ts-expect-error + /** + * @param {HTMLElement|null} elem + */ function openParentDetails(elem) { while (elem) { if (elem.tagName === "DETAILS") { + // @ts-expect-error elem.open = true; } - elem = elem.parentNode; + elem = elem.parentElement; } } - // @ts-expect-error + /** + * @param {string} id + */ function expandSection(id) { openParentDetails(document.getElementById(id)); } From da5da99999a81dd1e80e269a30d0f490c02ce6ab Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 13:36:12 -0500 Subject: [PATCH 35/42] main.js: handleEscape and handleShortcut accept KeyboardEvent --- src/librustdoc/html/static/js/main.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 9e98131a00725..728f47dbc4cf8 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -518,7 +518,9 @@ function preLoadCss(cssUrl) { openParentDetails(document.getElementById(id)); } - // @ts-expect-error + /** + * @param {KeyboardEvent} ev + */ function handleEscape(ev) { // @ts-expect-error searchState.clearInputTimeout(); @@ -530,7 +532,9 @@ function preLoadCss(cssUrl) { window.hideAllModals(true); // true = reset focus for tooltips } - // @ts-expect-error + /** + * @param {KeyboardEvent} ev + */ function handleShortcut(ev) { // Don't interfere with browser shortcuts const disableShortcuts = getSettingValue("disable-shortcuts") === "true"; From 6622111906f5fd0b2820263a92d23df4aba831a8 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 13:42:56 -0500 Subject: [PATCH 36/42] main.js: always refer to searchState through window.searchState --- src/librustdoc/html/static/js/main.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 728f47dbc4cf8..02e4839e8e68c 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -522,13 +522,10 @@ function preLoadCss(cssUrl) { * @param {KeyboardEvent} ev */ function handleEscape(ev) { - // @ts-expect-error - searchState.clearInputTimeout(); - // @ts-expect-error - searchState.hideResults(); + window.searchState.clearInputTimeout(); + window.searchState.hideResults(); ev.preventDefault(); - // @ts-expect-error - searchState.defocus(); + window.searchState.defocus(); window.hideAllModals(true); // true = reset focus for tooltips } @@ -563,8 +560,7 @@ function preLoadCss(cssUrl) { case "S": case "/": ev.preventDefault(); - // @ts-expect-error - searchState.focus(); + window.searchState.focus(); break; case "+": @@ -1699,8 +1695,7 @@ function preLoadCss(cssUrl) { addSidebarCrates(); onHashChange(null); window.addEventListener("hashchange", onHashChange); - // @ts-expect-error - searchState.setup(); + window.searchState.setup(); }()); // Hide, show, and resize the sidebar From f5efd2aba3003aff5461ce6495558a7dad0a3923 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 13:46:35 -0500 Subject: [PATCH 37/42] main.js(isDisplayed): coerce truthy values to boolean --- src/librustdoc/html/static/js/main.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 02e4839e8e68c..3fdff21e591b5 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -302,11 +302,10 @@ function preLoadCss(cssUrl) { window.searchState.timeout = null; } }, - // @ts-expect-error isDisplayed: () => { const outputElement = window.searchState.outputElement(); - return outputElement && - outputElement.parentElement && + return !!outputElement && + !!outputElement.parentElement && outputElement.parentElement.id === ALTERNATIVE_DISPLAY_ID; }, // Sets the focus on the search bar at the top of the page From ab180c29e36504b4faed64dbffb29fbeca71e61c Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 13:54:02 -0500 Subject: [PATCH 38/42] main.js: handle document.activeElement being null this is technically possible if someone sticks rustdoc in an iframe, i think? --- src/librustdoc/html/static/js/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 3fdff21e591b5..755b999e171e0 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -538,8 +538,8 @@ function preLoadCss(cssUrl) { return; } - // @ts-expect-error - if (document.activeElement.tagName === "INPUT" && + if (document.activeElement && + document.activeElement.tagName === "INPUT" && // @ts-expect-error document.activeElement.type !== "checkbox" && // @ts-expect-error From 2e1c8f088aa9b422490449a92466b71c4f115819 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 14:06:13 -0500 Subject: [PATCH 39/42] rustdoc.d.ts: window.SIDEBAR_ITEMS may exist. --- src/librustdoc/html/static/js/main.js | 1 - src/librustdoc/html/static/js/rustdoc.d.ts | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 755b999e171e0..b475e6418a747 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -585,7 +585,6 @@ function preLoadCss(cssUrl) { document.addEventListener("keydown", handleShortcut); function addSidebarItems() { - // @ts-expect-error if (!window.SIDEBAR_ITEMS) { return; } diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 1554c045a3271..def0bd4f71ee0 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -7,6 +7,8 @@ declare global { interface Window { /** Make the current theme easy to find */ currentTheme: HTMLLinkElement|null; + /** Generated in `render/context.rs` */ + SIDEBAR_ITEMS?: { [key: string]: string[] }; /** Used by the popover tooltip code. */ RUSTDOC_TOOLTIP_HOVER_MS: number; /** Used by the popover tooltip code. */ From 749b6bf79f0fb1cfa3d2ba12f3ae2f1cf0f374d0 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 14:29:08 -0500 Subject: [PATCH 40/42] rustdoc.d.ts: add window.{register_implementors,pending_implementors} --- src/librustdoc/html/static/js/main.js | 3 --- src/librustdoc/html/static/js/rustdoc.d.ts | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index b475e6418a747..26639a85601a7 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -673,7 +673,6 @@ function preLoadCss(cssUrl) { } // - // @ts-expect-error window.register_implementors = imp => { const implementors = document.getElementById("implementors-list"); const synthetic_implementors = document.getElementById("synthetic-implementors-list"); @@ -765,9 +764,7 @@ function preLoadCss(cssUrl) { } } }; - // @ts-expect-error if (window.pending_implementors) { - // @ts-expect-error window.register_implementors(window.pending_implementors); } diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index def0bd4f71ee0..4504642480b39 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -44,6 +44,15 @@ declare global { * Set up event listeners for a scraped source example. */ updateScrapedExample?: function(HTMLElement, HTMLElement), + /** + * register trait implementors, called by code generated in + * `write_shared.rs` + */ + register_implementors?: function(Implementors): void, + /** + * fallback in case `register_implementors` isn't defined yet. + */ + pending_implementors?: Implementors, } interface HTMLElement { /** Used by the popover tooltip code. */ @@ -415,4 +424,12 @@ declare namespace rustdoc { }; type VlqData = VlqData[] | number; + + /** + * Maps from crate names to trait implementation data. + * Provied by generated `trait.impl` files. + */ + type Implementors = { + [key: string]: Array<[string, number, Array]> + } } From 7421546f6b35393f0ba18988c2ee8a8e973b1e8b Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 14:40:38 -0500 Subject: [PATCH 41/42] main.js: typecheck things related to window.register_type_impls --- src/librustdoc/html/static/js/main.js | 8 ++------ src/librustdoc/html/static/js/rustdoc.d.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 26639a85601a7..5b4453b558977 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -797,16 +797,14 @@ function preLoadCss(cssUrl) { * * - After processing all of the impls, it sorts the sidebar items by name. * - * @param {{[cratename: string]: Array>}} imp + * @param {rustdoc.TypeImpls} imp */ - // @ts-expect-error window.register_type_impls = imp => { // @ts-expect-error if (!imp || !imp[window.currentCrate]) { return; } - // @ts-expect-error - window.pending_type_impls = null; + window.pending_type_impls = undefined; const idMap = new Map(); let implementations = document.getElementById("implementations-list"); @@ -992,9 +990,7 @@ function preLoadCss(cssUrl) { list.replaceChildren(...newChildren); } }; - // @ts-expect-error if (window.pending_type_impls) { - // @ts-expect-error window.register_type_impls(window.pending_type_impls); } diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 4504642480b39..4b43c00730d47 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -48,11 +48,13 @@ declare global { * register trait implementors, called by code generated in * `write_shared.rs` */ - register_implementors?: function(Implementors): void, + register_implementors?: function(rustdoc.Implementors): void, /** * fallback in case `register_implementors` isn't defined yet. */ - pending_implementors?: Implementors, + pending_implementors?: rustdoc.Implementors, + register_type_impls?: function(rustdoc.TypeImpls): void, + pending_type_impls?: rustdoc.TypeImpls, } interface HTMLElement { /** Used by the popover tooltip code. */ @@ -432,4 +434,8 @@ declare namespace rustdoc { type Implementors = { [key: string]: Array<[string, number, Array]> } + + type TypeImpls = { + [cratename: string]: Array> + } } From 20bac26165a05bb5383621ad5f65b3ae9dfdb9b4 Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 10 Mar 2025 16:38:11 -0500 Subject: [PATCH 42/42] main.js: remove searchState from globals. --- src/librustdoc/html/static/js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 5b4453b558977..4150c5609a97e 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1,5 +1,5 @@ // Local js definitions: -/* global addClass, getSettingValue, hasClass, searchState, updateLocalStorage */ +/* global addClass, getSettingValue, hasClass, updateLocalStorage */ /* global onEachLazy, removeClass, getVar */ "use strict";