From e1fc4a997ddac2b949ef6bb4037f1fb196c44f08 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Jul 2024 15:12:14 +1000 Subject: [PATCH 1/9] Don't store `thir::Pat` in error structs In several cases this avoids the need to clone the underlying pattern, and then print the clone later. --- compiler/rustc_middle/src/thir.rs | 7 --- compiler/rustc_mir_build/src/errors.rs | 2 +- compiler/rustc_pattern_analysis/src/errors.rs | 53 +++++++++---------- compiler/rustc_pattern_analysis/src/rustc.rs | 10 ++-- 4 files changed, 32 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b80d00719ee5e..1300a06f37510 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -9,7 +9,6 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; @@ -702,12 +701,6 @@ impl<'tcx> Pat<'tcx> { } } -impl<'tcx> IntoDiagArg for Pat<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - format!("{self}").into_diag_arg() - } -} - #[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Ascription<'tcx> { pub annotation: CanonicalUserTypeAnnotation<'tcx>, diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index bdc4b0ea97d18..2e508829fbe3c 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -856,7 +856,7 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub(crate) span: Span, pub(crate) origin: &'s str, #[subdiagnostic] - pub(crate) uncovered: Uncovered<'tcx>, + pub(crate) uncovered: Uncovered, #[subdiagnostic] pub(crate) inform: Option, #[subdiagnostic] diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 27f227e6d9c11..bad41ac77f098 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,6 +1,5 @@ use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; -use rustc_middle::thir::Pat; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -8,18 +7,18 @@ use crate::rustc::{RustcPatCtxt, WitnessPat}; #[derive(Subdiagnostic)] #[label(pattern_analysis_uncovered)] -pub struct Uncovered<'tcx> { +pub struct Uncovered { #[primary_span] span: Span, count: usize, - witness_1: Pat<'tcx>, - witness_2: Pat<'tcx>, - witness_3: Pat<'tcx>, + witness_1: String, // a printed pattern + witness_2: String, // a printed pattern + witness_3: String, // a printed pattern remainder: usize, } -impl<'tcx> Uncovered<'tcx> { - pub fn new<'p>( +impl Uncovered { + pub fn new<'p, 'tcx>( span: Span, cx: &RustcPatCtxt<'p, 'tcx>, witnesses: Vec>, @@ -27,19 +26,19 @@ impl<'tcx> Uncovered<'tcx> { where 'tcx: 'p, { - let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap()); + let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap()).to_string(); Self { span, count: witnesses.len(), // Substitute dummy values if witnesses is smaller than 3. These will never be read. witness_2: witnesses .get(1) - .map(|w| cx.hoist_witness_pat(w)) - .unwrap_or_else(|| witness_1.clone()), + .map(|w| cx.hoist_witness_pat(w).to_string()) + .unwrap_or_default(), witness_3: witnesses .get(2) - .map(|w| cx.hoist_witness_pat(w)) - .unwrap_or_else(|| witness_1.clone()), + .map(|w| cx.hoist_witness_pat(w).to_string()) + .unwrap_or_default(), witness_1, remainder: witnesses.len().saturating_sub(3), } @@ -49,19 +48,19 @@ impl<'tcx> Uncovered<'tcx> { #[derive(LintDiagnostic)] #[diag(pattern_analysis_overlapping_range_endpoints)] #[note] -pub struct OverlappingRangeEndpoints<'tcx> { +pub struct OverlappingRangeEndpoints { #[label] pub range: Span, #[subdiagnostic] - pub overlap: Vec>, + pub overlap: Vec, } -pub struct Overlap<'tcx> { +pub struct Overlap { pub span: Span, - pub range: Pat<'tcx>, + pub range: String, // a printed pattern } -impl<'tcx> Subdiagnostic for Overlap<'tcx> { +impl Subdiagnostic for Overlap { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, @@ -78,38 +77,38 @@ impl<'tcx> Subdiagnostic for Overlap<'tcx> { #[derive(LintDiagnostic)] #[diag(pattern_analysis_excluside_range_missing_max)] -pub struct ExclusiveRangeMissingMax<'tcx> { +pub struct ExclusiveRangeMissingMax { #[label] #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")] /// This is an exclusive range that looks like `lo..max` (i.e. doesn't match `max`). pub first_range: Span, /// Suggest `lo..=max` instead. pub suggestion: String, - pub max: Pat<'tcx>, + pub max: String, // a printed pattern } #[derive(LintDiagnostic)] #[diag(pattern_analysis_excluside_range_missing_gap)] -pub struct ExclusiveRangeMissingGap<'tcx> { +pub struct ExclusiveRangeMissingGap { #[label] #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")] /// This is an exclusive range that looks like `lo..gap` (i.e. doesn't match `gap`). pub first_range: Span, - pub gap: Pat<'tcx>, + pub gap: String, // a printed pattern /// Suggest `lo..=gap` instead. pub suggestion: String, #[subdiagnostic] /// All these ranges skipped over `gap` which we think is probably a mistake. - pub gap_with: Vec>, + pub gap_with: Vec, } -pub struct GappedRange<'tcx> { +pub struct GappedRange { pub span: Span, - pub gap: Pat<'tcx>, - pub first_range: Pat<'tcx>, + pub gap: String, // a printed pattern + pub first_range: String, // a printed pattern } -impl<'tcx> Subdiagnostic for GappedRange<'tcx> { +impl Subdiagnostic for GappedRange { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, @@ -134,7 +133,7 @@ impl<'tcx> Subdiagnostic for GappedRange<'tcx> { pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { pub scrut_ty: Ty<'tcx>, #[subdiagnostic] - pub uncovered: Uncovered<'tcx>, + pub uncovered: Uncovered, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 910dd4c6c1a84..ceddafa2f4ceb 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -966,7 +966,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { let overlaps: Vec<_> = overlaps_with .iter() .map(|pat| pat.data().span) - .map(|span| errors::Overlap { range: overlap_as_pat.clone(), span }) + .map(|span| errors::Overlap { range: overlap_as_pat.to_string(), span }) .collect(); let pat_span = pat.data().span; self.tcx.emit_node_span_lint( @@ -1014,7 +1014,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { // Point at this range. first_range: thir_pat.span, // That's the gap that isn't covered. - max: gap_as_pat.clone(), + max: gap_as_pat.to_string(), // Suggest `lo..=max` instead. suggestion: suggested_range.to_string(), }, @@ -1028,7 +1028,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { // Point at this range. first_range: thir_pat.span, // That's the gap that isn't covered. - gap: gap_as_pat.clone(), + gap: gap_as_pat.to_string(), // Suggest `lo..=gap` instead. suggestion: suggested_range.to_string(), // All these ranges skipped over `gap` which we think is probably a @@ -1037,8 +1037,8 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { .iter() .map(|pat| errors::GappedRange { span: pat.data().span, - gap: gap_as_pat.clone(), - first_range: thir_pat.clone(), + gap: gap_as_pat.to_string(), + first_range: thir_pat.to_string(), }) .collect(), }, From 41cf8374a640fca0f5d5b97c345aa4c3c0df9c25 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 28 Jul 2024 22:30:01 +0200 Subject: [PATCH 2/9] CI: move RFL job forward to v6.11-rc1 The tag has been released today, and since the original hash we had in the Rust CI (which was ~v6.10-rc1), we have accumulated a fair amount of changes and new code. In particular, v6.11-rc1 is the first Linux tag where the kernel is supporting an actual minimum Rust version (1.78.0), rather than a single version. Signed-off-by: Miguel Ojeda --- src/ci/docker/scripts/rfl-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index da7b029ca7329..3acc09e0b9b1a 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,7 @@ set -euo pipefail -LINUX_VERSION=c13320499ba0efd93174ef6462ae8a7a2933f6e7 +LINUX_VERSION=v6.11-rc1 # Build rustc, rustdoc and cargo ../x.py build --stage 1 library rustdoc From db05b0fd343e8204460b0e1f3e261cc4ae940e0a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Jul 2024 15:14:26 +1000 Subject: [PATCH 3/9] Encapsulate the printing of `WitnessPat` This hides the fact that we print `WitnessPat` by converting it to `thir::Pat` and then printing that. --- .../src/thir/pattern/check_match.rs | 8 ++++---- compiler/rustc_pattern_analysis/src/errors.rs | 12 +++--------- compiler/rustc_pattern_analysis/src/rustc.rs | 14 +++++++++++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 5e904057e732c..0632911671e12 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1077,7 +1077,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( let suggested_arm = if suggest_the_witnesses { let pattern = witnesses .iter() - .map(|witness| cx.hoist_witness_pat(witness).to_string()) + .map(|witness| cx.print_witness_pat(witness)) .collect::>() .join(" | "); if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns { @@ -1195,13 +1195,13 @@ fn joined_uncovered_patterns<'p, 'tcx>( witnesses: &[WitnessPat<'p, 'tcx>], ) -> String { const LIMIT: usize = 3; - let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.hoist_witness_pat(pat).to_string(); + let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.print_witness_pat(pat); match witnesses { [] => bug!(), - [witness] => format!("`{}`", cx.hoist_witness_pat(witness)), + [witness] => format!("`{}`", cx.print_witness_pat(witness)), [head @ .., tail] if head.len() < LIMIT => { let head: Vec<_> = head.iter().map(pat_to_str).collect(); - format!("`{}` and `{}`", head.join("`, `"), cx.hoist_witness_pat(tail)) + format!("`{}` and `{}`", head.join("`, `"), cx.print_witness_pat(tail)) } _ => { let (head, tail) = witnesses.split_at(LIMIT); diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index bad41ac77f098..1f7852e5190d2 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -26,19 +26,13 @@ impl Uncovered { where 'tcx: 'p, { - let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap()).to_string(); + let witness_1 = cx.print_witness_pat(witnesses.get(0).unwrap()); Self { span, count: witnesses.len(), // Substitute dummy values if witnesses is smaller than 3. These will never be read. - witness_2: witnesses - .get(1) - .map(|w| cx.hoist_witness_pat(w).to_string()) - .unwrap_or_default(), - witness_3: witnesses - .get(2) - .map(|w| cx.hoist_witness_pat(w).to_string()) - .unwrap_or_default(), + witness_2: witnesses.get(1).map(|w| cx.print_witness_pat(w)).unwrap_or_default(), + witness_3: witnesses.get(2).map(|w| cx.print_witness_pat(w)).unwrap_or_default(), witness_1, remainder: witnesses.len().saturating_sub(3), } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index ceddafa2f4ceb..b04c21a384c8c 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -744,7 +744,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Note: it is possible to get `isize/usize::MAX+1` here, as explained in the doc for /// [`IntRange::split`]. This cannot be represented as a `Const`, so we represent it with /// `PosInfinity`. - pub(crate) fn hoist_pat_range_bdy( + fn hoist_pat_range_bdy( &self, miint: MaybeInfiniteInt, ty: RevealedTy<'tcx>, @@ -775,7 +775,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } /// Convert back to a `thir::Pat` for diagnostic purposes. - pub(crate) fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> Pat<'tcx> { + fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> Pat<'tcx> { use MaybeInfiniteInt::*; let cx = self; let kind = if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) { @@ -811,9 +811,17 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { Pat { ty: ty.inner(), span: DUMMY_SP, kind } } + + /// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes. + pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String { + // This works by converting the witness pattern back to a `thir::Pat` + // and then printing that, but callers don't need to know that. + self.hoist_witness_pat(pat).to_string() + } + /// Convert back to a `thir::Pat` for diagnostic purposes. This panics for patterns that don't /// appear in diagnostics, like float ranges. - pub fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> Pat<'tcx> { + fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> Pat<'tcx> { let cx = self; let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild); let mut subpatterns = pat.iter_fields().map(|p| Box::new(cx.hoist_witness_pat(p))); From ae0ec731a86ac6a2f6d8d08c4996bb8a438afdc2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Jul 2024 14:02:41 +1000 Subject: [PATCH 4/9] Make `thir::Pat` not implement `fmt::Display` directly This gives a clearer view of the (diagnostic) code that expects to be able to print THIR patterns, and makes it possible to experiment with requiring some kind of context (for ID lookup) when printing patterns. --- compiler/rustc_middle/src/thir.rs | 65 ++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 1300a06f37510..9b63b3980d20f 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1073,8 +1073,33 @@ impl<'tcx> PatRangeBoundary<'tcx> { } } -impl<'tcx> fmt::Display for Pat<'tcx> { +impl<'tcx> Pat<'tcx> { + /// Prints a [`Pat`] to an owned string, for user-facing diagnostics. + /// + /// If we ever switch over to storing subpatterns as `PatId`, this will also + /// need to take a context that can resolve IDs to subpatterns. + pub fn to_string(&self) -> String { + format!("{}", self.display()) + } + + /// Used internally by [`fmt::Display`] for [`PatDisplay`]. + fn display(&self) -> PatDisplay<'_, 'tcx> { + PatDisplay { pat: self } + } +} + +/// Wrapper around [`&Pat<'tcx>`][`Pat`] that implements [`fmt::Display`]. +/// +/// If we ever switch over to storing subpatterns as `PatId`, this will also +/// need to hold a context that can resolve IDs to subpatterns. +struct PatDisplay<'pat, 'tcx> { + pat: &'pat Pat<'tcx>, +} + +impl<'pat, 'tcx> fmt::Display for PatDisplay<'pat, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let &Self { pat } = self; + // Printing lists is a chore. let mut first = true; let mut start_or_continue = |s| { @@ -1087,20 +1112,22 @@ impl<'tcx> fmt::Display for Pat<'tcx> { }; let mut start_or_comma = || start_or_continue(", "); - match self.kind { + match pat.kind { PatKind::Wild => write!(f, "_"), PatKind::Never => write!(f, "!"), - PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"), + PatKind::AscribeUserType { ref subpattern, .. } => { + write!(f, "{}: _", subpattern.display()) + } PatKind::Binding { name, mode, ref subpattern, .. } => { f.write_str(mode.prefix_str())?; write!(f, "{name}")?; if let Some(ref subpattern) = *subpattern { - write!(f, " @ {subpattern}")?; + write!(f, " @ {}", subpattern.display())?; } Ok(()) } PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { - let variant_and_name = match self.kind { + let variant_and_name = match pat.kind { PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| { let variant = adt_def.variant(variant_index); let adt_did = adt_def.did(); @@ -1113,7 +1140,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { }; Some((variant, name)) }), - _ => self.ty.ty_adt_def().and_then(|adt_def| { + _ => pat.ty.ty_adt_def().and_then(|adt_def| { if !adt_def.is_enum() { ty::tls::with(|tcx| { Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) @@ -1138,11 +1165,11 @@ impl<'tcx> fmt::Display for Pat<'tcx> { continue; } let name = variant.fields[p.field].name; - write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?; + write!(f, "{}{}: {}", start_or_comma(), name, p.pattern.display())?; printed += 1; } - let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union()); + let is_union = pat.ty.ty_adt_def().is_some_and(|adt| adt.is_union()); if printed < variant.fields.len() && (!is_union || printed == 0) { write!(f, "{}..", start_or_comma())?; } @@ -1161,14 +1188,14 @@ impl<'tcx> fmt::Display for Pat<'tcx> { // Common case: the field is where we expect it. if let Some(p) = subpatterns.get(i) { if p.field.index() == i { - write!(f, "{}", p.pattern)?; + write!(f, "{}", p.pattern.display())?; continue; } } // Otherwise, we have to go looking for it. if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { - write!(f, "{}", p.pattern)?; + write!(f, "{}", p.pattern.display())?; } else { write!(f, "_")?; } @@ -1179,45 +1206,45 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Ok(()) } PatKind::Deref { ref subpattern } => { - match self.ty.kind() { + match pat.ty.kind() { ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, ty::Ref(_, _, mutbl) => { write!(f, "&{}", mutbl.prefix_str())?; } - _ => bug!("{} is a bad Deref pattern type", self.ty), + _ => bug!("{} is a bad Deref pattern type", pat.ty), } - write!(f, "{subpattern}") + write!(f, "{}", subpattern.display()) } PatKind::DerefPattern { ref subpattern, .. } => { - write!(f, "deref!({subpattern})") + write!(f, "deref!({})", subpattern.display()) } PatKind::Constant { value } => write!(f, "{value}"), PatKind::InlineConstant { def: _, ref subpattern } => { - write!(f, "{} (from inline const)", subpattern) + write!(f, "{} (from inline const)", subpattern.display()) } PatKind::Range(ref range) => write!(f, "{range}"), PatKind::Slice { ref prefix, ref slice, ref suffix } | PatKind::Array { ref prefix, ref slice, ref suffix } => { write!(f, "[")?; for p in prefix.iter() { - write!(f, "{}{}", start_or_comma(), p)?; + write!(f, "{}{}", start_or_comma(), p.display())?; } if let Some(ref slice) = *slice { write!(f, "{}", start_or_comma())?; match slice.kind { PatKind::Wild => {} - _ => write!(f, "{slice}")?, + _ => write!(f, "{}", slice.display())?, } write!(f, "..")?; } for p in suffix.iter() { - write!(f, "{}{}", start_or_comma(), p)?; + write!(f, "{}{}", start_or_comma(), p.display())?; } write!(f, "]") } PatKind::Or { ref pats } => { for pat in pats.iter() { - write!(f, "{}{}", start_or_continue(" | "), pat)?; + write!(f, "{}{}", start_or_continue(" | "), pat.display())?; } Ok(()) } From 6e247195c644aa924a10c98cc8eb3a28e1a87929 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 25 Jul 2024 15:59:25 +0300 Subject: [PATCH 5/9] handle no_std targets on std builds This change unifies the `Step::run_make` logic and improves it by skipping std specific crates for no_std targets. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/check.rs | 4 ++-- src/bootstrap/src/core/build_steps/clippy.rs | 3 ++- src/bootstrap/src/core/build_steps/compile.rs | 23 +++++++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 11ddae2aa2413..8b71300cf85e7 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use crate::core::build_steps::compile::{ - add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, + add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, }; use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType}; use crate::core::builder::{ @@ -49,7 +49,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - let crates = run.make_run_crates(Alias::Library); + let crates = std_crates_for_run_make(&run); run.builder.ensure(Std { target: run.target, crates, override_build_kind: None }); } diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index e45b44b82ded1..4ee9fbc314263 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -4,6 +4,7 @@ use super::compile::{librustc_stamp, libstd_stamp, run_cargo, rustc_cargo, std_c use super::tool::{prepare_tool_cargo, SourceType}; use super::{check, compile}; use crate::builder::{Builder, ShouldRun}; +use crate::core::build_steps::compile::std_crates_for_run_make; use crate::core::builder; use crate::core::builder::{crate_description, Alias, Kind, RunConfig, Step}; use crate::{Mode, Subcommand, TargetSelection}; @@ -106,7 +107,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - let crates = run.make_run_crates(Alias::Library); + let crates = std_crates_for_run_make(&run); run.builder.ensure(Std { target: run.target, crates }); } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index ce456a7200223..3164de8451ff2 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -123,11 +123,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - // If the paths include "library", build the entire standard library. - let has_alias = - run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); - let crates = if has_alias { Default::default() } else { run.cargo_crates_in_set() }; - + let crates = std_crates_for_run_make(&run); run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, @@ -425,6 +421,23 @@ fn copy_self_contained_objects( target_deps } +/// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.). +pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec { + let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); + let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false); + + // For no_std targets, do not add any additional crates to the compilation other than what `compile::std_cargo` already adds for no_std targets. + if target_is_no_std { + vec![] + } + // If the paths include "library", build the entire standard library. + else if has_alias { + run.make_run_crates(builder::Alias::Library) + } else { + run.cargo_crates_in_set() + } +} + /// Configure cargo to compile the standard library, adding appropriate env vars /// and such. pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) { From 4c87e84f998378f125222f876ef454a71861a7f4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 25 Jul 2024 16:04:36 +0300 Subject: [PATCH 6/9] allow running `x doc` on std for no_std targets Since we now handle library crates properly, there's no need to panic for `no_std` targets anymore. `x doc library` now generates documentation for the `alloc` crate from standard library. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/doc.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 0b780dae9c29a..53925a3f54b8a 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -589,6 +589,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { + let crates = compile::std_crates_for_run_make(&run); run.builder.ensure(Std { stage: run.builder.top_stage, target: run.target, @@ -597,7 +598,7 @@ impl Step for Std { } else { DocumentationFormat::Html }, - crates: run.make_run_crates(Alias::Library), + crates, }); } @@ -695,13 +696,6 @@ fn doc_std( extra_args: &[&str], requested_crates: &[String], ) { - if builder.no_std(target) == Some(true) { - panic!( - "building std documentation for no_std target {target} is not supported\n\ - Set `docs = false` in the config to disable documentation, or pass `--skip library`." - ); - } - let compiler = builder.compiler(stage, builder.config.build); let target_doc_dir_name = if format == DocumentationFormat::Json { "json-doc" } else { "doc" }; From d3aed2cdb4d4069ef7b6c5c74a3679817272a6ba Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 26 Jul 2024 08:48:46 +0300 Subject: [PATCH 7/9] remove the requirement of `Builder` arg in `doc::Std::new` function `crates` field is handled in the `Step::make_run` just like in any other `Std` implementation, so we don't need to resolve them in `Std::new`. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/dist.rs | 1 - src/bootstrap/src/core/build_steps/doc.rs | 14 ++------------ src/bootstrap/src/core/build_steps/test.rs | 1 - src/bootstrap/src/core/builder/tests.rs | 4 ---- 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index f971bf115ee92..967ddbc0d3483 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -106,7 +106,6 @@ impl Step for JsonDocs { builder.ensure(crate::core::build_steps::doc::Std::new( builder.top_stage, host, - builder, DocumentationFormat::Json, )); diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 53925a3f54b8a..1541396bfdd98 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -564,18 +564,8 @@ pub struct Std { } impl Std { - pub(crate) fn new( - stage: u32, - target: TargetSelection, - builder: &Builder<'_>, - format: DocumentationFormat, - ) -> Self { - let crates = builder - .in_tree_crates("sysroot", Some(target)) - .into_iter() - .map(|krate| krate.name.to_string()) - .collect(); - Std { stage, target, format, crates } + pub(crate) fn new(stage: u32, target: TargetSelection, format: DocumentationFormat) -> Self { + Std { stage, target, format, crates: vec![] } } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 79b7dd78810d2..ec96307deb285 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -847,7 +847,6 @@ impl Step for RustdocJSStd { builder.ensure(crate::core::build_steps::doc::Std::new( builder.top_stage, self.target, - builder, DocumentationFormat::Html, )); let _guard = builder.msg( diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index a295c89730acb..f19a4dd6d490f 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -79,13 +79,9 @@ macro_rules! std { macro_rules! doc_std { ($host:ident => $target:ident, stage = $stage:literal) => {{ - let config = configure("doc", &["A-A"], &["A-A"]); - let build = Build::new(config); - let builder = Builder::new(&build); doc::Std::new( $stage, TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))), - &builder, DocumentationFormat::Html, ) }}; From f56d58e4a784b6429e742a411c2759900741894d Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 26 Jul 2024 08:54:55 +0300 Subject: [PATCH 8/9] ignore `crates` if running unit tests Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3164de8451ff2..268e89c7f6011 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -423,6 +423,11 @@ fn copy_self_contained_objects( /// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.). pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec { + // FIXME: Extend builder tests to cover the `crates` field of `Std` instances. + if cfg!(feature = "bootstrap-self-test") { + return vec![]; + } + let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false); From 6a6824a0ab5c14b5343fe108f10ec40c146b97e4 Mon Sep 17 00:00:00 2001 From: John Spray Date: Fri, 26 Jul 2024 15:58:24 +0100 Subject: [PATCH 9/9] Optimize empty case in Vec::retain --- library/alloc/src/vec/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 729d5dd4fe4d2..417b88bfe8dad 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1711,6 +1711,12 @@ impl Vec { F: FnMut(&mut T) -> bool, { let original_len = self.len(); + + if original_len == 0 { + // Empty case: explicit return allows better optimization, vs letting compiler infer it + return; + } + // Avoid double drop if the drop guard is not executed, // since we may make some holes during the process. unsafe { self.set_len(0) };