From d5d5ff7edfcc3885c38b5d76c19c641e001f78fe Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 29 Jul 2026 11:10:21 +0200 Subject: [PATCH 1/5] make `pad_i32` of `PassMode::cast` an integer so that we can specify more than one i32 of padding. --- .../src/abi/pass_mode.rs | 4 +-- compiler/rustc_codegen_gcc/src/abi.rs | 12 ++++---- compiler/rustc_codegen_gcc/src/type_of.rs | 4 +-- compiler/rustc_codegen_llvm/src/abi.rs | 28 ++++++++++--------- compiler/rustc_codegen_ssa/src/mir/block.rs | 9 +++--- compiler/rustc_codegen_ssa/src/mir/mod.rs | 8 +++--- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 4 +-- .../src/mono_checks/abi_check.rs | 2 +- compiler/rustc_public/src/abi.rs | 2 +- .../src/unstable/convert/stable/abi.rs | 4 +-- compiler/rustc_target/src/callconv/mips.rs | 2 +- compiler/rustc_target/src/callconv/mips64.rs | 2 +- compiler/rustc_target/src/callconv/mod.rs | 17 +++++------ compiler/rustc_target/src/callconv/sparc.rs | 2 +- compiler/rustc_target/src/callconv/sparc64.rs | 2 +- tests/ui/abi/pass-indirectly-attr.stderr | 2 +- 16 files changed, 55 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index c4d4ddcf6b753..1c552ca1a9c32 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -122,8 +122,8 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Cast { ref cast, pad_i32 } => { - assert!(!pad_i32, "padding support not yet implemented"); + PassMode::Cast { ref cast, pad_i32_count } => { + assert_eq!(pad_i32_count, 0, "padding support not yet implemented"); cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect() } PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 1b7bb8c907735..2901eb8b1a6d2 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -168,11 +168,13 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { )); continue; } - PassMode::Cast { ref cast, pad_i32 } => { - // add padding - if pad_i32 { - argument_tys.push(Reg::i32().gcc_type(cx)); - } + PassMode::Cast { ref cast, pad_i32_count } => { + // Add padding. + argument_tys.extend(std::iter::repeat_n( + Reg::i32().gcc_type(cx), + usize::from(pad_i32_count), + )); + let ty = cast.gcc_type(cx); apply_attrs(ty, &cast.attrs, argument_tys.len()) } diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index c6c32236ab49f..53192c0a087e4 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -346,8 +346,8 @@ impl<'gcc, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn_abi.ptr_to_gcc_type(self) } - fn reg_backend_type(&self, _ty: &Reg) -> Type<'gcc> { - unimplemented!(); + fn reg_backend_type(&self, ty: &Reg) -> Type<'gcc> { + ty.gcc_type(self) } fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 65bb32ee666f2..816ebe3fcf3d9 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -249,7 +249,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { bug!("unsized `ArgAbi` cannot be stored"); } - PassMode::Cast { cast, pad_i32: _ } => { + PassMode::Cast { cast, pad_i32_count: _ } => { // The ABI mandates that the value is passed as a different struct representation. // Spill and reload it from the stack to convert from the ABI representation to // the Rust representation. @@ -366,7 +366,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { let llreturn_ty = match &self.ret.mode { PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx), - PassMode::Cast { cast, pad_i32: _ } => cast.llvm_type(cx), + PassMode::Cast { cast, pad_i32_count: _ } => cast.llvm_type(cx), PassMode::Indirect { .. } => { llargument_tys.push(cx.type_ptr()); cx.type_void() @@ -405,11 +405,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { continue; } PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => cx.type_ptr(), - PassMode::Cast { cast, pad_i32 } => { - // add padding - if *pad_i32 { - llargument_tys.push(Reg::i32().llvm_type(cx)); - } + PassMode::Cast { cast, pad_i32_count } => { + // Add padding. + llargument_tys.extend(std::iter::repeat_n( + Reg::i32().llvm_type(cx), + usize::from(*pad_i32_count), + )); + // Compute the LLVM type we use for this function from the cast type. // We assume here that ABI-compatible Rust types have the same cast type. cast.llvm_type(cx) @@ -511,7 +513,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); } } - PassMode::Cast { cast, pad_i32: _ } => { + PassMode::Cast { cast, pad_i32_count: _ } => { cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); } _ => {} @@ -580,8 +582,8 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b); } } - PassMode::Cast { cast, pad_i32 } => { - if *pad_i32 { + PassMode::Cast { cast, pad_i32_count } => { + for _ in 0..*pad_i32_count { apply(&ArgAttributes::new()); } apply(&cast.attrs); @@ -630,7 +632,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]); } - PassMode::Cast { cast, pad_i32: _ } => { + PassMode::Cast { cast, pad_i32_count: _ } => { cast.attrs.apply_attrs_to_callsite( llvm::AttributePlace::ReturnValue, bx.cx, @@ -666,8 +668,8 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { apply(bx.cx, a); apply(bx.cx, b); } - PassMode::Cast { cast, pad_i32 } => { - if *pad_i32 { + PassMode::Cast { cast, pad_i32_count } => { + for _ in 0..*pad_i32_count { apply(bx.cx, &ArgAttributes::new()); } apply(bx.cx, &cast.attrs); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 7f907bc630b2f..afd9a88784c2f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -588,7 +588,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - PassMode::Cast { cast: cast_ty, pad_i32: _ } => { + PassMode::Cast { cast: cast_ty, pad_i32_count: _ } => { let op = match self.locals[mir::RETURN_PLACE] { LocalRef::Operand(op) => op, LocalRef::PendingOperand => bug!("use of return before def"), @@ -1936,9 +1936,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) { match arg.mode { PassMode::Ignore => return, - PassMode::Cast { pad_i32: true, .. } => { + PassMode::Cast { pad_i32_count, .. } => { // Fill padding with undef value, where applicable. - llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32()))); + let undef = bx.const_undef(bx.reg_backend_type(&Reg::i32())); + llargs.extend(std::iter::repeat_n(undef, usize::from(pad_i32_count))); } PassMode::Pair(..) => match op.val { Pair(a, b) => { @@ -2025,7 +2026,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if by_ref && !arg.is_indirect() { // Have to load the argument, maybe while casting it. - if let PassMode::Cast { cast, pad_i32: _ } = &arg.mode { + if let PassMode::Cast { cast, pad_i32_count: _ } = &arg.mode { // The ABI mandates that the value is passed as a different struct representation. // Spill and reload it from the stack to convert from the Rust representation to // the ABI representation. diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index f8f4f09f75825..6e87a295e9d2b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -501,8 +501,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( for i in 0..tupled_arg_tys.len() { let arg = &fx.fn_abi.args[idx]; idx += 1; - if let PassMode::Cast { pad_i32: true, .. } = arg.mode { - llarg_idx += 1; + if let PassMode::Cast { pad_i32_count, .. } = arg.mode { + llarg_idx += usize::from(pad_i32_count); } let pr_field = place.project_field(bx, i); bx.store_fn_arg(arg, &mut llarg_idx, pr_field); @@ -529,8 +529,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let arg = &fx.fn_abi.args[idx]; idx += 1; - if let PassMode::Cast { pad_i32: true, .. } = arg.mode { - llarg_idx += 1; + if let PassMode::Cast { pad_i32_count, .. } = arg.mode { + llarg_idx += usize::from(pad_i32_count); } if !memory_locals.contains(local) { diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 33cc321ea6d32..05b87bb6d7159 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -472,9 +472,9 @@ fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_t } other => unreachable!("{other:?}"), }, - PassMode::Cast { pad_i32, ref cast } => { + PassMode::Cast { pad_i32_count, ref cast } => { // For wasm, Cast is used for single-field primitive wrappers like `struct Wrapper(i64);` - assert!(!pad_i32, "not currently used by wasm calling convention"); + assert_eq!(pad_i32_count, 0, "not currently used by wasm calling convention"); assert!(cast.prefix.is_empty(), "no prefix"); assert_eq!(cast.rest.total, arg_abi.layout.size, "single item"); diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 5f44e2e288821..e6c278bd8ce7b 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -24,7 +24,7 @@ enum UsesVectorRegisters { fn passes_vectors_by_value(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters { match mode { PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No, - PassMode::Cast { pad_i32: _, cast } + PassMode::Cast { pad_i32_count: _, cast } if cast.prefix.iter().any(|x| matches!(x.kind, RegKind::Vector { .. })) || matches!(cast.rest.unit.kind, RegKind::Vector { .. }) => { diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 02674e4107c77..910f4a5745a7d 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -55,7 +55,7 @@ pub enum PassMode { /// The argument has a layout abi of `ScalarPair`. Pair(Opaque, Opaque), /// Pass the argument after casting it. - Cast { pad_i32: bool, cast: Opaque }, + Cast { pad_i32_count: u8, cast: Opaque }, /// Pass the argument indirectly via a hidden pointer. Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool }, } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 31104ce897ffb..4bb00b4c04394 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -165,8 +165,8 @@ impl<'tcx> Stable<'tcx> for callconv::PassMode { callconv::PassMode::Pair(first, second) => { PassMode::Pair(opaque(first), opaque(second)) } - callconv::PassMode::Cast { pad_i32, cast } => { - PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) } + callconv::PassMode::Cast { pad_i32_count, cast } => { + PassMode::Cast { pad_i32_count: *pad_i32_count, cast: opaque(cast) } } callconv::PassMode::Indirect { attrs, meta_attrs, on_stack } => PassMode::Indirect { attrs: opaque(attrs), diff --git a/compiler/rustc_target/src/callconv/mips.rs b/compiler/rustc_target/src/callconv/mips.rs index d2572cc035c1c..d3a39d05b4964 100644 --- a/compiler/rustc_target/src/callconv/mips.rs +++ b/compiler/rustc_target/src/callconv/mips.rs @@ -35,7 +35,7 @@ where let size = arg.layout.size; if arg.layout.is_aggregate() { - let pad_i32 = !offset.is_aligned(align); + let pad_i32 = u8::from(!offset.is_aligned(align)); arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32); } else { arg.extend_integer_width_to(32); diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index a9d5ec958889f..8002f98507ba8 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -96,7 +96,7 @@ where // Detect need for padding let align = Ord::clamp(arg.layout.align.abi, dl.i64_align, dl.i128_align); - let pad_i32 = !offset.is_aligned(align); + let pad_i32 = u8::from(!offset.is_aligned(align)); if !arg.layout.is_aggregate() { extend_integer_width_mips(arg, 64); diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index a06a6a0a69e12..26fedbd8a5481 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -55,8 +55,9 @@ pub enum PassMode { Pair(ArgAttributes, ArgAttributes), /// Pass the argument after casting it. See the `CastTarget` docs for details. /// - /// `pad_i32` indicates if a `Reg::i32()` dummy argument is emitted before the real argument. - Cast { pad_i32: bool, cast: Box }, + /// `pad_i32` indicates how many `Reg::i32()` dummy arguments are emitted before the real + /// argument. + Cast { pad_i32_count: u8, cast: Box }, /// Pass the argument indirectly via a hidden pointer. /// /// The `meta_attrs` value, if any, is for the metadata (vtable or length) of an unsized @@ -84,8 +85,8 @@ impl PassMode { (PassMode::Direct(a1), PassMode::Direct(a2)) => a1.eq_abi(a2), (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => a1.eq_abi(a2) && b1.eq_abi(b2), ( - PassMode::Cast { cast: c1, pad_i32: pad1 }, - PassMode::Cast { cast: c2, pad_i32: pad2 }, + PassMode::Cast { cast: c1, pad_i32_count: pad1 }, + PassMode::Cast { cast: c2, pad_i32_count: pad2 }, ) => c1.eq_abi(c2) && pad1 == pad2, ( PassMode::Indirect { attrs: a1, meta_attrs: None, on_stack: s1 }, @@ -507,12 +508,12 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } pub fn cast_to>(&mut self, target: T) { - self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32: false }; + self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32_count: 0 }; } pub fn cast_to_with_attrs>(&mut self, target: T, attrs: ArgAttributes) { self.mode = - PassMode::Cast { cast: Box::new(target.into().with_attrs(attrs)), pad_i32: false }; + PassMode::Cast { cast: Box::new(target.into().with_attrs(attrs)), pad_i32_count: 0 }; } /// Cast to `target`, forwarding `NoUndef` only when the layout provably has no uninit @@ -535,8 +536,8 @@ impl<'a, Ty> ArgAbi<'a, Ty> { self.cast_to_with_attrs(target, attr.into()); } - pub fn cast_to_and_pad_i32>(&mut self, target: T, pad_i32: bool) { - self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32 }; + pub fn cast_to_and_pad_i32>(&mut self, target: T, pad_i32_count: u8) { + self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32_count }; } pub fn is_indirect(&self) -> bool { diff --git a/compiler/rustc_target/src/callconv/sparc.rs b/compiler/rustc_target/src/callconv/sparc.rs index d424214aa497e..71af508915e59 100644 --- a/compiler/rustc_target/src/callconv/sparc.rs +++ b/compiler/rustc_target/src/callconv/sparc.rs @@ -34,7 +34,7 @@ where let align = arg.layout.align.abi.max(dl.i32_align).min(dl.i64_align); if arg.layout.is_aggregate() { - let pad_i32 = !offset.is_aligned(align); + let pad_i32 = u8::from(!offset.is_aligned(align)); arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32); } else { arg.extend_integer_width_to(32); diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 6b19f8ebd76ce..7e441d7100c39 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -190,7 +190,7 @@ fn classify_arg<'a, Ty, C>( _ => CastTarget::prefixed(regs, Uniform::new(Reg::i8(), Size::ZERO)), }; - arg.cast_to_and_pad_i32(cast_target.with_attrs(attrs.into()), pad); + arg.cast_to_and_pad_i32(cast_target.with_attrs(attrs.into()), u8::from(pad)); } pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr index 320840c8149f5..efeec0d86982b 100644 --- a/tests/ui/abi/pass-indirectly-attr.stderr +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -121,7 +121,7 @@ error: fn_abi_of(extern_rust) = FnAbi { }, }, mode: Cast { - pad_i32: false, + pad_i32_count: 0, cast: CastTarget { prefix: [], rest_offset: None, From eea5f8c2f2c1f8c9f5ef1e9f462a821ea3f76f77 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 23 Aug 2026 18:21:09 +1000 Subject: [PATCH 2/5] Rename some `build: &Builder<'_>` to `builder` --- src/bootstrap/src/core/build_steps/format.rs | 65 ++++++++++---------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index d4dc9c2de53e6..4d16812127641 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -56,14 +56,14 @@ fn rustfmt( } } -fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, BuildStamp)> { - let stamp_file = BuildStamp::new(&build.out).with_prefix("rustfmt"); +fn get_rustfmt_version(builder: &Builder<'_>) -> Option<(String, BuildStamp)> { + let stamp_file = BuildStamp::new(&builder.out).with_prefix("rustfmt"); - let rustfmt = build.ensure(InternalRustfmt); + let rustfmt = builder.ensure(InternalRustfmt); let mut cmd = command(rustfmt.as_ref()?); cmd.arg("--version"); - let output = cmd.allow_failure().run_capture(build); + let output = cmd.allow_failure().run_capture(builder); if output.is_failure() { return None; } @@ -71,16 +71,16 @@ fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, BuildStamp)> { } /// Return whether the format cache can be reused. -fn verify_rustfmt_version(build: &Builder<'_>) -> bool { - let Some((version, stamp_file)) = get_rustfmt_version(build) else { +fn verify_rustfmt_version(builder: &Builder<'_>) -> bool { + let Some((version, stamp_file)) = get_rustfmt_version(builder) else { return false; }; stamp_file.add_stamp(version).is_up_to_date() } /// Updates the last rustfmt version used. -fn update_rustfmt_version(build: &Builder<'_>) { - let Some((version, stamp_file)) = get_rustfmt_version(build) else { +fn update_rustfmt_version(builder: &Builder<'_>) { + let Some((version, stamp_file)) = get_rustfmt_version(builder) else { return; }; @@ -91,16 +91,17 @@ fn update_rustfmt_version(build: &Builder<'_>) { /// Does not include removed files. /// /// Returns `None` if all files should be formatted. -fn get_modified_rs_files(build: &Builder<'_>) -> Result>, String> { +fn get_modified_rs_files(builder: &Builder<'_>) -> Result>, String> { // In CI `get_git_modified_files` returns something different to normal environment. // This shouldn't be called in CI anyway. - assert!(!build.config.is_running_on_ci()); + assert!(!builder.config.is_running_on_ci()); - if !verify_rustfmt_version(build) { + if !verify_rustfmt_version(builder) { return Ok(None); } - get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]).map(Some) + get_git_modified_files(&builder.config.git_config(), Some(&builder.config.src), &["rs"]) + .map(Some) } /// Rustfmt set via the config, or downloaded from CI, used to format local Rust code. @@ -143,13 +144,13 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { } pub fn format( - build: &Builder<'_>, + builder: &Builder<'_>, rustfmt_path: PathBuf, check: bool, all: bool, paths: &[PathBuf], ) { - if build.kind == Kind::Format && build.top_stage != 0 { + if builder.kind == Kind::Format && builder.top_stage != 0 { eprintln!("ERROR: `x fmt` only supports stage 0."); eprintln!("HELP: Use `x run rustfmt` to run in-tree rustfmt."); helpers::exit_process(1); @@ -161,7 +162,7 @@ pub fn format( ); helpers::exit_process(1); }; - if build.config.dry_run() { + if builder.config.dry_run() { return; } @@ -169,13 +170,15 @@ pub fn format( // `--all` is specified or we are in CI. We check all files in CI to avoid bugs in // `get_modified_rs_files` letting regressions slip through; we also care about CI time less // since this is still very fast compared to building the compiler. - let all = all || build.config.is_running_on_ci(); + let all = all || builder.config.is_running_on_ci(); - let mut builder = ignore::types::TypesBuilder::new(); - builder.add_defaults(); - builder.select("rust"); - let matcher = builder.build().unwrap(); - let rustfmt_config = build.src.join("rustfmt.toml"); + let matcher = { + let mut types = ignore::types::TypesBuilder::new(); + types.add_defaults(); + types.select("rust"); + types.build().unwrap() + }; + let rustfmt_config = builder.src.join("rustfmt.toml"); if !rustfmt_config.exists() { eprintln!("fmt error: Not running formatting checks; rustfmt.toml does not exist."); eprintln!("fmt error: This may happen in distributed tarballs."); @@ -183,7 +186,7 @@ pub fn format( } let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config)); let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config)); - let mut override_builder = ignore::overrides::OverrideBuilder::new(&build.src); + let mut override_builder = ignore::overrides::OverrideBuilder::new(&builder.src); for ignore in rustfmt_config.ignore { if ignore.starts_with('!') { // A `!`-prefixed entry could be added as a whitelisted entry in `override_builder`, @@ -199,23 +202,23 @@ pub fn format( } } let git_available = - helpers::git(None).allow_failure().arg("--version").run_capture(build).is_success(); + helpers::git(None).allow_failure().arg("--version").run_capture(builder).is_success(); let mut adjective = None; if git_available { - let in_working_tree = helpers::git(Some(&build.src)) + let in_working_tree = helpers::git(Some(&builder.src)) .allow_failure() .arg("rev-parse") .arg("--is-inside-work-tree") - .run_capture(build) + .run_capture(builder) .is_success(); if in_working_tree { - let untracked_paths_output = helpers::git(Some(&build.src)) + let untracked_paths_output = helpers::git(Some(&builder.src)) .arg("status") .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") - .run_capture_stdout(build) + .run_capture_stdout(builder) .stdout(); let untracked_paths: Vec<_> = untracked_paths_output .split_terminator('\0') @@ -236,7 +239,7 @@ pub fn format( } if !all { adjective = Some("modified"); - match get_modified_rs_files(build) { + match get_modified_rs_files(builder) { Ok(Some(files)) => { if files.is_empty() { println!("fmt info: No modified files detected for formatting."); @@ -271,13 +274,13 @@ pub fn format( let override_ = override_builder.build().unwrap(); // `override` is a reserved keyword assert!(rustfmt_path.exists(), "{}", rustfmt_path.display()); - let src = build.src.clone(); + let src = builder.src.clone(); let (tx, rx): (SyncSender, _) = std::sync::mpsc::sync_channel(128); let walker = WalkBuilder::new(src.clone()).types(matcher).overrides(override_).build_parallel(); // There is a lot of blocking involved in spawning a child process and reading files to format. // Spawn more processes than available concurrency to keep the CPU busy. - let max_processes = build.jobs() as usize * 2; + let max_processes = builder.jobs() as usize * 2; // Spawn child processes on a separate thread so we can batch entries we have received from // ignore. @@ -370,5 +373,5 @@ pub fn format( // // NOTE: Because of the exit above, this is only reachable if formatting / format checking // succeeded. So we are not committing the version if formatting was not good. - update_rustfmt_version(build); + update_rustfmt_version(builder); } From 287084bf3061a74c8ad2ddc67e5f5810574fe7f3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 23 Aug 2026 18:28:06 +1000 Subject: [PATCH 3/5] Rename `Build` to `Session` This renaming should at least make Session and Builder easier to distinguish. --- src/bootstrap/src/cli_main.rs | 12 +-- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/clean.rs | 36 +++---- src/bootstrap/src/core/build_steps/compile.rs | 6 +- src/bootstrap/src/core/build_steps/dist.rs | 16 ++-- src/bootstrap/src/core/build_steps/gcc.rs | 10 +- src/bootstrap/src/core/build_steps/llvm.rs | 2 +- src/bootstrap/src/core/build_steps/perf.rs | 4 +- src/bootstrap/src/core/build_steps/run.rs | 6 +- src/bootstrap/src/core/build_steps/setup.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 18 ++-- src/bootstrap/src/core/build_steps/tool.rs | 6 +- src/bootstrap/src/core/build_steps/vendor.rs | 2 +- src/bootstrap/src/core/builder/cargo.rs | 26 +++--- .../src/core/builder/cli_paths/tests.rs | 8 +- src/bootstrap/src/core/builder/mod.rs | 47 +++++----- src/bootstrap/src/core/builder/tests.rs | 34 +++---- src/bootstrap/src/core/compiler.rs | 8 +- src/bootstrap/src/core/config/config.rs | 4 +- src/bootstrap/src/core/config/flags.rs | 6 +- src/bootstrap/src/core/metadata.rs | 26 +++--- src/bootstrap/src/core/sanity.rs | 93 +++++++++---------- src/bootstrap/src/core/session.rs | 69 +++++++------- src/bootstrap/src/utils/cc_detect.rs | 85 +++++++++-------- src/bootstrap/src/utils/cc_detect/tests.rs | 54 +++++------ src/bootstrap/src/utils/channel.rs | 6 +- src/bootstrap/src/utils/job.rs | 15 ++- src/bootstrap/src/utils/metrics.rs | 8 +- 28 files changed, 301 insertions(+), 310 deletions(-) diff --git a/src/bootstrap/src/cli_main.rs b/src/bootstrap/src/cli_main.rs index 8a74b2e598283..7fd4d3b692d99 100644 --- a/src/bootstrap/src/cli_main.rs +++ b/src/bootstrap/src/cli_main.rs @@ -16,7 +16,7 @@ use std::{env, process}; use crate::core::builder::StepStack; use crate::core::config::flags::{Flags, Subcommand}; use crate::core::config::{ChangeId, Config}; -use crate::core::session::Build; +use crate::core::session::Session; use crate::debug; use crate::utils::change_tracker::{ CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes, @@ -157,9 +157,9 @@ pub fn main() { t!(symlink_dir_inner(&tracing_dir, &latest_trace_dir)); } - debug!("creating new build based on config"); - let mut build = Build::new(config); - build.build(); + debug!("creating new session based on config"); + let mut sess = Session::new(config); + sess.build(); if suggest_setup { println!("WARNING: you have not made a `bootstrap.toml`"); @@ -213,8 +213,8 @@ pub fn main() { #[cfg(feature = "tracing")] { - build.report_summary(&tracing_dir.join("command-stats.txt"), _start_time); - build.report_step_graph(&tracing_dir); + sess.report_summary(&tracing_dir.join("command-stats.txt"), _start_time); + sess.report_step_graph(&tracing_dir); guard.copy_to_dir(&tracing_dir); eprintln!("Tracing/profiling output has been written to {}", latest_trace_dir.display()); } diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 4a75cdbb1562f..45d84d533fe14 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -647,7 +647,7 @@ impl CommandLineStep for GccCodegenBackend { fn run(self, builder: &Builder<'_>) { // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved - if builder.build.config.vendor { + if builder.sess.config.vendor { println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); return; } diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 23f12bbb63e72..1c96f5ccd00d8 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -14,7 +14,7 @@ use crate::core::builder::{ }; use crate::core::compiler::Compiler; use crate::core::config::flags::Subcommand; -use crate::core::session::{Build, Mode}; +use crate::core::session::{Mode, Session}; use crate::utils::build_stamp::BuildStamp; use crate::utils::helpers::t; @@ -47,7 +47,7 @@ impl CommandLineStep for CleanAll { panic!("--all and --stage can't be used at the same time for `x clean`"); } - clean(builder.build, all, stage) + clean(builder.sess, all, stage) } } @@ -105,8 +105,8 @@ clean_crate_tree! { Std, Mode::Std, "sysroot"; } -fn clean(build: &Build, all: bool, stage: Option) { - if build.config.dry_run() { +fn clean(sess: &Session, all: bool, stage: Option) { + if sess.config.dry_run() { return; } @@ -114,23 +114,23 @@ fn clean(build: &Build, all: bool, stage: Option) { // Clean the entire build directory if all { - rm_rf(&build.out); + rm_rf(&sess.out); return; } // Clean the target stage artifacts if let Some(stage) = stage { - clean_specific_stage(build, stage); + clean_specific_stage(sess, stage); return; } // Follow the default behaviour - clean_default(build); + clean_default(sess); } -fn clean_specific_stage(build: &Build, stage: u32) { - for host in &build.hosts { - let entries = match build.out.join(host).read_dir() { +fn clean_specific_stage(sess: &Session, stage: u32) { + for host in &sess.hosts { + let entries = match sess.out.join(host).read_dir() { Ok(iter) => iter, Err(_) => continue, }; @@ -150,18 +150,18 @@ fn clean_specific_stage(build: &Build, stage: u32) { } } -fn clean_default(build: &Build) { - rm_rf(&build.out.join("tmp")); - rm_rf(&build.out.join("dist")); - rm_rf(&build.out.join("bootstrap").join(".last-warned-change-id")); - rm_rf(&build.out.join("bootstrap-shims-dump")); - rm_rf(BuildStamp::new(&build.out).with_prefix("rustfmt").path()); +fn clean_default(sess: &Session) { + rm_rf(&sess.out.join("tmp")); + rm_rf(&sess.out.join("dist")); + rm_rf(&sess.out.join("bootstrap").join(".last-warned-change-id")); + rm_rf(&sess.out.join("bootstrap-shims-dump")); + rm_rf(BuildStamp::new(&sess.out).with_prefix("rustfmt").path()); - let mut hosts: Vec<_> = build.hosts.iter().map(|t| build.out.join(t)).collect(); + let mut hosts: Vec<_> = sess.hosts.iter().map(|t| sess.out.join(t)).collect(); // After cross-compilation, artifacts of the host architecture (which may differ from build.host) // might not get removed. // Adding its path (linked one for easier accessibility) will solve this problem. - hosts.push(build.out.join("host")); + hosts.push(sess.out.join("host")); for host in hosts { let entries = match host.read_dir() { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 9970c5b21056e..bb598d19c9fc9 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -777,7 +777,7 @@ impl Step for StdLink { }; let is_downloaded_beta_stage0 = builder - .build + .sess .config .initial_rustc .starts_with(builder.out.join(compiler.host).join("stage0/bin")); @@ -1147,7 +1147,7 @@ impl CommandLineStep for Rustc { cargo.arg("-p").arg(krate); } - if builder.build.config.enable_bolt_settings && build_compiler.stage == 1 { + if builder.sess.config.enable_bolt_settings && build_compiler.stage == 1 { // Relocations are required for BOLT to work. cargo.env("RUSTC_BOLT_LINK_FLAGS", "1"); } @@ -1256,7 +1256,7 @@ pub fn rustc_cargo( // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object // with direct references to protected symbols, so for now we only use protected symbols if // linking with LLD is enabled. - if builder.build.config.bootstrap_override_lld.is_used() { + if builder.sess.config.bootstrap_override_lld.is_used() { cargo.rustflag("-Zdefault-visibility=protected"); } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 53e7746d220f5..2112ec090f0b6 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -664,7 +664,7 @@ impl CommandLineStep for Rustc { let page_src = file_entry.path(); let page_dst = man_dst.join(file_entry.file_name()); let src_text = t!(std::fs::read_to_string(&page_src)); - let version = builder.rust_info().version(builder.build, &builder.version); + let version = builder.rust_info().version(builder.sess, &builder.version); let new_text = src_text.replace("", &version); t!(std::fs::write(&page_dst, &new_text)); } @@ -774,7 +774,7 @@ impl Step for DebuggerScripts { cp_debugger_script("gdb_load_rust_pretty_printers.py"); cp_debugger_script("gdb_lookup.py"); cp_debugger_script("gdb_providers.py"); - if builder.build.unstable_features() { + if builder.sess.unstable_features() { cp_debugger_script("gdb_trim_paths.py"); } @@ -787,7 +787,7 @@ impl Step for DebuggerScripts { cp_debugger_script("lldb_lookup.py"); cp_debugger_script("lldb_providers.py"); - if builder.build.unstable_features() { + if builder.sess.unstable_features() { cp_debugger_script("lldb_trim_paths.py"); } } @@ -1624,7 +1624,7 @@ impl CommandLineStep for Miri { // This prevents miri from being built for "dist" or "install" // on the stable/beta channels. It is a nightly-only tool and should // not be included. - if !builder.build.unstable_features() { + if !builder.sess.unstable_features() { return None; } @@ -1681,7 +1681,7 @@ impl CommandLineStep for CraneliftCodegenBackend { // This prevents rustc_codegen_cranelift from being built for "dist" // or "install" on the stable/beta channels. It is not yet stable and // should not be included. - if !builder.build.unstable_features() { + if !builder.sess.unstable_features() { return None; } @@ -1755,7 +1755,7 @@ impl CommandLineStep for GccCodegenBackend { // This prevents rustc_codegen_gcc from being built for "dist" // or "install" on the stable/beta channels. It is not yet stable and // should not be included. - if !builder.build.unstable_features() { + if !builder.sess.unstable_features() { return None; } @@ -2837,7 +2837,7 @@ impl CommandLineStep for Enzyme { // This prevents Enzyme from being built for "dist" // or "install" on the stable/beta channels. It is not yet stable and // should not be included. - if !builder.build.unstable_features() { + if !builder.sess.unstable_features() { return None; } @@ -3232,7 +3232,7 @@ impl CommandLineStep for Gcc { // This prevents gcc from being built for "dist" // or "install" on the stable/beta channels. It is not yet stable and // should not be included. - if !builder.build.unstable_features() { + if !builder.sess.unstable_features() { return None; } diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index d3540bd21b0e4..650921d7231fc 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -290,7 +290,7 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target_pair: GccTargetPair) // Target on which libgccjit.so will be executed. Here we will generate a dylib with // instructions for that target. let host = target_pair.host; - if builder.build.cc_tool(host).is_like_clang() || builder.build.cxx_tool(host).is_like_clang() { + if builder.sess.cc_tool(host).is_like_clang() || builder.sess.cxx_tool(host).is_like_clang() { panic!( "Attempting to build GCC using Clang, which is known to misbehave. Please use GCC as the host C/C++ compiler. " ); @@ -327,19 +327,19 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target_pair: GccTargetPair) .arg("--with-bugurl=https://github.com/rust-lang/gcc/") .arg(format!("--prefix={}", install_dir.display())); - let cc = builder.build.cc(host).display().to_string(); + let cc = builder.sess.cc(host).display().to_string(); let cc = builder - .build + .sess .config .ccache .as_ref() .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}")); configure_cmd.env("CC", cc); - if let Ok(ref cxx) = builder.build.cxx(host) { + if let Ok(ref cxx) = builder.sess.cxx(host) { let cxx = cxx.display().to_string(); let cxx = builder - .build + .sess .config .ccache .as_ref() diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 94c886649109f..378bbae220328 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1317,7 +1317,7 @@ impl CommandLineStep for OmpOffload { let offload_clang_dir = if !builder.config.llvm_clang { // We must have an external clang to use. - builder.build.config.offload_clang_dir.clone() + builder.sess.config.offload_clang_dir.clone() } else { // No need to specify it, since we use the in-tree clang None diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 2ea091532ae12..cc81d9243fe26 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -140,7 +140,7 @@ pub fn perf(builder: &Builder<'_>, args: &PerfArgs) { target: builder.config.host_target, }); - let rustc_perf_dir = builder.build.tempdir().join("rustc-perf"); + let rustc_perf_dir = builder.sess.tempdir().join("rustc-perf"); let results_dir = rustc_perf_dir.join("results"); builder.create_dir(&results_dir); @@ -158,7 +158,7 @@ pub fn perf(builder: &Builder<'_>, args: &PerfArgs) { | PerfCommand::Cachegrind { .. } => true, PerfCommand::Benchmark { .. } | PerfCommand::Compare { .. } => false, }; - if is_profiling && builder.build.config.rust_debuginfo_level_rustc == DebuginfoLevel::None { + if is_profiling && builder.sess.config.rust_debuginfo_level_rustc == DebuginfoLevel::None { builder.info(r#"WARNING: You are compiling rustc without debuginfo, this will make profiling less useful. Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#); } diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 243b09acaa308..6051f5a27d71f 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -148,7 +148,7 @@ impl CommandLineStep for Miri { } fn run(self, builder: &Builder<'_>) { - let host = builder.build.host_target; + let host = builder.sess.host_target; let compilers = self.compilers; let target = self.target; @@ -257,7 +257,7 @@ impl CommandLineStep for GenerateCopyright { let paths_to_vendor = default_paths_to_vendor(builder); for (_, submodules) in &paths_to_vendor { for submodule in submodules { - builder.build.require_submodule(submodule, None); + builder.sess.require_submodule(submodule, None); } } let cargo_manifests = paths_to_vendor @@ -491,7 +491,7 @@ impl CommandLineStep for Rustfmt { } fn run(self, builder: &Builder<'_>) { - let host = builder.build.host_target; + let host = builder.sess.host_target; // `x run` uses stage 0 by default but rustfmt does not work well with stage 0. // Change the stage to 1 if it's not set explicitly. diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 27a400406e144..efe29ee78d741 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -173,7 +173,7 @@ impl CommandLineStep for Profile { } fn run(self, builder: &Builder<'_>) { - setup(&builder.build.config, self); + setup(&builder.sess.config, self); } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 5c16416266139..cb3dbe34c24bf 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -719,7 +719,7 @@ impl CommandLineStep for Miri { /// Runs `cargo test` for miri. fn run(self, builder: &Builder<'_>) { - let host = builder.build.host_target; + let host = builder.sess.host_target; let target = self.target; let stage = builder.top_stage; if stage == 0 { @@ -813,7 +813,7 @@ impl CommandLineStep for CargoMiri { /// Tests `cargo miri test`. fn run(self, builder: &Builder<'_>) { - let host = builder.build.host_target; + let host = builder.sess.host_target; let target = self.target; let stage = builder.top_stage; if stage == 0 { @@ -897,7 +897,7 @@ impl CommandLineStep for Priroda { /// Runs `cargo test` for priroda, reusing the Miri sysroot and binary. fn run(self, builder: &Builder<'_>) { - let host = builder.build.host_target; + let host = builder.sess.host_target; let target = self.target; let stage = builder.top_stage; @@ -1509,7 +1509,7 @@ fn get_browser_ui_test_version_inner( let mut command = command(yarn); command .arg("--cwd") - .arg(&builder.build.out) + .arg(&builder.sess.out) .arg("list") .arg("--parseable") .arg("--long") @@ -2285,7 +2285,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // At stage 0 (stage - 1) we are using the stage0 compiler. Using `self.target` can lead // finding an incorrect compiler path on cross-targets, as the stage 0 is always equal to // `build.build` in the configuration. - let build = builder.build.host_target; + let build = builder.sess.host_target; test_compiler = builder.compiler(test_compiler.stage - 1, build); let test_stage = test_compiler.stage + 1; (test_stage, format!("stage{test_stage}-{build}")) @@ -2522,11 +2522,11 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--bypass-ignore-backends"); } - if builder.build.config.llvm_enzyme { + if builder.sess.config.llvm_enzyme { cmd.arg("--has-enzyme"); } - if builder.build.config.llvm_offload { + if builder.sess.config.llvm_offload { cmd.arg("--has-offload"); } @@ -4016,7 +4016,7 @@ impl CommandLineStep for BootstrapPy { // Forward command-line args after `--` to unittest, for filtering etc. .args(builder.config.test_args()) .env("BUILD_DIR", &builder.out) - .env("BUILD_PLATFORM", builder.build.host_target.triple) + .env("BUILD_PLATFORM", builder.sess.host_target.triple) .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc) .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo) .current_dir(builder.src.join("src/bootstrap/")); @@ -4049,7 +4049,7 @@ impl CommandLineStep for Bootstrap { let record_failed_tests = builder.ensure(SetupFailedTestsFile); // Some tests require cargo submodule to be present. - builder.build.require_submodule("src/tools/cargo", None); + builder.sess.require_submodule("src/tools/cargo", None); let mut cargo = tool::prepare_tool_cargo( builder, diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index e70352158feee..922784fb7e13a 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -212,7 +212,7 @@ pub fn prepare_tool_cargo( cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); let mut features = extra_features.to_vec(); - if builder.build.config.cargo_native_static { + if builder.sess.config.cargo_native_static { if path.ends_with("cargo") || path.ends_with("clippy") || path.ends_with("miri") @@ -865,7 +865,7 @@ impl CommandLineStep for Cargo { } fn run(self, builder: &Builder<'_>) -> ToolBuildResult { - builder.build.require_submodule("src/tools/cargo", None); + builder.sess.require_submodule("src/tools/cargo", None); builder.std(self.build_compiler, builder.host_target); builder.std(self.build_compiler, self.target); @@ -1523,7 +1523,7 @@ fn extended_rustc_tool_is_default_step( && builder.config.tools.as_ref().map_or( // By default, on nightly/dev enable all tools, else only // build stable tools. - stable || builder.build.unstable_features(), + stable || builder.sess.unstable_features(), // If `tools` is set, search list for this tool. |tools| { tools.iter().any(|tool| match tool.as_ref() { diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 1bf9331500f8b..c6dd815d532ac 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -101,7 +101,7 @@ impl CommandLineStep for Vendor { // These submodules must be present for `x vendor` to work. for (_, submodules) in &to_vendor { for submodule in submodules { - builder.build.require_submodule(submodule, None); + builder.sess.require_submodule(submodule, None); } } diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 81e95c5a6f4ac..83598a52ed62b 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -646,7 +646,7 @@ impl Builder<'_> { // from out of tree it shouldn't matter, since x.py is only used for // building in-tree. let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"]; - match self.build.config.color { + match self.sess.config.color { Color::Always => { cargo.arg("--color=always"); for log in &color_logs { @@ -1172,14 +1172,14 @@ impl Builder<'_> { match mode { Mode::Rustc | Mode::Codegen => { if let Some(ref map_to) = - self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler) + self.sess.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler) { // Tell the compiler which prefix was used for remapping the standard library cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to); } if let Some(ref map_to) = - self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::Compiler) + self.sess.debuginfo_map_to(GitRepo::Rustc, RemapScheme::Compiler) { // Tell the compiler which prefix was used for remapping the compiler it-self cargo.env("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR", map_to); @@ -1190,14 +1190,14 @@ impl Builder<'_> { format!("compiler/={map_to}/compiler"), // rustc creates absolute paths (in part bc of the `rust-src` unremap // and for working directory) so let's remap the build directory as well. - format!("{}={map_to}", self.build.src.display()), + format!("{}={map_to}", self.sess.src.display()), // remap OUT_DIR so they don't leak into artifacts. - format!("{}={map_to}/out", self.build.out.display()), + format!("{}={map_to}/out", self.sess.out.display()), // on windows, rustc may use forward slashes internally #[cfg(windows)] format!( "{}={map_to}\\out", - self.build.out.display().to_string().replace('/', "\\") + self.sess.out.display().to_string().replace('/', "\\") ), ] .join("\t"); @@ -1210,7 +1210,7 @@ impl Builder<'_> { | Mode::ToolStd | Mode::ToolTarget => { if let Some(ref map_to) = - self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler) + self.sess.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler) { // When building the standard library sources, we want to apply the std remap scheme. let map = [ @@ -1218,14 +1218,14 @@ impl Builder<'_> { format!("library/={map_to}/library"), // rustc creates absolute paths (in part bc of the `rust-src` unremap // and for working directory) so let's remap the build directory as well. - format!("{}={map_to}", self.build.src.display()), + format!("{}={map_to}", self.sess.src.display()), // remap OUT_DIR so they don't leak into artifacts. - format!("{}={map_to}/out", self.build.out.display()), + format!("{}={map_to}/out", self.sess.out.display()), // on windows, rustc may use forward slashes internally #[cfg(windows)] format!( "{}={map_to}\\out", - self.build.out.display().to_string().replace('/', "\\") + self.sess.out.display().to_string().replace('/', "\\") ), ] .join("\t"); @@ -1236,7 +1236,7 @@ impl Builder<'_> { if self.config.rust_remap_debuginfo { let mut env_var = OsString::new(); - if let Some(vendor) = self.build.vendored_crates_path() { + if let Some(vendor) = self.sess.vendored_crates_path() { env_var.push(vendor); env_var.push("=/rust/deps"); } else { @@ -1261,8 +1261,8 @@ impl Builder<'_> { prepare_shims_dump_dir(self); cargo - .env("DUMP_BOOTSTRAP_SHIMS", self.build.out.join("bootstrap-shims-dump")) - .env("BUILD_OUT", &self.build.out) + .env("DUMP_BOOTSTRAP_SHIMS", self.sess.out.join("bootstrap-shims-dump")) + .env("BUILD_OUT", &self.sess.out) .env("CARGO_HOME", t!(home::cargo_home())); }; diff --git a/src/bootstrap/src/core/builder/cli_paths/tests.rs b/src/bootstrap/src/core/builder/cli_paths/tests.rs index 3a92bf37bdf0a..a6754e063caf4 100644 --- a/src/bootstrap/src/core/builder/cli_paths/tests.rs +++ b/src/bootstrap/src/core/builder/cli_paths/tests.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use std::sync::{Arc, Mutex}; use crate::core::builder::{Builder, CommandLineStepDescription}; -use crate::core::session::Build; +use crate::core::session::Session; use crate::utils::tests::TestCtx; fn render_steps_for_cli_args(args_str: &str) -> String { @@ -25,11 +25,11 @@ fn render_steps_for_cli_args(args_str: &str) -> String { .hosts(hosts) .targets(targets) .create_config(); - let mut build = Build::new(config); + let mut sess = Session::new(config); // Some rustdoc test steps are only run by default if nodejs is // configured/discovered, causing inconsistency. - build.config.nodejs = Some(PathBuf::from("node")); - let mut builder = Builder::new(&build); + sess.config.nodejs = Some(PathBuf::from("node")); + let mut builder = Builder::new(&sess); // Tell the builder to log steps that it would run, instead of running them. let buf = Arc::new(Mutex::new(String::new())); diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 98fceeae9df5c..7f3a94b157efb 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -25,7 +25,7 @@ use crate::core::compiler::Compiler; use crate::core::config::flags::Subcommand; use crate::core::config::{DryRun, TargetSelection}; use crate::core::metadata::Crate; -use crate::core::session::Build; +use crate::core::session::Session; use crate::trace; use crate::utils::build_stamp::BuildStamp; use crate::utils::cache::Cache; @@ -43,7 +43,7 @@ mod tests; /// into account build configuration from e.g. bootstrap.toml. pub(crate) struct Builder<'a> { /// Build configuration from e.g. bootstrap.toml. - pub build: &'a Build, + pub sess: &'a Session, /// The stage to use. Either implicitly determined based on subcommand, or /// explicitly specified with `--stage N`. Normally this is the stage we @@ -69,7 +69,7 @@ pub(crate) struct Builder<'a> { /// "bar"]`. pub paths: Vec, - /// Cached list of submodules from self.build.src. + /// Cached list of submodules from self.sess.src. submodule_paths_cache: OnceLock>, /// When enabled by tests, this causes the top-level steps that _would_ be @@ -81,10 +81,10 @@ pub(crate) struct Builder<'a> { } impl Deref for Builder<'_> { - type Target = Build; + type Target = Session; fn deref(&self) -> &Self::Target { - self.build + self.sess } } @@ -278,7 +278,7 @@ pub struct RunConfig<'a> { impl RunConfig<'_> { pub fn build_triple(&self) -> TargetSelection { - self.builder.build.host_target + self.builder.sess.host_target } /// Return a list of crate names selected by `run.paths`. @@ -1024,19 +1024,19 @@ impl<'a> Builder<'a> { } Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), - // special-cased in Build::build() + // special-cased in Session::build() Kind::Format | Kind::Perf => vec![], Kind::MiriTest | Kind::MiriSetup => unreachable!(), } } - pub fn get_help(build: &Build, kind: Kind) -> Option { + pub fn get_help(sess: &Session, kind: Kind) -> Option { let step_descriptions = Builder::get_step_descriptions(kind); if step_descriptions.is_empty() { return None; } - let builder = Self::new_internal(build, kind, vec![]); + let builder = Self::new_internal(sess, kind, vec![]); let builder = &builder; let mut should_run = ShouldRun::new(builder); @@ -1062,10 +1062,10 @@ impl<'a> Builder<'a> { Some(help) } - fn new_internal(build: &Build, kind: Kind, paths: Vec) -> Builder<'_> { + fn new_internal(sess: &Session, kind: Kind, paths: Vec) -> Builder<'_> { Builder { - build, - top_stage: build.config.stage, + sess, + top_stage: sess.config.stage, kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -1076,9 +1076,9 @@ impl<'a> Builder<'a> { } } - pub fn new(build: &Build) -> Builder<'_> { - let paths = &build.config.paths; - let (kind, paths) = match build.config.cmd { + pub fn new(sess: &Session) -> Builder<'_> { + let paths = &sess.config.paths; + let (kind, paths) = match sess.config.cmd { Subcommand::Build { .. } => (Kind::Build, &paths[..]), Subcommand::Check { .. } => (Kind::Check, &paths[..]), Subcommand::Clippy { .. } => (Kind::Clippy, &paths[..]), @@ -1101,7 +1101,7 @@ impl<'a> Builder<'a> { }; StepStack::with_current(|stack| stack.clear()); - Self::new_internal(build, kind, paths.to_owned()) + Self::new_internal(sess, kind, paths.to_owned()) } pub fn execute_cli(&self) { @@ -1231,10 +1231,10 @@ impl<'a> Builder<'a> { host: TargetSelection, target: TargetSelection, ) -> Compiler { - let mut resolved_compiler = if self.build.force_use_stage2(stage) { + let mut resolved_compiler = if self.sess.force_use_stage2(stage) { trace!(target: "COMPILER_FOR", ?stage, "force_use_stage2"); self.compiler(2, self.config.host_target) - } else if self.build.force_use_stage1(stage, target) { + } else if self.sess.force_use_stage1(stage, target) { trace!(target: "COMPILER_FOR", ?stage, "force_use_stage1"); self.compiler(1, self.config.host_target) } else { @@ -1368,7 +1368,7 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path { match self.config.libdir_relative() { Some(relative_libdir) if compiler.stage >= 1 => relative_libdir, - _ if compiler.stage == 0 => &self.build.initial_relative_libdir, + _ if compiler.stage == 0 => &self.sess.initial_relative_libdir, _ => Path::new("lib"), } } @@ -1436,8 +1436,7 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0"); - let compilers = - RustcPrivateCompilers::new(self, run_compiler.stage, self.build.host_target); + let compilers = RustcPrivateCompilers::new(self, run_compiler.stage, self.sess.host_target); assert_eq!(run_compiler, compilers.target_compiler()); // Prepare the tools @@ -1467,7 +1466,7 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler .config .initial_cargo_clippy .clone() - .unwrap_or_else(|| self.build.config.download_clippy()); + .unwrap_or_else(|| self.sess.config.download_clippy()); let mut cmd = command(cargo_clippy); cmd.env("CARGO", &self.initial_cargo); @@ -1583,7 +1582,7 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler #[cfg(feature = "tracing")] { if let Some(parent) = stack.last() { - let mut graph = self.build.step_graph.borrow_mut(); + let mut graph = self.sess.step_graph.borrow_mut(); graph.register_cached_step(&step, parent, self.config.dry_run()); } } @@ -1593,7 +1592,7 @@ Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler #[cfg(feature = "tracing")] { let parent = stack.last(); - let mut graph = self.build.step_graph.borrow_mut(); + let mut graph = self.sess.step_graph.borrow_mut(); graph.register_step_execution(&step, parent, self.config.dry_run()); } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 5ef46a25a1e4f..fed59c3b14f2c 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -23,8 +23,8 @@ fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config { } fn run_build(paths: &[PathBuf], config: Config) -> Cache { - let build = Build::new(config); - let builder = Builder::new(&build); + let sess = Session::new(config); + let builder = Builder::new(&sess); builder.run_step_descriptions(&Builder::get_step_descriptions(builder.kind), paths); builder.cache } @@ -114,13 +114,13 @@ fn parse_config_download_rustc_at(path: &Path, download_rustc: &str, ci: bool) - mod sysroot_target_dirs { use super::{ - Build, Builder, Compiler, TEST_TRIPLE_1, TEST_TRIPLE_2, TargetSelection, configure, + Builder, Compiler, Session, TEST_TRIPLE_1, TEST_TRIPLE_2, TargetSelection, configure, }; #[test] fn test_sysroot_target_libdir() { - let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); - let builder = Builder::new(&build); + let sess = Session::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); + let builder = Builder::new(&sess); let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); let compiler = Compiler::new(1, target_triple_1); let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2); @@ -139,8 +139,8 @@ mod sysroot_target_dirs { #[test] fn test_sysroot_target_bindir() { - let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); - let builder = Builder::new(&build); + let sess = Session::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); + let builder = Builder::new(&sess); let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); let compiler = Compiler::new(1, target_triple_1); let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2); @@ -242,8 +242,8 @@ fn test_prebuilt_llvm_config_path_resolution() { "#, ); - let build = Build::new(config); - let builder = Builder::new(&build); + let sess = Session::new(config); + let builder = Builder::new(&sess); let expected = PathBuf::from("/some/path/to/llvm-config"); @@ -270,8 +270,8 @@ fn test_prebuilt_llvm_config_path_resolution() { "#, ); - let build = Build::new(config.clone()); - let builder = Builder::new(&build); + let sess = Session::new(config.clone()); + let builder = Builder::new(&sess); let actual = get_llvm_build_status(&builder, builder.config.host_target) .llvm_output() @@ -293,8 +293,8 @@ fn test_prebuilt_llvm_config_path_resolution() { // CI-LLVM isn't always available; check if it's enabled before testing. if config.llvm_ci_mode.download_from_ci() { - let build = Build::new(config.clone()); - let builder = Builder::new(&build); + let sess = Session::new(config.clone()); + let builder = Builder::new(&sess); let actual = get_llvm_build_status(&builder, builder.config.host_target) .llvm_output() @@ -317,8 +317,8 @@ fn test_is_builder_target() { for (target1, target2) in [(target1, target2), (target2, target1)] { let mut config = configure("build", &[], &[]); config.host_target = target1; - let build = Build::new(config); - let builder = Builder::new(&build); + let sess = Session::new(config); + let builder = Builder::new(&sess); assert!(builder.config.is_host_target(target1)); assert!(!builder.config.is_host_target(target2)); @@ -3126,8 +3126,8 @@ impl ConfigBuilder { fn run(self) -> Cache { let config = self.create_config(); - let build = Build::new(config); - let builder = Builder::new(&build); + let sess = Session::new(config); + let builder = Builder::new(&sess); builder .run_step_descriptions(&Builder::get_step_descriptions(builder.kind), &builder.paths); builder.cache diff --git a/src/bootstrap/src/core/compiler.rs b/src/bootstrap/src/core/compiler.rs index 5602e8ffd1efd..f0db8b3bd8ce4 100644 --- a/src/bootstrap/src/core/compiler.rs +++ b/src/bootstrap/src/core/compiler.rs @@ -1,7 +1,7 @@ use std::hash::{Hash, Hasher}; use crate::core::config::TargetSelection; -use crate::core::session::Build; +use crate::core::session::Session; /// A structure representing a Rust compiler. /// @@ -39,9 +39,9 @@ impl Compiler { self.forced_compiler = forced_compiler; } - /// Returns `true` if this is a snapshot compiler for `build`'s configuration - pub(crate) fn is_snapshot(&self, build: &Build) -> bool { - self.stage == 0 && self.host == build.host_target + /// Returns `true` if this is a snapshot compiler for the session's configuration + pub(crate) fn is_snapshot(&self, sess: &Session) -> bool { + self.stage == 0 && self.host == sess.host_target } /// Indicates whether the compiler was forced to use a specific stage. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index d96300e0789aa..6df39a0927738 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -94,7 +94,7 @@ pub(crate) struct Config { pub bypass_bootstrap_lock: bool, pub ccache: Option, pub sde: Option, - /// Call Build::ninja() instead of this. + /// Call `Session::ninja` instead of this. pub ninja_in_file: bool, pub submodules: Option, pub compiler_docs: bool, @@ -1853,7 +1853,7 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to /// /// This *does not* update the submodule if `bootstrap.toml` explicitly says /// not to, or if we're not in a git repository (like a plain source - /// tarball). Typically [`crate::core::session::Build::require_submodule`] should be + /// tarball). Typically [`crate::core::session::Session::require_submodule`] should be /// used instead to provide a nice error to the user if the submodule is /// missing. #[cfg_attr( diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index da479251c68ab..109eb916d3fbd 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -17,7 +17,7 @@ use crate::core::build_steps::test::TestTarget; use crate::core::builder::{Builder, Kind}; use crate::core::config::Config; use crate::core::config::target_selection::{TargetSelectionList, target_selection_list}; -use crate::core::session::Build; +use crate::core::session::Session; use crate::utils::helpers; #[derive(Copy, Clone, Default, Debug, ValueEnum)] @@ -223,8 +223,8 @@ impl Flags { println!("NOTE: updating submodules before printing available paths"); let flags = Self::parse(&[String::from("build")]); let config = Config::parse(flags); - let build = Build::new(config); - let paths = Builder::get_help(&build, subcommand); + let sess = Session::new(config); + let paths = Builder::get_help(&sess, subcommand); if let Some(s) = paths { println!("{s}"); } else { diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 5e88277008971..8e66598fda993 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -11,7 +11,7 @@ use std::path::PathBuf; use serde_derive::Deserialize; -use crate::core::session::Build; +use crate::core::session::Session; use crate::utils::exec::command; use crate::utils::helpers::t; @@ -24,8 +24,8 @@ pub(crate) struct Crate { } impl Crate { - pub(crate) fn local_path(&self, build: &Build) -> PathBuf { - self.path.strip_prefix(&build.config.src).unwrap().into() + pub(crate) fn local_path(&self, sess: &Session) -> PathBuf { + self.path.strip_prefix(&sess.config.src).unwrap().into() } } @@ -55,10 +55,10 @@ struct Dependency { source: Option, } -/// Collects and stores package metadata of each workspace members into `build`, +/// Collects and stores package metadata of each workspace members into `sess`, /// by executing `cargo metadata` commands. -pub fn build(build: &mut Build) { - for package in workspace_members(build) { +pub(crate) fn build(sess: &mut Session) { + for package in workspace_members(sess) { if package.source.is_none() { let name = package.name; let mut path = PathBuf::from(package.manifest_path); @@ -75,9 +75,9 @@ pub fn build(build: &mut Build) { path, features: package.features.keys().cloned().collect(), }; - let relative_path = krate.local_path(build); - build.crates.insert(name.clone(), krate); - let existing_path = build.crate_paths.insert(relative_path, name); + let relative_path = krate.local_path(sess); + sess.crates.insert(name.clone(), krate); + let existing_path = sess.crate_paths.insert(relative_path, name); assert!( existing_path.is_none(), "multiple crates with the same path: {}", @@ -91,9 +91,9 @@ pub fn build(build: &mut Build) { /// /// This is used to resolve specific crate paths in `fn should_run` to compile /// particular crate (e.g., `x build sysroot` to build library/sysroot). -fn workspace_members(build: &Build) -> Vec { +fn workspace_members(sess: &Session) -> Vec { let collect_metadata = |manifest_path| { - let mut cargo = command(&build.initial_cargo); + let mut cargo = command(&sess.initial_cargo); cargo // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. @@ -103,8 +103,8 @@ fn workspace_members(build: &Build) -> Vec { .arg("1") .arg("--no-deps") .arg("--manifest-path") - .arg(build.src.join(manifest_path)); - let metadata_output = cargo.run_in_dry_run().run_capture_stdout(build).stdout(); + .arg(sess.src.join(manifest_path)); + let metadata_output = cargo.run_in_dry_run().run_capture_stdout(sess).stdout(); let Output { packages, .. } = t!(serde_json::from_str(&metadata_output)); packages }; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 148f2ac1212c0..27638810fb7bb 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -18,7 +18,7 @@ use crate::core::build_steps::tool; use crate::core::builder::Builder; use crate::core::config::flags::Subcommand; use crate::core::config::{CompilerBuiltins, DebuggerPath, Target}; -use crate::core::session::Build; +use crate::core::session::Session; use crate::utils::exec::command; use crate::utils::helpers::{self, t}; @@ -78,15 +78,15 @@ impl Finder { } } -pub fn check(build: &mut Build) { +pub(crate) fn check(sess: &mut Session) { let mut skip_target_sanity = env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some_and(|s| s == "1" || s == "true"); - skip_target_sanity |= matches!(build.config.cmd, Subcommand::Check { .. }); + skip_target_sanity |= matches!(sess.config.cmd, Subcommand::Check { .. }); // Skip target sanity checks when we are doing anything with mir-opt tests or Miri let skipped_paths = [OsStr::new("mir-opt"), OsStr::new("miri")]; - skip_target_sanity |= build.config.paths.iter().any(|path| { + skip_target_sanity |= sess.config.paths.iter().any(|path| { path.components().any(|component| skipped_paths.contains(&component.as_os_str())) }); @@ -102,18 +102,18 @@ pub fn check(build: &mut Build) { let mut cmd_finder = Finder::new(); // If we've got a git directory we're gonna need git to update // submodules and learn about various other aspects. - if build.rust_info().is_managed_git_subrepository() { + if sess.rust_info().is_managed_git_subrepository() { cmd_finder.must_have("git"); } // Ensure that a compatible version of libstdc++ is available on the system when using `llvm.download-ci-llvm`. if cfg!(not(test)) - && !build.config.dry_run() - && !build.host_target.is_msvc() - && build.config.llvm_ci_mode.download_from_ci() + && !sess.config.dry_run() + && !sess.host_target.is_msvc() + && sess.config.llvm_ci_mode.download_from_ci() { - let builder = Builder::new(build); - let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.host_target }); + let builder = Builder::new(sess); + let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: sess.host_target }); match libcxx_version { tool::LibcxxVersion::Gnu(version) => { @@ -138,11 +138,11 @@ pub fn check(build: &mut Build) { } // We need cmake, but only if we're actually building LLVM or sanitizers. - let building_llvm = !build.config.llvm_ci_mode.download_from_ci() - && !build.config.local_rebuild - && build.hosts.iter().any(|host| { - build.config.llvm_enabled(*host) - && build + let building_llvm = !sess.config.llvm_ci_mode.download_from_ci() + && !sess.config.local_rebuild + && sess.hosts.iter().any(|host| { + sess.config.llvm_enabled(*host) + && sess .config .target_config .get(host) @@ -150,7 +150,7 @@ pub fn check(build: &mut Build) { .unwrap_or(true) }); - let need_cmake = building_llvm || build.config.any_sanitizers_to_build(); + let need_cmake = building_llvm || sess.config.any_sanitizers_to_build(); if need_cmake && cmd_finder.maybe_have("cmake").is_none() { eprintln!( " @@ -164,7 +164,7 @@ than building it. helpers::exit_process(1); } - build.config.python = build + sess.config.python = sess .config .python .take() @@ -174,7 +174,7 @@ than building it. .or_else(|| cmd_finder.maybe_have("python3")) .or_else(|| cmd_finder.maybe_have("python2")); - build.config.nodejs = build + sess.config.nodejs = sess .config .nodejs .take() @@ -182,29 +182,29 @@ than building it. .or_else(|| cmd_finder.maybe_have("node")) .or_else(|| cmd_finder.maybe_have("nodejs")); - build.config.yarn = build + sess.config.yarn = sess .config .yarn .take() .map(|p| cmd_finder.must_have(p)) .or_else(|| cmd_finder.maybe_have("yarn")); - build.config.gdb = build.config.gdb.take().map(|p| match p { + sess.config.gdb = sess.config.gdb.take().map(|p| match p { DebuggerPath::Discover => DebuggerPath::Discover, DebuggerPath::Path(path) => DebuggerPath::Path(cmd_finder.must_have(path)), }); - build.config.reuse = build + sess.config.reuse = sess .config .reuse .take() .map(|p| cmd_finder.must_have(p)) .or_else(|| cmd_finder.maybe_have("reuse")); - let stage0_supported_target_list: HashSet = command(&build.config.initial_rustc) + let stage0_supported_target_list: HashSet = command(&sess.config.initial_rustc) .args(["--print", "target-list"]) .run_in_dry_run() - .run_capture_stdout(&build) + .run_capture_stdout(&sess) .stdout() .lines() .map(|s| s.to_string()) @@ -214,9 +214,9 @@ than building it. // because they are not needed. // // See `cc_detect::find` for more details. - let skip_tools_checks = build.config.dry_run() + let skip_tools_checks = sess.config.dry_run() || matches!( - build.config.cmd, + sess.config.cmd, Subcommand::Clean { .. } | Subcommand::Check { .. } | Subcommand::Format { .. } @@ -225,7 +225,7 @@ than building it. // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. - for target in &build.targets { + for target in &sess.targets { // On emscripten we don't actually need the C compiler to just // build the target artifacts, only for testing. For the sake // of easier bot configuration, just skip detection. @@ -243,12 +243,12 @@ than building it. } // skip check for cross-targets - if skip_target_sanity && target != &build.host_target { + if skip_target_sanity && target != &sess.host_target { continue; } // Ignore fake targets that are only used for unit tests in bootstrap. - if cfg!(not(test)) && !skip_target_sanity && !build.local_rebuild { + if cfg!(not(test)) && !skip_target_sanity && !sess.local_rebuild { let mut has_target = false; let target_str = target.to_string(); @@ -301,33 +301,32 @@ than building it. } if !skip_tools_checks { - cmd_finder.must_have(build.cc(*target)); - if let Some(ar) = build.ar(*target) { + cmd_finder.must_have(sess.cc(*target)); + if let Some(ar) = sess.ar(*target) { cmd_finder.must_have(ar); } } } if !skip_tools_checks { - for host in &build.hosts { - cmd_finder.must_have(build.cxx(*host).unwrap()); + for host in &sess.hosts { + cmd_finder.must_have(sess.cxx(*host).unwrap()); } } - for target in &build.targets { - build - .config + for target in &sess.targets { + sess.config .target_config .entry(*target) .or_insert_with(|| Target::from_triple(&target.triple)); // compiler-rt c fallbacks for wasm cannot be built with gcc if target.contains("wasm") - && (*build.config.optimized_compiler_builtins(*target) + && (*sess.config.optimized_compiler_builtins(*target) != CompilerBuiltins::BuildRustOnly - || build.config.rust_std_features.contains("compiler-builtins-c")) + || sess.config.rust_std_features.contains("compiler-builtins-c")) { - let cc_tool = build.cc_tool(*target); + let cc_tool = sess.cc_tool(*target); if !cc_tool.is_like_clang() && !cc_tool.path().ends_with("emcc") { // emcc works as well panic!( @@ -340,19 +339,19 @@ than building it. } if (target.contains("-none-") || target.contains("nvptx")) - && build.no_std(*target) == Some(false) + && sess.no_std(*target) == Some(false) { panic!("All the *-none-* and nvptx* targets are no-std targets") } // skip check for cross-targets - if skip_target_sanity && target != &build.host_target { + if skip_target_sanity && target != &sess.host_target { continue; } // Make sure musl-root is valid. if target.contains("musl") && !target.contains("unikraft") { - match build.musl_libdir(*target) { + match sess.musl_libdir(*target) { Some(libdir) => { if fs::metadata(libdir.join("libc.a")).is_err() { panic!("couldn't find libc.a in musl libdir: {}", libdir.display()); @@ -371,7 +370,7 @@ than building it. // Cygwin. The Cygwin build does not have generators for Visual // Studio, so detect that here and error. let out = - command("cmake").arg("--help").run_in_dry_run().run_capture_stdout(&build).stdout(); + command("cmake").arg("--help").run_in_dry_run().run_capture_stdout(&sess).stdout(); if !out.contains("Visual Studio") { panic!( " @@ -395,15 +394,15 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake // but if it's disabled then double-check it's present on the system. if target.contains("wasip") && !target.contains("wasip1") - && !build.tool_enabled("wasm-component-ld") + && !sess.tool_enabled("wasm-component-ld") { cmd_finder.must_have("wasm-component-ld"); } // aarch64-unknown-linux-pauthtest must use clang if !skip_tools_checks && target.is_pauthtest() { - let cc_tool = build.cc_tool(*target); - let linker_path = build + let cc_tool = sess.cc_tool(*target); + let linker_path = sess .linker(*target) .unwrap_or_else(|| panic!("{} requires an explicit clang linker", target.triple)); @@ -431,7 +430,7 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake } let output = - command(cc_tool.path()).arg("-dumpversion").run_capture_stdout(&build).stdout(); + command(cc_tool.path()).arg("-dumpversion").run_capture_stdout(&sess).stdout(); let version_str = output.trim(); let mut parts = version_str.split('.').map(|s| s.parse::().unwrap_or(0)); let major = parts.next().unwrap_or(0); @@ -448,7 +447,7 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake } } - if let Some(ref s) = build.config.ccache { + if let Some(ref s) = sess.config.ccache { cmd_finder.must_have(s); } } diff --git a/src/bootstrap/src/core/session.rs b/src/bootstrap/src/core/session.rs index 3e6668258c641..f01a4e27c4e48 100644 --- a/src/bootstrap/src/core/session.rs +++ b/src/bootstrap/src/core/session.rs @@ -39,13 +39,8 @@ pub(crate) enum GitRepo { /// This structure transitively contains all configuration for the build system. /// All filesystem-encoded configuration is in `config`, all flags are in /// `flags`, and then parsed or probed information is listed in the keys below. -/// -/// This structure is a parameter of almost all methods in the build system, -/// although most functions are implemented as free functions rather than -/// methods specifically on this structure itself (to make it easier to -/// organize). -pub(crate) struct Build { - /// User-specified configuration from `bootstrap.toml`. +pub(crate) struct Session { + /// User-specified configuration from command-line flags and `bootstrap.toml`. pub(crate) config: Config, // Version information @@ -227,8 +222,8 @@ impl FileType { } macro_rules! forward { - ( $( $fn:ident( $($param:ident: $ty:ty),* ) $( -> $ret:ty)? ),+ $(,)? ) => { - impl Build { + ($( $fn:ident( $($param:ident: $ty:ty),* ) $( -> $ret:ty)? ),+ $(,)? ) => { + impl Session { $( pub(crate) fn $fn(&self, $($param: $ty),* ) $( -> $ret)? { self.config.$fn( $($param),* ) @@ -266,12 +261,12 @@ impl From for TargetAndStage { } } -impl Build { +impl Session { /// Creates a new set of build configuration from the `flags` on the command /// line and the filesystem `config`. /// /// By default all build output will be placed in the current directory. - pub(crate) fn new(mut config: Config) -> Build { + pub(crate) fn new(mut config: Config) -> Session { let src = config.src.clone(); let out = config.out.clone(); @@ -361,7 +356,7 @@ impl Build { config.description = Some("built from a source tarball".to_owned()); } - let mut build = Build { + let mut sess = Session { initial_lld, initial_relative_libdir, initial_rustc: config.initial_rustc.clone(), @@ -410,10 +405,10 @@ impl Build { // If local-rust is the same major.minor as the current version, then force a // local-rebuild - let local_version_verbose = command(&build.initial_rustc) + let local_version_verbose = command(&sess.initial_rustc) .run_in_dry_run() .args(["--version", "--verbose"]) - .run_capture_stdout(&build) + .run_capture_stdout(&sess) .stdout(); let local_release = local_version_verbose .lines() @@ -422,26 +417,26 @@ impl Build { .unwrap() .trim(); if local_release.split('.').take(2).eq(version.split('.').take(2)) { - build.do_if_verbose(|| println!("auto-detected local-rebuild {local_release}")); - build.local_rebuild = true; + sess.do_if_verbose(|| println!("auto-detected local-rebuild {local_release}")); + sess.local_rebuild = true; } - build.do_if_verbose(|| println!("finding compilers")); - crate::utils::cc_detect::fill_compilers(&mut build); + sess.do_if_verbose(|| println!("finding compilers")); + crate::utils::cc_detect::fill_compilers(&mut sess); // When running `setup`, the profile is about to change, so any requirements we have now may // be different on the next invocation. Don't check for them until the next time x.py is // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing. // // Similarly, for `setup` we don't actually need submodules or cargo metadata. - if !matches!(build.config.cmd, Subcommand::Setup { .. }) { - build.do_if_verbose(|| println!("running sanity check")); - crate::core::sanity::check(&mut build); + if !matches!(sess.config.cmd, Subcommand::Setup { .. }) { + sess.do_if_verbose(|| println!("running sanity check")); + crate::core::sanity::check(&mut sess); // Make sure we update these before gathering metadata so we don't get an error about missing // Cargo.toml files. let rust_submodules = ["library/backtrace"]; for s in rust_submodules { - build.require_submodule( + sess.require_submodule( s, Some( "The submodule is required for the standard library \ @@ -450,30 +445,30 @@ impl Build { ); } // Now, update all existing submodules. - build.update_existing_submodules(); + sess.update_existing_submodules(); - build.do_if_verbose(|| println!("learning about cargo")); - crate::core::metadata::build(&mut build); + sess.do_if_verbose(|| println!("learning about cargo")); + crate::core::metadata::build(&mut sess); } // Create symbolic link to use host sysroot from a consistent path (e.g., in the rust-analyzer config file). - let build_triple = build.out.join(build.host_target); + let build_triple = sess.out.join(sess.host_target); t!(fs::create_dir_all(&build_triple)); - let host = build.out.join("host"); + let host = sess.out.join("host"); if host.is_symlink() { // Left over from a previous build; overwrite it. - // This matters if `build.build` has changed between invocations. + // This matters if `sess.host_target` has changed between invocations. #[cfg(windows)] t!(fs::remove_dir(&host)); #[cfg(not(windows))] t!(fs::remove_file(&host)); } t!( - symlink_dir(&build.config, &build_triple, &host), + symlink_dir(&sess.config, &build_triple, &host), format!("symlink_dir({} => {}) failed", host.display(), build_triple.display()) ); - build + sess } /// Updates a submodule, and exits with a failure if submodule management @@ -488,10 +483,10 @@ impl Build { feature = "tracing", instrument( level = "trace", - name = "Build::require_submodule", + name = "Session::require_submodule", skip_all, fields(submodule = submodule), - ), + ) )] pub(crate) fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) { if self.rust_info().is_from_tarball() { @@ -566,7 +561,7 @@ impl Build { } /// Executes the entire build, as configured by the flags and configuration. - #[cfg_attr(feature = "tracing", instrument(level = "debug", name = "Build::build", skip_all))] + #[cfg_attr(feature = "tracing", instrument(level = "debug", name = "Session::build", skip_all))] pub(crate) fn build(&mut self) { trace!("setting up job management"); unsafe { @@ -884,7 +879,7 @@ impl Build { /// Return a `Group` guard for a [`Step`] that: /// - Performs `action` - /// - If the action is `Kind::Test`, use [`Build::msg_test`] instead. + /// - If the action is `Kind::Test`, use [`Session::msg_test`] instead. /// - On `what` /// - Where `what` possibly corresponds to a `mode` /// - `action` is performed with/on the given compiler (`target_and_stage`). @@ -907,7 +902,7 @@ impl Build { let action = action.into(); assert!( action != Kind::Test, - "Please use `Build::msg_test` instead of `Build::msg(Kind::Test)`" + "Please use `Session::msg_test` instead of `Session::msg(Kind::Test)`" ); let actual_stage = match mode.into() { @@ -946,7 +941,7 @@ impl Build { } /// Return a `Group` guard for a [`Step`] that tests `what` with the given `stage` and `target`. - /// Use this instead of [`Build::msg`] for test steps, because for them it is not always clear + /// Use this instead of [`Session::msg`] for test steps, because for them it is not always clear /// what exactly is a build compiler. /// /// [`Step`]: crate::core::builder::Step @@ -1863,7 +1858,7 @@ to download LLVM rather than building it. } } -impl AsRef for Build { +impl AsRef for Session { fn as_ref(&self) -> &ExecutionContext { &self.config.exec_ctx } diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index e753ee71683fd..24308cdadaa4a 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -27,29 +27,29 @@ use std::path::{Path, PathBuf}; use crate::core::config::flags::Subcommand; use crate::core::config::{CompressDebuginfo, TargetSelection}; -use crate::core::session::{Build, CLang, GitRepo}; +use crate::core::session::{CLang, GitRepo, Session}; use crate::utils::exec::{BootstrapCommand, command}; /// Creates and configures a new [`cc::Build`] instance for the given target. -fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { +fn new_cc_build(sess: &Session, target: TargetSelection) -> cc::Build { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false) .opt_level(2) .warnings(false) .debug(false) // We have to configure out_dir, otherwise flag_if_supported will not work - .out_dir(build.tempdir().join("cc-rs-out-dir")) + .out_dir(sess.tempdir().join("cc-rs-out-dir")) .target(&target.triple) - .host(&build.host_target.triple); + .host(&sess.host_target.triple); - match build.config.compress_debuginfo(target) { + match sess.config.compress_debuginfo(target) { CompressDebuginfo::Zlib => { cfg.flag_if_supported("-gz"); } CompressDebuginfo::Off => {} } - match build.crt_static(target) { + match sess.crt_static(target) { Some(a) => { cfg.static_crt(a); } @@ -62,31 +62,30 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { cfg } -/// Probes for C and C++ compilers and configures the corresponding entries in the [`Build`] +/// Probes for C and C++ compilers and configures the corresponding entries in the [`Session`] /// structure. /// /// This function determines which targets need a C compiler (and, if needed, a C++ compiler) /// by combining the primary build target, host targets, and any additional targets. For /// each target, it calls [`fill_target_compiler`] to configure the necessary compiler tools. -pub fn fill_compilers(build: &mut Build) { - let mut targets: HashSet<_> = match build.config.cmd { +pub(crate) fn fill_compilers(sess: &mut Session) { + let mut targets: HashSet<_> = match sess.config.cmd { // We don't need to check cross targets for these commands. Subcommand::Clean { .. } | Subcommand::Check { .. } | Subcommand::Format { .. } | Subcommand::Setup { .. } => { - build.hosts.iter().cloned().chain(iter::once(build.host_target)).collect() + sess.hosts.iter().cloned().chain(iter::once(sess.host_target)).collect() } _ => { // For all targets we're going to need a C compiler for building some shims // and such as well as for being a linker for Rust code. - build - .targets + sess.targets .iter() - .chain(&build.hosts) + .chain(&sess.hosts) .cloned() - .chain(iter::once(build.host_target)) + .chain(iter::once(sess.host_target)) .collect() } }; @@ -94,12 +93,12 @@ pub fn fill_compilers(build: &mut Build) { // When we intend to build wasm proc macros, we'll need to detect a toolchain for linking those // as well. In the future it would be good to make this a no-op given that we shouldn't need to // build any C/C++ code for wasm... - if build.config.wasm_proc_macros { + if sess.config.wasm_proc_macros { targets.insert(TargetSelection::from_user("wasm32-wasip2")); } for target in targets { - fill_target_compiler(build, target); + fill_target_compiler(sess, target); } } @@ -108,12 +107,12 @@ pub fn fill_compilers(build: &mut Build) { /// This function uses both user-specified configuration (from `bootstrap.toml`) and auto-detection /// logic to determine the correct C/C++ compilers for the target. It also determines the appropriate /// archiver (`ar`) and sets up additional compilation flags (both handled and unhandled). -pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { - let mut cfg = new_cc_build(build, target); - let config = build.config.target_config.get(&target); +fn fill_target_compiler(sess: &mut Session, target: TargetSelection) { + let mut cfg = new_cc_build(sess, target); + let config = sess.config.target_config.get(&target); if let Some(cc) = config .and_then(|c| c.cc.clone()) - .or_else(|| default_compiler(&cfg, Language::C, target, build)) + .or_else(|| default_compiler(&cfg, Language::C, target, sess)) { cfg.compiler(cc); } @@ -123,17 +122,17 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { .and_then(|c| c.ar.clone()) .or_else(|| cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok()); - build.cc.insert(target, compiler.clone()); - let mut cflags = build.cc_handled_cflags(target, CLang::C); - cflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C)); + sess.cc.insert(target, compiler.clone()); + let mut cflags = sess.cc_handled_cflags(target, CLang::C); + cflags.extend(sess.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C)); // If we use llvm-libunwind, we will need a C++ compiler as well for all targets // We'll need one anyways if the target triple is also a host triple - let mut cfg = new_cc_build(build, target); + let mut cfg = new_cc_build(sess, target); cfg.cpp(true); let cxx_configured = if let Some(cxx) = config .and_then(|c| c.cxx.clone()) - .or_else(|| default_compiler(&cfg, Language::CPlusPlus, target, build)) + .or_else(|| default_compiler(&cfg, Language::CPlusPlus, target, sess)) { cfg.compiler(cxx); true @@ -145,24 +144,24 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { // for VxWorks, record CXX compiler which will be used in lib.rs:linker() if cxx_configured || target.contains("vxworks") { let compiler = cfg.get_compiler(); - build.cxx.insert(target, compiler); + sess.cxx.insert(target, compiler); } - build.do_if_verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); - build.do_if_verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); - if let Ok(cxx) = build.cxx(target) { - let mut cxxflags = build.cc_handled_cflags(target, CLang::Cxx); - cxxflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx)); - build.do_if_verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); - build.do_if_verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); + sess.do_if_verbose(|| println!("CC_{} = {:?}", target.triple, sess.cc(target))); + sess.do_if_verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); + if let Ok(cxx) = sess.cxx(target) { + let mut cxxflags = sess.cc_handled_cflags(target, CLang::Cxx); + cxxflags.extend(sess.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx)); + sess.do_if_verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); + sess.do_if_verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); } if let Some(ar) = ar { - build.do_if_verbose(|| println!("AR_{} = {ar:?}", target.triple)); - build.ar.insert(target, ar); + sess.do_if_verbose(|| println!("AR_{} = {ar:?}", target.triple)); + sess.ar.insert(target, ar); } if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) { - build.ranlib.insert(target, ranlib); + sess.ranlib.insert(target, ranlib); } } @@ -172,14 +171,14 @@ fn default_compiler( cfg: &cc::Build, compiler: Language, target: TargetSelection, - build: &Build, + sess: &Session, ) -> Option { match &*target.triple { // When compiling for android we may have the NDK configured in the // bootstrap.toml in which case we look there. Otherwise the default // compiler already takes into account the triple in question. t if t.contains("android") => { - build.config.android_ndk.as_ref().map(|ndk| ndk_compiler(compiler, &target.triple, ndk)) + sess.config.android_ndk.as_ref().map(|ndk| ndk_compiler(compiler, &target.triple, ndk)) } // The default gcc version from OpenBSD may be too old, try using egcc, @@ -192,14 +191,14 @@ fn default_compiler( } let mut cmd = BootstrapCommand::from(c.to_command()); - let output = cmd.arg("--version").run_capture_stdout(build).stdout(); + let output = cmd.arg("--version").run_capture_stdout(sess).stdout(); let i = output.find(" 4.")?; match output[i + 3..].chars().next().unwrap() { '0'..='6' => {} _ => return None, } let alternative = format!("e{gnu_compiler}"); - if command(&alternative).run_capture(build).is_success() { + if command(&alternative).run_capture(sess).is_success() { Some(PathBuf::from(alternative)) } else { None @@ -222,7 +221,7 @@ fn default_compiler( } t if t.contains("musl") && compiler == Language::C => { - if let Some(root) = build.musl_root(target) { + if let Some(root) = sess.musl_root(target) { let guess = root.join("bin/musl-gcc"); if guess.exists() { Some(guess) } else { None } } else { @@ -231,10 +230,10 @@ fn default_compiler( } t if t.contains("-wasi") => { - let root = if let Some(path) = build.wasi_sdk_path.as_ref() { + let root = if let Some(path) = sess.wasi_sdk_path.as_ref() { path } else { - if build.config.is_running_on_ci() { + if sess.config.is_running_on_ci() { panic!("ERROR: WASI_SDK_PATH must be configured for a -wasi target on CI"); } println!("WARNING: WASI_SDK_PATH not set, using default cc/cxx compiler"); diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index 716407cb0cb1c..861c9953b52d1 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use super::*; use crate::core::config::{Target, TargetSelection}; -use crate::core::session::Build; +use crate::core::session::Session; use crate::utils::tests::TestCtx; #[test] @@ -70,9 +70,9 @@ fn test_language_clang() { #[test] fn test_new_cc_build() { let config = TestCtx::new().config("build").create_config(); - let build = Build::new(config); + let sess = Session::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); - let cfg = new_cc_build(&build, target.clone()); + let cfg = new_cc_build(&sess, target.clone()); let compiler = cfg.get_compiler(); assert!(!compiler.path().to_str().unwrap().is_empty(), "Compiler path should not be empty"); } @@ -80,13 +80,13 @@ fn test_new_cc_build() { #[test] fn test_default_compiler_wasi() { let config = TestCtx::new().config("build").create_config(); - let mut build = Build::new(config); + let mut sess = Session::new(config); let target = TargetSelection::from_user("wasm32-wasi"); let wasi_sdk = PathBuf::from("/wasi-sdk"); - build.wasi_sdk_path = Some(wasi_sdk.clone()); + sess.wasi_sdk_path = Some(wasi_sdk.clone()); let cfg = cc::Build::new(); - if let Some(result) = default_compiler(&cfg, Language::C, target.clone(), &build) { + if let Some(result) = default_compiler(&cfg, Language::C, target.clone(), &sess) { let expected = { let compiler = format!("{}-clang", target.triple); wasi_sdk.join("bin").join(compiler) @@ -102,59 +102,59 @@ fn test_default_compiler_wasi() { #[test] fn test_default_compiler_fallback() { let config = TestCtx::new().config("build").create_config(); - let build = Build::new(config); + let sess = Session::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let cfg = cc::Build::new(); - let result = default_compiler(&cfg, Language::C, target, &build); + let result = default_compiler(&cfg, Language::C, target, &sess); assert!(result.is_none(), "default_compiler should return None for generic targets"); } #[test] fn test_find_target_with_config() { let config = TestCtx::new().config("build").create_config(); - let mut build = Build::new(config); + let mut sess = Session::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut target_config = Target::default(); target_config.cc = Some(PathBuf::from("dummy-cc")); target_config.cxx = Some(PathBuf::from("dummy-cxx")); target_config.ar = Some(PathBuf::from("dummy-ar")); target_config.ranlib = Some(PathBuf::from("dummy-ranlib")); - build.config.target_config.insert(target.clone(), target_config); - fill_target_compiler(&mut build, target.clone()); - let cc_tool = build.cc.get(&target).unwrap(); + sess.config.target_config.insert(target.clone(), target_config); + fill_target_compiler(&mut sess, target.clone()); + let cc_tool = sess.cc.get(&target).unwrap(); assert_eq!(cc_tool.path(), &PathBuf::from("dummy-cc")); - let cxx_tool = build.cxx.get(&target).unwrap(); + let cxx_tool = sess.cxx.get(&target).unwrap(); assert_eq!(cxx_tool.path(), &PathBuf::from("dummy-cxx")); - let ar = build.ar.get(&target).unwrap(); + let ar = sess.ar.get(&target).unwrap(); assert_eq!(ar, &PathBuf::from("dummy-ar")); - let ranlib = build.ranlib.get(&target).unwrap(); + let ranlib = sess.ranlib.get(&target).unwrap(); assert_eq!(ranlib, &PathBuf::from("dummy-ranlib")); } #[test] fn test_find_target_without_config() { let config = TestCtx::new().config("build").create_config(); - let mut build = Build::new(config); + let mut sess = Session::new(config); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); - build.config.target_config.clear(); - fill_target_compiler(&mut build, target.clone()); - assert!(build.cc.contains_key(&target)); + sess.config.target_config.clear(); + fill_target_compiler(&mut sess, target.clone()); + assert!(sess.cc.contains_key(&target)); if !target.triple.contains("vxworks") { - assert!(build.cxx.contains_key(&target)); + assert!(sess.cxx.contains_key(&target)); } - assert!(build.ar.contains_key(&target)); + assert!(sess.ar.contains_key(&target)); } #[test] fn test_find() { let config = TestCtx::new().config("build").create_config(); - let mut build = Build::new(config); + let mut sess = Session::new(config); let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let target2 = TargetSelection::from_user("x86_64-unknown-openbsd"); - build.targets.push(target1.clone()); - build.hosts.push(target2.clone()); - fill_compilers(&mut build); - for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.host_target)) { - assert!(build.cc.contains_key(t), "CC not set for target {}", t.triple); + sess.targets.push(target1.clone()); + sess.hosts.push(target2.clone()); + fill_compilers(&mut sess); + for t in sess.hosts.iter().chain(sess.targets.iter()).chain(iter::once(&sess.host_target)) { + assert!(sess.cc.contains_key(t), "CC not set for target {}", t.triple); } } diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index ebb40edf9b262..0663bd0bf5215 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -10,7 +10,7 @@ use std::path::Path; use super::exec::ExecutionContext; use super::helpers; -use crate::core::session::Build; +use crate::core::session::Session; use crate::utils::helpers::t; #[derive(Clone, Default)] @@ -111,8 +111,8 @@ impl GitInfo { self.info().map(|s| &s.commit_date[..]) } - pub fn version(&self, build: &Build, num: &str) -> String { - let mut version = build.release(num); + pub fn version(&self, sess: &Session, num: &str) -> String { + let mut version = sess.release(num); if let Some(inner) = self.info() { version.push_str(" ("); version.push_str(&inner.short_sha); diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index 942ac6c80e4ee..45cff7c716ba9 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -1,14 +1,13 @@ #[cfg(windows)] -pub use for_windows::*; - -use crate::core::session::Build; +pub(crate) use self::for_windows::setup; +use crate::core::session::Session; #[cfg(any(target_os = "haiku", target_os = "hermit", not(any(unix, windows))))] -pub unsafe fn setup(_build: &mut Build) {} +pub(crate) unsafe fn setup(_sess: &Session) {} #[cfg(all(unix, not(target_os = "haiku")))] -pub unsafe fn setup(build: &mut Build) { - if build.config.low_priority { +pub(crate) unsafe fn setup(sess: &Session) { + if sess.config.low_priority { unsafe { libc::setpriority(libc::PRIO_PGRP as _, 0, 10); } @@ -60,7 +59,7 @@ mod for_windows { use windows::Win32::System::Threading::{BELOW_NORMAL_PRIORITY_CLASS, GetCurrentProcess}; use windows::core::PCWSTR; - pub unsafe fn setup(build: &mut super::Build) { + pub(crate) unsafe fn setup(sess: &super::Session) { // SAFETY: pretty much everything below is unsafe unsafe { // Enable the Windows Error Reporting dialog which msys disables, @@ -77,7 +76,7 @@ mod for_windows { // children will reside in the job by default. let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default(); info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - if build.config.low_priority { + if sess.config.low_priority { info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS; info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0; } diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index a309b1d53b8e9..79d967452d0c5 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -17,7 +17,7 @@ use build_helper::metrics::{ use sysinfo::{CpuRefreshKind, RefreshKind, System}; use crate::core::builder::{Builder, Step}; -use crate::core::session::Build; +use crate::core::session::Session; use crate::utils::helpers::t; // Update this number whenever a breaking change is made to the build metrics. @@ -156,11 +156,11 @@ impl BuildMetrics { step.cpu_usage_time_sec += cpu as f64 / 100.0 * elapsed.as_secs_f64(); } - pub(crate) fn persist(&self, build: &Build) { + pub(crate) fn persist(&self, sess: &Session) { let mut state = self.state.borrow_mut(); assert!(state.running_steps.is_empty(), "steps are still executing"); - let dest = build.out.join("metrics.json"); + let dest = sess.out.join("metrics.json"); let mut system = System::new_with_specifics( RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()), @@ -222,7 +222,7 @@ impl BuildMetrics { format_version: CURRENT_FORMAT_VERSION, system_stats, invocations, - ci_metadata: get_ci_metadata(build.config.ci_env), + ci_metadata: get_ci_metadata(sess.config.ci_env), }; t!(std::fs::create_dir_all(dest.parent().unwrap())); From 1bc25c317b87243245dea5d26000e7a163d7c2e5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 24 Jul 2026 10:27:42 +1000 Subject: [PATCH 4/5] Clarify token cursor behaviour The meaning of `TokenTreeCursor::index` is context-dependent: in the innermost (current) `TokenTreeCursor` it points to the next token tree, but in all the other (stack) `TokenTreeCursor`s it points to the current token tree. This makes the meanings of "current", "next", and "look_ahead" confusing for it and for `TokenCursor`. This commit clarifies things by adjusting the stack `TokenTreeCursor`s to also point to the next token tree, and by improving various comments. The commit also renames `TokenCursor::next` as `TokenCursor::next_and_bump` for consistency with everything else: `next` means "get the next thing" and `bump` means "advance the cursor", and this operation does both. --- compiler/rustc_ast/src/tokenstream.rs | 66 ++++++++++++++++---------- compiler/rustc_parse/src/parser/mod.rs | 21 ++++---- 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 428f37b8af450..e860ef61a5332 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -249,14 +249,14 @@ impl LazyAttrTokenStreamInner { break_last_token, node_replacements, } => { - // The token produced by the final call to `{,inlined_}next` was not + // The token produced by the final call to `{,inlined_}next_and_bump` was not // actually consumed by the callback. The combination of chaining the // initial token and using `take` produces the desired result - we // produce an empty `TokenStream` if no calls were made, and omit the // final token otherwise. let mut cursor_snapshot = cursor_snapshot.clone(); let tokens = iter::once(FlatToken::Token(*start_token)) - .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next()))) + .chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next_and_bump()))) .take(*num_calls as usize); if node_replacements.is_empty() { @@ -883,36 +883,48 @@ impl<'t> Iterator for TokenStreamIter<'t> { #[derive(Clone, Debug)] struct TokenTreeCursor { stream: TokenStream, - /// Points to the current token tree in the stream. In `TokenCursor::curr`, - /// this can be any token tree. In `TokenCursor::stack`, this is always a - /// `TokenTree::Delimited`. - index: usize, + /// Points to the next token tree (or one past the end of the stream). + next_idx: usize, } impl TokenTreeCursor { #[inline] fn new(stream: TokenStream) -> Self { - TokenTreeCursor { stream, index: 0 } + TokenTreeCursor { stream, next_idx: 0 } } + /// Gets the current token tree within this cursor. In a debug build it panics on a cursor that + /// hasn't been bumped; in a release build it will return `None`. #[inline] fn curr(&self) -> Option<&TokenTree> { - self.stream.get(self.index) + debug_assert!(self.next_idx > 0); + self.stream.get(self.next_idx - 1) } + /// Gets the next token tree without advancing. + #[inline] + fn next(&self) -> Option<&TokenTree> { + self.stream.get(self.next_idx) + } + + /// Gets the token tree `n` ahead. `look_ahead(1)` is equivalent to `next()`. `look_ahead(0)` + /// isn't allowed and will panic. + #[inline] fn look_ahead(&self, n: usize) -> Option<&TokenTree> { - self.stream.get(self.index + n) + assert_ne!(n, 0); + self.stream.get(self.next_idx + (n - 1)) } + /// Move the cursor to the next token tree. #[inline] fn bump(&mut self) { - self.index += 1; + self.next_idx += 1; } - // For skipping ahead in rare circumstances. + /// For skipping ahead in rare circumstances. #[inline] fn bump_to_end(&mut self) { - self.index = self.stream.len(); + self.next_idx = self.stream.len(); } } @@ -922,15 +934,16 @@ impl TokenTreeCursor { /// what the parser expects, for the most part. #[derive(Clone, Debug)] pub struct TokenCursor { - // Cursor for the current (innermost) token stream. The index within the + // Cursor for the current (innermost) token stream. The `next_idx` within the // cursor can point to any token tree in the stream (or one past the end). - // The delimiters for this token stream are found in `self.stack.last()`; - // if that is `None` we are in the outermost token stream which never has - // delimiters. + // The delimiters for this token stream are found in the current token tree + // in `self.stack.last()`; if that is `None` we are in the outermost token + // stream which never has delimiters. curr: TokenTreeCursor, - // Token streams surrounding the current one. The index within each cursor - // always points to a `TokenTree::Delimited`. + // Token streams surrounding the current one. The `next_idx` within each cursor + // is always greater than zero and always points one past the current + // `TokenTree::Delimited`. stack: Vec, } @@ -940,12 +953,13 @@ impl TokenCursor { TokenCursor { curr: TokenTreeCursor::new(stream), stack: vec![] } } - pub fn next(&mut self) -> (Token, Spacing) { - self.inlined_next() + /// Gets the next token and advances the cursor by one. + pub fn next_and_bump(&mut self) -> (Token, Spacing) { + self.inlined_next_and_bump() } - /// An `n` of zero is the next token tree in the current token stream; won't look outside the - /// current token stream. + /// An `n` of 1 is the next token tree in the current token stream; won't look outside the + /// current token stream. `look_ahead(0)` isn't allowed and will panic. #[inline] pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> { self.curr.look_ahead(n) @@ -955,7 +969,7 @@ impl TokenCursor { /// delimited sequence. Panics if we are not within a delimited sequence. #[inline] pub fn look_ahead_past_close_delim(&self) -> Option<&TokenTree> { - self.stack.last().unwrap().look_ahead(1) + self.stack.last().unwrap().next() } /// Clones the `TokenTree::Delimited` that we are currently within. Panics if we are not within @@ -991,12 +1005,12 @@ impl TokenCursor { /// This always-inlined version should only be used on hot code paths. #[inline(always)] - pub fn inlined_next(&mut self) -> (Token, Spacing) { + pub fn inlined_next_and_bump(&mut self) -> (Token, Spacing) { loop { // FIXME: we currently don't return `Delimiter::Invisible` open/close delims. To fix // #67062 we will need to, whereupon the `delim != Delimiter::Invisible` conditions // below can be removed. - if let Some(tree) = self.curr.curr() { + if let Some(tree) = self.curr.next() { match tree { &TokenTree::Token(token, spacing) => { debug_assert!(!token.kind.is_delim()); @@ -1006,6 +1020,7 @@ impl TokenCursor { } &TokenTree::Delimited(sp, spacing, delim, ref tts) => { let trees = TokenTreeCursor::new(tts.clone()); + self.curr.bump(); // move past the `Delimited` self.stack.push(mem::replace(&mut self.curr, trees)); if !delim.skip() { return (Token::new(delim.as_open_token_kind(), sp.open), spacing.open); @@ -1019,7 +1034,6 @@ impl TokenCursor { panic!("parent should be Delimited") }; self.curr = parent; - self.curr.bump(); // move past the `Delimited` if !delim.skip() { return (Token::new(delim.as_close_token_kind(), span.close), spacing.close); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7bbace5bdc6d2..80c1eeb4ef041 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -496,9 +496,7 @@ impl<'a> Parser<'a> { // Check the first token after the delimiter that closes the current // delimited sequence. (Panics if used in the outermost token stream, which - // has no delimiters.) It uses a clone of the relevant tree cursor to skip - // past the entire `TokenTree::Delimited` in a single step, avoiding the - // need for unbounded token lookahead. + // has no delimiters.) // // Primarily used when `self.token` matches `OpenInvisible(_))`, to look // ahead through the current metavar expansion. @@ -1125,7 +1123,7 @@ impl<'a> Parser<'a> { pub fn bump(&mut self) { // Note: destructuring here would give nicer code, but it was found in #96210 to be slower // than `.0`/`.1` access. - let mut next = self.token_cursor.inlined_next(); + let mut next = self.token_cursor.inlined_next_and_bump(); self.num_bump_calls += 1; // We got a token from the underlying cursor and no longer need to // worry about an unglued token. See `break_and_eat` for more details. @@ -1153,8 +1151,8 @@ impl<'a> Parser<'a> { // Typically around 98% of the `dist > 0` cases have `dist == 1`, so we // have a fast special case for that. if dist == 1 { - // `look_ahead(0)` returns the *next* token. - match self.token_cursor.look_ahead(0) { + // `look_ahead(1)` returns the next token. + match self.token_cursor.look_ahead(1) { Some(tree) => { // Indexing stayed within the current token tree. match tree { @@ -1180,13 +1178,13 @@ impl<'a> Parser<'a> { } } - // Just clone the token cursor and use `next`, skipping delimiters as + // Just clone the token cursor and use `next_and_bump`, skipping delimiters as // necessary. Slow but simple. let mut cursor = self.token_cursor.clone(); let mut i = 0; let mut token = Token::dummy(); while i < dist { - token = cursor.next().0; + token = cursor.next_and_bump().0; if let token::OpenInvisible(origin) | token::CloseInvisible(origin) = token.kind && origin.skip() { @@ -1198,14 +1196,13 @@ impl<'a> Parser<'a> { } /// Like `look_ahead`, but skips over token trees rather than tokens. Useful - /// when looking past possible metavariable pasting sites. + /// when looking past possible metavariable pasting sites. Panics if `dist` is zero. pub fn tree_look_ahead( &self, dist: usize, looker: impl FnOnce(&TokenTree) -> R, ) -> Option { - assert_ne!(dist, 0); - self.token_cursor.look_ahead(dist - 1).map(looker) + self.token_cursor.look_ahead(dist).map(looker) } /// Returns whether any of the given keywords are `dist` tokens ahead of the current one. @@ -1411,7 +1408,7 @@ impl<'a> Parser<'a> { debug_assert_eq!(self.token_cursor.depth(), target_depth); } else { loop { - // Advance one token at a time, so `TokenCursor::next()` + // Advance one token at a time, so `TokenCursor::next_and_bump()` // can capture these tokens if necessary. self.bump(); if self.token_cursor.depth() == target_depth { From 0c10bfa358038555506c6e708c80838fe39e0257 Mon Sep 17 00:00:00 2001 From: zakrad <49591476+zakrad@users.noreply.github.com> Date: Mon, 24 Aug 2026 11:53:07 +0330 Subject: [PATCH 5/5] Add codegen test for Vec::clear lowering to an unconditional store --- .../issues/vec-clear-no-branch-45459.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/codegen-llvm/issues/vec-clear-no-branch-45459.rs diff --git a/tests/codegen-llvm/issues/vec-clear-no-branch-45459.rs b/tests/codegen-llvm/issues/vec-clear-no-branch-45459.rs new file mode 100644 index 0000000000000..e6ff4684a8a41 --- /dev/null +++ b/tests/codegen-llvm/issues/vec-clear-no-branch-45459.rs @@ -0,0 +1,19 @@ +// Tests that clearing a `Vec` of a type without drop glue lowers to an +// unconditional store of the new length, without a comparison and branch +// guarding it. +// See . + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @clear_vec( +// CHECK-NOT: icmp +// CHECK-NOT: br {{.*}} +// CHECK: store i{{[0-9]+}} 0 +// CHECK-NOT: br {{.*}} +// CHECK: ret void +#[no_mangle] +pub fn clear_vec(v: &mut Vec) { + v.clear(); +}