From df983ce470e58584dcb9f3657d78ae74f77f1a90 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 9 Nov 2024 13:48:06 +0000 Subject: [PATCH 001/107] Merge commit '1fa693ca4462fc1f790693464cf765ad693616af' into sync_cg_clif-2024-11-09 --- ...-coretests-Disable-not-compiling-tests.patch | 2 +- ...027-coretests-128bit-atomic-operations.patch | 2 +- rust-toolchain | 2 +- scripts/test_bootstrap.sh | 17 +++++++++++++++++ src/abi/comments.rs | 2 +- src/abi/mod.rs | 8 ++++---- src/abi/pass_mode.rs | 5 +++-- src/abi/returning.rs | 2 +- src/base.rs | 2 +- src/common.rs | 16 ++++++++-------- src/debuginfo/mod.rs | 2 +- src/driver/aot.rs | 8 +++++++- src/inline_asm.rs | 2 +- src/intrinsics/simd.rs | 2 +- src/lib.rs | 2 ++ src/pointer.rs | 2 +- src/pretty_clif.rs | 2 +- 17 files changed, 52 insertions(+), 26 deletions(-) diff --git a/patches/0022-coretests-Disable-not-compiling-tests.patch b/patches/0022-coretests-Disable-not-compiling-tests.patch index 6ed22c5a18e5..1860810e7f3b 100644 --- a/patches/0022-coretests-Disable-not-compiling-tests.patch +++ b/patches/0022-coretests-Disable-not-compiling-tests.patch @@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644 @@ -1,3 +1,4 @@ +#![cfg(test)] // tidy-alphabetical-start + #![cfg_attr(bootstrap, feature(const_three_way_compare))] #![cfg_attr(bootstrap, feature(strict_provenance))] - #![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] -- 2.21.0 (Apple Git-122) diff --git a/patches/0027-coretests-128bit-atomic-operations.patch b/patches/0027-coretests-128bit-atomic-operations.patch index 50a42aea322c..59653c6e875f 100644 --- a/patches/0027-coretests-128bit-atomic-operations.patch +++ b/patches/0027-coretests-128bit-atomic-operations.patch @@ -15,7 +15,7 @@ index 1e336bf..35e6f54 100644 --- a/lib.rs +++ b/lib.rs @@ -2,7 +2,6 @@ - // tidy-alphabetical-start + #![cfg_attr(bootstrap, feature(const_three_way_compare))] #![cfg_attr(bootstrap, feature(strict_provenance))] #![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] diff --git a/rust-toolchain b/rust-toolchain index 2558b2b9f5dd..a223cd7dbb85 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-11-02" +channel = "nightly-2024-11-09" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/scripts/test_bootstrap.sh b/scripts/test_bootstrap.sh index 791d457993de..770f2b6df6c1 100755 --- a/scripts/test_bootstrap.sh +++ b/scripts/test_bootstrap.sh @@ -11,5 +11,22 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src} cp ../Cargo.* compiler/rustc_codegen_cranelift/ cp -r ../src compiler/rustc_codegen_cranelift/src +# FIXME(rust-lang/rust#132719) remove once it doesn't break without this patch +cat <) -> Compiler { + } + } + +- { ++ if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled { + // \`llvm-strip\` is used by rustc, which is actually just a symlink to \`llvm-objcopy\`, + // so copy and rename \`llvm-objcopy\`. + let src_exe = exe("llvm-objcopy", target_compiler.host); +EOF + ./x.py build --stage 1 library/std popd diff --git a/src/abi/comments.rs b/src/abi/comments.rs index daea789ee3eb..521a250ab82c 100644 --- a/src/abi/comments.rs +++ b/src/abi/comments.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; -use rustc_target::abi::call::PassMode; +use rustc_target::callconv::PassMode; use crate::prelude::*; diff --git a/src/abi/mod.rs b/src/abi/mod.rs index dfca5dcbec8e..f647ee36c482 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -10,6 +10,7 @@ use std::mem; use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; +use rustc_abi::ExternAbi; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -18,8 +19,7 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_target::abi::call::{Conv, FnAbi, PassMode}; -use rustc_target::spec::abi::Abi; +use rustc_target::callconv::{Conv, FnAbi, PassMode}; use self::pass_mode::*; pub(crate) use self::returning::codegen_return; @@ -443,7 +443,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args) }; - let is_cold = if fn_sig.abi() == Abi::RustCold { + let is_cold = if fn_sig.abi() == ExternAbi::RustCold { true } else { instance.is_some_and(|inst| { @@ -458,7 +458,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( } // Unpack arguments tuple for closures - let mut args = if fn_sig.abi() == Abi::RustCall { + let mut args = if fn_sig.abi() == ExternAbi::RustCall { let (self_arg, pack_arg) = match args { [pack_arg] => (None, codegen_call_argument_operand(fx, &pack_arg.node)), [self_arg, pack_arg] => ( diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index ad0a13dc7e57..7594a53fc758 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -1,8 +1,9 @@ //! Argument passing use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose}; -use rustc_target::abi::call::{ - ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind, +use rustc_abi::{Reg, RegKind}; +use rustc_target::callconv::{ + ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, }; use smallvec::{SmallVec, smallvec}; diff --git a/src/abi/returning.rs b/src/abi/returning.rs index a294c789b220..9e048c7badb8 100644 --- a/src/abi/returning.rs +++ b/src/abi/returning.rs @@ -1,6 +1,6 @@ //! Return value handling -use rustc_target::abi::call::{ArgAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, PassMode}; use smallvec::{SmallVec, smallvec}; use crate::prelude::*; diff --git a/src/base.rs b/src/base.rs index 10d5dce9b36b..da3818ca25e9 100644 --- a/src/base.rs +++ b/src/base.rs @@ -934,7 +934,7 @@ fn codegen_stmt<'tcx>( let dst = codegen_operand(fx, dst); let pointee = dst .layout() - .pointee_info_at(fx, rustc_target::abi::Size::ZERO) + .pointee_info_at(fx, rustc_abi::Size::ZERO) .expect("Expected pointer"); let dst = dst.load_scalar(fx); let src = codegen_operand(fx, src).load_scalar(fx); diff --git a/src/common.rs b/src/common.rs index 69a32cc3d43c..27e71b925618 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,13 +1,13 @@ use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; +use rustc_abi::{Float, Integer, Primitive}; use rustc_index::IndexVec; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, }; use rustc_span::source_map::Spanned; -use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{Float, Integer, Primitive}; +use rustc_target::callconv::FnAbi; use rustc_target::spec::{HasTargetSpec, Target}; use crate::constant::ConstantCx; @@ -162,8 +162,8 @@ pub(crate) fn codegen_icmp_imm( pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value { let mut flags = MemFlags::new(); flags.set_endianness(match fx.tcx.data_layout.endian { - rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big, - rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little, + rustc_abi::Endian::Big => cranelift_codegen::ir::Endianness::Big, + rustc_abi::Endian::Little => cranelift_codegen::ir::Endianness::Little, }); fx.bcx.ins().bitcast(dst_ty, flags, val) } @@ -333,8 +333,8 @@ impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> { } } -impl<'tcx> rustc_target::abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> { - fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout { +impl<'tcx> rustc_abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> { + fn data_layout(&self) -> &rustc_abi::TargetDataLayout { &self.tcx.data_layout } } @@ -491,8 +491,8 @@ impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> { } } -impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> { - fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout { +impl<'tcx> rustc_abi::HasDataLayout for RevealAllLayoutCx<'tcx> { + fn data_layout(&self) -> &rustc_abi::TargetDataLayout { &self.0.data_layout } } diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 78ae43b1c4d7..9025ea97b81d 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -20,7 +20,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; use rustc_session::Session; use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId}; -use rustc_target::abi::call::FnAbi; +use rustc_target::callconv::FnAbi; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; pub(crate) use self::types::TypeDebugContext; diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 419efa906008..8eab73ad5f9f 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -2,6 +2,7 @@ //! standalone executable. use std::fs::{self, File}; +use std::io::BufWriter; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::thread::JoinHandle; @@ -397,14 +398,19 @@ fn emit_module( } let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name)); - let mut file = match File::create(&tmp_file) { + let file = match File::create(&tmp_file) { Ok(file) => file, Err(err) => return Err(format!("error creating object file: {}", err)), }; + let mut file = BufWriter::new(file); if let Err(err) = object.write_stream(&mut file) { return Err(format!("error writing object file: {}", err)); } + let file = match file.into_inner() { + Ok(file) => file, + Err(err) => return Err(format!("error writing object file: {}", err)), + }; prof.artifact_size("object_file", &*name, file.metadata().unwrap().len()); diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 0fbd5a16830e..a3f816f70a94 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -464,7 +464,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| { let reg_size = reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap(); - let align = rustc_target::abi::Align::from_bytes(reg_size.bytes()).unwrap(); + let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap(); let offset = slot_size.align_to(align); *slot_size = offset + reg_size; offset diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index 36a35d42c3e2..f787b8a6fd94 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -1,7 +1,7 @@ //! Codegen SIMD intrinsics. use cranelift_codegen::ir::immediates::Offset32; -use rustc_target::abi::Endian; +use rustc_abi::Endian; use super::*; use crate::prelude::*; diff --git a/src/lib.rs b/src/lib.rs index aba0c28f6b88..19a1de53d1dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,6 +241,8 @@ impl CodegenBackend for CraneliftCodegenBackend { sess: &Session, outputs: &OutputFilenames, ) -> (CodegenResults, FxIndexMap) { + let _timer = sess.timer("finish_ongoing_codegen"); + ongoing_codegen.downcast::().unwrap().join( sess, outputs, diff --git a/src/pointer.rs b/src/pointer.rs index 11ac6b946783..2750caa216e6 100644 --- a/src/pointer.rs +++ b/src/pointer.rs @@ -2,7 +2,7 @@ //! operations. use cranelift_codegen::ir::immediates::Offset32; -use rustc_target::abi::Align; +use rustc_abi::Align; use crate::prelude::*; diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index 282763279dd8..cd254b04ed9e 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -64,7 +64,7 @@ use cranelift_codegen::ir::entities::AnyEntity; use cranelift_codegen::write::{FuncWriter, PlainWriter}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::config::{OutputFilenames, OutputType}; -use rustc_target::abi::call::FnAbi; +use rustc_target::callconv::FnAbi; use crate::prelude::*; From 995ccb684b4d7587217e40f326919bcd3eb05ff3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 9 Nov 2024 20:42:56 +0000 Subject: [PATCH 002/107] Add a default implementation for CodegenBackend::link As a side effect this should add raw-dylib support to cg_gcc as the default ArchiveBuilderBuilder that is used implements create_dll_import_lib. I haven't tested if the raw-dylib support actually works however. --- src/archive.rs | 12 ------------ src/lib.rs | 13 ------------- 2 files changed, 25 deletions(-) delete mode 100644 src/archive.rs diff --git a/src/archive.rs b/src/archive.rs deleted file mode 100644 index c7725e49c944..000000000000 --- a/src/archive.rs +++ /dev/null @@ -1,12 +0,0 @@ -use rustc_codegen_ssa::back::archive::{ - ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, -}; -use rustc_session::Session; - -pub(crate) struct ArArchiveBuilderBuilder; - -impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { - fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box { - Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) - } -} diff --git a/src/lib.rs b/src/lib.rs index 19a1de53d1dd..b506b1f57315 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,6 @@ use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_errors::ErrorGuaranteed; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; @@ -56,7 +55,6 @@ use crate::prelude::*; mod abi; mod allocator; mod analyze; -mod archive; mod base; mod cast; mod codegen_i128; @@ -249,17 +247,6 @@ impl CodegenBackend for CraneliftCodegenBackend { self.config.borrow().as_ref().unwrap(), ) } - - fn link( - &self, - sess: &Session, - codegen_results: CodegenResults, - outputs: &OutputFilenames, - ) -> Result<(), ErrorGuaranteed> { - use rustc_codegen_ssa::back::link::link_binary; - - link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs) - } } fn target_triple(sess: &Session) -> target_lexicon::Triple { From 35e138e7deb250c1d43852bbe82dcb28bb36cc86 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:43:40 +0000 Subject: [PATCH 003/107] Rustup to rustc 1.84.0-nightly (81eef2d36 2024-11-11) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index a223cd7dbb85..6aa7493c5a45 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-11-09" +channel = "nightly-2024-11-12" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 89c5aa9e857562235392b9b0ab35b8c4928d3675 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 12 Nov 2024 19:11:47 +0000 Subject: [PATCH 004/107] Fix rustc test suite --- scripts/rustc-clif.rs | 5 +++++ scripts/test_bootstrap.sh | 17 ----------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/scripts/rustc-clif.rs b/scripts/rustc-clif.rs index 92defd21cd9b..a27b9983bf18 100644 --- a/scripts/rustc-clif.rs +++ b/scripts/rustc-clif.rs @@ -33,6 +33,11 @@ fn main() { args.push(OsString::from("--sysroot")); args.push(OsString::from(sysroot.to_str().unwrap())); } + if passed_args.is_empty() { + // Don't pass any arguments when the user didn't pass any arguments + // either to ensure the help message is shown. + args.clear(); + } args.extend(passed_args); let rustc = if let Some(rustc) = option_env!("RUSTC") { diff --git a/scripts/test_bootstrap.sh b/scripts/test_bootstrap.sh index 770f2b6df6c1..791d457993de 100755 --- a/scripts/test_bootstrap.sh +++ b/scripts/test_bootstrap.sh @@ -11,22 +11,5 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src} cp ../Cargo.* compiler/rustc_codegen_cranelift/ cp -r ../src compiler/rustc_codegen_cranelift/src -# FIXME(rust-lang/rust#132719) remove once it doesn't break without this patch -cat <) -> Compiler { - } - } - -- { -+ if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled { - // \`llvm-strip\` is used by rustc, which is actually just a symlink to \`llvm-objcopy\`, - // so copy and rename \`llvm-objcopy\`. - let src_exe = exe("llvm-objcopy", target_compiler.host); -EOF - ./x.py build --stage 1 library/std popd From b98b6205003fecfca2d75ebc3a3e173d960a159c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 11 Nov 2024 16:36:54 +0100 Subject: [PATCH 005/107] Disable clif ir verifier by default It's been a while since it last found something outside of development, yet it is rather expensive. It is still enabled when debug assertions are enabled for cg_clif or when -Z verify-llvm-ir=yes is passed. --- src/base.rs | 11 +++++++++-- src/driver/aot.rs | 1 + src/driver/jit.rs | 15 +++++++++++++-- src/lib.rs | 3 ++- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/base.rs b/src/base.rs index da3818ca25e9..922c9c412659 100644 --- a/src/base.rs +++ b/src/base.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; +use crate::BackendConfig; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; use crate::inline_asm::codegen_naked_asm; @@ -30,6 +31,7 @@ pub(crate) struct CodegenedFunction { pub(crate) fn codegen_fn<'tcx>( tcx: TyCtxt<'tcx>, + backend_config: &BackendConfig, cx: &mut crate::CodegenCx, type_dbg: &mut TypeDebugContext<'tcx>, cached_func: Function, @@ -162,7 +164,7 @@ pub(crate) fn codegen_fn<'tcx>( } // Verify function - verify_func(tcx, &clif_comments, &func); + verify_func(tcx, backend_config, &clif_comments, &func); Some(CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }) } @@ -264,11 +266,16 @@ pub(crate) fn compile_fn( }); } -pub(crate) fn verify_func( +fn verify_func( tcx: TyCtxt<'_>, + backend_config: &BackendConfig, writer: &crate::pretty_clif::CommentWriter, func: &Function, ) { + if !tcx.sess.verify_llvm_ir() && !backend_config.enable_verifier { + return; + } + tcx.prof.generic_activity("verify clif ir").run(|| { let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder()); match cranelift_codegen::verify_function(&func, &flags) { diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 8eab73ad5f9f..2baa0f7f6023 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -516,6 +516,7 @@ fn module_codegen( MonoItem::Fn(inst) => { if let Some(codegened_function) = crate::base::codegen_fn( tcx, + &backend_config, &mut cx, &mut type_dbg, Function::new(), diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 0d62a13b4724..1ec4d6b55eb1 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -20,6 +20,7 @@ use crate::{BackendConfig, CodegenCx, CodegenMode}; struct JitState { jit_module: UnwindModule, + backend_config: BackendConfig, } thread_local! { @@ -115,6 +116,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { CodegenMode::Jit => { codegen_and_compile_fn( tcx, + &backend_config, &mut cx, &mut cached_context, &mut jit_module, @@ -169,7 +171,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { LAZY_JIT_STATE.with(|lazy_jit_state| { let mut lazy_jit_state = lazy_jit_state.borrow_mut(); assert!(lazy_jit_state.is_none()); - *lazy_jit_state = Some(JitState { jit_module }); + *lazy_jit_state = Some(JitState { jit_module, backend_config }); }); let f: extern "C" fn(c_int, *const *const c_char) -> c_int = @@ -205,6 +207,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { pub(crate) fn codegen_and_compile_fn<'tcx>( tcx: TyCtxt<'tcx>, + backend_config: &BackendConfig, cx: &mut crate::CodegenCx, cached_context: &mut Context, module: &mut dyn Module, @@ -221,6 +224,7 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( let cached_func = std::mem::replace(&mut cached_context.func, Function::new()); if let Some(codegened_func) = crate::base::codegen_fn( tcx, + &backend_config, cx, &mut TypeDebugContext::default(), cached_func, @@ -282,7 +286,14 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> false, Symbol::intern("dummy_cgu_name"), ); - codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance); + codegen_and_compile_fn( + tcx, + &lazy_jit_state.backend_config, + &mut cx, + &mut Context::new(), + jit_module, + instance, + ); assert!(cx.global_asm.is_empty()); jit_module.finalize_definitions(); diff --git a/src/lib.rs b/src/lib.rs index 19a1de53d1dd..e201a43bdc2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -278,7 +278,8 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc Date: Fri, 26 Jul 2024 15:51:46 +0200 Subject: [PATCH 006/107] Likely unlikely fix --- src/intrinsics/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 1e2e41b31227..b92885cc1a79 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -453,11 +453,6 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().trap(TrapCode::user(2).unwrap()); return Ok(()); } - sym::likely | sym::unlikely => { - intrinsic_args!(fx, args => (a); intrinsic); - - ret.write_cvalue(fx, a); - } sym::breakpoint => { intrinsic_args!(fx, args => (); intrinsic); @@ -1267,6 +1262,10 @@ fn codegen_regular_intrinsic_call<'tcx>( ); } + sym::cold_path => { + // This is a no-op. The intrinsic is just a hint to the optimizer. + } + // Unimplemented intrinsics must have a fallback body. The fallback body is obtained // by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`. _ => { From 22b0e3c0d4b59cadf83031ff91e4c08fa95ed2ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Nov 2024 08:41:28 +0100 Subject: [PATCH 007/107] remove pointless cold_path impl in interpreter --- src/intrinsics/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index b92885cc1a79..6cf1cff183d7 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -1264,6 +1264,7 @@ fn codegen_regular_intrinsic_call<'tcx>( sym::cold_path => { // This is a no-op. The intrinsic is just a hint to the optimizer. + // We still have an impl here to avoid it being turned into a call. } // Unimplemented intrinsics must have a fallback body. The fallback body is obtained From 19a8eb2a7f139feb647d96945925d8e55d8386cc Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 15 Nov 2024 13:53:31 +0100 Subject: [PATCH 008/107] use `TypingEnv` when no `infcx` is available the behavior of the type system not only depends on the current assumptions, but also the currentnphase of the compiler. This is mostly necessary as we need to decide whether and how to reveal opaque types. We track this via the `TypingMode`. --- src/abi/mod.rs | 2 +- src/base.rs | 10 +++++++--- src/common.rs | 18 +++++++++--------- src/constant.rs | 11 ++++++++--- src/debuginfo/mod.rs | 8 +++++--- src/inline_asm.rs | 10 +++++----- src/intrinsics/mod.rs | 9 ++++++--- src/lib.rs | 2 +- src/main_shim.rs | 6 +++--- src/unsize.rs | 3 ++- src/value_and_place.rs | 18 ++++++++---------- 11 files changed, 55 insertions(+), 42 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index f647ee36c482..7dd2139cf90c 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -376,7 +376,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() { let instance = ty::Instance::expect_resolve( fx.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, fn_args, source_info.span, diff --git a/src/base.rs b/src/base.rs index da3818ca25e9..1b91d251bfdd 100644 --- a/src/base.rs +++ b/src/base.rs @@ -666,7 +666,7 @@ fn codegen_stmt<'tcx>( let func_ref = fx.get_function_ref( Instance::resolve_for_fn_ptr( fx.tcx, - ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, ) @@ -841,14 +841,18 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } Rvalue::NullaryOp(ref null_op, ty) => { - assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all())); + assert!(lval.layout().ty.is_sized(fx.tcx, ty::ParamEnv::reveal_all())); let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), NullOp::OffsetOf(fields) => fx .tcx - .offset_of_subfield(ParamEnv::reveal_all(), layout, fields.iter()) + .offset_of_subfield( + ty::TypingEnv::fully_monomorphized(), + layout, + fields.iter(), + ) .bytes(), NullOp::UbChecks => { let val = fx.tcx.sess.ub_checks(); diff --git a/src/common.rs b/src/common.rs index 27e71b925618..add081bc795b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -103,11 +103,11 @@ fn clif_pair_type_from_ty<'tcx>( /// Is a pointer to this type a wide ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - if ty.is_sized(tcx, ParamEnv::reveal_all()) { + if ty.is_sized(tcx, ty::ParamEnv::reveal_all()) { return false; } - let tail = tcx.struct_tail_for_codegen(ty, ParamEnv::reveal_all()); + let tail = tcx.struct_tail_for_codegen(ty, ty::TypingEnv::fully_monomorphized()); match tail.kind() { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, @@ -339,9 +339,9 @@ impl<'tcx> rustc_abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> { } } -impl<'tcx> layout::HasParamEnv<'tcx> for FunctionCx<'_, '_, 'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - ParamEnv::reveal_all() +impl<'tcx> layout::HasTypingEnv<'tcx> for FunctionCx<'_, '_, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() } } @@ -358,7 +358,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { { self.instance.instantiate_mir_and_normalize_erasing_regions( self.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(value), ) } @@ -497,9 +497,9 @@ impl<'tcx> rustc_abi::HasDataLayout for RevealAllLayoutCx<'tcx> { } } -impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> { - fn param_env(&self) -> ParamEnv<'tcx> { - ParamEnv::reveal_all() +impl<'tcx> layout::HasTypingEnv<'tcx> for RevealAllLayoutCx<'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + ty::TypingEnv::fully_monomorphized() } } diff --git a/src/constant.rs b/src/constant.rs index ab78584332a0..5311547309c5 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -78,7 +78,7 @@ pub(crate) fn eval_mir_constant<'tcx>( let cv = fx.monomorphize(constant.const_); // This cannot fail because we checked all required_consts in advance. let val = cv - .eval(fx.tcx, ty::ParamEnv::reveal_all(), constant.span) + .eval(fx.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) .expect("erroneous constant missed by mono item collection"); (val, cv.ty()) } @@ -265,8 +265,13 @@ fn data_id_for_static( assert!(!definition); assert!(!tcx.is_mutable_static(def_id)); - let ty = instance.ty(tcx, ParamEnv::reveal_all()); - let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes(); + let ty = instance.ty(tcx, ty::TypingEnv::fully_monomorphized()); + let align = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) + .unwrap() + .align + .pref + .bytes(); let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak || import_linkage == rustc_middle::mir::mono::Linkage::WeakAny diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 9025ea97b81d..f3a8623e2161 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -210,7 +210,7 @@ impl DebugContext { type_names::push_generic_params( tcx, - tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), args), &mut name, ); @@ -275,8 +275,10 @@ impl DebugContext { let span = tcx.def_span(def_id); let (file_id, line, _column) = self.get_span_loc(tcx, span, span); - let static_type = Instance::mono(tcx, def_id).ty(tcx, ty::ParamEnv::reveal_all()); - let static_layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(static_type)).unwrap(); + let static_type = Instance::mono(tcx, def_id).ty(tcx, ty::TypingEnv::fully_monomorphized()); + let static_layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(static_type)) + .unwrap(); // FIXME use the actual type layout let type_id = self.debug_type(tcx, type_dbg, static_type); diff --git a/src/inline_asm.rs b/src/inline_asm.rs index a3f816f70a94..0df1a30fc0a4 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -92,7 +92,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( fx.tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, ) @@ -227,11 +227,11 @@ pub(crate) fn codegen_naked_asm<'tcx>( InlineAsmOperand::Const { ref value } => { let cv = instance.instantiate_mir_and_normalize_erasing_regions( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(value.const_), ); let const_value = cv - .eval(tcx, ty::ParamEnv::reveal_all(), value.span) + .eval(tcx, ty::TypingEnv::fully_monomorphized(), value.span) .expect("erroneous constant missed by mono item collection"); let value = rustc_codegen_ssa::common::asm_const_to_str( @@ -250,13 +250,13 @@ pub(crate) fn codegen_naked_asm<'tcx>( let const_ = instance.instantiate_mir_and_normalize_erasing_regions( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), ty::EarlyBinder::bind(value.const_), ); if let ty::FnDef(def_id, args) = *const_.ty().kind() { let instance = ty::Instance::resolve_for_fn_ptr( tcx, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), def_id, args, ) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index b92885cc1a79..1afe252ff04a 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -20,7 +20,7 @@ mod simd; use cranelift_codegen::ir::AtomicRmwOp; use rustc_middle::ty; use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement}; +use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{Symbol, sym}; @@ -682,7 +682,10 @@ fn codegen_regular_intrinsic_call<'tcx>( if let Some(requirement) = requirement { let do_panic = !fx .tcx - .check_validity_requirement((requirement, fx.param_env().and(ty))) + .check_validity_requirement(( + requirement, + ty::TypingEnv::fully_monomorphized().as_query_input(ty), + )) .expect("expect to have layout during codegen"); if do_panic { @@ -741,7 +744,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let const_val = fx .tcx - .const_eval_instance(ParamEnv::reveal_all(), instance, source_info.span) + .const_eval_instance(ty::ParamEnv::reveal_all(), instance, source_info.span) .unwrap(); let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty); ret.write_cvalue(fx, val); diff --git a/src/lib.rs b/src/lib.rs index b506b1f57315..e6f6ae305816 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,7 @@ mod prelude { pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy, + self, FloatTy, Instance, InstanceKind, IntTy, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; diff --git a/src/main_shim.rs b/src/main_shim.rs index df92bc58bf53..2ee4ff5cec72 100644 --- a/src/main_shim.rs +++ b/src/main_shim.rs @@ -49,7 +49,7 @@ pub(crate) fn maybe_create_entry_wrapper( // regions must appear in the argument // listing. let main_ret_ty = tcx.normalize_erasing_regions( - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), main_ret_ty.no_bound_vars().unwrap(), ); @@ -113,7 +113,7 @@ pub(crate) fn maybe_create_entry_wrapper( .unwrap(); let report = Instance::expect_resolve( tcx, - ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), report.def_id, tcx.mk_args(&[GenericArg::from(main_ret_ty)]), DUMMY_SP, @@ -139,7 +139,7 @@ pub(crate) fn maybe_create_entry_wrapper( let start_def_id = tcx.require_lang_item(LangItem::Start, None); let start_instance = Instance::expect_resolve( tcx, - ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), start_def_id, tcx.mk_args(&[main_ret_ty.into()]), DUMMY_SP, diff --git a/src/unsize.rs b/src/unsize.rs index 336934354e11..2843e5bbdfb2 100644 --- a/src/unsize.rs +++ b/src/unsize.rs @@ -3,6 +3,7 @@ //! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize` use rustc_codegen_ssa::base::validate_trivial_unsize; +use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use crate::base::codegen_panic_nounwind; @@ -23,7 +24,7 @@ pub(crate) fn unsized_info<'tcx>( old_info: Option, ) -> Value { let (source, target) = - fx.tcx.struct_lockstep_tails_for_codegen(source, target, ParamEnv::reveal_all()); + fx.tcx.struct_lockstep_tails_for_codegen(source, target, fx.typing_env()); match (&source.kind(), &target.kind()) { (&ty::Array(_, len), &ty::Slice(_)) => fx.bcx.ins().iconst( fx.pointer_type, diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 900d7e69714e..6676e684ca02 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -4,6 +4,7 @@ use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::immediates::Offset32; use cranelift_frontend::Variable; use rustc_middle::ty::FnSig; +use rustc_middle::ty::layout::HasTypingEnv; use crate::prelude::*; @@ -884,19 +885,17 @@ pub(crate) fn assert_assignable<'tcx>( assert_assignable(fx, *a, *b, limit - 1); } (ty::FnPtr(..), ty::FnPtr(..)) => { - let from_sig = fx.tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - from_ty.fn_sig(fx.tcx), - ); + let from_sig = fx + .tcx + .normalize_erasing_late_bound_regions(fx.typing_env(), from_ty.fn_sig(fx.tcx)); let FnSig { inputs_and_output: types_from, c_variadic: c_variadic_from, safety: unsafety_from, abi: abi_from, } = from_sig; - let to_sig = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_ty.fn_sig(fx.tcx)); + let to_sig = + fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to_ty.fn_sig(fx.tcx)); let FnSig { inputs_and_output: types_to, c_variadic: c_variadic_to, @@ -932,9 +931,8 @@ pub(crate) fn assert_assignable<'tcx>( (&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => { // FIXME(dyn-star): Do the right thing with DynKinds for (from, to) in from_traits.iter().zip(to_traits) { - let from = - fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); - let to = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); + let from = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), from); + let to = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to); assert_eq!( from, to, "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", From c5c3709d8061ace23cd529426b2aed4c6c5ba4e4 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 19 Nov 2024 20:00:58 +0800 Subject: [PATCH 009/107] Explicitly disable llvm tools for cranelift --- scripts/setup_rust_fork.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 2f13b0b9cb83..5b3f2a912072 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -38,6 +38,11 @@ local-rebuild = true codegen-backends = ["cranelift"] deny-warnings = false verbose-tests = false +# The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is +# disabled bootstrap will crash trying to copy llvm tools for the bootstrap +# compiler. +llvm_tools = false + EOF popd From a4acd22dbbce131992994e16c65f436169dce0f6 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 16:13:55 +0100 Subject: [PATCH 010/107] move `fn is_item_raw` to `TypingEnv` --- src/base.rs | 4 ++-- src/common.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/base.rs b/src/base.rs index 1b91d251bfdd..77ee97739405 100644 --- a/src/base.rs +++ b/src/base.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::InlineAsmMacro; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; use rustc_middle::ty::print::with_no_trimmed_paths; use crate::constant::ConstantCx; @@ -841,7 +841,7 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } Rvalue::NullaryOp(ref null_op, ty) => { - assert!(lval.layout().ty.is_sized(fx.tcx, ty::ParamEnv::reveal_all())); + assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env())); let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), diff --git a/src/common.rs b/src/common.rs index add081bc795b..c663fa329652 100644 --- a/src/common.rs +++ b/src/common.rs @@ -103,7 +103,7 @@ fn clif_pair_type_from_ty<'tcx>( /// Is a pointer to this type a wide ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - if ty.is_sized(tcx, ty::ParamEnv::reveal_all()) { + if ty.is_sized(tcx, ty::TypingEnv::fully_monomorphized()) { return false; } From bf45e9f7f39a2698ea9c494e2f73d8736c85f19c Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 20:10:42 +0100 Subject: [PATCH 011/107] `InterpCx` store `TypingEnv` instead of a `ParamEnv` --- src/intrinsics/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index c663f6fc2d32..3318c0797ec3 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -744,7 +744,11 @@ fn codegen_regular_intrinsic_call<'tcx>( let const_val = fx .tcx - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, source_info.span) + .const_eval_instance( + ty::TypingEnv::fully_monomorphized(), + instance, + source_info.span, + ) .unwrap(); let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty); ret.write_cvalue(fx, val); From 329cd79cb4849e00b6dd64a484fff070ec9e5a4a Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 2 Sep 2024 01:13:07 +0800 Subject: [PATCH 012/107] reduce false positives of tail-expr-drop-order from consumed values take 2 open up coroutines tweak the wordings the lint works up until 2021 We were missing one case, for ADTs, which was causing `Result` to yield incorrect results. only include field spans with significant types deduplicate and eliminate field spans switch to emit spans to impl Drops Co-authored-by: Niko Matsakis collect drops instead of taking liveness diff apply some suggestions and add explantory notes small fix on the cache let the query recurse through coroutine new suggestion format with extracted variable name fine-tune the drop span and messages bugfix on runtime borrows tweak message wording filter out ecosystem types earlier apply suggestions clippy check lint level at session level further restrict applicability of the lint translate bid into nop for stable mir detect cycle in type structure --- src/base.rs | 1 + src/constant.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/base.rs b/src/base.rs index 77ee97739405..70b7d92ce15b 100644 --- a/src/base.rs +++ b/src/base.rs @@ -924,6 +924,7 @@ fn codegen_stmt<'tcx>( | StatementKind::FakeRead(..) | StatementKind::Retag { .. } | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::AscribeUserType(..) => {} StatementKind::Coverage { .. } => unreachable!(), diff --git a/src/constant.rs b/src/constant.rs index 5311547309c5..abe6085b04f4 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -583,6 +583,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( | StatementKind::PlaceMention(..) | StatementKind::Coverage(_) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } From a960aac0ba604136882cef9a01b00822b20f46de Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 21 Nov 2024 10:31:35 +0000 Subject: [PATCH 013/107] Rustup to rustc 1.84.0-nightly (3fee0f12e 2024-11-20) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 6aa7493c5a45..c9717cacd1af 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-11-12" +channel = "nightly-2024-11-21" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From 9d1de630fcbe8d78c4583589bda4670ba7c09dab Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:11:49 +0000 Subject: [PATCH 014/107] Fix rustc test suite --- scripts/setup_rust_fork.sh | 3 ++- scripts/test_rustc_tests.sh | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index 5b3f2a912072..54f6baff4fec 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -35,13 +35,14 @@ full-bootstrap = true local-rebuild = true [rust] +download-rustc = false codegen-backends = ["cranelift"] deny-warnings = false verbose-tests = false # The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is # disabled bootstrap will crash trying to copy llvm tools for the bootstrap # compiler. -llvm_tools = false +llvm-tools = false EOF popd diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index a820da286f5c..1b4321b8e240 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -57,6 +57,7 @@ rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes rm -r tests/run-make/embed-source-dwarf # embedding sources in debuginfo +rm tests/ui/simd-abi-checks.rs # vector types >128bits not yet supported # requires LTO rm -r tests/run-make/cdylib From ebacaee16b35fa1a99a8ad5558e01532ff8c3419 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 7 Nov 2024 12:04:08 +0000 Subject: [PATCH 015/107] Update to Cranelift 0.114 --- Cargo.lock | 77 ++++++++++++++++++++++++++++++++++-------------------- Cargo.toml | 12 ++++----- src/lib.rs | 10 +++++++ 3 files changed, 65 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4f77472802c..d81e7214961f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,24 +46,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5e7afe85cadb55c4c1176268a2ac046fdff8dfaeca39e18581b9dc319ca9e" +checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ab25ef3be935a80680e393183e1f94ef507e93a24a8369494d2c6818aedb3e3" +checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156" [[package]] name = "cranelift-codegen" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900a19b84545924f1851cbfe386962edfc4ecbc3366a254825cf1ecbcda8ba08" +checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b" dependencies = [ "bumpalo", "cranelift-bforest", @@ -78,48 +78,49 @@ dependencies = [ "log", "regalloc2", "rustc-hash", + "serde", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c73b2395ffe9e7b4fdf7e2ebc052e7e27af13f68a964985346be4da477a5fc" +checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9ed0854e96a4ff0879bff39d078de8dea7f002721c9494c1fdb4e1baa86ccc" +checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895" [[package]] name = "cranelift-control" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4aca921dd422e781409de0129c255768fec5dec1dae83239b497fb9138abb89" +checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d770e6605eccee15b49decdd82cd26f2b6404767802471459ea49c57379a98" +checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29268711cb889cb39215b10faf88b9087d4c9e1d2633581e4f722a2bf4bb4ef9" +checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e" dependencies = [ "cranelift-codegen", "log", @@ -129,15 +130,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc65156f010aed1985767ad1bff0eb8d186743b7b03e23d0c17604a253e3f356" +checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8" [[package]] name = "cranelift-jit" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ba6b46367a4f466cfb1abe32793fa1a0f96d862251491b01a44726b8ed9445" +checksum = "62699329d4ced20fe281fbaef45e11b473b7ab310491b4bdebcd8b818a8ef7fe" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,9 +156,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "007607022a4883ebdffc46c0925e2e10babf2a565ae78518034ade722aa825d2" +checksum = "2f20b0b51ba962dac30fc7e812b86e4390d908acd4f59bcc8ac7610a8f3e0977" dependencies = [ "anyhow", "cranelift-codegen", @@ -166,9 +167,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bf9b361eaf5a7627647270fabf1dc910d993edbeaf272a652c107861ebe9c2" +checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f" dependencies = [ "cranelift-codegen", "libc", @@ -177,9 +178,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca5c38fa00c0cd943035391bdcc84ed00748f17c66c682e410f5a62f234d44" +checksum = "ee231640a7ecceedd0f1f2782d9288db6a6908cc70675ed9427e3bf0ea6daacd" dependencies = [ "anyhow", "cranelift-codegen", @@ -363,6 +364,26 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "slice-group-by" version = "0.3.1" @@ -412,9 +433,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e458e6a1a010a53f86ac8d75837c0c6b2ce3e54b7503b2f1dc5629a4a541f5a" +checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad" dependencies = [ "anyhow", "cfg-if", diff --git a/Cargo.toml b/Cargo.toml index f352ef72cb05..b2fed3c490ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.113.0", default-features = false, features = ["std", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.113.0" } -cranelift-module = { version = "0.113.0" } -cranelift-native = { version = "0.113.0" } -cranelift-jit = { version = "0.113.0", optional = true } -cranelift-object = { version = "0.113.0" } +cranelift-codegen = { version = "0.114.0", default-features = false, features = ["std", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.114.0" } +cranelift-module = { version = "0.114.0" } +cranelift-native = { version = "0.114.0" } +cranelift-jit = { version = "0.114.0", optional = true } +cranelift-object = { version = "0.114.0" } target-lexicon = "0.12.0" gimli = { version = "0.31", default-features = false, features = ["write"] } object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } diff --git a/src/lib.rs b/src/lib.rs index 5618101ede29..15163fa715f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -301,6 +301,16 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc Date: Thu, 21 Nov 2024 12:38:14 +0000 Subject: [PATCH 016/107] Remove enable_verifier from BackendConfig --- src/base.rs | 14 ++++---------- src/config.rs | 10 ---------- src/driver/aot.rs | 23 ++++++----------------- src/driver/jit.rs | 30 ++++++------------------------ src/lib.rs | 16 +++++++++++++--- 5 files changed, 29 insertions(+), 64 deletions(-) diff --git a/src/base.rs b/src/base.rs index 3c1c1ae66507..043e7c878fb5 100644 --- a/src/base.rs +++ b/src/base.rs @@ -14,9 +14,9 @@ use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; use rustc_middle::ty::print::with_no_trimmed_paths; -use crate::BackendConfig; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; +use crate::enable_verifier; use crate::inline_asm::codegen_naked_asm; use crate::prelude::*; use crate::pretty_clif::CommentWriter; @@ -31,7 +31,6 @@ pub(crate) struct CodegenedFunction { pub(crate) fn codegen_fn<'tcx>( tcx: TyCtxt<'tcx>, - backend_config: &BackendConfig, cx: &mut crate::CodegenCx, type_dbg: &mut TypeDebugContext<'tcx>, cached_func: Function, @@ -164,7 +163,7 @@ pub(crate) fn codegen_fn<'tcx>( } // Verify function - verify_func(tcx, backend_config, &clif_comments, &func); + verify_func(tcx, &clif_comments, &func); Some(CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }) } @@ -266,13 +265,8 @@ pub(crate) fn compile_fn( }); } -fn verify_func( - tcx: TyCtxt<'_>, - backend_config: &BackendConfig, - writer: &crate::pretty_clif::CommentWriter, - func: &Function, -) { - if !tcx.sess.verify_llvm_ir() && !backend_config.enable_verifier { +fn verify_func(tcx: TyCtxt<'_>, writer: &crate::pretty_clif::CommentWriter, func: &Function) { + if !enable_verifier(tcx.sess) { return; } diff --git a/src/config.rs b/src/config.rs index 12bce680d9e1..885d7105da3d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -42,14 +42,6 @@ pub struct BackendConfig { /// Defaults to the value of `CG_CLIF_JIT_ARGS`. pub jit_args: Vec, - /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run - /// once before passing the clif ir to Cranelift for compilation. - /// - /// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is - /// compiled with debug assertions enabled or false otherwise. Can be set using - /// `-Cllvm-args=enable_verifier=...`. - pub enable_verifier: bool, - /// Don't cache object files in the incremental cache. Useful during development of cg_clif /// to make it possible to use incremental mode for all analyses performed by rustc without /// caching object files when their content should have been changed by a change to cg_clif. @@ -72,7 +64,6 @@ impl Default for BackendConfig { } } }, - enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"), disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"), } } @@ -95,7 +86,6 @@ impl BackendConfig { if let Some((name, value)) = opt.split_once('=') { match name { "mode" => config.codegen_mode = value.parse()?, - "enable_verifier" => config.enable_verifier = parse_bool(name, value)?, "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?, _ => return Err(format!("Unknown option `{}`", name)), } diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 2baa0f7f6023..8d1f88ba062e 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -322,12 +322,8 @@ fn produce_final_output_artifacts( // These are used in linking steps and will be cleaned up afterward. } -fn make_module( - sess: &Session, - backend_config: &BackendConfig, - name: String, -) -> UnwindModule { - let isa = crate::build_isa(sess, backend_config); +fn make_module(sess: &Session, name: String) -> UnwindModule { + let isa = crate::build_isa(sess); let mut builder = ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); @@ -488,8 +484,7 @@ fn reuse_workproduct_for_cgu( fn module_codegen( tcx: TyCtxt<'_>, - (backend_config, global_asm_config, cgu_name, token): ( - BackendConfig, + (global_asm_config, cgu_name, token): ( Arc, rustc_span::Symbol, ConcurrencyLimiterToken, @@ -500,7 +495,7 @@ fn module_codegen( let cgu = tcx.codegen_unit(cgu_name); let mono_items = cgu.items_in_deterministic_order(tcx); - let mut module = make_module(tcx.sess, &backend_config, cgu_name.as_str().to_string()); + let mut module = make_module(tcx.sess, cgu_name.as_str().to_string()); let mut cx = crate::CodegenCx::new( tcx, @@ -516,7 +511,6 @@ fn module_codegen( MonoItem::Fn(inst) => { if let Some(codegened_function) = crate::base::codegen_fn( tcx, - &backend_config, &mut cx, &mut type_dbg, Function::new(), @@ -648,12 +642,7 @@ pub(crate) fn run_aot( .with_task( dep_node, tcx, - ( - backend_config.clone(), - global_asm_config.clone(), - cgu.name(), - concurrency_limiter.acquire(tcx.dcx()), - ), + (global_asm_config.clone(), cgu.name(), concurrency_limiter.acquire(tcx.dcx())), module_codegen, Some(rustc_middle::dep_graph::hash_result), ) @@ -667,7 +656,7 @@ pub(crate) fn run_aot( modules }); - let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string()); + let mut allocator_module = make_module(tcx.sess, "allocator_shim".to_string()); let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module); let allocator_module = if created_alloc_shim { diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 1ec4d6b55eb1..ebbbc2697d10 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -20,7 +20,6 @@ use crate::{BackendConfig, CodegenCx, CodegenMode}; struct JitState { jit_module: UnwindModule, - backend_config: BackendConfig, } thread_local! { @@ -60,14 +59,10 @@ impl UnsafeMessage { } } -fn create_jit_module( - tcx: TyCtxt<'_>, - backend_config: &BackendConfig, - hotswap: bool, -) -> (UnwindModule, CodegenCx) { +fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule, CodegenCx) { let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string()); - let isa = crate::build_isa(tcx.sess, backend_config); + let isa = crate::build_isa(tcx.sess); let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); jit_builder.hotswap(hotswap); crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); @@ -91,11 +86,8 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { tcx.dcx().fatal("can't jit non-executable crate"); } - let (mut jit_module, mut cx) = create_jit_module( - tcx, - &backend_config, - matches!(backend_config.codegen_mode, CodegenMode::JitLazy), - ); + let (mut jit_module, mut cx) = + create_jit_module(tcx, matches!(backend_config.codegen_mode, CodegenMode::JitLazy)); let mut cached_context = Context::new(); let (_, cgus) = tcx.collect_and_partition_mono_items(()); @@ -116,7 +108,6 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { CodegenMode::Jit => { codegen_and_compile_fn( tcx, - &backend_config, &mut cx, &mut cached_context, &mut jit_module, @@ -171,7 +162,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { LAZY_JIT_STATE.with(|lazy_jit_state| { let mut lazy_jit_state = lazy_jit_state.borrow_mut(); assert!(lazy_jit_state.is_none()); - *lazy_jit_state = Some(JitState { jit_module, backend_config }); + *lazy_jit_state = Some(JitState { jit_module }); }); let f: extern "C" fn(c_int, *const *const c_char) -> c_int = @@ -207,7 +198,6 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { pub(crate) fn codegen_and_compile_fn<'tcx>( tcx: TyCtxt<'tcx>, - backend_config: &BackendConfig, cx: &mut crate::CodegenCx, cached_context: &mut Context, module: &mut dyn Module, @@ -224,7 +214,6 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( let cached_func = std::mem::replace(&mut cached_context.func, Function::new()); if let Some(codegened_func) = crate::base::codegen_fn( tcx, - &backend_config, cx, &mut TypeDebugContext::default(), cached_func, @@ -286,14 +275,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> false, Symbol::intern("dummy_cgu_name"), ); - codegen_and_compile_fn( - tcx, - &lazy_jit_state.backend_config, - &mut cx, - &mut Context::new(), - jit_module, - instance, - ); + codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance); assert!(cx.global_asm.is_empty()); jit_module.finalize_definitions(); diff --git a/src/lib.rs b/src/lib.rs index 15163fa715f1..f418224efe97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ extern crate rustc_driver; use std::any::Any; use std::cell::{Cell, RefCell}; +use std::env; use std::sync::Arc; use cranelift_codegen::isa::TargetIsa; @@ -249,6 +250,16 @@ impl CodegenBackend for CraneliftCodegenBackend { } } +/// Determine if the Cranelift ir verifier should run. +/// +/// Returns true when `-Zverify-llvm-ir` is passed, the `CG_CLIF_ENABLE_VERIFIER` env var is set to +/// 1 or when cg_clif is compiled with debug assertions enabled or false otherwise. +fn enable_verifier(sess: &Session) -> bool { + sess.verify_llvm_ir() + || cfg!(debug_assertions) + || env::var("CG_CLIF_ENABLE_VERIFIER").as_deref() == Ok("1") +} + fn target_triple(sess: &Session) -> target_lexicon::Triple { // FIXME(madsmtm): Use `sess.target.llvm_target` once target-lexicon supports unversioned macOS. // See @@ -258,15 +269,14 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple { } } -fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc { +fn build_isa(sess: &Session) -> Arc { use target_lexicon::BinaryFormat; let target_triple = crate::target_triple(sess); let mut flags_builder = settings::builder(); flags_builder.enable("is_pic").unwrap(); - let enable_verifier = - if sess.verify_llvm_ir() || backend_config.enable_verifier { "true" } else { "false" }; + let enable_verifier = if enable_verifier(sess) { "true" } else { "false" }; flags_builder.set("enable_verifier", enable_verifier).unwrap(); flags_builder.set("regalloc_checker", enable_verifier).unwrap(); From bd209edb7df38bffcea8ab3f3b417ae1ff2d83b1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:44:54 +0000 Subject: [PATCH 017/107] Remove disable_incr_cache from BackendConfig --- src/config.rs | 19 ------------------- src/driver/aot.rs | 14 +++++++++----- src/lib.rs | 8 ++------ 3 files changed, 11 insertions(+), 30 deletions(-) diff --git a/src/config.rs b/src/config.rs index 885d7105da3d..cccad2d4749d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,10 +1,5 @@ -use std::env; use std::str::FromStr; -fn bool_env_var(key: &str) -> bool { - env::var(key).as_deref() == Ok("1") -} - /// The mode to use for compilation. #[derive(Copy, Clone, Debug)] pub enum CodegenMode { @@ -41,14 +36,6 @@ pub struct BackendConfig { /// /// Defaults to the value of `CG_CLIF_JIT_ARGS`. pub jit_args: Vec, - - /// Don't cache object files in the incremental cache. Useful during development of cg_clif - /// to make it possible to use incremental mode for all analyses performed by rustc without - /// caching object files when their content should have been changed by a change to cg_clif. - /// - /// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false - /// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`. - pub disable_incr_cache: bool, } impl Default for BackendConfig { @@ -64,7 +51,6 @@ impl Default for BackendConfig { } } }, - disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"), } } } @@ -72,10 +58,6 @@ impl Default for BackendConfig { impl BackendConfig { /// Parse the configuration passed in using `-Cllvm-args`. pub fn from_opts(opts: &[String]) -> Result { - fn parse_bool(name: &str, value: &str) -> Result { - value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name)) - } - let mut config = BackendConfig::default(); for opt in opts { if opt.starts_with("-import-instr-limit") { @@ -86,7 +68,6 @@ impl BackendConfig { if let Some((name, value)) = opt.split_once('=') { match name { "mode" => config.codegen_mode = value.parse()?, - "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?, _ => return Err(format!("Unknown option `{}`", name)), } } else { diff --git a/src/driver/aot.rs b/src/driver/aot.rs index 8d1f88ba062e..cb5b66611e91 100644 --- a/src/driver/aot.rs +++ b/src/driver/aot.rs @@ -1,6 +1,7 @@ //! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a //! standalone executable. +use std::env; use std::fs::{self, File}; use std::io::BufWriter; use std::path::{Path, PathBuf}; @@ -25,13 +26,16 @@ use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; use rustc_session::Session; use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; -use crate::BackendConfig; use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; use crate::debuginfo::TypeDebugContext; use crate::global_asm::GlobalAsmConfig; use crate::prelude::*; use crate::unwind_module::UnwindModule; +fn disable_incr_cache() -> bool { + env::var("CG_CLIF_DISABLE_INCR_CACHE").as_deref() == Ok("1") +} + struct ModuleCodegenResult { module_regular: CompiledModule, module_global_asm: Option, @@ -63,10 +67,10 @@ impl OngoingCodegen { self, sess: &Session, outputs: &OutputFilenames, - backend_config: &BackendConfig, ) -> (CodegenResults, FxIndexMap) { let mut work_products = FxIndexMap::default(); let mut modules = vec![]; + let disable_incr_cache = disable_incr_cache(); for module_codegen in self.modules { let module_codegen_result = match module_codegen { @@ -87,7 +91,7 @@ impl OngoingCodegen { if let Some((work_product_id, work_product)) = existing_work_product { work_products.insert(work_product_id, work_product); } else { - let work_product = if backend_config.disable_incr_cache { + let work_product = if disable_incr_cache { None } else if let Some(module_global_asm) = &module_global_asm { rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir( @@ -580,7 +584,6 @@ fn module_codegen( pub(crate) fn run_aot( tcx: TyCtxt<'_>, - backend_config: BackendConfig, metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box { @@ -626,9 +629,10 @@ pub(crate) fn run_aot( let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx)); + let disable_incr_cache = disable_incr_cache(); let (todo_cgus, done_cgus) = cgus.into_iter().enumerate().partition::, _>(|&(i, _)| match cgu_reuse[i] { - _ if backend_config.disable_incr_cache => true, + _ if disable_incr_cache => true, CguReuse::No => true, CguReuse::PreLto | CguReuse::PostLto => false, }); diff --git a/src/lib.rs b/src/lib.rs index f418224efe97..f00a568cfed5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -223,7 +223,7 @@ impl CodegenBackend for CraneliftCodegenBackend { tcx.dcx().abort_if_errors(); let config = self.config.borrow().clone().unwrap(); match config.codegen_mode { - CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module), + CodegenMode::Aot => driver::aot::run_aot(tcx, metadata, need_metadata_module), CodegenMode::Jit | CodegenMode::JitLazy => { #[cfg(feature = "jit")] driver::jit::run_jit(tcx, config); @@ -242,11 +242,7 @@ impl CodegenBackend for CraneliftCodegenBackend { ) -> (CodegenResults, FxIndexMap) { let _timer = sess.timer("finish_ongoing_codegen"); - ongoing_codegen.downcast::().unwrap().join( - sess, - outputs, - self.config.borrow().as_ref().unwrap(), - ) + ongoing_codegen.downcast::().unwrap().join(sess, outputs) } } From 5d5cd2a22b2ac93dc53a982285fbe31eed341fc8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:48:12 +0000 Subject: [PATCH 018/107] Avoid RefCell in CodegenBackend --- src/lib.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f00a568cfed5..66c154ff6543 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ extern crate rustc_target; extern crate rustc_driver; use std::any::Any; -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::env; use std::sync::Arc; @@ -155,7 +155,7 @@ impl CodegenCx { } pub struct CraneliftCodegenBackend { - pub config: RefCell>, + pub config: Option, } impl CodegenBackend for CraneliftCodegenBackend { @@ -177,13 +177,6 @@ impl CodegenBackend for CraneliftCodegenBackend { sess.dcx() .fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift"); } - - let mut config = self.config.borrow_mut(); - if config.is_none() { - let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args) - .unwrap_or_else(|err| sess.dcx().fatal(err)); - *config = Some(new_config); - } } fn target_features(&self, sess: &Session, _allow_unstable: bool) -> Vec { @@ -221,7 +214,10 @@ impl CodegenBackend for CraneliftCodegenBackend { need_metadata_module: bool, ) -> Box { tcx.dcx().abort_if_errors(); - let config = self.config.borrow().clone().unwrap(); + let config = self.config.clone().unwrap_or_else(|| { + BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) + .unwrap_or_else(|err| tcx.sess.dcx().fatal(err)) + }); match config.codegen_mode { CodegenMode::Aot => driver::aot::run_aot(tcx, metadata, need_metadata_module), CodegenMode::Jit | CodegenMode::JitLazy => { @@ -369,5 +365,5 @@ fn build_isa(sess: &Session) -> Arc { /// This is the entrypoint for a hot plugged rustc_codegen_cranelift #[no_mangle] pub fn __rustc_codegen_backend() -> Box { - Box::new(CraneliftCodegenBackend { config: RefCell::new(None) }) + Box::new(CraneliftCodegenBackend { config: None }) } From 56a64baa03aac9d25a598751636967ff41eeff3a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:49:45 +0000 Subject: [PATCH 019/107] Avoid Cell in CodegenCx --- src/inline_asm.rs | 15 ++++++--------- src/lib.rs | 5 ++--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 0df1a30fc0a4..302e379da5ec 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -102,13 +102,12 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( // Pass a wrapper rather than the function itself as the function itself may not // be exported from the main codegen unit and may thus be unreachable from the // object file created by an external assembler. - let inline_asm_index = fx.cx.inline_asm_index.get(); - fx.cx.inline_asm_index.set(inline_asm_index + 1); let wrapper_name = format!( "__inline_asm_{}_wrapper_n{}", fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - inline_asm_index + fx.cx.inline_asm_index ); + fx.cx.inline_asm_index += 1; let sig = get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance); create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name); @@ -167,13 +166,12 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>( asm_gen.allocate_registers(); asm_gen.allocate_stack_slots(); - let inline_asm_index = fx.cx.inline_asm_index.get(); - fx.cx.inline_asm_index.set(inline_asm_index + 1); let asm_name = format!( "__inline_asm_{}_n{}", fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - inline_asm_index + fx.cx.inline_asm_index ); + fx.cx.inline_asm_index += 1; let generated_asm = asm_gen.generate_asm_wrapper(&asm_name); fx.cx.global_asm.push_str(&generated_asm); @@ -266,13 +264,12 @@ pub(crate) fn codegen_naked_asm<'tcx>( // Pass a wrapper rather than the function itself as the function itself may not // be exported from the main codegen unit and may thus be unreachable from the // object file created by an external assembler. - let inline_asm_index = cx.inline_asm_index.get(); - cx.inline_asm_index.set(inline_asm_index + 1); let wrapper_name = format!( "__inline_asm_{}_wrapper_n{}", cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - inline_asm_index + cx.inline_asm_index ); + cx.inline_asm_index += 1; let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance); create_wrapper_function(module, sig, &wrapper_name, symbol.name); diff --git a/src/lib.rs b/src/lib.rs index 66c154ff6543..ddd5556b04e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,6 @@ extern crate rustc_target; extern crate rustc_driver; use std::any::Any; -use std::cell::Cell; use std::env; use std::sync::Arc; @@ -128,7 +127,7 @@ struct CodegenCx { output_filenames: Arc, should_write_ir: bool, global_asm: String, - inline_asm_index: Cell, + inline_asm_index: usize, debug_context: Option, cgu_name: Symbol, } @@ -147,7 +146,7 @@ impl CodegenCx { output_filenames: tcx.output_filenames(()).clone(), should_write_ir: crate::pretty_clif::should_write_ir(tcx), global_asm: String::new(), - inline_asm_index: Cell::new(0), + inline_asm_index: 0, debug_context, cgu_name, } From 5644a0879ce9aba31ea67b1636b69947a16868de Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:00:00 +0000 Subject: [PATCH 020/107] Stop passing BackendConfig to run_jit --- src/driver/jit.rs | 10 +++++----- src/lib.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/driver/jit.rs b/src/driver/jit.rs index ebbbc2697d10..40c8894e21ab 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -16,7 +16,7 @@ use rustc_span::Symbol; use crate::debuginfo::TypeDebugContext; use crate::prelude::*; use crate::unwind_module::UnwindModule; -use crate::{BackendConfig, CodegenCx, CodegenMode}; +use crate::{CodegenCx, CodegenMode}; struct JitState { jit_module: UnwindModule, @@ -77,7 +77,7 @@ fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule (jit_module, cx) } -pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { +pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec) -> ! { if !tcx.sess.opts.output_types.should_codegen() { tcx.dcx().fatal("JIT mode doesn't work with `cargo check`"); } @@ -87,7 +87,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { } let (mut jit_module, mut cx) = - create_jit_module(tcx, matches!(backend_config.codegen_mode, CodegenMode::JitLazy)); + create_jit_module(tcx, matches!(codegen_mode, CodegenMode::JitLazy)); let mut cached_context = Context::new(); let (_, cgus) = tcx.collect_and_partition_mono_items(()); @@ -103,7 +103,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { super::predefine_mono_items(tcx, &mut jit_module, &mono_items); for (mono_item, _) in mono_items { match mono_item { - MonoItem::Fn(inst) => match backend_config.codegen_mode { + MonoItem::Fn(inst) => match codegen_mode { CodegenMode::Aot => unreachable!(), CodegenMode::Jit => { codegen_and_compile_fn( @@ -144,7 +144,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { ); let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()) - .chain(backend_config.jit_args.iter().map(|arg| &**arg)) + .chain(jit_args.iter().map(|arg| &**arg)) .map(|arg| CString::new(arg).unwrap()) .collect::>(); diff --git a/src/lib.rs b/src/lib.rs index ddd5556b04e8..1f0f7a592602 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -221,7 +221,7 @@ impl CodegenBackend for CraneliftCodegenBackend { CodegenMode::Aot => driver::aot::run_aot(tcx, metadata, need_metadata_module), CodegenMode::Jit | CodegenMode::JitLazy => { #[cfg(feature = "jit")] - driver::jit::run_jit(tcx, config); + driver::jit::run_jit(tcx, config.codegen_mode, config.jit_args); #[cfg(not(feature = "jit"))] tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift"); From cb51cfe3d0564643064258a71063ced474c9e805 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:06:30 +0000 Subject: [PATCH 021/107] Simplify config.rs --- src/config.rs | 53 ++++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/src/config.rs b/src/config.rs index cccad2d4749d..d784f6e9d9eb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - /// The mode to use for compilation. #[derive(Copy, Clone, Debug)] pub enum CodegenMode { @@ -11,19 +9,6 @@ pub enum CodegenMode { JitLazy, } -impl FromStr for CodegenMode { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "aot" => Ok(CodegenMode::Aot), - "jit" => Ok(CodegenMode::Jit), - "jit-lazy" => Ok(CodegenMode::JitLazy), - _ => Err(format!("Unknown codegen mode `{}`", s)), - } - } -} - /// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars. #[derive(Clone, Debug)] pub struct BackendConfig { @@ -38,27 +23,20 @@ pub struct BackendConfig { pub jit_args: Vec, } -impl Default for BackendConfig { - fn default() -> Self { - BackendConfig { - codegen_mode: CodegenMode::Aot, - jit_args: { - match std::env::var("CG_CLIF_JIT_ARGS") { - Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(), - Err(std::env::VarError::NotPresent) => vec![], - Err(std::env::VarError::NotUnicode(s)) => { - panic!("CG_CLIF_JIT_ARGS not unicode: {:?}", s); - } - } - }, - } - } -} - impl BackendConfig { /// Parse the configuration passed in using `-Cllvm-args`. pub fn from_opts(opts: &[String]) -> Result { - let mut config = BackendConfig::default(); + let mut config = BackendConfig { + codegen_mode: CodegenMode::Aot, + jit_args: match std::env::var("CG_CLIF_JIT_ARGS") { + Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(), + Err(std::env::VarError::NotPresent) => vec![], + Err(std::env::VarError::NotUnicode(s)) => { + panic!("CG_CLIF_JIT_ARGS not unicode: {:?}", s); + } + }, + }; + for opt in opts { if opt.starts_with("-import-instr-limit") { // Silently ignore -import-instr-limit. It is set by rust's build system even when @@ -67,7 +45,14 @@ impl BackendConfig { } if let Some((name, value)) = opt.split_once('=') { match name { - "mode" => config.codegen_mode = value.parse()?, + "mode" => { + config.codegen_mode = match value { + "aot" => CodegenMode::Aot, + "jit" => CodegenMode::Jit, + "jit-lazy" => CodegenMode::JitLazy, + _ => return Err(format!("Unknown codegen mode `{}`", value)), + }; + } _ => return Err(format!("Unknown option `{}`", name)), } } else { From 1c372caa3354f2b47622f58a734ef10b5075f6c5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:40:20 +0000 Subject: [PATCH 022/107] Make the cold_path intrinsic mark the current block as cold --- src/intrinsics/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/intrinsics/mod.rs b/src/intrinsics/mod.rs index 3318c0797ec3..5f1b71eff6b3 100644 --- a/src/intrinsics/mod.rs +++ b/src/intrinsics/mod.rs @@ -1270,8 +1270,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } sym::cold_path => { - // This is a no-op. The intrinsic is just a hint to the optimizer. - // We still have an impl here to avoid it being turned into a call. + fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); } // Unimplemented intrinsics must have a fallback body. The fallback body is obtained From 4f213adf09fb52e7c95a7b6d36bc1ca4f09ac9e8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:59:41 +0000 Subject: [PATCH 023/107] Inline all RelPath::ensure_fresh --- build_system/build_sysroot.rs | 5 +++-- build_system/path.rs | 7 ------- build_system/tests.rs | 6 ++++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index f1f4489bcbc8..1df1ec729021 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -281,13 +281,14 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option { return None; } - RTSTARTUP_SYSROOT.ensure_fresh(dirs); + let rtstartup_sysroot = RTSTARTUP_SYSROOT.to_path(dirs); + ensure_empty_dir(&rtstartup_sysroot); let rtstartup_src = STDLIB_SRC.to_path(dirs).join("library").join("rtstartup"); let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] }; for file in ["rsbegin", "rsend"] { - let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o")); + let obj = rtstartup_sysroot.join(format!("{file}.o")); let mut build_rtstartup_cmd = Command::new(&compiler.rustc); build_rtstartup_cmd .arg("--target") diff --git a/build_system/path.rs b/build_system/path.rs index 35e7e81c5285..a81902d84701 100644 --- a/build_system/path.rs +++ b/build_system/path.rs @@ -1,8 +1,6 @@ use std::fs; use std::path::PathBuf; -use crate::utils::ensure_empty_dir; - #[derive(Debug, Clone)] pub(crate) struct Dirs { pub(crate) source_dir: PathBuf, @@ -61,9 +59,4 @@ impl RelPath { pub(crate) fn ensure_exists(&self, dirs: &Dirs) { fs::create_dir_all(self.to_path(dirs)).unwrap(); } - - pub(crate) fn ensure_fresh(&self, dirs: &Dirs) { - let path = self.to_path(dirs); - ensure_empty_dir(&path); - } } diff --git a/build_system/tests.rs b/build_system/tests.rs index fd94e80f6312..74fe2fbed4df 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -7,7 +7,7 @@ use crate::path::{Dirs, RelPath}; use crate::prepare::{GitRepo, apply_patches}; use crate::rustc_info::get_default_sysroot; use crate::shared_utils::rustflags_from_env; -use crate::utils::{CargoProject, Compiler, LogGroup, spawn_and_wait}; +use crate::utils::{CargoProject, Compiler, LogGroup, ensure_empty_dir, spawn_and_wait}; use crate::{CodegenBackend, SysrootKind, build_sysroot, config}; static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example"); @@ -267,7 +267,9 @@ pub(crate) fn run_tests( stdlib_source.clone(), ); - BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs); + let path = BUILD_EXAMPLE_OUT_DIR.to_path(dirs); + ensure_empty_dir(&path); + runner.run_testsuite(NO_SYSROOT_SUITE); } else { eprintln!("[SKIP] no_sysroot tests"); From 5763c09be110e080e690f28bd1ce5200b054bea0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:48:08 +0000 Subject: [PATCH 024/107] Remove RelPath::DOWNLOAD --- build_system/abi_cafe.rs | 4 ++-- build_system/path.rs | 3 --- build_system/prepare.rs | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index 9292778806a2..674acfbd3097 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -1,4 +1,4 @@ -use crate::path::{Dirs, RelPath}; +use crate::path::Dirs; use crate::prepare::GitRepo; use crate::utils::{CargoProject, Compiler, spawn_and_wait}; use crate::{CodegenBackend, SysrootKind, build_sysroot}; @@ -20,7 +20,7 @@ pub(crate) fn run( rustup_toolchain_name: Option<&str>, bootstrap_host_compiler: &Compiler, ) { - RelPath::DOWNLOAD.ensure_exists(dirs); + std::fs::create_dir_all(&dirs.download_dir).unwrap(); ABI_CAFE_REPO.fetch(dirs); ABI_CAFE_REPO.patch(dirs); diff --git a/build_system/path.rs b/build_system/path.rs index a81902d84701..3fa246cbe355 100644 --- a/build_system/path.rs +++ b/build_system/path.rs @@ -14,7 +14,6 @@ pub(crate) struct Dirs { #[derive(Debug, Copy, Clone)] pub(crate) enum PathBase { Source, - Download, Build, Dist, } @@ -23,7 +22,6 @@ impl PathBase { fn to_path(self, dirs: &Dirs) -> PathBuf { match self { PathBase::Source => dirs.source_dir.clone(), - PathBase::Download => dirs.download_dir.clone(), PathBase::Build => dirs.build_dir.clone(), PathBase::Dist => dirs.dist_dir.clone(), } @@ -38,7 +36,6 @@ pub(crate) enum RelPath { impl RelPath { pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source); - pub(crate) const DOWNLOAD: RelPath = RelPath::Base(PathBase::Download); pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build); pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist); diff --git a/build_system/prepare.rs b/build_system/prepare.rs index c6f979f02786..60363c279360 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -8,7 +8,7 @@ use crate::path::{Dirs, RelPath}; use crate::utils::{copy_dir_recursively, ensure_empty_dir, spawn_and_wait}; pub(crate) fn prepare(dirs: &Dirs) { - RelPath::DOWNLOAD.ensure_exists(dirs); + std::fs::create_dir_all(&dirs.download_dir).unwrap(); crate::tests::RAND_REPO.fetch(dirs); crate::tests::REGEX_REPO.fetch(dirs); } @@ -79,7 +79,7 @@ impl GitRepo { fn download_dir(&self, dirs: &Dirs) -> PathBuf { match self.url { - GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo).to_path(dirs), + GitRepoUrl::Github { user: _, repo } => dirs.download_dir.join(repo), } } From fdca75c263d1281129c1b64f6bad86ce0890b351 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:07:02 +0000 Subject: [PATCH 025/107] Refactor and reduce usage of RelPath --- build_system/bench.rs | 14 +++++++------- build_system/build_backend.rs | 2 +- build_system/build_sysroot.rs | 16 ++++++++-------- build_system/main.rs | 5 ++--- build_system/path.rs | 31 +++++++++---------------------- build_system/prepare.rs | 6 +++--- build_system/tests.rs | 8 ++++---- build_system/utils.rs | 2 +- 8 files changed, 35 insertions(+), 49 deletions(-) diff --git a/build_system/bench.rs b/build_system/bench.rs index ebeb67722507..73a0f325fc21 100644 --- a/build_system/bench.rs +++ b/build_system/bench.rs @@ -3,7 +3,7 @@ use std::io::Write; use std::path::Path; use std::process::Command; -use crate::path::{Dirs, RelPath}; +use crate::path::Dirs; use crate::prepare::GitRepo; use crate::rustc_info::get_file_name; use crate::utils::{Compiler, spawn_and_wait}; @@ -39,11 +39,11 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { }; eprintln!("[BENCH COMPILE] ebobby/simple-raytracer"); - let cargo_clif = RelPath::DIST - .to_path(dirs) + let cargo_clif = dirs + .dist_dir .join(get_file_name(&bootstrap_host_compiler.rustc, "cargo_clif", "bin").replace('_', "-")); let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml"); - let target_dir = RelPath::BUILD.join("simple_raytracer").to_path(dirs); + let target_dir = dirs.build_dir.join("simple_raytracer"); let clean_cmd = format!( "RUSTC=rustc cargo clean --manifest-path {manifest_path} --target-dir {target_dir}", @@ -68,7 +68,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { target_dir = target_dir.display(), ); - let bench_compile_markdown = RelPath::DIST.to_path(dirs).join("bench_compile.md"); + let bench_compile_markdown = dirs.dist_dir.join("bench_compile.md"); let bench_compile = hyperfine_command( 1, @@ -92,7 +92,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { eprintln!("[BENCH RUN] ebobby/simple-raytracer"); - let bench_run_markdown = RelPath::DIST.to_path(dirs).join("bench_run.md"); + let bench_run_markdown = dirs.dist_dir.join("bench_run.md"); let raytracer_cg_llvm = Path::new(".").join(get_file_name( &bootstrap_host_compiler.rustc, @@ -120,7 +120,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) { ], &bench_run_markdown, ); - bench_run.current_dir(RelPath::BUILD.to_path(dirs)); + bench_run.current_dir(&dirs.build_dir); spawn_and_wait(bench_run); if let Some(gha_step_summary) = gha_step_summary.as_mut() { diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index 02da89f737cf..72bc422523d5 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -6,7 +6,7 @@ use crate::rustc_info::get_file_name; use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env}; use crate::utils::{CargoProject, Compiler, LogGroup}; -static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif"); +static CG_CLIF: CargoProject = CargoProject::new(&RelPath::source("."), "cg_clif"); pub(crate) fn build_backend( dirs: &Dirs, diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 1df1ec729021..62cef3dc1726 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -22,9 +22,9 @@ pub(crate) fn build_sysroot( eprintln!("[BUILD] sysroot {:?}", sysroot_kind); - let dist_dir = RelPath::DIST.to_path(dirs); + let dist_dir = &dirs.dist_dir; - ensure_empty_dir(&dist_dir); + ensure_empty_dir(dist_dir); fs::create_dir_all(dist_dir.join("bin")).unwrap(); fs::create_dir_all(dist_dir.join("lib")).unwrap(); @@ -55,7 +55,7 @@ pub(crate) fn build_sysroot( let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc); let wrapper_path = dist_dir.join(&wrapper_name); build_cargo_wrapper_cmd - .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs"))) + .arg(dirs.source_dir.join("scripts").join(&format!("{wrapper}.rs"))) .arg("-o") .arg(&wrapper_path) .arg("-Cstrip=debuginfo"); @@ -85,7 +85,7 @@ pub(crate) fn build_sysroot( &cg_clif_dylib_path, sysroot_kind, ); - host.install_into_sysroot(&dist_dir); + host.install_into_sysroot(dist_dir); if !is_native { build_sysroot_for_triple( @@ -99,7 +99,7 @@ pub(crate) fn build_sysroot( &cg_clif_dylib_path, sysroot_kind, ) - .install_into_sysroot(&dist_dir); + .install_into_sysroot(dist_dir); } let mut target_compiler = { @@ -143,10 +143,10 @@ impl SysrootTarget { } } -static STDLIB_SRC: RelPath = RelPath::BUILD.join("stdlib"); +static STDLIB_SRC: RelPath = RelPath::build("stdlib"); static STANDARD_LIBRARY: CargoProject = - CargoProject::new(&STDLIB_SRC.join("library/sysroot"), "stdlib_target"); -static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup"); + CargoProject::new(&RelPath::build("stdlib/library/sysroot"), "stdlib_target"); +static RTSTARTUP_SYSROOT: RelPath = RelPath::build("rtstartup"); fn build_sysroot_for_triple( dirs: &Dirs, diff --git a/build_system/main.rs b/build_system/main.rs index b68ac7c09267..99e6146657f3 100644 --- a/build_system/main.rs +++ b/build_system/main.rs @@ -185,12 +185,11 @@ fn main() { frozen, }; - path::RelPath::BUILD.ensure_exists(&dirs); + std::fs::create_dir_all(&dirs.build_dir).unwrap(); { // Make sure we always explicitly specify the target dir - let target = - path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs); + let target = dirs.build_dir.join("target_dir_should_be_set_explicitly"); env::set_var("CARGO_TARGET_DIR", &target); let _ = std::fs::remove_file(&target); std::fs::File::create(target).unwrap(); diff --git a/build_system/path.rs b/build_system/path.rs index 3fa246cbe355..20a81156b71d 100644 --- a/build_system/path.rs +++ b/build_system/path.rs @@ -1,4 +1,3 @@ -use std::fs; use std::path::PathBuf; #[derive(Debug, Clone)] @@ -15,7 +14,6 @@ pub(crate) struct Dirs { pub(crate) enum PathBase { Source, Build, - Dist, } impl PathBase { @@ -23,37 +21,26 @@ impl PathBase { match self { PathBase::Source => dirs.source_dir.clone(), PathBase::Build => dirs.build_dir.clone(), - PathBase::Dist => dirs.dist_dir.clone(), } } } #[derive(Debug, Copy, Clone)] -pub(crate) enum RelPath { - Base(PathBase), - Join(&'static RelPath, &'static str), +pub(crate) struct RelPath { + base: PathBase, + suffix: &'static str, } impl RelPath { - pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source); - pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build); - pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist); + pub(crate) const fn source(suffix: &'static str) -> RelPath { + RelPath { base: PathBase::Source, suffix } + } - pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts"); - pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches"); - - pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath { - RelPath::Join(self, suffix) + pub(crate) const fn build(suffix: &'static str) -> RelPath { + RelPath { base: PathBase::Build, suffix } } pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf { - match self { - RelPath::Base(base) => base.to_path(dirs), - RelPath::Join(base, suffix) => base.to_path(dirs).join(suffix), - } - } - - pub(crate) fn ensure_exists(&self, dirs: &Dirs) { - fs::create_dir_all(self.to_path(dirs)).unwrap(); + self.base.to_path(dirs).join(self.suffix) } } diff --git a/build_system/prepare.rs b/build_system/prepare.rs index 60363c279360..a4e9cb5f5c8c 100644 --- a/build_system/prepare.rs +++ b/build_system/prepare.rs @@ -85,7 +85,7 @@ impl GitRepo { pub(crate) const fn source_dir(&self) -> RelPath { match self.url { - GitRepoUrl::Github { user: _, repo } => RelPath::BUILD.join(repo), + GitRepoUrl::Github { user: _, repo } => RelPath::build(repo), } } @@ -130,7 +130,7 @@ impl GitRepo { } let source_lockfile = - RelPath::PATCHES.to_path(dirs).join(format!("{}-lock.toml", self.patch_name)); + dirs.source_dir.join("patches").join(format!("{}-lock.toml", self.patch_name)); let target_lockfile = download_dir.join("Cargo.lock"); if source_lockfile.exists() { assert!(!target_lockfile.exists()); @@ -191,7 +191,7 @@ fn init_git_repo(repo_dir: &Path) { } fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec { - let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs)) + let mut patches: Vec<_> = fs::read_dir(dirs.source_dir.join("patches")) .unwrap() .map(|entry| entry.unwrap().path()) .filter(|path| path.extension() == Some(OsStr::new("patch"))) diff --git a/build_system/tests.rs b/build_system/tests.rs index 74fe2fbed4df..6d7ba59183b8 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -10,7 +10,7 @@ use crate::shared_utils::rustflags_from_env; use crate::utils::{CargoProject, Compiler, LogGroup, ensure_empty_dir, spawn_and_wait}; use crate::{CodegenBackend, SysrootKind, build_sysroot, config}; -static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example"); +static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::build("example"); struct TestCase { config: &'static str, @@ -129,11 +129,11 @@ pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); -static PORTABLE_SIMD_SRC: RelPath = RelPath::BUILD.join("portable-simd"); +static PORTABLE_SIMD_SRC: RelPath = RelPath::build("portable-simd"); static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); -static LIBCORE_TESTS_SRC: RelPath = RelPath::BUILD.join("coretests"); +static LIBCORE_TESTS_SRC: RelPath = RelPath::build("coretests"); static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "coretests_target"); @@ -162,7 +162,7 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ &LIBCORE_TESTS_SRC.to_path(&runner.dirs), ); - let source_lockfile = RelPath::PATCHES.to_path(&runner.dirs).join("coretests-lock.toml"); + let source_lockfile = runner.dirs.source_dir.join("patches/coretests-lock.toml"); let target_lockfile = LIBCORE_TESTS_SRC.to_path(&runner.dirs).join("Cargo.lock"); fs::copy(source_lockfile, target_lockfile).unwrap(); diff --git a/build_system/utils.rs b/build_system/utils.rs index 22a9487a202d..c2114caf8692 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -93,7 +93,7 @@ impl CargoProject { } pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf { - RelPath::BUILD.join(self.target).to_path(dirs) + dirs.build_dir.join(self.target) } #[must_use] From 510943ab554801afb8aa96da6bc02ebe580c96f5 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 20 Nov 2024 11:59:52 +0100 Subject: [PATCH 026/107] remove remaining references to `Reveal` --- src/abi/mod.rs | 18 +++++++++--------- src/base.rs | 2 +- src/common.rs | 18 +++++++++--------- src/debuginfo/types.rs | 16 +++++++++++----- src/global_asm.rs | 2 +- src/inline_asm.rs | 2 +- 6 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 7dd2139cf90c..cab5b35c18dc 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -80,7 +80,7 @@ pub(crate) fn get_function_sig<'tcx>( clif_sig_from_fn_abi( tcx, default_call_conv, - &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()), + &FullyMonomorphizedLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()), ) } @@ -438,9 +438,9 @@ pub(crate) fn codegen_terminator_call<'tcx>( extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.node.ty(fx.mir, fx.tcx))), ); let fn_abi = if let Some(instance) = instance { - RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args) + FullyMonomorphizedLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args) } else { - RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args) + FullyMonomorphizedLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args) }; let is_cold = if fn_sig.abi() == ExternAbi::RustCold { @@ -721,8 +721,8 @@ pub(crate) fn codegen_drop<'tcx>( def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0), args: drop_instance.args, }; - let fn_abi = - RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty()); + let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx) + .fn_abi_of_instance(virtual_drop, ty::List::empty()); let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); let sig = fx.bcx.import_signature(sig); @@ -764,8 +764,8 @@ pub(crate) fn codegen_drop<'tcx>( def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0), args: drop_instance.args, }; - let fn_abi = - RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty()); + let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx) + .fn_abi_of_instance(virtual_drop, ty::List::empty()); let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi); let sig = fx.bcx.import_signature(sig); @@ -774,8 +774,8 @@ pub(crate) fn codegen_drop<'tcx>( _ => { assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _))); - let fn_abi = - RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty()); + let fn_abi = FullyMonomorphizedLayoutCx(fx.tcx) + .fn_abi_of_instance(drop_instance, ty::List::empty()); let arg_value = drop_place.place_ref( fx, diff --git a/src/base.rs b/src/base.rs index 70b7d92ce15b..06cc57548946 100644 --- a/src/base.rs +++ b/src/base.rs @@ -103,7 +103,7 @@ pub(crate) fn codegen_fn<'tcx>( let block_map: IndexVec = (0..mir.basic_blocks.len()).map(|_| bcx.create_block()).collect(); - let fn_abi = RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()); + let fn_abi = FullyMonomorphizedLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()); // Make FunctionCx let target_config = module.target_config(); diff --git a/src/common.rs b/src/common.rs index c663fa329652..534557fcd41b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -311,7 +311,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty) + FullyMonomorphizedLayoutCx(self.tcx).handle_layout_err(err, span, ty) } } @@ -323,7 +323,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> { span: Span, fn_abi_request: FnAbiRequest<'tcx>, ) -> ! { - RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request) + FullyMonomorphizedLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request) } } @@ -443,9 +443,9 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { } } -pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); +pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); -impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { +impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { @@ -459,7 +459,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { } } -impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { +impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> { #[inline] fn handle_fn_abi_err( &self, @@ -485,25 +485,25 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { } } -impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> { +impl<'tcx> layout::HasTyCtxt<'tcx> for FullyMonomorphizedLayoutCx<'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.0 } } -impl<'tcx> rustc_abi::HasDataLayout for RevealAllLayoutCx<'tcx> { +impl<'tcx> rustc_abi::HasDataLayout for FullyMonomorphizedLayoutCx<'tcx> { fn data_layout(&self) -> &rustc_abi::TargetDataLayout { &self.0.data_layout } } -impl<'tcx> layout::HasTypingEnv<'tcx> for RevealAllLayoutCx<'tcx> { +impl<'tcx> layout::HasTypingEnv<'tcx> for FullyMonomorphizedLayoutCx<'tcx> { fn typing_env(&self) -> ty::TypingEnv<'tcx> { ty::TypingEnv::fully_monomorphized() } } -impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> { +impl<'tcx> HasTargetSpec for FullyMonomorphizedLayoutCx<'tcx> { fn target_spec(&self) -> &Target { &self.0.sess.target } diff --git a/src/debuginfo/types.rs b/src/debuginfo/types.rs index 714742aeaffe..a2f6691cdd23 100644 --- a/src/debuginfo/types.rs +++ b/src/debuginfo/types.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; -use crate::{DebugContext, RevealAllLayoutCx, has_ptr_meta}; +use crate::{DebugContext, FullyMonomorphizedLayoutCx, has_ptr_meta}; #[derive(Default)] pub(crate) struct TypeDebugContext<'tcx> { @@ -85,7 +85,7 @@ impl DebugContext { type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(encoding)); type_entry.set( gimli::DW_AT_byte_size, - AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()), + AttributeValue::Udata(FullyMonomorphizedLayoutCx(tcx).layout_of(ty).size.bytes()), ); type_id @@ -159,7 +159,7 @@ impl DebugContext { return_if_type_created_in_meantime!(type_dbg, tuple_type); let name = type_names::compute_debuginfo_type_name(tcx, tuple_type, false); - let layout = RevealAllLayoutCx(tcx).layout_of(tuple_type); + let layout = FullyMonomorphizedLayoutCx(tcx).layout_of(tuple_type); let tuple_type_id = self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_structure_type); @@ -178,7 +178,9 @@ impl DebugContext { member_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty)); member_entry.set( gimli::DW_AT_alignment, - AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of(ty).align.pref.bytes()), + AttributeValue::Udata( + FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.pref.bytes(), + ), ); member_entry.set( gimli::DW_AT_data_member_location, @@ -198,7 +200,11 @@ impl DebugContext { self.debug_type( tcx, type_dbg, - Ty::new_array(tcx, tcx.types.u8, RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()), + Ty::new_array( + tcx, + tcx.types.u8, + FullyMonomorphizedLayoutCx(tcx).layout_of(ty).size.bytes(), + ), ) } } diff --git a/src/global_asm.rs b/src/global_asm.rs index 6f90d17920d6..c0a3ce84d529 100644 --- a/src/global_asm.rs +++ b/src/global_asm.rs @@ -42,7 +42,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, tcx, op_sp, const_value, - RevealAllLayoutCx(tcx).layout_of(ty), + FullyMonomorphizedLayoutCx(tcx).layout_of(ty), ); global_asm.push_str(&string); } diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 0df1a30fc0a4..70176754f337 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -238,7 +238,7 @@ pub(crate) fn codegen_naked_asm<'tcx>( tcx, span, const_value, - RevealAllLayoutCx(tcx).layout_of(cv.ty()), + FullyMonomorphizedLayoutCx(tcx).layout_of(cv.ty()), ); CInlineAsmOperand::Const { value } } From 8f9d76550bc15e50372020a8270ecc1b969c151f Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 23 Nov 2024 14:31:20 -0500 Subject: [PATCH 027/107] Add simd_relaxed_fma intrinsic --- src/intrinsics/simd.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index f787b8a6fd94..e0ebe30752af 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -415,7 +415,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - sym::simd_fma => { + // FIXME: simd_relaxed_fma doesn't relax to non-fused multiply-add + sym::simd_fma | sym::simd_relaxed_fma => { intrinsic_args!(fx, args => (a, b, c); intrinsic); if !a.layout().ty.is_simd() { From 1876e520e8fd8a73404e38f1350405387b01ef59 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 24 Nov 2024 21:42:22 +0900 Subject: [PATCH 028/107] Make s390x non-clobber-only vector register support unstable --- src/inline_asm.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 0df1a30fc0a4..a2fb711b9e16 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -462,8 +462,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { let mut slots_output = vec![None; self.operands.len()]; let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| { - let reg_size = - reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap(); + let reg_size = reg_class + .supported_types(self.arch, true) + .iter() + .map(|(ty, _)| ty.size()) + .max() + .unwrap(); let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap(); let offset = slot_size.align_to(align); *slot_size = offset + reg_size; From b9e2bdd050f1e076fc3a215e2a02e19b3f9a3fc1 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Mon, 25 Nov 2024 00:36:22 +0900 Subject: [PATCH 029/107] Fix clobber_abi in RV32E and RV64E inline assembly --- src/inline_asm.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 70176754f337..73ee47b2c63a 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -472,9 +472,14 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { let mut new_slot = |x| new_slot_fn(&mut slot_size, x); // Allocate stack slots for saving clobbered registers - let abi_clobber = InlineAsmClobberAbi::parse(self.arch, &self.tcx.sess.target, sym::C) - .unwrap() - .clobbered_regs(); + let abi_clobber = InlineAsmClobberAbi::parse( + self.arch, + &self.tcx.sess.target, + &self.tcx.sess.unstable_target_features, + sym::C, + ) + .unwrap() + .clobbered_regs(); for (i, reg) in self.registers.iter().enumerate().filter_map(|(i, r)| r.map(|r| (i, r))) { let mut need_save = true; // If the register overlaps with a register clobbered by function call, then From e5bc7e38c3c9d75a993435e4dfdcc15644e2262b Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 26 Nov 2024 03:10:22 +0900 Subject: [PATCH 030/107] Fix handling of x18 in AArch64 inline assembly on ohos/trusty or with -Zfixed-x18 --- src/inline_asm.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 7bc500b18147..d74c366a87ff 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -476,9 +476,14 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { let mut new_slot = |x| new_slot_fn(&mut slot_size, x); // Allocate stack slots for saving clobbered registers - let abi_clobber = InlineAsmClobberAbi::parse(self.arch, &self.tcx.sess.target, sym::C) - .unwrap() - .clobbered_regs(); + let abi_clobber = InlineAsmClobberAbi::parse( + self.arch, + &self.tcx.sess.target, + &self.tcx.sess.unstable_target_features, + sym::C, + ) + .unwrap() + .clobbered_regs(); for (i, reg) in self.registers.iter().enumerate().filter_map(|(i, r)| r.map(|r| (i, r))) { let mut need_save = true; // If the register overlaps with a register clobbered by function call, then From a2e9aac9057a99ba772860c3b6e2850172b67877 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Wed, 27 Nov 2024 17:52:57 +0000 Subject: [PATCH 031/107] Replace `Symbol::intern` calls with preinterned symbols --- src/driver/jit.rs | 9 ++------- src/lib.rs | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 0d62a13b4724..ae9578eeffb6 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -74,7 +74,7 @@ fn create_jit_module( jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8); let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false); - let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, Symbol::intern("dummy_cgu_name")); + let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name); crate::allocator::codegen(tcx, &mut jit_module); @@ -276,12 +276,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) -> jit_module.module.prepare_for_function_redefine(func_id).unwrap(); - let mut cx = crate::CodegenCx::new( - tcx, - jit_module.isa(), - false, - Symbol::intern("dummy_cgu_name"), - ); + let mut cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name); codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance); assert!(cx.global_asm.is_empty()); diff --git a/src/lib.rs b/src/lib.rs index e6f6ae305816..cac9975f04ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,18 +189,13 @@ impl CodegenBackend for CraneliftCodegenBackend { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] if sess.target.arch == "x86_64" && sess.target.os != "none" { // x86_64 mandates SSE2 support - vec![Symbol::intern("fxsr"), sym::sse, Symbol::intern("sse2")] + vec![sym::fsxr, sym::sse, sym::sse2] } else if sess.target.arch == "aarch64" { match &*sess.target.os { "none" => vec![], // On macOS the aes, sha2 and sha3 features are enabled by default and ring // fails to compile on macOS when they are not present. - "macos" => vec![ - sym::neon, - Symbol::intern("aes"), - Symbol::intern("sha2"), - Symbol::intern("sha3"), - ], + "macos" => vec![sym::neon, sym::aes, sym::sha2, sym::sha3], // AArch64 mandates Neon support _ => vec![sym::neon], } From e595d03b1d2351c3f57034b19443f79fe8b744e4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Nov 2024 17:46:12 +0000 Subject: [PATCH 032/107] Rustup to rustc 1.85.0-nightly (6b6a867ae 2024-11-27) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index c9717cacd1af..aa4773a13e26 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-11-21" +channel = "nightly-2024-11-28" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" From e82b533efdc804f3d3f67746ff0355a1d2e7eb17 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:10:15 +0000 Subject: [PATCH 033/107] Fix rustc test suite --- scripts/test_rustc_tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 1b4321b8e240..e291ec204649 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -76,6 +76,8 @@ rm -r tests/ui/instrument-coverage/ rm tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs rm tests/ui/asm/aarch64/type-f16.rs rm tests/ui/float/conv-bits-runtime-const.rs +rm tests/ui/consts/const-eval/float_methods.rs +rm tests/ui/match/match-float.rs # optimization tests # ================== From 95bb635853f09b213ee85a6c750d5bc107fb270c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:17:48 +0000 Subject: [PATCH 034/107] Fix std_example on s390x --- example/std_example.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example/std_example.rs b/example/std_example.rs index 3078288c2861..0b1d83c56309 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -8,6 +8,9 @@ unboxed_closures )] #![allow(internal_features)] +// FIXME once abi_unsupported_vector_types is a hard error disable the foo test when the respective +// target feature is not enabled. +#![allow(abi_unsupported_vector_types)] #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; From 0ac93cd579ca394b66589cf176dc93406dc4aeb2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 27 Nov 2024 20:15:06 +0000 Subject: [PATCH 035/107] Structurally resolve before adjust_for_branches --- compiler/rustc_hir_typeck/src/_match.rs | 2 +- compiler/rustc_hir_typeck/src/expectation.rs | 8 ++++++-- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../typeck/structurally-resolve-in-resolve_for_branch.rs | 8 ++++++++ 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 tests/ui/traits/next-solver/typeck/structurally-resolve-in-resolve_for_branch.rs diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index bfdf764d299b..7e3cb7914a9f 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -57,7 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type in that case) let mut all_arms_diverge = Diverges::WarnedAlways; - let expected = orig_expected.adjust_for_branches(self); + let expected = orig_expected.adjust_for_branches(self, expr.span); debug!(?expected); let mut coercion = { diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 4653458b5ddc..93fa6f863d17 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -39,10 +39,14 @@ impl<'a, 'tcx> Expectation<'tcx> { // an expected type. Otherwise, we might write parts of the type // when checking the 'then' block which are incompatible with the // 'else' branch. - pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + pub(super) fn adjust_for_branches( + &self, + fcx: &FnCtxt<'a, 'tcx>, + span: Span, + ) -> Expectation<'tcx> { match *self { ExpectHasType(ety) => { - let ety = fcx.shallow_resolve(ety); + let ety = fcx.try_structurally_resolve_type(span, ety); if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } } ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 1610848958e5..dd1650e0634a 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1290,7 +1290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cond_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); - let expected = orig_expected.adjust_for_branches(self); + let expected = orig_expected.adjust_for_branches(self, sp); let then_ty = self.check_expr_with_expectation(then_expr, expected); let then_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); diff --git a/tests/ui/traits/next-solver/typeck/structurally-resolve-in-resolve_for_branch.rs b/tests/ui/traits/next-solver/typeck/structurally-resolve-in-resolve_for_branch.rs new file mode 100644 index 000000000000..d406f3949a28 --- /dev/null +++ b/tests/ui/traits/next-solver/typeck/structurally-resolve-in-resolve_for_branch.rs @@ -0,0 +1,8 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +pub fn repro() -> impl FnMut() { + if true { || () } else { || () } +} + +fn main() {} From cfb78419cd865a19dac54d234d2a6abde0f14628 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 11 May 2023 11:43:09 +0000 Subject: [PATCH 036/107] implement checks for tail calls this implements checks necessary to guarantee that we can actually perform a tail call. while extremely restrictive, this is what is documented in the RFC, and all these checks are needed for one reason or another. --- compiler/rustc_middle/src/query/mod.rs | 6 + compiler/rustc_mir_build/src/build/mod.rs | 4 + .../rustc_mir_build/src/check_tail_calls.rs | 387 ++++++++++++++++++ compiler/rustc_mir_build/src/lib.rs | 2 + tests/ui/explicit-tail-calls/become-macro.rs | 13 + .../explicit-tail-calls/become-operator.fixed | 42 ++ .../ui/explicit-tail-calls/become-operator.rs | 42 ++ .../become-operator.stderr | 75 ++++ .../become-uncallable.fixed | 18 + .../explicit-tail-calls/become-uncallable.rs | 18 + .../become-uncallable.stderr | 44 ++ tests/ui/explicit-tail-calls/closure.fixed | 31 ++ tests/ui/explicit-tail-calls/closure.rs | 31 ++ tests/ui/explicit-tail-calls/closure.stderr | 46 +++ tests/ui/explicit-tail-calls/in-closure.rs | 8 + .../ui/explicit-tail-calls/in-closure.stderr | 8 + .../explicit-tail-calls/signature-mismatch.rs | 33 ++ .../signature-mismatch.stderr | 40 ++ 18 files changed, 848 insertions(+) create mode 100644 compiler/rustc_mir_build/src/check_tail_calls.rs create mode 100644 tests/ui/explicit-tail-calls/become-macro.rs create mode 100644 tests/ui/explicit-tail-calls/become-operator.fixed create mode 100644 tests/ui/explicit-tail-calls/become-operator.rs create mode 100644 tests/ui/explicit-tail-calls/become-operator.stderr create mode 100644 tests/ui/explicit-tail-calls/become-uncallable.fixed create mode 100644 tests/ui/explicit-tail-calls/become-uncallable.rs create mode 100644 tests/ui/explicit-tail-calls/become-uncallable.stderr create mode 100644 tests/ui/explicit-tail-calls/closure.fixed create mode 100644 tests/ui/explicit-tail-calls/closure.rs create mode 100644 tests/ui/explicit-tail-calls/closure.stderr create mode 100644 tests/ui/explicit-tail-calls/in-closure.rs create mode 100644 tests/ui/explicit-tail-calls/in-closure.stderr create mode 100644 tests/ui/explicit-tail-calls/signature-mismatch.rs create mode 100644 tests/ui/explicit-tail-calls/signature-mismatch.stderr diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0f2a6d598a0f..d3748af40777 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -916,6 +916,12 @@ rustc_queries! { cache_on_disk_if { true } } + /// Checks well-formedness of tail calls (`become f()`). + query check_tail_calls(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> { + desc { |tcx| "tail-call-checking `{}`", tcx.def_path_str(key) } + cache_on_disk_if { true } + } + /// Returns the types assumed to be well formed while "inside" of the given item. /// /// Note that we've liberated the late bound regions of function signatures, so diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 3317f3b7f8ac..f43c29d8f5d6 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -50,6 +50,10 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx return construct_error(tcx, def, e); } + if let Err(err) = tcx.check_tail_calls(def) { + return construct_error(tcx, def, err); + } + let body = match tcx.thir_body(def) { Err(error_reported) => construct_error(tcx, def, error_reported), Ok((thir, expr)) => { diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs new file mode 100644 index 000000000000..911a6cb7de60 --- /dev/null +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -0,0 +1,387 @@ +use rustc_abi::ExternAbi; +use rustc_errors::Applicability; +use rustc_hir::LangItem; +use rustc_hir::def::DefKind; +use rustc_middle::span_bug; +use rustc_middle::thir::visit::{self, Visitor}; +use rustc_middle::thir::{BodyTy, Expr, ExprId, ExprKind, Thir}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; + +pub(crate) fn check_tail_calls(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), ErrorGuaranteed> { + let (thir, expr) = tcx.thir_body(def)?; + let thir = &thir.borrow(); + + // If `thir` is empty, a type error occurred, skip this body. + if thir.exprs.is_empty() { + return Ok(()); + } + + let is_closure = matches!(tcx.def_kind(def), DefKind::Closure); + let caller_ty = tcx.type_of(def).skip_binder(); + + let mut visitor = TailCallCkVisitor { + tcx, + thir, + found_errors: Ok(()), + // FIXME(#132279): we're clearly in a body here. + typing_env: ty::TypingEnv::non_body_analysis(tcx, def), + is_closure, + caller_ty, + }; + + visitor.visit_expr(&thir[expr]); + + visitor.found_errors +} + +struct TailCallCkVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + thir: &'a Thir<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + /// Whatever the currently checked body is one of a closure + is_closure: bool, + /// The result of the checks, `Err(_)` if there was a problem with some + /// tail call, `Ok(())` if all of them were fine. + found_errors: Result<(), ErrorGuaranteed>, + /// Type of the caller function. + caller_ty: Ty<'tcx>, +} + +impl<'tcx> TailCallCkVisitor<'_, 'tcx> { + fn check_tail_call(&mut self, call: &Expr<'_>, expr: &Expr<'_>) { + if self.is_closure { + self.report_in_closure(expr); + return; + } + + let BodyTy::Fn(caller_sig) = self.thir.body_type else { + span_bug!( + call.span, + "`become` outside of functions should have been disallowed by hit_typeck" + ) + }; + + let ExprKind::Scope { value, .. } = call.kind else { + span_bug!(call.span, "expected scope, found: {call:?}") + }; + let value = &self.thir[value]; + + if matches!( + value.kind, + ExprKind::Binary { .. } + | ExprKind::Unary { .. } + | ExprKind::AssignOp { .. } + | ExprKind::Index { .. } + ) { + self.report_builtin_op(call, expr); + return; + } + + let ExprKind::Call { ty, fun, ref args, from_hir_call, fn_span } = value.kind else { + self.report_non_call(value, expr); + return; + }; + + if !from_hir_call { + self.report_op(ty, args, fn_span, expr); + } + + // Closures in thir look something akin to + // `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}` + // So we have to check for them in this weird way... + if let &ty::FnDef(did, substs) = ty.kind() { + let parent = self.tcx.parent(did); + let fn_ = self.tcx.require_lang_item(LangItem::Fn, Some(expr.span)); + let fn_once = self.tcx.require_lang_item(LangItem::FnOnce, Some(expr.span)); + let fn_mut = self.tcx.require_lang_item(LangItem::FnMut, Some(expr.span)); + if [fn_, fn_once, fn_mut].contains(&parent) { + if substs.first().and_then(|arg| arg.as_type()).is_some_and(|t| t.is_closure()) { + self.report_calling_closure( + &self.thir[fun], + substs[1].as_type().unwrap(), + expr, + ); + + // Tail calling is likely to cause unrelated errors (ABI, argument mismatches) + return; + } + }; + } + + // Erase regions since tail calls don't care about lifetimes + let callee_sig = + self.tcx.normalize_erasing_late_bound_regions(self.typing_env, ty.fn_sig(self.tcx)); + + if caller_sig.abi != callee_sig.abi { + self.report_abi_mismatch(expr.span, caller_sig.abi, callee_sig.abi); + } + + if caller_sig.inputs_and_output != callee_sig.inputs_and_output { + if caller_sig.inputs() != callee_sig.inputs() { + self.report_arguments_mismatch(expr.span, caller_sig, callee_sig); + } + + if caller_sig.output() != callee_sig.output() { + span_bug!(expr.span, "hir typeck should have checked the return type already"); + } + } + + { + let caller_needs_location = self.needs_location(self.caller_ty); + let callee_needs_location = self.needs_location(ty); + + if caller_needs_location != callee_needs_location { + self.report_track_caller_mismatch(expr.span, caller_needs_location); + } + } + + if caller_sig.c_variadic { + self.report_c_variadic_caller(expr.span); + } + + if callee_sig.c_variadic { + self.report_c_variadic_callee(expr.span); + } + } + + /// Returns true if function of type `ty` needs location argument + /// (i.e. if a function is marked as `#[track_caller]`) + fn needs_location(&self, ty: Ty<'tcx>) -> bool { + if let &ty::FnDef(did, substs) = ty.kind() { + let instance = + ty::Instance::expect_resolve(self.tcx, self.typing_env, did, substs, DUMMY_SP) + .polymorphize(self.tcx); + + instance.def.requires_caller_location(self.tcx) + } else { + false + } + } + + fn report_in_closure(&mut self, expr: &Expr<'_>) { + let err = self.tcx.dcx().span_err(expr.span, "`become` is not allowed in closures"); + self.found_errors = Err(err); + } + + fn report_builtin_op(&mut self, value: &Expr<'_>, expr: &Expr<'_>) { + let err = self + .tcx + .dcx() + .struct_span_err(value.span, "`become` does not support operators") + .with_note("using `become` on a builtin operator is not useful") + .with_span_suggestion( + value.span.until(expr.span), + "try using `return` instead", + "return ", + Applicability::MachineApplicable, + ) + .emit(); + self.found_errors = Err(err); + } + + fn report_op(&mut self, fun_ty: Ty<'_>, args: &[ExprId], fn_span: Span, expr: &Expr<'_>) { + let mut err = + self.tcx.dcx().struct_span_err(fn_span, "`become` does not support operators"); + + if let &ty::FnDef(did, _substs) = fun_ty.kind() + && let parent = self.tcx.parent(did) + && matches!(self.tcx.def_kind(parent), DefKind::Trait) + && let Some(method) = op_trait_as_method_name(self.tcx, parent) + { + match args { + &[arg] => { + let arg = &self.thir[arg]; + + err.multipart_suggestion( + "try using the method directly", + vec![ + (fn_span.shrink_to_lo().until(arg.span), "(".to_owned()), + (arg.span.shrink_to_hi(), format!(").{method}()")), + ], + Applicability::MaybeIncorrect, + ); + } + &[lhs, rhs] => { + let lhs = &self.thir[lhs]; + let rhs = &self.thir[rhs]; + + err.multipart_suggestion( + "try using the method directly", + vec![ + (lhs.span.shrink_to_lo(), format!("(")), + (lhs.span.between(rhs.span), format!(").{method}(")), + (rhs.span.between(expr.span.shrink_to_hi()), ")".to_owned()), + ], + Applicability::MaybeIncorrect, + ); + } + _ => span_bug!(expr.span, "operator with more than 2 args? {args:?}"), + } + } + + self.found_errors = Err(err.emit()); + } + + fn report_non_call(&mut self, value: &Expr<'_>, expr: &Expr<'_>) { + let err = self + .tcx + .dcx() + .struct_span_err(value.span, "`become` requires a function call") + .with_span_note(value.span, "not a function call") + .with_span_suggestion( + value.span.until(expr.span), + "try using `return` instead", + "return ", + Applicability::MaybeIncorrect, + ) + .emit(); + self.found_errors = Err(err); + } + + fn report_calling_closure(&mut self, fun: &Expr<'_>, tupled_args: Ty<'_>, expr: &Expr<'_>) { + let underscored_args = match tupled_args.kind() { + ty::Tuple(tys) if tys.is_empty() => "".to_owned(), + ty::Tuple(tys) => std::iter::repeat("_, ").take(tys.len() - 1).chain(["_"]).collect(), + _ => "_".to_owned(), + }; + + let err = self + .tcx + .dcx() + .struct_span_err(expr.span, "tail calling closures directly is not allowed") + .with_multipart_suggestion( + "try casting the closure to a function pointer type", + vec![ + (fun.span.shrink_to_lo(), "(".to_owned()), + (fun.span.shrink_to_hi(), format!(" as fn({underscored_args}) -> _)")), + ], + Applicability::MaybeIncorrect, + ) + .emit(); + self.found_errors = Err(err); + } + + fn report_abi_mismatch(&mut self, sp: Span, caller_abi: ExternAbi, callee_abi: ExternAbi) { + let err = self + .tcx + .dcx() + .struct_span_err(sp, "mismatched function ABIs") + .with_note("`become` requires caller and callee to have the same ABI") + .with_note(format!("caller ABI is `{caller_abi}`, while callee ABI is `{callee_abi}`")) + .emit(); + self.found_errors = Err(err); + } + + fn report_arguments_mismatch( + &mut self, + sp: Span, + caller_sig: ty::FnSig<'_>, + callee_sig: ty::FnSig<'_>, + ) { + let err = self + .tcx + .dcx() + .struct_span_err(sp, "mismatched signatures") + .with_note("`become` requires caller and callee to have matching signatures") + .with_note(format!("caller signature: `{caller_sig}`")) + .with_note(format!("callee signature: `{callee_sig}`")) + .emit(); + self.found_errors = Err(err); + } + + fn report_track_caller_mismatch(&mut self, sp: Span, caller_needs_location: bool) { + let err = match caller_needs_location { + true => self + .tcx + .dcx() + .struct_span_err( + sp, + "a function marked with `#[track_caller]` cannot tail-call one that is not", + ) + .emit(), + false => self + .tcx + .dcx() + .struct_span_err( + sp, + "a function mot marked with `#[track_caller]` cannot tail-call one that is", + ) + .emit(), + }; + + self.found_errors = Err(err); + } + + fn report_c_variadic_caller(&mut self, sp: Span) { + let err = self + .tcx + .dcx() + // FIXME(explicit_tail_calls): highlight the `...` + .struct_span_err(sp, "tail-calls are not allowed in c-variadic functions") + .emit(); + + self.found_errors = Err(err); + } + + fn report_c_variadic_callee(&mut self, sp: Span) { + let err = self + .tcx + .dcx() + // FIXME(explicit_tail_calls): highlight the function or something... + .struct_span_err(sp, "c-variadic functions can't be tail-called") + .emit(); + + self.found_errors = Err(err); + } +} + +impl<'a, 'tcx> Visitor<'a, 'tcx> for TailCallCkVisitor<'a, 'tcx> { + fn thir(&self) -> &'a Thir<'tcx> { + &self.thir + } + + fn visit_expr(&mut self, expr: &'a Expr<'tcx>) { + if let ExprKind::Become { value } = expr.kind { + let call = &self.thir[value]; + self.check_tail_call(call, expr); + } + + visit::walk_expr(self, expr); + } +} + +fn op_trait_as_method_name(tcx: TyCtxt<'_>, trait_did: DefId) -> Option<&'static str> { + let trait_did = Some(trait_did); + let items = tcx.lang_items(); + let m = match () { + _ if trait_did == items.get(LangItem::Add) => "add", + _ if trait_did == items.get(LangItem::Sub) => "sub", + _ if trait_did == items.get(LangItem::Mul) => "mul", + _ if trait_did == items.get(LangItem::Div) => "div", + _ if trait_did == items.get(LangItem::Rem) => "rem", + _ if trait_did == items.get(LangItem::Neg) => "neg", + _ if trait_did == items.get(LangItem::Not) => "not", + _ if trait_did == items.get(LangItem::BitXor) => "bitxor", + _ if trait_did == items.get(LangItem::BitAnd) => "bitand", + _ if trait_did == items.get(LangItem::BitOr) => "bitor", + _ if trait_did == items.get(LangItem::Shl) => "shl", + _ if trait_did == items.get(LangItem::Shr) => "shr", + _ if trait_did == items.get(LangItem::AddAssign) => "add_assign", + _ if trait_did == items.get(LangItem::SubAssign) => "sub_assign", + _ if trait_did == items.get(LangItem::MulAssign) => "mul_assign", + _ if trait_did == items.get(LangItem::DivAssign) => "div_assign", + _ if trait_did == items.get(LangItem::RemAssign) => "rem_assign", + _ if trait_did == items.get(LangItem::BitXorAssign) => "bitxor_assign", + _ if trait_did == items.get(LangItem::BitAndAssign) => "bitand_assign", + _ if trait_did == items.get(LangItem::BitOrAssign) => "bitor_assign", + _ if trait_did == items.get(LangItem::ShlAssign) => "shl_assign", + _ if trait_did == items.get(LangItem::ShrAssign) => "shr_assign", + _ if trait_did == items.get(LangItem::Index) => "index", + _ if trait_did == items.get(LangItem::IndexMut) => "index_mut", + _ => return None, + }; + + Some(m) +} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 3dbb552cdbbe..833e5019865e 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -12,6 +12,7 @@ // tidy-alphabetical-end mod build; +mod check_tail_calls; mod check_unsafety; mod errors; pub mod lints; @@ -28,6 +29,7 @@ pub fn provide(providers: &mut Providers) { providers.closure_saved_names_of_captured_variables = build::closure_saved_names_of_captured_variables; providers.check_unsafety = check_unsafety::check_unsafety; + providers.check_tail_calls = check_tail_calls::check_tail_calls; providers.thir_body = thir::cx::thir_body; providers.hooks.thir_tree = thir::print::thir_tree; providers.hooks.thir_flat = thir::print::thir_flat; diff --git a/tests/ui/explicit-tail-calls/become-macro.rs b/tests/ui/explicit-tail-calls/become-macro.rs new file mode 100644 index 000000000000..0bbc483b2c70 --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-macro.rs @@ -0,0 +1,13 @@ +//@ check-pass +#![allow(incomplete_features)] +#![feature(explicit_tail_calls, decl_macro)] + +macro call($f:expr $(, $args:expr)* $(,)?) { + ($f)($($args),*) +} + +fn main() { + become call!(f); +} + +fn f() {} diff --git a/tests/ui/explicit-tail-calls/become-operator.fixed b/tests/ui/explicit-tail-calls/become-operator.fixed new file mode 100644 index 000000000000..36925d21b7a9 --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-operator.fixed @@ -0,0 +1,42 @@ +//@ run-rustfix +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] +#![allow(unused)] +use std::num::Wrapping; +use std::ops::{Not, Add, BitXorAssign}; + +// built-ins and overloaded operators are handled differently + +fn f(a: u64, b: u64) -> u64 { + return a + b; //~ error: `become` does not support operators +} + +fn g(a: String, b: &str) -> String { + become (a).add(b); //~ error: `become` does not support operators +} + +fn h(x: u64) -> u64 { + return !x; //~ error: `become` does not support operators +} + +fn i_do_not_know_any_more_letters(x: Wrapping) -> Wrapping { + become (x).not(); //~ error: `become` does not support operators +} + +fn builtin_index(x: &[u8], i: usize) -> u8 { + return x[i] //~ error: `become` does not support operators +} + +// FIXME(explicit_tail_calls): overloaded index is represented like `[&]*x.index(i)`, +// and so need additional handling + +fn a(a: &mut u8, _: u8) { + return *a ^= 1; //~ error: `become` does not support operators +} + +fn b(b: &mut Wrapping, _: u8) { + become (*b).bitxor_assign(1); //~ error: `become` does not support operators +} + + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/become-operator.rs b/tests/ui/explicit-tail-calls/become-operator.rs new file mode 100644 index 000000000000..b1af3f59df7f --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-operator.rs @@ -0,0 +1,42 @@ +//@ run-rustfix +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] +#![allow(unused)] +use std::num::Wrapping; +use std::ops::{Not, Add, BitXorAssign}; + +// built-ins and overloaded operators are handled differently + +fn f(a: u64, b: u64) -> u64 { + become a + b; //~ error: `become` does not support operators +} + +fn g(a: String, b: &str) -> String { + become a + b; //~ error: `become` does not support operators +} + +fn h(x: u64) -> u64 { + become !x; //~ error: `become` does not support operators +} + +fn i_do_not_know_any_more_letters(x: Wrapping) -> Wrapping { + become !x; //~ error: `become` does not support operators +} + +fn builtin_index(x: &[u8], i: usize) -> u8 { + become x[i] //~ error: `become` does not support operators +} + +// FIXME(explicit_tail_calls): overloaded index is represented like `[&]*x.index(i)`, +// and so need additional handling + +fn a(a: &mut u8, _: u8) { + become *a ^= 1; //~ error: `become` does not support operators +} + +fn b(b: &mut Wrapping, _: u8) { + become *b ^= 1; //~ error: `become` does not support operators +} + + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/become-operator.stderr b/tests/ui/explicit-tail-calls/become-operator.stderr new file mode 100644 index 000000000000..26e4343faaea --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-operator.stderr @@ -0,0 +1,75 @@ +error: `become` does not support operators + --> $DIR/become-operator.rs:11:12 + | +LL | become a + b; + | -------^^^^^ + | | + | help: try using `return` instead: `return` + | + = note: using `become` on a builtin operator is not useful + +error: `become` does not support operators + --> $DIR/become-operator.rs:15:12 + | +LL | become a + b; + | ^^^^^ + | +help: try using the method directly + | +LL | become (a).add(b); + | + ~~~~~~ + + +error: `become` does not support operators + --> $DIR/become-operator.rs:19:12 + | +LL | become !x; + | -------^^ + | | + | help: try using `return` instead: `return` + | + = note: using `become` on a builtin operator is not useful + +error: `become` does not support operators + --> $DIR/become-operator.rs:23:12 + | +LL | become !x; + | ^^ + | +help: try using the method directly + | +LL | become (x).not(); + | ~ +++++++ + +error: `become` does not support operators + --> $DIR/become-operator.rs:27:12 + | +LL | become x[i] + | -------^^^^ + | | + | help: try using `return` instead: `return` + | + = note: using `become` on a builtin operator is not useful + +error: `become` does not support operators + --> $DIR/become-operator.rs:34:12 + | +LL | become *a ^= 1; + | -------^^^^^^^ + | | + | help: try using `return` instead: `return` + | + = note: using `become` on a builtin operator is not useful + +error: `become` does not support operators + --> $DIR/become-operator.rs:38:12 + | +LL | become *b ^= 1; + | ^^^^^^^ + | +help: try using the method directly + | +LL | become (*b).bitxor_assign(1); + | + ~~~~~~~~~~~~~~~~ + + +error: aborting due to 7 previous errors + diff --git a/tests/ui/explicit-tail-calls/become-uncallable.fixed b/tests/ui/explicit-tail-calls/become-uncallable.fixed new file mode 100644 index 000000000000..af6785e08fe6 --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-uncallable.fixed @@ -0,0 +1,18 @@ +//@ run-rustfix +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] +#![allow(unused)] + +fn f() -> u64 { + return 1; //~ error: `become` requires a function call +} + +fn g() { + return { h() }; //~ error: `become` requires a function call +} + +fn h() { + return *&g(); //~ error: `become` requires a function call +} + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/become-uncallable.rs b/tests/ui/explicit-tail-calls/become-uncallable.rs new file mode 100644 index 000000000000..60026b0d5d6f --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-uncallable.rs @@ -0,0 +1,18 @@ +//@ run-rustfix +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] +#![allow(unused)] + +fn f() -> u64 { + become 1; //~ error: `become` requires a function call +} + +fn g() { + become { h() }; //~ error: `become` requires a function call +} + +fn h() { + become *&g(); //~ error: `become` requires a function call +} + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/become-uncallable.stderr b/tests/ui/explicit-tail-calls/become-uncallable.stderr new file mode 100644 index 000000000000..90f10b05d2af --- /dev/null +++ b/tests/ui/explicit-tail-calls/become-uncallable.stderr @@ -0,0 +1,44 @@ +error: `become` requires a function call + --> $DIR/become-uncallable.rs:7:12 + | +LL | become 1; + | -------^ + | | + | help: try using `return` instead: `return` + | +note: not a function call + --> $DIR/become-uncallable.rs:7:12 + | +LL | become 1; + | ^ + +error: `become` requires a function call + --> $DIR/become-uncallable.rs:11:12 + | +LL | become { h() }; + | -------^^^^^^^ + | | + | help: try using `return` instead: `return` + | +note: not a function call + --> $DIR/become-uncallable.rs:11:12 + | +LL | become { h() }; + | ^^^^^^^ + +error: `become` requires a function call + --> $DIR/become-uncallable.rs:15:12 + | +LL | become *&g(); + | -------^^^^^ + | | + | help: try using `return` instead: `return` + | +note: not a function call + --> $DIR/become-uncallable.rs:15:12 + | +LL | become *&g(); + | ^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/explicit-tail-calls/closure.fixed b/tests/ui/explicit-tail-calls/closure.fixed new file mode 100644 index 000000000000..18384d91e0ff --- /dev/null +++ b/tests/ui/explicit-tail-calls/closure.fixed @@ -0,0 +1,31 @@ +//@ run-rustfix +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] + +fn a() { + become ((|| ()) as fn() -> _)(); + //~^ ERROR: tail calling closures directly is not allowed +} + +fn aa((): ()) { + become ((|()| ()) as fn(_) -> _)(()); + //~^ ERROR: tail calling closures directly is not allowed +} + +fn aaa((): (), _: i32) { + become ((|(), _| ()) as fn(_, _) -> _)((), 1); + //~^ ERROR: tail calling closures directly is not allowed +} + +fn v((): (), ((), ()): ((), ())) -> (((), ()), ()) { + let f = |(), ((), ())| (((), ()), ()); + become (f as fn(_, _) -> _)((), ((), ())); + //~^ ERROR: tail calling closures directly is not allowed +} + +fn main() { + a(); + aa(()); + aaa((), 1); + v((), ((), ())); +} diff --git a/tests/ui/explicit-tail-calls/closure.rs b/tests/ui/explicit-tail-calls/closure.rs new file mode 100644 index 000000000000..b65ebed594bf --- /dev/null +++ b/tests/ui/explicit-tail-calls/closure.rs @@ -0,0 +1,31 @@ +//@ run-rustfix +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] + +fn a() { + become (|| ())(); + //~^ ERROR: tail calling closures directly is not allowed +} + +fn aa((): ()) { + become (|()| ())(()); + //~^ ERROR: tail calling closures directly is not allowed +} + +fn aaa((): (), _: i32) { + become (|(), _| ())((), 1); + //~^ ERROR: tail calling closures directly is not allowed +} + +fn v((): (), ((), ()): ((), ())) -> (((), ()), ()) { + let f = |(), ((), ())| (((), ()), ()); + become f((), ((), ())); + //~^ ERROR: tail calling closures directly is not allowed +} + +fn main() { + a(); + aa(()); + aaa((), 1); + v((), ((), ())); +} diff --git a/tests/ui/explicit-tail-calls/closure.stderr b/tests/ui/explicit-tail-calls/closure.stderr new file mode 100644 index 000000000000..5d57bece68e2 --- /dev/null +++ b/tests/ui/explicit-tail-calls/closure.stderr @@ -0,0 +1,46 @@ +error: tail calling closures directly is not allowed + --> $DIR/closure.rs:6:5 + | +LL | become (|| ())(); + | ^^^^^^^^^^^^^^^^ + | +help: try casting the closure to a function pointer type + | +LL | become ((|| ()) as fn() -> _)(); + | + +++++++++++++ + +error: tail calling closures directly is not allowed + --> $DIR/closure.rs:11:5 + | +LL | become (|()| ())(()); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: try casting the closure to a function pointer type + | +LL | become ((|()| ()) as fn(_) -> _)(()); + | + ++++++++++++++ + +error: tail calling closures directly is not allowed + --> $DIR/closure.rs:16:5 + | +LL | become (|(), _| ())((), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try casting the closure to a function pointer type + | +LL | become ((|(), _| ()) as fn(_, _) -> _)((), 1); + | + +++++++++++++++++ + +error: tail calling closures directly is not allowed + --> $DIR/closure.rs:22:5 + | +LL | become f((), ((), ())); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try casting the closure to a function pointer type + | +LL | become (f as fn(_, _) -> _)((), ((), ())); + | + +++++++++++++++++ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/explicit-tail-calls/in-closure.rs b/tests/ui/explicit-tail-calls/in-closure.rs new file mode 100644 index 000000000000..225bc0a7fd76 --- /dev/null +++ b/tests/ui/explicit-tail-calls/in-closure.rs @@ -0,0 +1,8 @@ +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] + +fn main() { + || become f(); //~ error: `become` is not allowed in closures +} + +fn f() {} diff --git a/tests/ui/explicit-tail-calls/in-closure.stderr b/tests/ui/explicit-tail-calls/in-closure.stderr new file mode 100644 index 000000000000..d221f732e938 --- /dev/null +++ b/tests/ui/explicit-tail-calls/in-closure.stderr @@ -0,0 +1,8 @@ +error: `become` is not allowed in closures + --> $DIR/in-closure.rs:5:8 + | +LL | || become f(); + | ^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/explicit-tail-calls/signature-mismatch.rs b/tests/ui/explicit-tail-calls/signature-mismatch.rs new file mode 100644 index 000000000000..3a01cc1ca2fd --- /dev/null +++ b/tests/ui/explicit-tail-calls/signature-mismatch.rs @@ -0,0 +1,33 @@ +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] +#![feature(c_variadic)] + +fn _f0((): ()) { + become _g0(); //~ error: mismatched signatures +} + +fn _g0() {} + + +fn _f1() { + become _g1(()); //~ error: mismatched signatures +} + +fn _g1((): ()) {} + + +extern "C" fn _f2() { + become _g2(); //~ error: mismatched function ABIs +} + +fn _g2() {} + + +fn _f3() { + become _g3(); //~ error: mismatched function ABIs +} + +extern "C" fn _g3() {} + + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/signature-mismatch.stderr b/tests/ui/explicit-tail-calls/signature-mismatch.stderr new file mode 100644 index 000000000000..ba9e9dcb9848 --- /dev/null +++ b/tests/ui/explicit-tail-calls/signature-mismatch.stderr @@ -0,0 +1,40 @@ +error: mismatched signatures + --> $DIR/signature-mismatch.rs:6:5 + | +LL | become _g0(); + | ^^^^^^^^^^^^ + | + = note: `become` requires caller and callee to have matching signatures + = note: caller signature: `fn(())` + = note: callee signature: `fn()` + +error: mismatched signatures + --> $DIR/signature-mismatch.rs:13:5 + | +LL | become _g1(()); + | ^^^^^^^^^^^^^^ + | + = note: `become` requires caller and callee to have matching signatures + = note: caller signature: `fn()` + = note: callee signature: `fn(())` + +error: mismatched function ABIs + --> $DIR/signature-mismatch.rs:20:5 + | +LL | become _g2(); + | ^^^^^^^^^^^^ + | + = note: `become` requires caller and callee to have the same ABI + = note: caller ABI is `"C"`, while callee ABI is `"Rust"` + +error: mismatched function ABIs + --> $DIR/signature-mismatch.rs:27:5 + | +LL | become _g3(); + | ^^^^^^^^^^^^ + | + = note: `become` requires caller and callee to have the same ABI + = note: caller ABI is `"Rust"`, while callee ABI is `"C"` + +error: aborting due to 4 previous errors + From 3208b8649e2e117b08e5bbcae46061d44bf72203 Mon Sep 17 00:00:00 2001 From: Maybe Lapkin Date: Fri, 29 Nov 2024 04:28:02 +0100 Subject: [PATCH 037/107] use `expect(incomplete_feature)` instead of `allow` in tail call tests --- tests/ui/explicit-tail-calls/become-macro.rs | 2 +- tests/ui/explicit-tail-calls/become-operator.fixed | 2 +- tests/ui/explicit-tail-calls/become-operator.rs | 2 +- tests/ui/explicit-tail-calls/become-outside.rs | 2 +- tests/ui/explicit-tail-calls/become-uncallable.fixed | 2 +- tests/ui/explicit-tail-calls/become-uncallable.rs | 2 +- tests/ui/explicit-tail-calls/closure.fixed | 2 +- tests/ui/explicit-tail-calls/closure.rs | 2 +- tests/ui/explicit-tail-calls/constck.rs | 2 +- tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs | 2 +- tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs | 2 +- tests/ui/explicit-tail-calls/ctfe-arg-move.rs | 2 +- tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs | 2 +- tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs | 2 +- tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs | 2 +- tests/ui/explicit-tail-calls/drop-order.rs | 2 +- tests/ui/explicit-tail-calls/in-closure.rs | 2 +- tests/ui/explicit-tail-calls/return-lifetime-sub.rs | 2 +- tests/ui/explicit-tail-calls/return-mismatches.rs | 2 +- tests/ui/explicit-tail-calls/signature-mismatch.rs | 2 +- tests/ui/explicit-tail-calls/unsafeck.rs | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/ui/explicit-tail-calls/become-macro.rs b/tests/ui/explicit-tail-calls/become-macro.rs index 0bbc483b2c70..0a9d069ceb3c 100644 --- a/tests/ui/explicit-tail-calls/become-macro.rs +++ b/tests/ui/explicit-tail-calls/become-macro.rs @@ -1,5 +1,5 @@ //@ check-pass -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls, decl_macro)] macro call($f:expr $(, $args:expr)* $(,)?) { diff --git a/tests/ui/explicit-tail-calls/become-operator.fixed b/tests/ui/explicit-tail-calls/become-operator.fixed index 36925d21b7a9..24baef42d69a 100644 --- a/tests/ui/explicit-tail-calls/become-operator.fixed +++ b/tests/ui/explicit-tail-calls/become-operator.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] #![allow(unused)] use std::num::Wrapping; diff --git a/tests/ui/explicit-tail-calls/become-operator.rs b/tests/ui/explicit-tail-calls/become-operator.rs index b1af3f59df7f..e547e979b648 100644 --- a/tests/ui/explicit-tail-calls/become-operator.rs +++ b/tests/ui/explicit-tail-calls/become-operator.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] #![allow(unused)] use std::num::Wrapping; diff --git a/tests/ui/explicit-tail-calls/become-outside.rs b/tests/ui/explicit-tail-calls/become-outside.rs index 9c90d929111e..29738bb9a299 100644 --- a/tests/ui/explicit-tail-calls/become-outside.rs +++ b/tests/ui/explicit-tail-calls/become-outside.rs @@ -1,5 +1,5 @@ //@ revisions: constant array -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] #[cfg(constant)] diff --git a/tests/ui/explicit-tail-calls/become-uncallable.fixed b/tests/ui/explicit-tail-calls/become-uncallable.fixed index af6785e08fe6..b77c46ea4354 100644 --- a/tests/ui/explicit-tail-calls/become-uncallable.fixed +++ b/tests/ui/explicit-tail-calls/become-uncallable.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] #![allow(unused)] diff --git a/tests/ui/explicit-tail-calls/become-uncallable.rs b/tests/ui/explicit-tail-calls/become-uncallable.rs index 60026b0d5d6f..a73b9258aaab 100644 --- a/tests/ui/explicit-tail-calls/become-uncallable.rs +++ b/tests/ui/explicit-tail-calls/become-uncallable.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] #![allow(unused)] diff --git a/tests/ui/explicit-tail-calls/closure.fixed b/tests/ui/explicit-tail-calls/closure.fixed index 18384d91e0ff..4af71c5d4cc9 100644 --- a/tests/ui/explicit-tail-calls/closure.fixed +++ b/tests/ui/explicit-tail-calls/closure.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] fn a() { diff --git a/tests/ui/explicit-tail-calls/closure.rs b/tests/ui/explicit-tail-calls/closure.rs index b65ebed594bf..79a1b5296b0a 100644 --- a/tests/ui/explicit-tail-calls/closure.rs +++ b/tests/ui/explicit-tail-calls/closure.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] fn a() { diff --git a/tests/ui/explicit-tail-calls/constck.rs b/tests/ui/explicit-tail-calls/constck.rs index 938f15f12c09..36fc3ef6f995 100644 --- a/tests/ui/explicit-tail-calls/constck.rs +++ b/tests/ui/explicit-tail-calls/constck.rs @@ -1,4 +1,4 @@ -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] const fn f() { diff --git a/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs b/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs index 5a105ee4eb59..0a61c90bd00a 100644 --- a/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs +++ b/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.rs @@ -1,4 +1,4 @@ -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] pub const fn test(_: &Type) { diff --git a/tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs b/tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs index 50bf6c946ca8..a34482a35272 100644 --- a/tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs +++ b/tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs @@ -1,5 +1,5 @@ //@ check-pass -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] pub const fn test(x: &Type) { diff --git a/tests/ui/explicit-tail-calls/ctfe-arg-move.rs b/tests/ui/explicit-tail-calls/ctfe-arg-move.rs index 88ff3a4a5ad1..610eb74a91e3 100644 --- a/tests/ui/explicit-tail-calls/ctfe-arg-move.rs +++ b/tests/ui/explicit-tail-calls/ctfe-arg-move.rs @@ -1,5 +1,5 @@ //@ check-pass -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] pub const fn test(s: String) -> String { diff --git a/tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs b/tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs index 86041b669601..53d46d92bd7b 100644 --- a/tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs +++ b/tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs @@ -1,5 +1,5 @@ //@ run-pass -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] /// A very unnecessarily complicated "implementation" of the Collatz conjecture. diff --git a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs index 54e68b2b7f79..2a04d4893e68 100644 --- a/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs +++ b/tests/ui/explicit-tail-calls/ctfe-id-unlimited.rs @@ -1,6 +1,6 @@ //@ revisions: become return //@ [become] run-pass -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] // This is an identity function (`|x| x`), but implemented using recursion. diff --git a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs index 3d69cde29895..fba4a2692afe 100644 --- a/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs +++ b/tests/ui/explicit-tail-calls/ctfe-tail-call-panic.rs @@ -1,4 +1,4 @@ -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] pub const fn f() { diff --git a/tests/ui/explicit-tail-calls/drop-order.rs b/tests/ui/explicit-tail-calls/drop-order.rs index e20730446ec5..242336be4845 100644 --- a/tests/ui/explicit-tail-calls/drop-order.rs +++ b/tests/ui/explicit-tail-calls/drop-order.rs @@ -1,7 +1,7 @@ // FIXME(explicit_tail_calls): enable this test once rustc_codegen_ssa supports tail calls //@ ignore-test: tail calls are not implemented in rustc_codegen_ssa yet, so this causes 🧊 //@ run-pass -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] use std::cell::RefCell; diff --git a/tests/ui/explicit-tail-calls/in-closure.rs b/tests/ui/explicit-tail-calls/in-closure.rs index 225bc0a7fd76..b23ff5a1e05b 100644 --- a/tests/ui/explicit-tail-calls/in-closure.rs +++ b/tests/ui/explicit-tail-calls/in-closure.rs @@ -1,4 +1,4 @@ -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] fn main() { diff --git a/tests/ui/explicit-tail-calls/return-lifetime-sub.rs b/tests/ui/explicit-tail-calls/return-lifetime-sub.rs index 1243fba9b588..df0982cc02bd 100644 --- a/tests/ui/explicit-tail-calls/return-lifetime-sub.rs +++ b/tests/ui/explicit-tail-calls/return-lifetime-sub.rs @@ -1,5 +1,5 @@ //@ check-pass -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] fn _f<'a>() -> &'a [u8] { diff --git a/tests/ui/explicit-tail-calls/return-mismatches.rs b/tests/ui/explicit-tail-calls/return-mismatches.rs index 935a1a1d28b0..e48766b89b00 100644 --- a/tests/ui/explicit-tail-calls/return-mismatches.rs +++ b/tests/ui/explicit-tail-calls/return-mismatches.rs @@ -1,4 +1,4 @@ -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] fn _f0<'a>() -> &'static [u8] { diff --git a/tests/ui/explicit-tail-calls/signature-mismatch.rs b/tests/ui/explicit-tail-calls/signature-mismatch.rs index 3a01cc1ca2fd..a32ac9d8bfee 100644 --- a/tests/ui/explicit-tail-calls/signature-mismatch.rs +++ b/tests/ui/explicit-tail-calls/signature-mismatch.rs @@ -1,4 +1,4 @@ -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] #![feature(c_variadic)] diff --git a/tests/ui/explicit-tail-calls/unsafeck.rs b/tests/ui/explicit-tail-calls/unsafeck.rs index 872a70ca3a0a..f8a8140cedc3 100644 --- a/tests/ui/explicit-tail-calls/unsafeck.rs +++ b/tests/ui/explicit-tail-calls/unsafeck.rs @@ -1,4 +1,4 @@ -#![allow(incomplete_features)] +#![expect(incomplete_features)] #![feature(explicit_tail_calls)] const fn f() { From d93ea6bc79a06bcf6c8cbbd3af24f8724acd5009 Mon Sep 17 00:00:00 2001 From: Maybe Lapkin Date: Fri, 29 Nov 2024 20:25:57 +0100 Subject: [PATCH 038/107] simplify things by using `tcx.fn_trait_kind_from_def_id` --- .../rustc_mir_build/src/check_tail_calls.rs | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 911a6cb7de60..f7264341c0a8 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -91,22 +91,16 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { // Closures in thir look something akin to // `for<'a> extern "rust-call" fn(&'a [closure@...], ()) -> <[closure@...] as FnOnce<()>>::Output {<[closure@...] as Fn<()>>::call}` // So we have to check for them in this weird way... - if let &ty::FnDef(did, substs) = ty.kind() { + if let &ty::FnDef(did, args) = ty.kind() { let parent = self.tcx.parent(did); - let fn_ = self.tcx.require_lang_item(LangItem::Fn, Some(expr.span)); - let fn_once = self.tcx.require_lang_item(LangItem::FnOnce, Some(expr.span)); - let fn_mut = self.tcx.require_lang_item(LangItem::FnMut, Some(expr.span)); - if [fn_, fn_once, fn_mut].contains(&parent) { - if substs.first().and_then(|arg| arg.as_type()).is_some_and(|t| t.is_closure()) { - self.report_calling_closure( - &self.thir[fun], - substs[1].as_type().unwrap(), - expr, - ); + if self.tcx.fn_trait_kind_from_def_id(parent).is_some() + && args.first().and_then(|arg| arg.as_type()).is_some_and(Ty::is_closure) + { + self.report_calling_closure(&self.thir[fun], args[1].as_type().unwrap(), expr); - // Tail calling is likely to cause unrelated errors (ABI, argument mismatches) - return; - } + // Tail calling is likely to cause unrelated errors (ABI, argument mismatches), + // skip them, producing an error about calling a closure is enough. + return; }; } From ef5808a03596385b32bdb74de55ac10c6e74f0ba Mon Sep 17 00:00:00 2001 From: Maybe Lapkin Date: Fri, 29 Nov 2024 20:26:30 +0100 Subject: [PATCH 039/107] add a fixme for tailcalls with opaque types --- compiler/rustc_mir_build/src/check_tail_calls.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index f7264341c0a8..e6a25634e29d 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -117,6 +117,14 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { self.report_arguments_mismatch(expr.span, caller_sig, callee_sig); } + // FIXME(explicit_tail_calls): this currenly fails for cases where opaques are used. + // e.g. + // ``` + // fn a() -> impl Sized { become b() } // ICE + // fn b() -> u8 { 0 } + // ``` + // we should think what is the expected behavior here. + // (we should probably just accept this by revealing opaques?) if caller_sig.output() != callee_sig.output() { span_bug!(expr.span, "hir typeck should have checked the return type already"); } From c6454dd582c66a53bbf91947098af59689f61c1e Mon Sep 17 00:00:00 2001 From: Maybe Lapkin Date: Fri, 29 Nov 2024 20:27:24 +0100 Subject: [PATCH 040/107] don't polymorphize without a reason to --- compiler/rustc_mir_build/src/check_tail_calls.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index e6a25634e29d..6eade2049702 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -153,8 +153,7 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { fn needs_location(&self, ty: Ty<'tcx>) -> bool { if let &ty::FnDef(did, substs) = ty.kind() { let instance = - ty::Instance::expect_resolve(self.tcx, self.typing_env, did, substs, DUMMY_SP) - .polymorphize(self.tcx); + ty::Instance::expect_resolve(self.tcx, self.typing_env, did, substs, DUMMY_SP); instance.def.requires_caller_location(self.tcx) } else { From 144d6cc65ba5d3ebdf1e20cc1a27bd3964402921 Mon Sep 17 00:00:00 2001 From: Maybe Lapkin Date: Fri, 29 Nov 2024 20:28:02 +0100 Subject: [PATCH 041/107] simplify things using `tcx.as_lang_item` --- .../rustc_mir_build/src/check_tail_calls.rs | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 6eade2049702..b1f46d37d506 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -354,33 +354,31 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for TailCallCkVisitor<'a, 'tcx> { } fn op_trait_as_method_name(tcx: TyCtxt<'_>, trait_did: DefId) -> Option<&'static str> { - let trait_did = Some(trait_did); - let items = tcx.lang_items(); - let m = match () { - _ if trait_did == items.get(LangItem::Add) => "add", - _ if trait_did == items.get(LangItem::Sub) => "sub", - _ if trait_did == items.get(LangItem::Mul) => "mul", - _ if trait_did == items.get(LangItem::Div) => "div", - _ if trait_did == items.get(LangItem::Rem) => "rem", - _ if trait_did == items.get(LangItem::Neg) => "neg", - _ if trait_did == items.get(LangItem::Not) => "not", - _ if trait_did == items.get(LangItem::BitXor) => "bitxor", - _ if trait_did == items.get(LangItem::BitAnd) => "bitand", - _ if trait_did == items.get(LangItem::BitOr) => "bitor", - _ if trait_did == items.get(LangItem::Shl) => "shl", - _ if trait_did == items.get(LangItem::Shr) => "shr", - _ if trait_did == items.get(LangItem::AddAssign) => "add_assign", - _ if trait_did == items.get(LangItem::SubAssign) => "sub_assign", - _ if trait_did == items.get(LangItem::MulAssign) => "mul_assign", - _ if trait_did == items.get(LangItem::DivAssign) => "div_assign", - _ if trait_did == items.get(LangItem::RemAssign) => "rem_assign", - _ if trait_did == items.get(LangItem::BitXorAssign) => "bitxor_assign", - _ if trait_did == items.get(LangItem::BitAndAssign) => "bitand_assign", - _ if trait_did == items.get(LangItem::BitOrAssign) => "bitor_assign", - _ if trait_did == items.get(LangItem::ShlAssign) => "shl_assign", - _ if trait_did == items.get(LangItem::ShrAssign) => "shr_assign", - _ if trait_did == items.get(LangItem::Index) => "index", - _ if trait_did == items.get(LangItem::IndexMut) => "index_mut", + let m = match tcx.as_lang_item(trait_did)? { + LangItem::Add => "add", + LangItem::Sub => "sub", + LangItem::Mul => "mul", + LangItem::Div => "div", + LangItem::Rem => "rem", + LangItem::Neg => "neg", + LangItem::Not => "not", + LangItem::BitXor => "bitxor", + LangItem::BitAnd => "bitand", + LangItem::BitOr => "bitor", + LangItem::Shl => "shl", + LangItem::Shr => "shr", + LangItem::AddAssign => "add_assign", + LangItem::SubAssign => "sub_assign", + LangItem::MulAssign => "mul_assign", + LangItem::DivAssign => "div_assign", + LangItem::RemAssign => "rem_assign", + LangItem::BitXorAssign => "bitxor_assign", + LangItem::BitAndAssign => "bitand_assign", + LangItem::BitOrAssign => "bitor_assign", + LangItem::ShlAssign => "shl_assign", + LangItem::ShrAssign => "shr_assign", + LangItem::Index => "index", + LangItem::IndexMut => "index_mut", _ => return None, }; From 9aab517d6310223ac5a89c640723a64b695d49d2 Mon Sep 17 00:00:00 2001 From: Andrew Zhogin Date: Tue, 24 Sep 2024 16:35:00 +0700 Subject: [PATCH 042/107] rust_for_linux: -Zreg-struct-return commandline flag for X86 (#116973) --- compiler/rustc_codegen_gcc/src/context.rs | 5 +- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_middle/src/ty/layout.rs | 5 +- compiler/rustc_session/messages.ftl | 1 + compiler/rustc_session/src/errors.rs | 4 + compiler/rustc_session/src/options.rs | 3 + compiler/rustc_session/src/session.rs | 5 + compiler/rustc_target/src/callconv/mod.rs | 4 +- compiler/rustc_target/src/callconv/x86.rs | 3 +- compiler/rustc_target/src/spec/mod.rs | 2 + .../src/compiler-flags/reg-struct-return.md | 15 ++ tests/codegen/reg-struct-return.rs | 206 ++++++++++++++++++ .../requires-x86.aarch64.stderr | 4 + .../reg-struct-return/requires-x86.rs | 21 ++ .../requires-x86.x86_64.stderr | 4 + 15 files changed, 279 insertions(+), 4 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/reg-struct-return.md create mode 100644 tests/codegen/reg-struct-return.rs create mode 100644 tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.aarch64.stderr create mode 100644 tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.rs create mode 100644 tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.x86_64.stderr diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 3846d0255377..f67dcf0cb116 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -544,7 +544,10 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> { fn x86_abi_opt(&self) -> X86Abi { - X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm } + X86Abi { + regparm: self.tcx.sess.opts.unstable_opts.regparm, + reg_struct_return: self.tcx.sess.opts.unstable_opts.reg_struct_return, + } } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6beae14100d9..3e74a014093f 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -831,6 +831,7 @@ fn test_unstable_options_tracking_hash() { tracked!(precise_enum_drop_elaboration, false); tracked!(profile_sample_use, Some(PathBuf::from("abc"))); tracked!(profiler_runtime, "abc".to_string()); + tracked!(reg_struct_return, true); tracked!(regparm, Some(3)); tracked!(relax_elf_relocations, Some(true)); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 01ad76aedc37..07573a792600 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -552,7 +552,10 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> { impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> { fn x86_abi_opt(&self) -> X86Abi { - X86Abi { regparm: self.sess.opts.unstable_opts.regparm } + X86Abi { + regparm: self.sess.opts.unstable_opts.regparm, + reg_struct_return: self.sess.opts.unstable_opts.reg_struct_return, + } } } diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 8fd87893a98c..eb14b78a0030 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -135,5 +135,6 @@ session_unsupported_crate_type_for_target = session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 +session_unsupported_reg_struct_return_arch = `-Zreg-struct-return` is only supported on x86 session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3) session_unsupported_regparm_arch = `-Zregparm=N` is only supported on x86 diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 736a5ce07049..6c26a7814871 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -489,6 +489,10 @@ pub(crate) struct UnsupportedRegparm { #[diag(session_unsupported_regparm_arch)] pub(crate) struct UnsupportedRegparmArch; +#[derive(Diagnostic)] +#[diag(session_unsupported_reg_struct_return_arch)] +pub(crate) struct UnsupportedRegStructReturnArch; + #[derive(Diagnostic)] #[diag(session_failed_to_create_profiler)] pub(crate) struct FailedToCreateProfiler { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a2d75917c826..ecff392b6774 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1985,6 +1985,9 @@ options! { "enable queries of the dependency graph for regression testing (default: no)"), randomize_layout: bool = (false, parse_bool, [TRACKED], "randomize the layout of types (default: no)"), + reg_struct_return: bool = (false, parse_bool, [TRACKED], + "On x86-32 targets, it overrides the default ABI to return small structs in registers. + It is UNSOUND to link together crates that use different values for this flag!"), regparm: Option = (None, parse_opt_number, [TRACKED], "On x86-32 targets, setting this to N causes the compiler to pass N arguments \ in registers EAX, EDX, and ECX instead of on the stack for\ diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f585410adb97..cc5569836b24 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1305,6 +1305,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.dcx().emit_err(errors::UnsupportedRegparmArch); } } + if sess.opts.unstable_opts.reg_struct_return { + if sess.target.arch != "x86" { + sess.dcx().emit_err(errors::UnsupportedRegStructReturnArch); + } + } // The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is // kept as a `match` to force a change if new ones are added, even if we currently only support diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index fb0fe4029348..746e81738076 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -661,7 +661,9 @@ impl<'a, Ty> FnAbi<'a, Ty> { } _ => (x86::Flavor::General, None), }; - x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm }); + let reg_struct_return = cx.x86_abi_opt().reg_struct_return; + let opts = x86::X86Options { flavor, regparm, reg_struct_return }; + x86::compute_abi_info(cx, self, opts); } "x86_64" => match abi { spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self), diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index a5af975d4d24..cd8465c09ca9 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -14,6 +14,7 @@ pub(crate) enum Flavor { pub(crate) struct X86Options { pub flavor: Flavor, pub regparm: Option, + pub reg_struct_return: bool, } pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options) @@ -31,7 +32,7 @@ where // https://www.angelcode.com/dev/callconv/callconv.html // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp let t = cx.target_spec(); - if t.abi_return_struct_as_int { + if t.abi_return_struct_as_int || opts.reg_struct_return { // According to Clang, everyone but MSVC returns single-element // float aggregates directly in a floating-point register. if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index fead20ec7d1f..b2561cfb7bab 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2108,6 +2108,8 @@ pub struct X86Abi { /// On x86-32 targets, the regparm N causes the compiler to pass arguments /// in registers EAX, EDX, and ECX instead of on the stack. pub regparm: Option, + /// Override the default ABI to return small structs in registers + pub reg_struct_return: bool, } pub trait HasX86AbiOpt { diff --git a/src/doc/unstable-book/src/compiler-flags/reg-struct-return.md b/src/doc/unstable-book/src/compiler-flags/reg-struct-return.md new file mode 100644 index 000000000000..35b782f38dc4 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/reg-struct-return.md @@ -0,0 +1,15 @@ +# `reg-struct-return` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116973. + +------------------------ + +Option -Zreg-struct-return causes the compiler to return small structs in registers +instead of on the stack for extern "C"-like functions. +It is UNSOUND to link together crates that use different values for this flag. +It is only supported on `x86`. + +It is equivalent to [Clang]'s and [GCC]'s `-freg-struct-return`. + +[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-freg-struct-return +[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-freg-struct-return diff --git a/tests/codegen/reg-struct-return.rs b/tests/codegen/reg-struct-return.rs new file mode 100644 index 000000000000..73816745ea86 --- /dev/null +++ b/tests/codegen/reg-struct-return.rs @@ -0,0 +1,206 @@ +// Checks how `reg-struct-return` flag works with different calling conventions: +// Return struct with 8/16/32/64 bit size will be converted into i8/i16/i32/i64 +// (like abi_return_struct_as_int target spec). +// x86 only. + +//@ revisions: ENABLED DISABLED +//@ add-core-stubs +//@ compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes +//@ [ENABLED] compile-flags: -Zreg-struct-return +//@ needs-llvm-components: x86 + +#![crate_type = "lib"] +#![no_std] +#![no_core] +#![feature(no_core, lang_items)] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +pub struct Foo { + x: u32, + y: u32, +} + +#[repr(C)] +pub struct Foo1 { + x: u32, +} + +#[repr(C)] +pub struct Foo2 { + x: bool, + y: bool, + z: i16, +} + +#[repr(C)] +pub struct Foo3 { + x: i16, + y: bool, + z: bool, +} + +#[repr(C)] +pub struct Foo4 { + x: char, + y: bool, + z: u8, +} + +#[repr(C)] +pub struct Foo5 { + x: u32, + y: u16, + z: u8, + a: bool, +} + +#[repr(C)] +pub struct FooOversize1 { + x: u32, + y: u32, + z: u32, +} + +#[repr(C)] +pub struct FooOversize2 { + f0: u16, + f1: u16, + f2: u16, + f3: u16, + f4: u16, +} + +#[repr(C)] +pub struct FooFloat1 { + x: f32, + y: f32, +} + +#[repr(C)] +pub struct FooFloat2 { + x: f64, +} + +#[repr(C)] +pub struct FooFloat3 { + x: f32, +} + +pub mod tests { + use { + Foo, Foo1, Foo2, Foo3, Foo4, Foo5, FooFloat1, FooFloat2, FooFloat3, FooOversize1, + FooOversize2, + }; + + // ENABLED: i64 @f1() + // DISABLED: void @f1(ptr {{.*}}sret + #[no_mangle] + pub extern "fastcall" fn f1() -> Foo { + Foo { x: 1, y: 2 } + } + + // CHECK: { i32, i32 } @f2() + #[no_mangle] + pub extern "Rust" fn f2() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i64 @f3() + // DISABLED: void @f3(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f3() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i64 @f4() + // DISABLED: void @f4(ptr {{.*}}sret + #[no_mangle] + pub extern "cdecl" fn f4() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i64 @f5() + // DISABLED: void @f5(ptr {{.*}}sret + #[no_mangle] + pub extern "stdcall" fn f5() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i64 @f6() + // DISABLED: void @f6(ptr {{.*}}sret + #[no_mangle] + pub extern "thiscall" fn f6() -> Foo { + Foo { x: 1, y: 2 } + } + + // ENABLED: i32 @f7() + // DISABLED: void @f7(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f7() -> Foo1 { + Foo1 { x: 1 } + } + + // ENABLED: i32 @f8() + // DISABLED: void @f8(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f8() -> Foo2 { + Foo2 { x: true, y: false, z: 5 } + } + + // ENABLED: i32 @f9() + // DISABLED: void @f9(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f9() -> Foo3 { + Foo3 { x: 5, y: false, z: true } + } + + // ENABLED: i64 @f10() + // DISABLED: void @f10(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f10() -> Foo4 { + Foo4 { x: 'x', y: true, z: 170 } + } + + // ENABLED: i64 @f11() + // DISABLED: void @f11(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f11() -> Foo5 { + Foo5 { x: 1, y: 2, z: 3, a: true } + } + + // CHECK: void @f12(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f12() -> FooOversize1 { + FooOversize1 { x: 1, y: 2, z: 3 } + } + + // CHECK: void @f13(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f13() -> FooOversize2 { + FooOversize2 { f0: 1, f1: 2, f2: 3, f3: 4, f4: 5 } + } + + // ENABLED: i64 @f14() + // DISABLED: void @f14(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f14() -> FooFloat1 { + FooFloat1 { x: 1.0, y: 1.0 } + } + + // ENABLED: double @f15() + // DISABLED: void @f15(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f15() -> FooFloat2 { + FooFloat2 { x: 1.0 } + } + + // ENABLED: float @f16() + // DISABLED: void @f16(ptr {{.*}}sret + #[no_mangle] + pub extern "C" fn f16() -> FooFloat3 { + FooFloat3 { x: 1.0 } + } +} diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.aarch64.stderr b/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.aarch64.stderr new file mode 100644 index 000000000000..9bc85cc7e62d --- /dev/null +++ b/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.aarch64.stderr @@ -0,0 +1,4 @@ +error: `-Zreg-struct-return` is only supported on x86 + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.rs b/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.rs new file mode 100644 index 000000000000..b5e34bece320 --- /dev/null +++ b/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.rs @@ -0,0 +1,21 @@ +//@ revisions: x86 x86_64 aarch64 + +//@ compile-flags: -Zreg-struct-return + +//@[x86] check-pass +//@[x86] needs-llvm-components: x86 +//@[x86] compile-flags: --target i686-unknown-linux-gnu + +//@[x86_64] check-fail +//@[x86_64] needs-llvm-components: x86 +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] error-pattern: `-Zreg-struct-return` is only supported on x86 + +//@[aarch64] check-fail +//@[aarch64] needs-llvm-components: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] error-pattern: `-Zreg-struct-return` is only supported on x86 + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.x86_64.stderr b/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.x86_64.stderr new file mode 100644 index 000000000000..9bc85cc7e62d --- /dev/null +++ b/tests/ui/invalid-compile-flags/reg-struct-return/requires-x86.x86_64.stderr @@ -0,0 +1,4 @@ +error: `-Zreg-struct-return` is only supported on x86 + +error: aborting due to 1 previous error + From b81391ec76f8f18b92b0aee7369c7bda2864e0d9 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Tue, 3 Dec 2024 08:17:33 +0100 Subject: [PATCH 043/107] CI: use free runners for i686-gnu jobs --- .../host-x86_64/i686-gnu-nopt/Dockerfile | 4 +- src/ci/docker/host-x86_64/i686-gnu/Dockerfile | 9 +-- src/ci/docker/run.sh | 35 +++++++----- src/ci/github-actions/jobs.yml | 55 +++++++++++++++++-- 4 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile index e2b66c2cff1d..e27367206073 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -27,5 +27,5 @@ RUN echo "[rust]" > /config/nopt-std-config.toml RUN echo "optimize = false" >> /config/nopt-std-config.toml ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests -ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \ - && python3 ../x.py --stage 2 test +ARG SCRIPT_ARG +ENV SCRIPT=${SCRIPT_ARG} diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index 61811c41904c..dec25461bb4e 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -24,10 +24,5 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu -# Skip some tests that are unlikely to be platform specific, to speed up -# this slow job. -ENV SCRIPT python3 ../x.py --stage 2 test \ - --skip src/bootstrap \ - --skip tests/rustdoc-js \ - --skip src/tools/error_index_generator \ - --skip src/tools/linkchecker +ARG SCRIPT_ARG +ENV SCRIPT=${SCRIPT_ARG} diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index d554186df4cf..a0adf60b6b2c 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -105,6 +105,23 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then # It seems that it cannot be the same as $IMAGE_TAG, otherwise it overwrites the cache CACHE_IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci-cache:${cksum} + # Docker build arguments. + build_args=( + "build" + "--rm" + "-t" "rust-ci" + "-f" "$dockerfile" + "$context" + ) + + # If the environment variable DOCKER_SCRIPT is defined, + # set the build argument SCRIPT_ARG to DOCKER_SCRIPT. + # In this way, we run the script defined in CI, + # instead of the one defined in the Dockerfile. + if [ -n "${DOCKER_SCRIPT+x}" ]; then + build_args+=("--build-arg" "SCRIPT_ARG=${DOCKER_SCRIPT}") + fi + # On non-CI jobs, we try to download a pre-built image from the rust-lang-ci # ghcr.io registry. If it is not possible, we fall back to building the image # locally. @@ -115,7 +132,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then docker tag "${IMAGE_TAG}" rust-ci else echo "Building local Docker image" - retry docker build --rm -t rust-ci -f "$dockerfile" "$context" + retry docker "${build_args[@]}" fi # On PR CI jobs, we don't have permissions to write to the registry cache, # but we can still read from it. @@ -127,13 +144,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then # Build the image using registry caching backend retry docker \ buildx \ - build \ - --rm \ - -t rust-ci \ - -f "$dockerfile" \ + "${build_args[@]}" \ --cache-from type=registry,ref=${CACHE_IMAGE_TAG} \ - --output=type=docker \ - "$context" + --output=type=docker # On auto/try builds, we can also write to the cache. else # Log into the Docker registry, so that we can read/write cache and the final image @@ -147,14 +160,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then # Build the image using registry caching backend retry docker \ buildx \ - build \ - --rm \ - -t rust-ci \ - -f "$dockerfile" \ + "${build_args[@]}" \ --cache-from type=registry,ref=${CACHE_IMAGE_TAG} \ --cache-to type=registry,ref=${CACHE_IMAGE_TAG},compression=zstd \ - --output=type=docker \ - "$context" + --output=type=docker # Print images for debugging purposes docker images diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 454c855c75d2..e74e4875453e 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -58,6 +58,22 @@ envs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 + # Different set of tests to run tests in parallel in multiple jobs. + stage_2_test_set1: &stage_2_test_set1 + DOCKER_SCRIPT: >- + python3 ../x.py --stage 2 test + --skip compiler + --skip src + + stage_2_test_set2: &stage_2_test_set2 + DOCKER_SCRIPT: >- + python3 ../x.py --stage 2 test + --skip tests + --skip coverage-map + --skip coverage-run + --skip library + --skip tidyselftest + production: &production DEPLOY_BUCKET: rust-lang-ci2 @@ -212,11 +228,42 @@ auto: - image: dist-x86_64-netbsd <<: *job-linux-4c - - image: i686-gnu - <<: *job-linux-8c + # The i686-gnu job is split into multiple jobs to run tests in parallel. + # i686-gnu-1 skips tests that run in i686-gnu-2. + - image: i686-gnu-1 + env: + IMAGE: i686-gnu + <<: *stage_2_test_set1 + <<: *job-linux-4c - - image: i686-gnu-nopt - <<: *job-linux-8c + # Skip tests that run in i686-gnu-1 + - image: i686-gnu-2 + env: + IMAGE: i686-gnu + <<: *stage_2_test_set2 + <<: *job-linux-4c + + # The i686-gnu-nopt job is split into multiple jobs to run tests in parallel. + # i686-gnu-nopt-1 skips tests that run in i686-gnu-nopt-2 + - image: i686-gnu-nopt-1 + env: + IMAGE: i686-gnu-nopt + <<: *stage_2_test_set1 + <<: *job-linux-4c + + # Skip tests that run in i686-gnu-nopt-1 + - image: i686-gnu-nopt-2 + env: + IMAGE: i686-gnu-nopt + DOCKER_SCRIPT: >- + python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std && + python3 ../x.py --stage 2 test + --skip tests + --skip coverage-map + --skip coverage-run + --skip library + --skip tidyselftest + <<: *job-linux-4c - image: mingw-check <<: *job-linux-4c From 059f6272c346654dfce7a68a6bb0c0aeb1ed756a Mon Sep 17 00:00:00 2001 From: "Brian J. Tarricone" Date: Mon, 15 Feb 2021 23:32:16 -0800 Subject: [PATCH 044/107] Teach rust core about Xtensa VaListImpl and add a custom lowering of vaarg for xtensa. LLVM does not include an implementation of the va_arg instruction for Xtensa. From what I understand, this is a conscious decision and instead language frontends are encouraged to implement it themselves. The rationale seems to be that loading values correctly requires language and ABI-specific knowledge that LLVM lacks. This is true of most architectures, and rustc already provides implementation for a number of them. This commit extends the support to include Xtensa. See https://lists.llvm.org/pipermail/llvm-dev/2017-August/116337.html for some discussion on the topic. Unfortunately there does not seem to be a reference document for the semantics of the va_list and va_arg on Xtensa. The most reliable source is the GCC implementation, which this commit tries to follow. Clang also provides its own compatible implementation. This was tested for all the types that rustc allows in variadics. Co-authored-by: Brian Tarricone Co-authored-by: Jonathan Bastien-Filiatrault Co-authored-by: Paul Lietar --- compiler/rustc_codegen_llvm/src/va_arg.rs | 113 +++++++++++++++++++++- library/core/Cargo.toml | 1 + library/core/src/ffi/va_list.rs | 19 ++++ 3 files changed, 131 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index e4c3e748cb5d..8baa69cefe1e 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -10,6 +10,15 @@ use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; +fn round_up_to_alignment<'ll>( + bx: &mut Builder<'_, 'll, '_>, + mut value: &'ll Value, + align: Align, +) -> &'ll Value { + value = bx.add(value, bx.cx().const_i32(align.bytes() as i32 - 1)); + return bx.and(value, bx.cx().const_i32(-(align.bytes() as i32))); +} + fn round_pointer_up_to_alignment<'ll>( bx: &mut Builder<'_, 'll, '_>, addr: &'ll Value, @@ -17,8 +26,7 @@ fn round_pointer_up_to_alignment<'ll>( ptr_ty: &'ll Type, ) -> &'ll Value { let mut ptr_as_int = bx.ptrtoint(addr, bx.cx().type_isize()); - ptr_as_int = bx.add(ptr_as_int, bx.cx().const_i32(align.bytes() as i32 - 1)); - ptr_as_int = bx.and(ptr_as_int, bx.cx().const_i32(-(align.bytes() as i32))); + ptr_as_int = round_up_to_alignment(bx, ptr_as_int, align); bx.inttoptr(ptr_as_int, ptr_ty) } @@ -270,6 +278,106 @@ fn emit_s390x_va_arg<'ll, 'tcx>( bx.load(val_type, val_addr, layout.align.abi) } +fn emit_xtensa_va_arg<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, + list: OperandRef<'tcx, &'ll Value>, + target_ty: Ty<'tcx>, +) -> &'ll Value { + // Implementation of va_arg for Xtensa. There doesn't seem to be an authoritative source for + // this, other than "what GCC does". + // + // The va_list type has three fields: + // struct __va_list_tag { + // int32_t *va_stk; // Arguments passed on the stack + // int32_t *va_reg; // Arguments passed in registers, saved to memory by the prologue. + // int32_t va_ndx; // Offset into the arguments, in bytes + // }; + // + // The first 24 bytes (equivalent to 6 registers) come from va_reg, the rest from va_stk. + // Thus if va_ndx is less than 24, the next va_arg *may* read from va_reg, + // otherwise it must come from va_stk. + // + // Primitive arguments are never split between registers and the stack. For example, if loading an 8 byte + // primitive value and va_ndx = 20, we instead bump the offset and read everything from va_stk. + let va_list_addr = list.immediate(); + // FIXME: handle multi-field structs that split across regsave/stack? + let layout = bx.cx.layout_of(target_ty); + let from_stack = bx.append_sibling_block("va_arg.from_stack"); + let from_regsave = bx.append_sibling_block("va_arg.from_regsave"); + let end = bx.append_sibling_block("va_arg.end"); + + // (*va).va_ndx + let va_reg_offset = 4; + let va_ndx_offset = va_reg_offset + 4; + let offset_ptr = + bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(va_ndx_offset)]); + + let offset = bx.load(bx.type_i32(), offset_ptr, bx.tcx().data_layout.i32_align.abi); + let offset = round_up_to_alignment(bx, offset, layout.align.abi); + + let slot_size = layout.size.align_to(Align::from_bytes(4).unwrap()).bytes() as i32; + + // Update the offset in va_list, by adding the slot's size. + let offset_next = bx.add(offset, bx.const_i32(slot_size)); + + // Figure out where to look for our value. We do that by checking the end of our slot (offset_next). + // If that is within the regsave area, then load from there. Otherwise load from the stack area. + let regsave_size = bx.const_i32(24); + let use_regsave = bx.icmp(IntPredicate::IntULE, offset_next, regsave_size); + bx.cond_br(use_regsave, from_regsave, from_stack); + + bx.switch_to_block(from_regsave); + // update va_ndx + bx.store(offset_next, offset_ptr, bx.tcx().data_layout.pointer_align.abi); + + // (*va).va_reg + let regsave_area_ptr = + bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(va_reg_offset)]); + let regsave_area = + bx.load(bx.type_ptr(), regsave_area_ptr, bx.tcx().data_layout.pointer_align.abi); + let regsave_value_ptr = bx.inbounds_gep(bx.type_i8(), regsave_area, &[offset]); + bx.br(end); + + bx.switch_to_block(from_stack); + + // The first time we switch from regsave to stack we needs to adjust our offsets a bit. + // va_stk is set up such that the first stack argument is always at va_stk + 32. + // The corrected offset is written back into the va_list struct. + + // let offset_corrected = cmp::max(offset, 32); + let stack_offset_start = bx.const_i32(32); + let needs_correction = bx.icmp(IntPredicate::IntULE, offset, stack_offset_start); + let offset_corrected = bx.select(needs_correction, stack_offset_start, offset); + + // let offset_next_corrected = offset_corrected + slot_size; + // va_ndx = offset_next_corrected; + let offset_next_corrected = bx.add(offset_next, bx.const_i32(slot_size)); + // update va_ndx + bx.store(offset_next_corrected, offset_ptr, bx.tcx().data_layout.pointer_align.abi); + + // let stack_value_ptr = unsafe { (*va).va_stk.byte_add(offset_corrected) }; + let stack_area_ptr = bx.inbounds_gep(bx.type_i8(), va_list_addr, &[bx.cx.const_usize(0)]); + let stack_area = bx.load(bx.type_ptr(), stack_area_ptr, bx.tcx().data_layout.pointer_align.abi); + let stack_value_ptr = bx.inbounds_gep(bx.type_i8(), stack_area, &[offset_corrected]); + bx.br(end); + + bx.switch_to_block(end); + + // On big-endian, for values smaller than the slot size we'd have to align the read to the end + // of the slot rather than the start. While the ISA and GCC support big-endian, all the Xtensa + // targets supported by rustc are litte-endian so don't worry about it. + + // if from_regsave { + // unsafe { *regsave_value_ptr } + // } else { + // unsafe { *stack_value_ptr } + // } + assert!(bx.tcx().sess.target.endian == Endian::Little); + let value_ptr = + bx.phi(bx.type_ptr(), &[regsave_value_ptr, stack_value_ptr], &[from_regsave, from_stack]); + return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi); +} + pub(super) fn emit_va_arg<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, addr: OperandRef<'tcx, &'ll Value>, @@ -302,6 +410,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( let indirect: bool = target_ty_size > 8 || !target_ty_size.is_power_of_two(); emit_ptr_va_arg(bx, addr, target_ty, indirect, Align::from_bytes(8).unwrap(), false) } + "xtensa" => emit_xtensa_va_arg(bx, addr, target_ty), // For all other architecture/OS combinations fall back to using // the LLVM va_arg instruction. // https://llvm.org/docs/LangRef.html#va-arg-instruction diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index cace4582b489..46c55c437cce 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -43,6 +43,7 @@ check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', 'cfg(stdarch_intel_sde)', + 'cfg(target_arch, values("xtensa"))', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 3a224e4d8fe5..f67c592d8d8f 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -15,6 +15,7 @@ use crate::ops::{Deref, DerefMut}; not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "s390x"), + not(target_arch = "xtensa"), not(target_arch = "x86_64") ), all(target_arch = "aarch64", target_vendor = "apple"), @@ -37,6 +38,7 @@ pub struct VaListImpl<'f> { not(target_arch = "aarch64"), not(target_arch = "powerpc"), not(target_arch = "s390x"), + not(target_arch = "xtensa"), not(target_arch = "x86_64") ), all(target_arch = "aarch64", target_vendor = "apple"), @@ -113,6 +115,18 @@ pub struct VaListImpl<'f> { _marker: PhantomData<&'f mut &'f c_void>, } +/// Xtensa ABI implementation of a `va_list`. +#[cfg(target_arch = "xtensa")] +#[repr(C)] +#[derive(Debug)] +#[lang = "va_list"] +pub struct VaListImpl<'f> { + stk: *mut i32, + reg: *mut i32, + ndx: i32, + _marker: PhantomData<&'f mut &'f c_void>, +} + /// A wrapper for a `va_list` #[repr(transparent)] #[derive(Debug)] @@ -124,6 +138,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), + target_arch = "xtensa", all(target_arch = "aarch64", target_vendor = "apple"), target_family = "wasm", target_os = "uefi", @@ -138,6 +153,7 @@ pub struct VaList<'a, 'f: 'a> { target_arch = "s390x", target_arch = "x86_64" ), + not(target_arch = "xtensa"), any(not(target_arch = "aarch64"), not(target_vendor = "apple")), not(target_family = "wasm"), not(target_os = "uefi"), @@ -155,6 +171,7 @@ pub struct VaList<'a, 'f: 'a> { not(target_arch = "s390x"), not(target_arch = "x86_64") ), + target_arch = "xtensa", all(target_arch = "aarch64", target_vendor = "apple"), target_family = "wasm", target_os = "uefi", @@ -173,8 +190,10 @@ impl<'f> VaListImpl<'f> { target_arch = "aarch64", target_arch = "powerpc", target_arch = "s390x", + target_arch = "xtensa", target_arch = "x86_64" ), + not(target_arch = "xtensa"), any(not(target_arch = "aarch64"), not(target_vendor = "apple")), not(target_family = "wasm"), not(target_os = "uefi"), From 733871099c3da6c5ff37048a6ee81564385cf779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 3 Dec 2024 21:59:41 +0100 Subject: [PATCH 045/107] Fix typo --- src/tools/tidy/src/ext_tool_checks.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 8f21338c7dbc..bf1a33387976 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -34,7 +34,7 @@ const REL_PY_PATH: &[&str] = &["bin", "python3"]; const RUFF_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "ruff.toml"]; const BLACK_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "black.toml"]; /// Location within build directory -const RUFF_CACH_PATH: &[&str] = &["cache", "ruff_cache"]; +const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"]; const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"]; pub fn check( @@ -96,7 +96,7 @@ fn check_impl( let mut cfg_path = root_path.to_owned(); cfg_path.extend(RUFF_CONFIG_PATH); let mut cache_dir = outdir.to_owned(); - cache_dir.extend(RUFF_CACH_PATH); + cache_dir.extend(RUFF_CACHE_PATH); cfg_args_ruff.extend([ "--config".as_ref(), From f676ed2d2cb4cb96acc35b95b4c9ffefc4fc7737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 3 Dec 2024 22:02:15 +0100 Subject: [PATCH 046/107] Fix copy-pasted tool name --- src/tools/tidy/src/ext_tool_checks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index bf1a33387976..f10844435d9e 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -445,7 +445,7 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { } let status = Command::new("shellcheck").args(args).status()?; - if status.success() { Ok(()) } else { Err(Error::FailedCheck("black")) } + if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } } /// Check git for tracked files matching an extension From b24d608967183b940f79c1edd3a596d3eae9044e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 3 Dec 2024 22:02:58 +0100 Subject: [PATCH 047/107] Replace `black` with `ruff` for formatting Python code --- src/tools/tidy/src/ext_tool_checks.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index f10844435d9e..9792650d37d3 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -32,7 +32,6 @@ const REL_PY_PATH: &[&str] = &["Scripts", "python3.exe"]; const REL_PY_PATH: &[&str] = &["bin", "python3"]; const RUFF_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "ruff.toml"]; -const BLACK_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "black.toml"]; /// Location within build directory const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"]; const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"]; @@ -124,33 +123,36 @@ fn check_impl( } if python_fmt { - let mut cfg_args_black = cfg_args.clone(); - let mut file_args_black = file_args.clone(); + let mut cfg_args_ruff = cfg_args.clone(); + let mut file_args_ruff = file_args.clone(); if bless { eprintln!("formatting python files"); } else { eprintln!("checking python file formatting"); - cfg_args_black.push("--check".as_ref()); + cfg_args_ruff.push("--check".as_ref()); } let mut cfg_path = root_path.to_owned(); - cfg_path.extend(BLACK_CONFIG_PATH); + cfg_path.extend(RUFF_CONFIG_PATH); + let mut cache_dir = outdir.to_owned(); + cache_dir.extend(RUFF_CACHE_PATH); - cfg_args_black.extend(["--config".as_ref(), cfg_path.as_os_str()]); + cfg_args_ruff.extend(["--config".as_ref(), cfg_path.as_os_str()]); - if file_args_black.is_empty() { - file_args_black.push(root_path.as_os_str()); + if file_args_ruff.is_empty() { + file_args_ruff.push(root_path.as_os_str()); } - let mut args = merge_args(&cfg_args_black, &file_args_black); - let res = py_runner(py_path.as_ref().unwrap(), true, None, "black", &args); + let mut args = merge_args(&cfg_args_ruff, &file_args_ruff); + args.insert(0, "format".as_ref()); + let res = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args); if res.is_err() && show_diff { eprintln!("\npython formatting does not match! Printing diff:"); args.insert(0, "--diff".as_ref()); - let _ = py_runner(py_path.as_ref().unwrap(), true, None, "black", &args); + let _ = py_runner(py_path.as_ref().unwrap(), true, None, "ruff", &args); } // Rethrow error let _ = res?; From d5eb93b7e78105d51b7a77bbbee62cee6aabf078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 3 Dec 2024 22:06:38 +0100 Subject: [PATCH 048/107] Remove dependency on `black` --- src/tools/tidy/config/black.toml | 18 --------- src/tools/tidy/config/requirements.in | 1 - src/tools/tidy/config/requirements.txt | 52 -------------------------- 3 files changed, 71 deletions(-) delete mode 100644 src/tools/tidy/config/black.toml diff --git a/src/tools/tidy/config/black.toml b/src/tools/tidy/config/black.toml deleted file mode 100644 index d5b8b198afb3..000000000000 --- a/src/tools/tidy/config/black.toml +++ /dev/null @@ -1,18 +0,0 @@ -[tool.black] -# Ignore all submodules -extend-exclude = """(\ - src/doc/nomicon|\ - src/tools/cargo/|\ - src/doc/reference/|\ - src/doc/book/|\ - src/doc/rust-by-example/|\ - library/stdarch/|\ - src/doc/rustc-dev-guide/|\ - src/doc/edition-guide/|\ - src/llvm-project/|\ - src/doc/embedded-book/|\ - src/tools/rustc-perf/|\ - src/tools/enzyme/|\ - library/backtrace/|\ - src/gcc/ - )""" diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in index 8938dc032438..1b2c38f2b5d3 100644 --- a/src/tools/tidy/config/requirements.in +++ b/src/tools/tidy/config/requirements.in @@ -6,6 +6,5 @@ # Note: this generation step should be run with the oldest supported python # version (currently 3.9) to ensure backward compatibility -black==24.4.2 ruff==0.4.9 clang-format==18.1.7 diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt index 790eabf5cf8a..938179d5b3e0 100644 --- a/src/tools/tidy/config/requirements.txt +++ b/src/tools/tidy/config/requirements.txt @@ -4,30 +4,6 @@ # # pip-compile --generate-hashes --strip-extras src/tools/tidy/config/requirements.in # -black==24.4.2 \ - --hash=sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474 \ - --hash=sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1 \ - --hash=sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0 \ - --hash=sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8 \ - --hash=sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96 \ - --hash=sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1 \ - --hash=sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04 \ - --hash=sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021 \ - --hash=sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94 \ - --hash=sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d \ - --hash=sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c \ - --hash=sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7 \ - --hash=sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c \ - --hash=sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc \ - --hash=sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7 \ - --hash=sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d \ - --hash=sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c \ - --hash=sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741 \ - --hash=sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce \ - --hash=sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb \ - --hash=sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063 \ - --hash=sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e - # via -r src/tools/tidy/config/requirements.in clang-format==18.1.7 \ --hash=sha256:035204410f65d03f98cb81c9c39d6d193f9987917cc88de9d0dbd01f2aa9c302 \ --hash=sha256:05c482a854287a5d21f7567186c0bd4b8dbd4a871751e655a45849185f30b931 \ @@ -45,26 +21,6 @@ clang-format==18.1.7 \ --hash=sha256:f4f77ac0f4f9a659213fedda0f2d216886c410132e6e7dd4b13f92b34e925554 \ --hash=sha256:f935d34152a2e11e55120eb9182862f432bc9789ab819f680c9f6db4edebf9e3 # via -r src/tools/tidy/config/requirements.in -click==8.1.3 \ - --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ - --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 - # via black -mypy-extensions==1.0.0 \ - --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ - --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 - # via black -packaging==23.1 \ - --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \ - --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f - # via black -pathspec==0.11.1 \ - --hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 \ - --hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293 - # via black -platformdirs==4.2.2 \ - --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ - --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 - # via black ruff==0.4.9 \ --hash=sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893 \ --hash=sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff \ @@ -84,11 +40,3 @@ ruff==0.4.9 \ --hash=sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde \ --hash=sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3 # via -r src/tools/tidy/config/requirements.in -tomli==2.0.1 \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f - # via black -typing-extensions==4.12.2 \ - --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ - --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 - # via black From 7cc6f4da881b4947f0132defdd97444772c2165b Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Tue, 3 Dec 2024 23:24:59 +0100 Subject: [PATCH 049/107] CI: rfl: move job forward to Linux v6.13-rc1 Linux v6.13-rc1 contains commit 28e848386b92 ("rust: block: fix formatting of `kernel::block::mq::request` module"), which in turn contains commit c95bbb59a9b2 ("rust: enable arbitrary_self_types and remove `Receiver`"), which is why we had a hash rather than a tag. Signed-off-by: Miguel Ojeda --- src/ci/docker/scripts/rfl-build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index f07515f7784f..8776e0f0be90 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,7 @@ set -euo pipefail -LINUX_VERSION=28e848386b92645f93b9f2fdba5882c3ca7fb3e2 +LINUX_VERSION=v6.13-rc1 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt @@ -64,7 +64,7 @@ make -C linux LLVM=1 -j$(($(nproc) + 1)) \ BUILD_TARGETS=" samples/rust/rust_minimal.o - samples/rust/rust_print.o + samples/rust/rust_print_main.o drivers/net/phy/ax88796b_rust.o rust/doctests_kernel_generated.o " From eff1c5d627196461ac458b22b6806dc1c2720065 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:25:10 +0000 Subject: [PATCH 050/107] Rustup to rustc 1.85.0-nightly (c44b3d50f 2024-12-03) --- patches/0022-coretests-Disable-not-compiling-tests.patch | 4 ++-- patches/0027-coretests-128bit-atomic-operations.patch | 7 +++---- rust-toolchain | 2 +- src/driver/jit.rs | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/patches/0022-coretests-Disable-not-compiling-tests.patch b/patches/0022-coretests-Disable-not-compiling-tests.patch index 1860810e7f3b..161173d47650 100644 --- a/patches/0022-coretests-Disable-not-compiling-tests.patch +++ b/patches/0022-coretests-Disable-not-compiling-tests.patch @@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644 @@ -1,3 +1,4 @@ +#![cfg(test)] // tidy-alphabetical-start - #![cfg_attr(bootstrap, feature(const_three_way_compare))] - #![cfg_attr(bootstrap, feature(strict_provenance))] + #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] + #![cfg_attr(test, feature(cfg_match))] -- 2.21.0 (Apple Git-122) diff --git a/patches/0027-coretests-128bit-atomic-operations.patch b/patches/0027-coretests-128bit-atomic-operations.patch index 59653c6e875f..06840624ceff 100644 --- a/patches/0027-coretests-128bit-atomic-operations.patch +++ b/patches/0027-coretests-128bit-atomic-operations.patch @@ -14,10 +14,9 @@ diff --git a/lib.rs b/lib.rs index 1e336bf..35e6f54 100644 --- a/lib.rs +++ b/lib.rs -@@ -2,7 +2,6 @@ - #![cfg_attr(bootstrap, feature(const_three_way_compare))] - #![cfg_attr(bootstrap, feature(strict_provenance))] - #![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] +@@ -2,6 +2,5 @@ + #![cfg(test)] + // tidy-alphabetical-start -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] #![cfg_attr(test, feature(cfg_match))] #![feature(alloc_layout_extra)] diff --git a/rust-toolchain b/rust-toolchain index aa4773a13e26..fe9719628d68 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-11-28" +channel = "nightly-2024-12-04" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/src/driver/jit.rs b/src/driver/jit.rs index f44fd615bd8e..3405ce19ffdf 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -11,7 +11,7 @@ use cranelift_jit::{JITBuilder, JITModule}; use rustc_codegen_ssa::CrateInfo; use rustc_middle::mir::mono::MonoItem; use rustc_session::Session; -use rustc_span::Symbol; +use rustc_span::sym; use crate::debuginfo::TypeDebugContext; use crate::prelude::*; From 28533886c33bff1a54ce8f3ea52321fb67978783 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 4 Dec 2024 12:24:24 +0000 Subject: [PATCH 051/107] Fix rustc test suite --- build_system/build_sysroot.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 62cef3dc1726..e47e98299162 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -247,6 +247,7 @@ fn build_clif_sysroot_for_triple( let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs); build_cmd.arg("--release"); build_cmd.arg("--features").arg("backtrace panic-unwind compiler-builtins-no-f16-f128"); + build_cmd.arg(format!("-Zroot-dir={}", STDLIB_SRC.to_path(dirs).display())); build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true"); build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif"); if compiler.triple.contains("apple") { From 357deaa849ac5c4c1caa109b32615645282eefae Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:38:37 +0000 Subject: [PATCH 052/107] Move disabling of f16 and f128 in compiler-builtins to liballoc This way it gets disabled even when trying to compile just liballoc and not the sysroot crate. --- ...le-f16-and-f128-in-compiler-builtins.patch | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index ada35145e293..6012af6a8dd2 100644 --- a/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -4,22 +4,23 @@ Date: Fri, 9 Aug 2024 15:44:51 +0000 Subject: [PATCH] Disable f16 and f128 in compiler-builtins --- - library/sysroot/Cargo.toml | 2 +- + library/liballoc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml +diff --git a/library/liballoc/Cargo.toml b/library/liballoc/Cargo.toml index 7165c3e48af..968552ad435 100644 ---- a/library/sysroot/Cargo.toml -+++ b/library/sysroot/Cargo.toml +--- a/library/alloc/Cargo.toml ++++ b/library/alloc/Cargo.toml @@ -11,7 +11,7 @@ test = { path = "../test" } + edition = "2021" - # Forward features to the `std` crate as necessary - [features] --default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] -+default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind", "compiler-builtins-no-f16-f128"] - backtrace = ["std/backtrace"] - compiler-builtins-c = ["std/compiler-builtins-c"] - compiler-builtins-mem = ["std/compiler-builtins-mem"] + [dependencies] + core = { path = "../core" } +-compiler_builtins = { version = "=0.1.138", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.138", features = ['rustc-dep-of-std', 'no-f16-f128'] } + + [dev-dependencies] + rand = { version = "0.8.5", default-features = false, features = ["alloc"] } -- 2.34.1 From 76f9aa1d7edb579621f0ab50d18665461bc6ae48 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 5 Dec 2024 04:23:57 +0900 Subject: [PATCH 053/107] Fix "std" support status of some tier 3 targets --- .../spec/targets/powerpc64le_unknown_freebsd.rs | 4 ++-- .../src/spec/targets/powerpc_unknown_freebsd.rs | 2 +- .../spec/targets/riscv32gc_unknown_linux_gnu.rs | 2 +- .../spec/targets/riscv32gc_unknown_linux_musl.rs | 2 +- .../src/spec/targets/riscv64_linux_android.rs | 2 +- .../spec/targets/riscv64gc_unknown_freebsd.rs | 2 +- .../spec/targets/riscv64gc_unknown_fuchsia.rs | 2 +- .../spec/targets/riscv64gc_unknown_linux_musl.rs | 2 +- .../src/spec/targets/s390x_unknown_linux_musl.rs | 2 +- src/doc/rustc/src/platform-support.md | 16 ++++++++-------- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index e194f5f8a36f..0c1218bd0593 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -12,8 +12,8 @@ pub(crate) fn target() -> Target { metadata: crate::spec::TargetMetadata { description: Some("PPC64LE FreeBSD".into()), tier: Some(3), - host_tools: Some(false), - std: Some(false), + host_tools: Some(true), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-Fn32-i64:64-n32:64".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs index 393946980f8b..b72f8e8acf8d 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_freebsd.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { description: Some("PowerPC FreeBSD".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: None, }, pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs index 8b0a140c9ade..e9c57b99b927 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { description: Some("RISC-V Linux (kernel 5.4, glibc 2.33)".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs index 212de791e499..db8482110eb6 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { ), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: None, }, pointer_width: 32, data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs index 8b5d4751a573..38bf4b006eb7 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { description: Some("RISC-V 64-bit Android".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: None, }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs index d1b0d801fd60..db56e264e943 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_freebsd.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { description: Some("RISC-V FreeBSD".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: None, }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs index 6de51f9b07e2..75b7dfcbb092 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { description: Some("RISC-V Fuchsia".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: None, }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs index 2e6fce91d4c7..397c202ec1a5 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { description: Some("RISC-V Linux (kernel 4.20, musl 1.2.3)".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index 4bde0fb729c7..7a78004927b1 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { description: Some("S390x Linux (kernel 3.2, musl 1.2.3)".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64".into(), diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 243cb3b2fc83..3b82d123276d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -344,15 +344,15 @@ target | std | host | notes [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | | [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2) -`powerpc64le-unknown-freebsd` | | | PPC64LE FreeBSD -`powerpc-unknown-freebsd` | | | PowerPC FreeBSD +`powerpc64le-unknown-freebsd` | ✓ | ✓ | PPC64LE FreeBSD +`powerpc-unknown-freebsd` | ? | | PowerPC FreeBSD `powerpc64-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | `powerpc64le-unknown-linux-musl` | ? | | 64-bit PowerPC Linux with musl 1.2.3, Little Endian [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) -`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) -`riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches) +`riscv32gc-unknown-linux-gnu` | ✓ | | RISC-V Linux (kernel 5.4, glibc 2.33) +`riscv32gc-unknown-linux-musl` | ? | | RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches) [`riscv32im-risc0-zkvm-elf`](platform-support/riscv32im-risc0-zkvm-elf.md) | ? | | RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA) [`riscv32ima-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | | Bare RISC-V (RV32IMA ISA) [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA) @@ -361,13 +361,13 @@ target | std | host | notes [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit -`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD -`riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia +`riscv64gc-unknown-freebsd` | ? | | RISC-V FreeBSD +`riscv64gc-unknown-fuchsia` | ? | | RISC-V Fuchsia [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 -[`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android +[`riscv64-linux-android`](platform-support/android.md) | ? | | RISC-V 64-bit Android [`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | -[`s390x-unknown-linux-musl`](platform-support/s390x-unknown-linux-musl.md) | | | S390x Linux (kernel 3.2, musl 1.2.3) +[`s390x-unknown-linux-musl`](platform-support/s390x-unknown-linux-musl.md) | ✓ | | S390x Linux (kernel 3.2, musl 1.2.3) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+ [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64 From 0b737a163eb47e9eb6e6c461159764758722e6f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 4 Dec 2024 23:01:58 +0100 Subject: [PATCH 054/107] Exclude additional subtrees in `ruff` config --- src/tools/tidy/config/ruff.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/tidy/config/ruff.toml b/src/tools/tidy/config/ruff.toml index de23d93593c1..4a5aa618be15 100644 --- a/src/tools/tidy/config/ruff.toml +++ b/src/tools/tidy/config/ruff.toml @@ -19,6 +19,9 @@ extend-exclude = [ "src/tools/enzyme/", "src/tools/rustc-perf/", "src/gcc/", + "compiler/rustc_codegen_gcc", + "src/tools/clippy", + "src/tools/miri", # Hack: CI runs from a subdirectory under the main checkout "../src/doc/nomicon/", "../src/tools/cargo/", @@ -34,6 +37,9 @@ extend-exclude = [ "../src/tools/enzyme/", "../src/tools/rustc-perf/", "../src/gcc/", + "../compiler/rustc_codegen_gcc", + "../src/tools/clippy", + "../src/tools/miri", ] [lint] From 536516f949ff37b0e10eaed835c2d3592d03e576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 4 Dec 2024 23:02:25 +0100 Subject: [PATCH 055/107] Reformat Python code with `ruff` --- library/core/src/unicode/printable.py | 53 +- src/bootstrap/bootstrap.py | 665 +++++++++++------- src/bootstrap/bootstrap_test.py | 42 +- src/bootstrap/configure.py | 519 +++++++++----- src/ci/cpu-usage-over-time.py | 36 +- .../test-various/uefi_qemu_test/run.py | 147 ++-- src/ci/docker/scripts/android-sdk-manager.py | 60 +- src/ci/docker/scripts/fuchsia-test-runner.py | 8 +- src/ci/github-actions/calculate-job-matrix.py | 13 +- src/ci/scripts/upload-build-metrics.py | 21 +- src/etc/dec2flt_table.py | 46 +- src/etc/gdb_load_rust_pretty_printers.py | 1 + src/etc/gdb_lookup.py | 7 +- src/etc/gdb_providers.py | 35 +- src/etc/generate-deriving-span-tests.py | 60 +- src/etc/generate-keyword-tests.py | 8 +- src/etc/htmldocck.py | 260 ++++--- src/etc/lldb_batchmode.py | 69 +- src/etc/lldb_providers.py | 186 +++-- src/etc/rust_types.py | 3 +- src/tools/publish_toolstate.py | 226 +++--- .../dependency-with-embedded-visualizers.py | 3 + tests/debuginfo/embedded-visualizer-point.py | 3 + tests/debuginfo/embedded-visualizer.py | 3 + x.py | 9 +- 25 files changed, 1540 insertions(+), 943 deletions(-) diff --git a/library/core/src/unicode/printable.py b/library/core/src/unicode/printable.py index 4d39ace066c4..260fa9f9e6ad 100755 --- a/library/core/src/unicode/printable.py +++ b/library/core/src/unicode/printable.py @@ -9,7 +9,8 @@ import csv import os import subprocess -NUM_CODEPOINTS=0x110000 +NUM_CODEPOINTS = 0x110000 + def to_ranges(iter): current = None @@ -23,11 +24,15 @@ def to_ranges(iter): if current is not None: yield tuple(current) + def get_escaped(codepoints): for c in codepoints: - if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): + if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord( + " " + ): yield c.value + def get_file(f): try: return open(os.path.basename(f)) @@ -35,7 +40,9 @@ def get_file(f): subprocess.run(["curl", "-O", f], check=True) return open(os.path.basename(f)) -Codepoint = namedtuple('Codepoint', 'value class_') + +Codepoint = namedtuple("Codepoint", "value class_") + def get_codepoints(f): r = csv.reader(f, delimiter=";") @@ -66,13 +73,14 @@ def get_codepoints(f): for c in range(prev_codepoint + 1, NUM_CODEPOINTS): yield Codepoint(c, None) + def compress_singletons(singletons): - uppers = [] # (upper, # items in lowers) + uppers = [] # (upper, # items in lowers) lowers = [] for i in singletons: upper = i >> 8 - lower = i & 0xff + lower = i & 0xFF if len(uppers) == 0 or uppers[-1][0] != upper: uppers.append((upper, 1)) else: @@ -82,10 +90,11 @@ def compress_singletons(singletons): return uppers, lowers + def compress_normal(normal): # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff - compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] prev_start = 0 for start, count in normal: @@ -95,21 +104,22 @@ def compress_normal(normal): assert truelen < 0x8000 and falselen < 0x8000 entry = [] - if truelen > 0x7f: + if truelen > 0x7F: entry.append(0x80 | (truelen >> 8)) - entry.append(truelen & 0xff) + entry.append(truelen & 0xFF) else: - entry.append(truelen & 0x7f) - if falselen > 0x7f: + entry.append(truelen & 0x7F) + if falselen > 0x7F: entry.append(0x80 | (falselen >> 8)) - entry.append(falselen & 0xff) + entry.append(falselen & 0xFF) else: - entry.append(falselen & 0x7f) + entry.append(falselen & 0x7F) compressed.append(entry) return compressed + def print_singletons(uppers, lowers, uppersname, lowersname): print("#[rustfmt::skip]") print("const {}: &[(u8, u8)] = &[".format(uppersname)) @@ -119,9 +129,12 @@ def print_singletons(uppers, lowers, uppersname, lowersname): print("#[rustfmt::skip]") print("const {}: &[u8] = &[".format(lowersname)) for i in range(0, len(lowers), 8): - print(" {}".format(" ".join("{:#04x},".format(x) for x in lowers[i:i+8]))) + print( + " {}".format(" ".join("{:#04x},".format(x) for x in lowers[i : i + 8])) + ) print("];") + def print_normal(normal, normalname): print("#[rustfmt::skip]") print("const {}: &[u8] = &[".format(normalname)) @@ -129,12 +142,13 @@ def print_normal(normal, normalname): print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) print("];") + def main(): file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt") codepoints = get_codepoints(file) - CUTOFF=0x10000 + CUTOFF = 0x10000 singletons0 = [] singletons1 = [] normal0 = [] @@ -234,10 +248,11 @@ pub(crate) fn is_printable(x: char) -> bool { }\ """) print() - print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') - print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') - print_normal(normal0, 'NORMAL0') - print_normal(normal1, 'NORMAL1') + print_singletons(singletons0u, singletons0l, "SINGLETONS0U", "SINGLETONS0L") + print_singletons(singletons1u, singletons1l, "SINGLETONS1U", "SINGLETONS1L") + print_normal(normal0, "NORMAL0") + print_normal(normal1, "NORMAL1") -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 762f4e653e91..95aa2e992dd2 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -19,14 +19,17 @@ try: except ImportError: lzma = None + def platform_is_win32(): - return sys.platform == 'win32' + return sys.platform == "win32" + if platform_is_win32(): EXE_SUFFIX = ".exe" else: EXE_SUFFIX = "" + def get_cpus(): if hasattr(os, "sched_getaffinity"): return len(os.sched_getaffinity(0)) @@ -51,11 +54,14 @@ def get(base, url, path, checksums, verbose=False): try: if url not in checksums: - raise RuntimeError(("src/stage0 doesn't contain a checksum for {}. " - "Pre-built artifacts might not be available for this " - "target at this time, see https://doc.rust-lang.org/nightly" - "/rustc/platform-support.html for more information.") - .format(url)) + raise RuntimeError( + ( + "src/stage0 doesn't contain a checksum for {}. " + "Pre-built artifacts might not be available for this " + "target at this time, see https://doc.rust-lang.org/nightly" + "/rustc/platform-support.html for more information." + ).format(url) + ) sha256 = checksums[url] if os.path.exists(path): if verify(path, sha256, False): @@ -64,8 +70,11 @@ def get(base, url, path, checksums, verbose=False): return else: if verbose: - eprint("ignoring already-download file", - path, "due to failed verification") + eprint( + "ignoring already-download file", + path, + "due to failed verification", + ) os.unlink(path) download(temp_path, "{}/{}".format(base, url), True, verbose) if not verify(temp_path, sha256, verbose): @@ -79,12 +88,14 @@ def get(base, url, path, checksums, verbose=False): eprint("removing", temp_path) os.unlink(temp_path) + def curl_version(): m = re.match(bytes("^curl ([0-9]+)\\.([0-9]+)", "utf8"), require(["curl", "-V"])) if m is None: return (0, 0) return (int(m[1]), int(m[2])) + def download(path, url, probably_big, verbose): for _ in range(4): try: @@ -114,32 +125,53 @@ def _download(path, url, probably_big, verbose, exception): require(["curl", "--version"], exception=platform_is_win32()) extra_flags = [] if curl_version() > (7, 70): - extra_flags = [ "--retry-all-errors" ] + extra_flags = ["--retry-all-errors"] # options should be kept in sync with # src/bootstrap/src/core/download.rs # for consistency. # they are also more compreprensivly explained in that file. - run(["curl", option] + extra_flags + [ - # Follow redirect. - "--location", - # timeout if speed is < 10 bytes/sec for > 30 seconds - "--speed-time", "30", "--speed-limit", "10", - # timeout if cannot connect within 30 seconds - "--connect-timeout", "30", - "--output", path, - "--continue-at", "-", - "--retry", "3", "--show-error", "--remote-time", "--fail", url], + run( + ["curl", option] + + extra_flags + + [ + # Follow redirect. + "--location", + # timeout if speed is < 10 bytes/sec for > 30 seconds + "--speed-time", + "30", + "--speed-limit", + "10", + # timeout if cannot connect within 30 seconds + "--connect-timeout", + "30", + "--output", + path, + "--continue-at", + "-", + "--retry", + "3", + "--show-error", + "--remote-time", + "--fail", + url, + ], verbose=verbose, - exception=True, # Will raise RuntimeError on failure + exception=True, # Will raise RuntimeError on failure ) except (subprocess.CalledProcessError, OSError, RuntimeError): # see http://serverfault.com/questions/301128/how-to-download + script = "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;" if platform_is_win32(): - run_powershell([ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", - "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format(url, path)], + run_powershell( + [ + script, + "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')".format( + url, path + ), + ], verbose=verbose, - exception=exception) + exception=exception, + ) # Check if the RuntimeError raised by run(curl) should be silenced elif verbose or exception: raise @@ -153,9 +185,11 @@ def verify(path, expected, verbose): found = hashlib.sha256(source.read()).hexdigest() verified = found == expected if not verified: - eprint("invalid checksum:\n" - " found: {}\n" - " expected: {}".format(found, expected)) + eprint( + "invalid checksum:\n" " found: {}\n" " expected: {}".format( + found, expected + ) + ) return verified @@ -170,7 +204,7 @@ def unpack(tarball, tarball_suffix, dst, verbose=False, match=None): name = member.replace(fname + "/", "", 1) if match is not None and not name.startswith(match): continue - name = name[len(match) + 1:] + name = name[len(match) + 1 :] dst_path = os.path.join(dst, name) if verbose: @@ -186,18 +220,18 @@ def unpack(tarball, tarball_suffix, dst, verbose=False, match=None): def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs): """Run a child program in a new process""" if verbose: - eprint("running: " + ' '.join(args)) + eprint("running: " + " ".join(args)) sys.stdout.flush() # Ensure that the .exe is used on Windows just in case a Linux ELF has been # compiled in the same directory. - if os.name == 'nt' and not args[0].endswith('.exe'): - args[0] += '.exe' + if os.name == "nt" and not args[0].endswith(".exe"): + args[0] += ".exe" # Use Popen here instead of call() as it apparently allows powershell on # Windows to not lock up waiting for input presumably. ret = subprocess.Popen(args, **kwargs) code = ret.wait() if code != 0: - err = "failed to run: " + ' '.join(args) + err = "failed to run: " + " ".join(args) if verbose or exception: raise RuntimeError(err) # For most failures, we definitely do want to print this error, or the user will have no @@ -209,30 +243,30 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs): else: sys.exit(err) + def run_powershell(script, *args, **kwargs): """Run a powershell script""" run(["PowerShell.exe", "/nologo", "-Command"] + script, *args, **kwargs) def require(cmd, exit=True, exception=False): - '''Run a command, returning its output. + """Run a command, returning its output. On error, If `exception` is `True`, raise the error Otherwise If `exit` is `True`, exit the process - Else return None.''' + Else return None.""" try: return subprocess.check_output(cmd).strip() except (subprocess.CalledProcessError, OSError) as exc: if exception: raise elif exit: - eprint("ERROR: unable to run `{}`: {}".format(' '.join(cmd), exc)) + eprint("ERROR: unable to run `{}`: {}".format(" ".join(cmd), exc)) eprint("Please make sure it's installed and in the path.") sys.exit(1) return None - def format_build_time(duration): """Return a nicer format for build time @@ -252,13 +286,16 @@ def default_build_triple(verbose): if platform_is_win32(): try: - version = subprocess.check_output(["rustc", "--version", "--verbose"], - stderr=subprocess.DEVNULL) + version = subprocess.check_output( + ["rustc", "--version", "--verbose"], stderr=subprocess.DEVNULL + ) version = version.decode(default_encoding) - host = next(x for x in version.split('\n') if x.startswith("host: ")) + host = next(x for x in version.split("\n") if x.startswith("host: ")) triple = host.split("host: ")[1] if verbose: - eprint("detected default triple {} from pre-installed rustc".format(triple)) + eprint( + "detected default triple {} from pre-installed rustc".format(triple) + ) return triple except Exception as e: if verbose: @@ -270,148 +307,149 @@ def default_build_triple(verbose): # If we do not have `uname`, assume Windows. if uname is None: - return 'x86_64-pc-windows-msvc' + return "x86_64-pc-windows-msvc" kernel, cputype, processor = uname.decode(default_encoding).split(maxsplit=2) # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. kerneltype_mapper = { - 'Darwin': 'apple-darwin', - 'DragonFly': 'unknown-dragonfly', - 'FreeBSD': 'unknown-freebsd', - 'Haiku': 'unknown-haiku', - 'NetBSD': 'unknown-netbsd', - 'OpenBSD': 'unknown-openbsd', - 'GNU': 'unknown-hurd', + "Darwin": "apple-darwin", + "DragonFly": "unknown-dragonfly", + "FreeBSD": "unknown-freebsd", + "Haiku": "unknown-haiku", + "NetBSD": "unknown-netbsd", + "OpenBSD": "unknown-openbsd", + "GNU": "unknown-hurd", } # Consider the direct transformation first and then the special cases if kernel in kerneltype_mapper: kernel = kerneltype_mapper[kernel] - elif kernel == 'Linux': + elif kernel == "Linux": # Apple doesn't support `-o` so this can't be used in the combined # uname invocation above ostype = require(["uname", "-o"], exit=required).decode(default_encoding) - if ostype == 'Android': - kernel = 'linux-android' + if ostype == "Android": + kernel = "linux-android" else: - kernel = 'unknown-linux-gnu' - elif kernel == 'SunOS': - kernel = 'pc-solaris' + kernel = "unknown-linux-gnu" + elif kernel == "SunOS": + kernel = "pc-solaris" # On Solaris, uname -m will return a machine classification instead # of a cpu type, so uname -p is recommended instead. However, the # output from that option is too generic for our purposes (it will # always emit 'i386' on x86/amd64 systems). As such, isainfo -k # must be used instead. - cputype = require(['isainfo', '-k']).decode(default_encoding) + cputype = require(["isainfo", "-k"]).decode(default_encoding) # sparc cpus have sun as a target vendor - if 'sparc' in cputype: - kernel = 'sun-solaris' - elif kernel.startswith('MINGW'): + if "sparc" in cputype: + kernel = "sun-solaris" + elif kernel.startswith("MINGW"): # msys' `uname` does not print gcc configuration, but prints msys # configuration. so we cannot believe `uname -m`: # msys1 is always i686 and msys2 is always x86_64. # instead, msys defines $MSYSTEM which is MINGW32 on i686 and # MINGW64 on x86_64. - kernel = 'pc-windows-gnu' - cputype = 'i686' - if os.environ.get('MSYSTEM') == 'MINGW64': - cputype = 'x86_64' - elif kernel.startswith('MSYS'): - kernel = 'pc-windows-gnu' - elif kernel.startswith('CYGWIN_NT'): - cputype = 'i686' - if kernel.endswith('WOW64'): - cputype = 'x86_64' - kernel = 'pc-windows-gnu' + kernel = "pc-windows-gnu" + cputype = "i686" + if os.environ.get("MSYSTEM") == "MINGW64": + cputype = "x86_64" + elif kernel.startswith("MSYS"): + kernel = "pc-windows-gnu" + elif kernel.startswith("CYGWIN_NT"): + cputype = "i686" + if kernel.endswith("WOW64"): + cputype = "x86_64" + kernel = "pc-windows-gnu" elif platform_is_win32(): # Some Windows platforms might have a `uname` command that returns a # non-standard string (e.g. gnuwin32 tools returns `windows32`). In # these cases, fall back to using sys.platform. - return 'x86_64-pc-windows-msvc' - elif kernel == 'AIX': + return "x86_64-pc-windows-msvc" + elif kernel == "AIX": # `uname -m` returns the machine ID rather than machine hardware on AIX, # so we are unable to use cputype to form triple. AIX 7.2 and # above supports 32-bit and 64-bit mode simultaneously and `uname -p` # returns `powerpc`, however we only supports `powerpc64-ibm-aix` in # rust on AIX. For above reasons, kerneltype_mapper and cputype_mapper # are not used to infer AIX's triple. - return 'powerpc64-ibm-aix' + return "powerpc64-ibm-aix" else: err = "unknown OS type: {}".format(kernel) sys.exit(err) - if cputype in ['powerpc', 'riscv'] and kernel == 'unknown-freebsd': - cputype = subprocess.check_output( - ['uname', '-p']).strip().decode(default_encoding) + if cputype in ["powerpc", "riscv"] and kernel == "unknown-freebsd": + cputype = ( + subprocess.check_output(["uname", "-p"]).strip().decode(default_encoding) + ) cputype_mapper = { - 'BePC': 'i686', - 'aarch64': 'aarch64', - 'aarch64eb': 'aarch64', - 'amd64': 'x86_64', - 'arm64': 'aarch64', - 'i386': 'i686', - 'i486': 'i686', - 'i686': 'i686', - 'i686-AT386': 'i686', - 'i786': 'i686', - 'loongarch64': 'loongarch64', - 'm68k': 'm68k', - 'csky': 'csky', - 'powerpc': 'powerpc', - 'powerpc64': 'powerpc64', - 'powerpc64le': 'powerpc64le', - 'ppc': 'powerpc', - 'ppc64': 'powerpc64', - 'ppc64le': 'powerpc64le', - 'riscv64': 'riscv64gc', - 's390x': 's390x', - 'x64': 'x86_64', - 'x86': 'i686', - 'x86-64': 'x86_64', - 'x86_64': 'x86_64' + "BePC": "i686", + "aarch64": "aarch64", + "aarch64eb": "aarch64", + "amd64": "x86_64", + "arm64": "aarch64", + "i386": "i686", + "i486": "i686", + "i686": "i686", + "i686-AT386": "i686", + "i786": "i686", + "loongarch64": "loongarch64", + "m68k": "m68k", + "csky": "csky", + "powerpc": "powerpc", + "powerpc64": "powerpc64", + "powerpc64le": "powerpc64le", + "ppc": "powerpc", + "ppc64": "powerpc64", + "ppc64le": "powerpc64le", + "riscv64": "riscv64gc", + "s390x": "s390x", + "x64": "x86_64", + "x86": "i686", + "x86-64": "x86_64", + "x86_64": "x86_64", } # Consider the direct transformation first and then the special cases if cputype in cputype_mapper: cputype = cputype_mapper[cputype] - elif cputype in {'xscale', 'arm'}: - cputype = 'arm' - if kernel == 'linux-android': - kernel = 'linux-androideabi' - elif kernel == 'unknown-freebsd': + elif cputype in {"xscale", "arm"}: + cputype = "arm" + if kernel == "linux-android": + kernel = "linux-androideabi" + elif kernel == "unknown-freebsd": cputype = processor - kernel = 'unknown-freebsd' - elif cputype == 'armv6l': - cputype = 'arm' - if kernel == 'linux-android': - kernel = 'linux-androideabi' + kernel = "unknown-freebsd" + elif cputype == "armv6l": + cputype = "arm" + if kernel == "linux-android": + kernel = "linux-androideabi" else: - kernel += 'eabihf' - elif cputype in {'armv7l', 'armv8l'}: - cputype = 'armv7' - if kernel == 'linux-android': - kernel = 'linux-androideabi' + kernel += "eabihf" + elif cputype in {"armv7l", "armv8l"}: + cputype = "armv7" + if kernel == "linux-android": + kernel = "linux-androideabi" else: - kernel += 'eabihf' - elif cputype == 'mips': - if sys.byteorder == 'big': - cputype = 'mips' - elif sys.byteorder == 'little': - cputype = 'mipsel' + kernel += "eabihf" + elif cputype == "mips": + if sys.byteorder == "big": + cputype = "mips" + elif sys.byteorder == "little": + cputype = "mipsel" else: raise ValueError("unknown byteorder: {}".format(sys.byteorder)) - elif cputype == 'mips64': - if sys.byteorder == 'big': - cputype = 'mips64' - elif sys.byteorder == 'little': - cputype = 'mips64el' + elif cputype == "mips64": + if sys.byteorder == "big": + cputype = "mips64" + elif sys.byteorder == "little": + cputype = "mips64el" else: - raise ValueError('unknown byteorder: {}'.format(sys.byteorder)) + raise ValueError("unknown byteorder: {}".format(sys.byteorder)) # only the n64 ABI is supported, indicate it - kernel += 'abi64' - elif cputype == 'sparc' or cputype == 'sparcv9' or cputype == 'sparc64': + kernel += "abi64" + elif cputype == "sparc" or cputype == "sparcv9" or cputype == "sparc64": pass else: err = "unknown cpu type: {}".format(cputype) @@ -422,8 +460,8 @@ def default_build_triple(verbose): @contextlib.contextmanager def output(filepath): - tmp = filepath + '.tmp' - with open(tmp, 'w') as f: + tmp = filepath + ".tmp" + with open(tmp, "w") as f: yield f try: if os.path.exists(filepath): @@ -467,6 +505,7 @@ class DownloadInfo: self.pattern = pattern self.verbose = verbose + def download_component(download_info): if not os.path.exists(download_info.tarball_path): get( @@ -477,6 +516,7 @@ def download_component(download_info): verbose=download_info.verbose, ) + def unpack_component(download_info): unpack( download_info.tarball_path, @@ -486,26 +526,30 @@ def unpack_component(download_info): verbose=download_info.verbose, ) + class FakeArgs: """Used for unit tests to avoid updating all call sites""" + def __init__(self): - self.build = '' - self.build_dir = '' + self.build = "" + self.build_dir = "" self.clean = False self.verbose = False self.json_output = False - self.color = 'auto' - self.warnings = 'default' + self.color = "auto" + self.warnings = "default" + class RustBuild(object): """Provide all the methods required to build Rust""" + def __init__(self, config_toml="", args=None): if args is None: args = FakeArgs() self.git_version = None self.nix_deps_dir = None self._should_fix_bins_and_dylibs = None - self.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) + self.rust_root = os.path.abspath(os.path.join(__file__, "../../..")) self.config_toml = config_toml @@ -515,26 +559,28 @@ class RustBuild(object): self.color = args.color self.warnings = args.warnings - config_verbose_count = self.get_toml('verbose', 'build') + config_verbose_count = self.get_toml("verbose", "build") if config_verbose_count is not None: self.verbose = max(self.verbose, int(config_verbose_count)) - self.use_vendored_sources = self.get_toml('vendor', 'build') == 'true' - self.use_locked_deps = self.get_toml('locked-deps', 'build') == 'true' + self.use_vendored_sources = self.get_toml("vendor", "build") == "true" + self.use_locked_deps = self.get_toml("locked-deps", "build") == "true" - build_dir = args.build_dir or self.get_toml('build-dir', 'build') or 'build' + build_dir = args.build_dir or self.get_toml("build-dir", "build") or "build" self.build_dir = os.path.abspath(build_dir) - self.stage0_data = parse_stage0_file(os.path.join(self.rust_root, "src", "stage0")) - self.stage0_compiler = Stage0Toolchain( - self.stage0_data["compiler_date"], - self.stage0_data["compiler_version"] + self.stage0_data = parse_stage0_file( + os.path.join(self.rust_root, "src", "stage0") + ) + self.stage0_compiler = Stage0Toolchain( + self.stage0_data["compiler_date"], self.stage0_data["compiler_version"] + ) + self.download_url = ( + os.getenv("RUSTUP_DIST_SERVER") or self.stage0_data["dist_server"] ) - self.download_url = os.getenv("RUSTUP_DIST_SERVER") or self.stage0_data["dist_server"] self.build = args.build or self.build_triple() - def download_toolchain(self): """Fetch the build system for Rust, written in Rust @@ -550,58 +596,73 @@ class RustBuild(object): key = self.stage0_compiler.date is_outdated = self.program_out_of_date(self.rustc_stamp(), key) - need_rustc = self.rustc().startswith(bin_root) and (not os.path.exists(self.rustc()) \ - or is_outdated) - need_cargo = self.cargo().startswith(bin_root) and (not os.path.exists(self.cargo()) \ - or is_outdated) + need_rustc = self.rustc().startswith(bin_root) and ( + not os.path.exists(self.rustc()) or is_outdated + ) + need_cargo = self.cargo().startswith(bin_root) and ( + not os.path.exists(self.cargo()) or is_outdated + ) if need_rustc or need_cargo: if os.path.exists(bin_root): # HACK: On Windows, we can't delete rust-analyzer-proc-macro-server while it's # running. Kill it. if platform_is_win32(): - print("Killing rust-analyzer-proc-macro-srv before deleting stage0 toolchain") - regex = '{}\\\\(host|{})\\\\stage0\\\\libexec'.format( - os.path.basename(self.build_dir), - self.build + print( + "Killing rust-analyzer-proc-macro-srv before deleting stage0 toolchain" + ) + regex = "{}\\\\(host|{})\\\\stage0\\\\libexec".format( + os.path.basename(self.build_dir), self.build ) script = ( # NOTE: can't use `taskkill` or `Get-Process -Name` because they error if # the server isn't running. - 'Get-Process | ' + - 'Where-Object {$_.Name -eq "rust-analyzer-proc-macro-srv"} |' + - 'Where-Object {{$_.Path -match "{}"}} |'.format(regex) + - 'Stop-Process' + "Get-Process | " + + 'Where-Object {$_.Name -eq "rust-analyzer-proc-macro-srv"} |' + + 'Where-Object {{$_.Path -match "{}"}} |'.format(regex) + + "Stop-Process" ) run_powershell([script]) shutil.rmtree(bin_root) - cache_dst = (self.get_toml('bootstrap-cache-path', 'build') or - os.path.join(self.build_dir, "cache")) + cache_dst = self.get_toml("bootstrap-cache-path", "build") or os.path.join( + self.build_dir, "cache" + ) rustc_cache = os.path.join(cache_dst, key) if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) - tarball_suffix = '.tar.gz' if lzma is None else '.tar.xz' + tarball_suffix = ".tar.gz" if lzma is None else ".tar.xz" - toolchain_suffix = "{}-{}{}".format(rustc_channel, self.build, tarball_suffix) + toolchain_suffix = "{}-{}{}".format( + rustc_channel, self.build, tarball_suffix + ) tarballs_to_download = [] if need_rustc: tarballs_to_download.append( - ("rust-std-{}".format(toolchain_suffix), "rust-std-{}".format(self.build)) + ( + "rust-std-{}".format(toolchain_suffix), + "rust-std-{}".format(self.build), + ) + ) + tarballs_to_download.append( + ("rustc-{}".format(toolchain_suffix), "rustc") ) - tarballs_to_download.append(("rustc-{}".format(toolchain_suffix), "rustc")) if need_cargo: - tarballs_to_download.append(("cargo-{}".format(toolchain_suffix), "cargo")) + tarballs_to_download.append( + ("cargo-{}".format(toolchain_suffix), "cargo") + ) tarballs_download_info = [ DownloadInfo( base_download_url=self.download_url, - download_path="dist/{}/{}".format(self.stage0_compiler.date, filename), + download_path="dist/{}/{}".format( + self.stage0_compiler.date, filename + ), bin_root=self.bin_root(), tarball_path=os.path.join(rustc_cache, filename), tarball_suffix=tarball_suffix, @@ -620,7 +681,11 @@ class RustBuild(object): # In Python 2.7, Pool cannot be used as a context manager. pool_size = min(len(tarballs_download_info), get_cpus()) if self.verbose: - print('Choosing a pool size of', pool_size, 'for the unpacking of the tarballs') + print( + "Choosing a pool size of", + pool_size, + "for the unpacking of the tarballs", + ) p = Pool(pool_size) try: # FIXME: A cheap workaround for https://github.com/rust-lang/rust/issues/125578, @@ -639,7 +704,9 @@ class RustBuild(object): self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root)) self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root)) - self.fix_bin_or_dylib("{}/libexec/rust-analyzer-proc-macro-srv".format(bin_root)) + self.fix_bin_or_dylib( + "{}/libexec/rust-analyzer-proc-macro-srv".format(bin_root) + ) lib_dir = "{}/lib".format(bin_root) rustlib_bin_dir = "{}/rustlib/{}/bin".format(lib_dir, self.build) self.fix_bin_or_dylib("{}/rust-lld".format(rustlib_bin_dir)) @@ -667,12 +734,15 @@ class RustBuild(object): def get_answer(): default_encoding = sys.getdefaultencoding() try: - ostype = subprocess.check_output( - ['uname', '-s']).strip().decode(default_encoding) + ostype = ( + subprocess.check_output(["uname", "-s"]) + .strip() + .decode(default_encoding) + ) except subprocess.CalledProcessError: return False except OSError as reason: - if getattr(reason, 'winerror', None) is not None: + if getattr(reason, "winerror", None) is not None: return False raise reason @@ -690,17 +760,23 @@ class RustBuild(object): # The latter one does not exist on NixOS when using tmpfs as root. try: with open("/etc/os-release", "r") as f: - is_nixos = any(ln.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') - for ln in f) + is_nixos = any( + ln.strip() in ("ID=nixos", "ID='nixos'", 'ID="nixos"') + for ln in f + ) except FileNotFoundError: is_nixos = False # If not on NixOS, then warn if user seems to be atop Nix shell if not is_nixos: - in_nix_shell = os.getenv('IN_NIX_SHELL') + in_nix_shell = os.getenv("IN_NIX_SHELL") if in_nix_shell: - eprint("The IN_NIX_SHELL environment variable is `{}`;".format(in_nix_shell), - "you may need to set `patch-binaries-for-nix=true` in config.toml") + eprint( + "The IN_NIX_SHELL environment variable is `{}`;".format( + in_nix_shell + ), + "you may need to set `patch-binaries-for-nix=true` in config.toml", + ) return is_nixos @@ -736,7 +812,7 @@ class RustBuild(object): # zlib: Needed as a system dependency of `libLLVM-*.so`. # patchelf: Needed for patching ELF binaries (see doc comment above). nix_deps_dir = "{}/{}".format(self.build_dir, ".nix-deps") - nix_expr = ''' + nix_expr = """ with (import {}); symlinkJoin { name = "rust-stage0-dependencies"; @@ -746,24 +822,30 @@ class RustBuild(object): stdenv.cc.bintools ]; } - ''' + """ try: - subprocess.check_output([ - "nix-build", "-E", nix_expr, "-o", nix_deps_dir, - ]) + subprocess.check_output( + [ + "nix-build", + "-E", + nix_expr, + "-o", + nix_deps_dir, + ] + ) except subprocess.CalledProcessError as reason: eprint("WARNING: failed to call nix-build:", reason) return self.nix_deps_dir = nix_deps_dir patchelf = "{}/bin/patchelf".format(nix_deps_dir) - rpath_entries = [ - os.path.join(os.path.realpath(nix_deps_dir), "lib") - ] + rpath_entries = [os.path.join(os.path.realpath(nix_deps_dir), "lib")] patchelf_args = ["--add-rpath", ":".join(rpath_entries)] if ".so" not in fname: # Finally, set the correct .interp for binaries - with open("{}/nix-support/dynamic-linker".format(nix_deps_dir)) as dynamic_linker: + with open( + "{}/nix-support/dynamic-linker".format(nix_deps_dir) + ) as dynamic_linker: patchelf_args += ["--set-interpreter", dynamic_linker.read().rstrip()] try: @@ -781,13 +863,13 @@ class RustBuild(object): >>> expected = os.path.join("build", "host", "stage0", ".rustc-stamp") >>> assert rb.rustc_stamp() == expected, rb.rustc_stamp() """ - return os.path.join(self.bin_root(), '.rustc-stamp') + return os.path.join(self.bin_root(), ".rustc-stamp") def program_out_of_date(self, stamp_path, key): """Check if the given program stamp is out of date""" if not os.path.exists(stamp_path) or self.clean: return True - with open(stamp_path, 'r') as stamp: + with open(stamp_path, "r") as stamp: return key != stamp.read() def bin_root(self): @@ -834,11 +916,11 @@ class RustBuild(object): def get_toml_static(config_toml, key, section=None): cur_section = None for line in config_toml.splitlines(): - section_match = re.match(r'^\s*\[(.*)\]\s*$', line) + section_match = re.match(r"^\s*\[(.*)\]\s*$", line) if section_match is not None: cur_section = section_match.group(1) - match = re.match(r'^{}\s*=(.*)$'.format(key), line) + match = re.match(r"^{}\s*=(.*)$".format(key), line) if match is not None: value = match.group(1) if section is None or section == cur_section: @@ -847,11 +929,11 @@ class RustBuild(object): def cargo(self): """Return config path for cargo""" - return self.program_config('cargo') + return self.program_config("cargo") def rustc(self): """Return config path for rustc""" - return self.program_config('rustc') + return self.program_config("rustc") def program_config(self, program): """Return config path for the given program at the given stage @@ -886,12 +968,12 @@ class RustBuild(object): """ start = line.find('"') if start != -1: - end = start + 1 + line[start + 1:].find('"') - return line[start + 1:end] - start = line.find('\'') + end = start + 1 + line[start + 1 :].find('"') + return line[start + 1 : end] + start = line.find("'") if start != -1: - end = start + 1 + line[start + 1:].find('\'') - return line[start + 1:end] + end = start + 1 + line[start + 1 :].find("'") + return line[start + 1 : end] return None def bootstrap_out(self): @@ -941,24 +1023,37 @@ class RustBuild(object): del env["CARGO_BUILD_TARGET"] env["CARGO_TARGET_DIR"] = build_dir env["RUSTC"] = self.rustc() - env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ - (os.pathsep + env["LD_LIBRARY_PATH"]) \ - if "LD_LIBRARY_PATH" in env else "" - env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ - (os.pathsep + env["DYLD_LIBRARY_PATH"]) \ - if "DYLD_LIBRARY_PATH" in env else "" - env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ - (os.pathsep + env["LIBRARY_PATH"]) \ - if "LIBRARY_PATH" in env else "" - env["LIBPATH"] = os.path.join(self.bin_root(), "lib") + \ - (os.pathsep + env["LIBPATH"]) \ - if "LIBPATH" in env else "" + env["LD_LIBRARY_PATH"] = ( + os.path.join(self.bin_root(), "lib") + (os.pathsep + env["LD_LIBRARY_PATH"]) + if "LD_LIBRARY_PATH" in env + else "" + ) + env["DYLD_LIBRARY_PATH"] = ( + os.path.join(self.bin_root(), "lib") + + (os.pathsep + env["DYLD_LIBRARY_PATH"]) + if "DYLD_LIBRARY_PATH" in env + else "" + ) + env["LIBRARY_PATH"] = ( + os.path.join(self.bin_root(), "lib") + (os.pathsep + env["LIBRARY_PATH"]) + if "LIBRARY_PATH" in env + else "" + ) + env["LIBPATH"] = ( + os.path.join(self.bin_root(), "lib") + (os.pathsep + env["LIBPATH"]) + if "LIBPATH" in env + else "" + ) # Export Stage0 snapshot compiler related env variables build_section = "target.{}".format(self.build) host_triple_sanitized = self.build.replace("-", "_") var_data = { - "CC": "cc", "CXX": "cxx", "LD": "linker", "AR": "ar", "RANLIB": "ranlib" + "CC": "cc", + "CXX": "cxx", + "LD": "linker", + "AR": "ar", + "RANLIB": "ranlib", } for var_name, toml_key in var_data.items(): toml_val = self.get_toml(toml_key, build_section) @@ -1023,14 +1118,16 @@ class RustBuild(object): if "RUSTFLAGS_BOOTSTRAP" in env: env["RUSTFLAGS"] += " " + env["RUSTFLAGS_BOOTSTRAP"] - env["PATH"] = os.path.join(self.bin_root(), "bin") + \ - os.pathsep + env["PATH"] + env["PATH"] = os.path.join(self.bin_root(), "bin") + os.pathsep + env["PATH"] if not os.path.isfile(self.cargo()): - raise Exception("no cargo executable found at `{}`".format( - self.cargo())) - args = [self.cargo(), "build", "--manifest-path", - os.path.join(self.rust_root, "src/bootstrap/Cargo.toml"), - "-Zroot-dir="+self.rust_root] + raise Exception("no cargo executable found at `{}`".format(self.cargo())) + args = [ + self.cargo(), + "build", + "--manifest-path", + os.path.join(self.rust_root, "src/bootstrap/Cargo.toml"), + "-Zroot-dir=" + self.rust_root, + ] args.extend("--verbose" for _ in range(self.verbose)) if self.use_locked_deps: args.append("--locked") @@ -1058,83 +1155,103 @@ class RustBuild(object): Note that `default_build_triple` is moderately expensive, so use `self.build` where possible. """ - config = self.get_toml('build') + config = self.get_toml("build") return config or default_build_triple(self.verbose) def check_vendored_status(self): """Check that vendoring is configured properly""" # keep this consistent with the equivalent check in bootstrap: # https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/lib.rs#L399-L405 - if 'SUDO_USER' in os.environ and not self.use_vendored_sources: + if "SUDO_USER" in os.environ and not self.use_vendored_sources: if os.getuid() == 0: self.use_vendored_sources = True - eprint('INFO: looks like you\'re trying to run this command as root') - eprint(' and so in order to preserve your $HOME this will now') - eprint(' use vendored sources by default.') + eprint("INFO: looks like you're trying to run this command as root") + eprint(" and so in order to preserve your $HOME this will now") + eprint(" use vendored sources by default.") - cargo_dir = os.path.join(self.rust_root, '.cargo') + cargo_dir = os.path.join(self.rust_root, ".cargo") + url = "https://ci-artifacts.rust-lang.org/rustc-builds//rustc-nightly-src.tar.xz" if self.use_vendored_sources: - vendor_dir = os.path.join(self.rust_root, 'vendor') + vendor_dir = os.path.join(self.rust_root, "vendor") if not os.path.exists(vendor_dir): - eprint('ERROR: vendoring required, but vendor directory does not exist.') - eprint(' Run `x.py vendor` to initialize the vendor directory.') - eprint(' Alternatively, use the pre-vendored `rustc-src` dist component.') - eprint(' To get a stable/beta/nightly version, download it from: ') - eprint(' ' - 'https://forge.rust-lang.org/infra/other-installation-methods.html#source-code') - eprint(' To get a specific commit version, download it using the below URL,') - eprint(' replacing with a specific commit checksum: ') - eprint(' ' - 'https://ci-artifacts.rust-lang.org/rustc-builds//rustc-nightly-src.tar.xz') - eprint(' Once you have the source downloaded, place the vendor directory') - eprint(' from the archive in the root of the rust project.') + eprint( + "ERROR: vendoring required, but vendor directory does not exist." + ) + eprint(" Run `x.py vendor` to initialize the vendor directory.") + eprint( + " Alternatively, use the pre-vendored `rustc-src` dist component." + ) + eprint( + " To get a stable/beta/nightly version, download it from: " + ) + eprint( + " " + "https://forge.rust-lang.org/infra/other-installation-methods.html#source-code" + ) + eprint( + " To get a specific commit version, download it using the below URL," + ) + eprint(" replacing with a specific commit checksum: ") + eprint(" ", url) + eprint( + " Once you have the source downloaded, place the vendor directory" + ) + eprint(" from the archive in the root of the rust project.") raise Exception("{} not found".format(vendor_dir)) if not os.path.exists(cargo_dir): - eprint('ERROR: vendoring required, but .cargo/config does not exist.') + eprint("ERROR: vendoring required, but .cargo/config does not exist.") raise Exception("{} not found".format(cargo_dir)) + def parse_args(args): """Parse the command line arguments that the python script needs.""" parser = argparse.ArgumentParser(add_help=False) - parser.add_argument('-h', '--help', action='store_true') - parser.add_argument('--config') - parser.add_argument('--build-dir') - parser.add_argument('--build') - parser.add_argument('--color', choices=['always', 'never', 'auto']) - parser.add_argument('--clean', action='store_true') - parser.add_argument('--json-output', action='store_true') - parser.add_argument('--warnings', choices=['deny', 'warn', 'default'], default='default') - parser.add_argument('-v', '--verbose', action='count', default=0) + parser.add_argument("-h", "--help", action="store_true") + parser.add_argument("--config") + parser.add_argument("--build-dir") + parser.add_argument("--build") + parser.add_argument("--color", choices=["always", "never", "auto"]) + parser.add_argument("--clean", action="store_true") + parser.add_argument("--json-output", action="store_true") + parser.add_argument( + "--warnings", choices=["deny", "warn", "default"], default="default" + ) + parser.add_argument("-v", "--verbose", action="count", default=0) return parser.parse_known_args(args)[0] + def parse_stage0_file(path): result = {} - with open(path, 'r') as file: + with open(path, "r") as file: for line in file: line = line.strip() - if line and not line.startswith('#'): - key, value = line.split('=', 1) + if line and not line.startswith("#"): + key, value = line.split("=", 1) result[key.strip()] = value.strip() return result + def bootstrap(args): """Configure, fetch, build and run the initial bootstrap""" - rust_root = os.path.abspath(os.path.join(__file__, '../../..')) + rust_root = os.path.abspath(os.path.join(__file__, "../../..")) - if not os.path.exists(os.path.join(rust_root, '.git')) and \ - os.path.exists(os.path.join(rust_root, '.github')): - eprint("warn: Looks like you are trying to bootstrap Rust from a source that is neither a " - "git clone nor distributed tarball.\nThis build may fail due to missing submodules " - "unless you put them in place manually.") + if not os.path.exists(os.path.join(rust_root, ".git")) and os.path.exists( + os.path.join(rust_root, ".github") + ): + eprint( + "warn: Looks like you are trying to bootstrap Rust from a source that is neither a " + "git clone nor distributed tarball.\nThis build may fail due to missing submodules " + "unless you put them in place manually." + ) # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, # then `config.toml` in the root directory. - toml_path = args.config or os.getenv('RUST_BOOTSTRAP_CONFIG') + toml_path = args.config or os.getenv("RUST_BOOTSTRAP_CONFIG") using_default_path = toml_path is None if using_default_path: - toml_path = 'config.toml' + toml_path = "config.toml" if not os.path.exists(toml_path): toml_path = os.path.join(rust_root, toml_path) @@ -1144,23 +1261,23 @@ def bootstrap(args): with open(toml_path) as config: config_toml = config.read() else: - config_toml = '' + config_toml = "" - profile = RustBuild.get_toml_static(config_toml, 'profile') + profile = RustBuild.get_toml_static(config_toml, "profile") if profile is not None: # Allows creating alias for profile names, allowing # profiles to be renamed while maintaining back compatibility # Keep in sync with `profile_aliases` in config.rs - profile_aliases = { - "user": "dist" - } - include_file = 'config.{}.toml'.format(profile_aliases.get(profile) or profile) - include_dir = os.path.join(rust_root, 'src', 'bootstrap', 'defaults') + profile_aliases = {"user": "dist"} + include_file = "config.{}.toml".format(profile_aliases.get(profile) or profile) + include_dir = os.path.join(rust_root, "src", "bootstrap", "defaults") include_path = os.path.join(include_dir, include_file) if not os.path.exists(include_path): - raise Exception("Unrecognized config profile '{}'. Check src/bootstrap/defaults" - " for available options.".format(profile)) + raise Exception( + "Unrecognized config profile '{}'. Check src/bootstrap/defaults" + " for available options.".format(profile) + ) # HACK: This works because `self.get_toml()` returns the first match it finds for a # specific key, so appending our defaults at the end allows the user to override them @@ -1194,8 +1311,8 @@ def main(): start_time = time() # x.py help ... - if len(sys.argv) > 1 and sys.argv[1] == 'help': - sys.argv[1] = '-h' + if len(sys.argv) > 1 and sys.argv[1] == "help": + sys.argv[1] = "-h" args = parse_args(sys.argv) help_triggered = args.help or len(sys.argv) == 1 @@ -1205,14 +1322,15 @@ def main(): if help_triggered: eprint( "INFO: Downloading and building bootstrap before processing --help command.\n" - " See src/bootstrap/README.md for help with common commands.") + " See src/bootstrap/README.md for help with common commands." + ) exit_code = 0 success_word = "successfully" try: bootstrap(args) except (SystemExit, KeyboardInterrupt) as error: - if hasattr(error, 'code') and isinstance(error.code, int): + if hasattr(error, "code") and isinstance(error.code, int): exit_code = error.code else: exit_code = 1 @@ -1220,9 +1338,14 @@ def main(): success_word = "unsuccessfully" if not help_triggered: - eprint("Build completed", success_word, "in", format_build_time(time() - start_time)) + eprint( + "Build completed", + success_word, + "in", + format_build_time(time() - start_time), + ) sys.exit(exit_code) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py index 70ed12b96e87..7494536539d7 100644 --- a/src/bootstrap/bootstrap_test.py +++ b/src/bootstrap/bootstrap_test.py @@ -16,8 +16,9 @@ from shutil import rmtree bootstrap_dir = os.path.dirname(os.path.abspath(__file__)) # For the import below, have Python search in src/bootstrap first. sys.path.insert(0, bootstrap_dir) -import bootstrap # noqa: E402 -import configure # noqa: E402 +import bootstrap # noqa: E402 +import configure # noqa: E402 + def serialize_and_parse(configure_args, bootstrap_args=None): from io import StringIO @@ -32,15 +33,20 @@ def serialize_and_parse(configure_args, bootstrap_args=None): try: import tomllib + # Verify this is actually valid TOML. tomllib.loads(build.config_toml) except ImportError: - print("WARNING: skipping TOML validation, need at least python 3.11", file=sys.stderr) + print( + "WARNING: skipping TOML validation, need at least python 3.11", + file=sys.stderr, + ) return build class VerifyTestCase(unittest.TestCase): """Test Case for verify""" + def setUp(self): self.container = tempfile.mkdtemp() self.src = os.path.join(self.container, "src.txt") @@ -68,14 +74,14 @@ class VerifyTestCase(unittest.TestCase): class ProgramOutOfDate(unittest.TestCase): """Test if a program is out of date""" + def setUp(self): self.container = tempfile.mkdtemp() os.mkdir(os.path.join(self.container, "stage0")) self.build = bootstrap.RustBuild() self.build.date = "2017-06-15" self.build.build_dir = self.container - self.rustc_stamp_path = os.path.join(self.container, "stage0", - ".rustc-stamp") + self.rustc_stamp_path = os.path.join(self.container, "stage0", ".rustc-stamp") self.key = self.build.date + str(None) def tearDown(self): @@ -97,11 +103,14 @@ class ProgramOutOfDate(unittest.TestCase): """Return False both dates match""" with open(self.rustc_stamp_path, "w") as rustc_stamp: rustc_stamp.write("2017-06-15None") - self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key)) + self.assertFalse( + self.build.program_out_of_date(self.rustc_stamp_path, self.key) + ) class ParseArgsInConfigure(unittest.TestCase): """Test if `parse_args` function in `configure.py` works properly""" + @patch("configure.err") def test_unknown_args(self, err): # It should be print an error message if the argument doesn't start with '--' @@ -148,28 +157,35 @@ class ParseArgsInConfigure(unittest.TestCase): class GenerateAndParseConfig(unittest.TestCase): """Test that we can serialize and deserialize a config.toml file""" + def test_no_args(self): build = serialize_and_parse([]) - self.assertEqual(build.get_toml("profile"), 'dist') + self.assertEqual(build.get_toml("profile"), "dist") self.assertIsNone(build.get_toml("llvm.download-ci-llvm")) def test_set_section(self): build = serialize_and_parse(["--set", "llvm.download-ci-llvm"]) - self.assertEqual(build.get_toml("download-ci-llvm", section="llvm"), 'true') + self.assertEqual(build.get_toml("download-ci-llvm", section="llvm"), "true") def test_set_target(self): build = serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"]) - self.assertEqual(build.get_toml("cc", section="target.x86_64-unknown-linux-gnu"), 'gcc') + self.assertEqual( + build.get_toml("cc", section="target.x86_64-unknown-linux-gnu"), "gcc" + ) def test_set_top_level(self): build = serialize_and_parse(["--set", "profile=compiler"]) - self.assertEqual(build.get_toml("profile"), 'compiler') + self.assertEqual(build.get_toml("profile"), "compiler") def test_set_codegen_backends(self): build = serialize_and_parse(["--set", "rust.codegen-backends=cranelift"]) - self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift']"), -1) + self.assertNotEqual( + build.config_toml.find("codegen-backends = ['cranelift']"), -1 + ) build = serialize_and_parse(["--set", "rust.codegen-backends=cranelift,llvm"]) - self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift', 'llvm']"), -1) + self.assertNotEqual( + build.config_toml.find("codegen-backends = ['cranelift', 'llvm']"), -1 + ) build = serialize_and_parse(["--enable-full-tools"]) self.assertNotEqual(build.config_toml.find("codegen-backends = ['llvm']"), -1) @@ -223,7 +239,7 @@ class BuildBootstrap(unittest.TestCase): self.assertTrue("--timings" in args) def test_warnings(self): - for toml_warnings in ['false', 'true', None]: + for toml_warnings in ["false", "true", None]: configure_args = [] if toml_warnings is not None: configure_args = ["--set", "rust.deny-warnings=" + toml_warnings] diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 70f4e70962ab..717500221454 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -6,11 +6,12 @@ from __future__ import absolute_import, division, print_function import shlex import sys import os + rust_dir = os.path.dirname(os.path.abspath(__file__)) rust_dir = os.path.dirname(rust_dir) rust_dir = os.path.dirname(rust_dir) sys.path.append(os.path.join(rust_dir, "src", "bootstrap")) -import bootstrap # noqa: E402 +import bootstrap # noqa: E402 class Option(object): @@ -32,26 +33,62 @@ def v(*args): options.append(Option(*args, value=True)) -o("debug", "rust.debug", "enables debugging environment; does not affect optimization of bootstrapped code") +o( + "debug", + "rust.debug", + "enables debugging environment; does not affect optimization of bootstrapped code", +) o("docs", "build.docs", "build standard library documentation") o("compiler-docs", "build.compiler-docs", "build compiler documentation") o("optimize-tests", "rust.optimize-tests", "build tests with optimizations") o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests") -o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds") +o( + "ccache", + "llvm.ccache", + "invoke gcc/clang via ccache to reuse object files between builds", +) o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds") o("local-rust", None, "use an installed rustc rather than downloading a snapshot") v("local-rust-root", None, "set prefix for local rust binary") -o("local-rebuild", "build.local-rebuild", "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version") -o("llvm-static-stdcpp", "llvm.static-libstdcpp", "statically link to libstdc++ for LLVM") -o("llvm-link-shared", "llvm.link-shared", "prefer shared linking to LLVM (llvm-config --link-shared)") +o( + "local-rebuild", + "build.local-rebuild", + "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version", +) +o( + "llvm-static-stdcpp", + "llvm.static-libstdcpp", + "statically link to libstdc++ for LLVM", +) +o( + "llvm-link-shared", + "llvm.link-shared", + "prefer shared linking to LLVM (llvm-config --link-shared)", +) o("rpath", "rust.rpath", "build rpaths into rustc itself") o("codegen-tests", "rust.codegen-tests", "run the tests/codegen tests") -o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)") +o( + "ninja", + "llvm.ninja", + "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)", +) o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date") o("vendor", "build.vendor", "enable usage of vendored Rust crates") -o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, dfsan, lsan, msan, tsan, hwasan)") -o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball") -o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo") +o( + "sanitizers", + "build.sanitizers", + "build the sanitizer runtimes (asan, dfsan, lsan, msan, tsan, hwasan)", +) +o( + "dist-src", + "rust.dist-src", + "when building tarballs enables building a source tarball", +) +o( + "cargo-native-static", + "build.cargo-native-static", + "static native libraries in cargo", +) o("profiler", "build.profiler", "build the profiler runtime") o("full-tools", None, "enable all tools") o("lld", "rust.lld", "build lld") @@ -59,7 +96,11 @@ o("llvm-bitcode-linker", "rust.llvm-bitcode-linker", "build llvm bitcode linker" o("clang", "llvm.clang", "build clang") o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++") o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard") -o("patch-binaries-for-nix", "build.patch-binaries-for-nix", "whether patch binaries for usage with Nix toolchains") +o( + "patch-binaries-for-nix", + "build.patch-binaries-for-nix", + "whether patch binaries for usage with Nix toolchains", +) o("new-symbol-mangling", "rust.new-symbol-mangling", "use symbol-mangling-version v0") v("llvm-cflags", "llvm.cflags", "build LLVM with these extra compiler flags") @@ -76,16 +117,48 @@ o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme") o("llvm-offload", "llvm.offload", "build LLVM with gpu offload support") o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface") o("debug-assertions", "rust.debug-assertions", "build with debugging assertions") -o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions") +o( + "debug-assertions-std", + "rust.debug-assertions-std", + "build the standard library with debugging assertions", +) o("overflow-checks", "rust.overflow-checks", "build with overflow checks") -o("overflow-checks-std", "rust.overflow-checks-std", "build the standard library with overflow checks") -o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger metadata") +o( + "overflow-checks-std", + "rust.overflow-checks-std", + "build the standard library with overflow checks", +) +o( + "llvm-release-debuginfo", + "llvm.release-debuginfo", + "build LLVM with debugger metadata", +) v("debuginfo-level", "rust.debuginfo-level", "debuginfo level for Rust code") -v("debuginfo-level-rustc", "rust.debuginfo-level-rustc", "debuginfo level for the compiler") -v("debuginfo-level-std", "rust.debuginfo-level-std", "debuginfo level for the standard library") -v("debuginfo-level-tools", "rust.debuginfo-level-tools", "debuginfo level for the tools") -v("debuginfo-level-tests", "rust.debuginfo-level-tests", "debuginfo level for the test suites run with compiletest") -v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file") +v( + "debuginfo-level-rustc", + "rust.debuginfo-level-rustc", + "debuginfo level for the compiler", +) +v( + "debuginfo-level-std", + "rust.debuginfo-level-std", + "debuginfo level for the standard library", +) +v( + "debuginfo-level-tools", + "rust.debuginfo-level-tools", + "debuginfo level for the tools", +) +v( + "debuginfo-level-tests", + "rust.debuginfo-level-tests", + "debuginfo level for the test suites run with compiletest", +) +v( + "save-toolstates", + "rust.save-toolstates", + "save build and test status of external tools into this file", +) v("prefix", "install.prefix", "set installation prefix") v("localstatedir", "install.localstatedir", "local state directory") @@ -102,50 +175,117 @@ v("llvm-config", None, "set path to llvm-config") v("llvm-filecheck", None, "set path to LLVM's FileCheck utility") v("python", "build.python", "set path to python") v("android-ndk", "build.android-ndk", "set path to Android NDK") -v("musl-root", "target.x86_64-unknown-linux-musl.musl-root", - "MUSL root installation directory (deprecated)") -v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root", - "x86_64-unknown-linux-musl install directory") -v("musl-root-i586", "target.i586-unknown-linux-musl.musl-root", - "i586-unknown-linux-musl install directory") -v("musl-root-i686", "target.i686-unknown-linux-musl.musl-root", - "i686-unknown-linux-musl install directory") -v("musl-root-arm", "target.arm-unknown-linux-musleabi.musl-root", - "arm-unknown-linux-musleabi install directory") -v("musl-root-armhf", "target.arm-unknown-linux-musleabihf.musl-root", - "arm-unknown-linux-musleabihf install directory") -v("musl-root-armv5te", "target.armv5te-unknown-linux-musleabi.musl-root", - "armv5te-unknown-linux-musleabi install directory") -v("musl-root-armv7", "target.armv7-unknown-linux-musleabi.musl-root", - "armv7-unknown-linux-musleabi install directory") -v("musl-root-armv7hf", "target.armv7-unknown-linux-musleabihf.musl-root", - "armv7-unknown-linux-musleabihf install directory") -v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root", - "aarch64-unknown-linux-musl install directory") -v("musl-root-mips", "target.mips-unknown-linux-musl.musl-root", - "mips-unknown-linux-musl install directory") -v("musl-root-mipsel", "target.mipsel-unknown-linux-musl.musl-root", - "mipsel-unknown-linux-musl install directory") -v("musl-root-mips64", "target.mips64-unknown-linux-muslabi64.musl-root", - "mips64-unknown-linux-muslabi64 install directory") -v("musl-root-mips64el", "target.mips64el-unknown-linux-muslabi64.musl-root", - "mips64el-unknown-linux-muslabi64 install directory") -v("musl-root-riscv32gc", "target.riscv32gc-unknown-linux-musl.musl-root", - "riscv32gc-unknown-linux-musl install directory") -v("musl-root-riscv64gc", "target.riscv64gc-unknown-linux-musl.musl-root", - "riscv64gc-unknown-linux-musl install directory") -v("musl-root-loongarch64", "target.loongarch64-unknown-linux-musl.musl-root", - "loongarch64-unknown-linux-musl install directory") -v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs", - "rootfs in qemu testing, you probably don't want to use this") -v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs", - "rootfs in qemu testing, you probably don't want to use this") -v("qemu-riscv64-rootfs", "target.riscv64gc-unknown-linux-gnu.qemu-rootfs", - "rootfs in qemu testing, you probably don't want to use this") -v("experimental-targets", "llvm.experimental-targets", - "experimental LLVM targets to build") +v( + "musl-root", + "target.x86_64-unknown-linux-musl.musl-root", + "MUSL root installation directory (deprecated)", +) +v( + "musl-root-x86_64", + "target.x86_64-unknown-linux-musl.musl-root", + "x86_64-unknown-linux-musl install directory", +) +v( + "musl-root-i586", + "target.i586-unknown-linux-musl.musl-root", + "i586-unknown-linux-musl install directory", +) +v( + "musl-root-i686", + "target.i686-unknown-linux-musl.musl-root", + "i686-unknown-linux-musl install directory", +) +v( + "musl-root-arm", + "target.arm-unknown-linux-musleabi.musl-root", + "arm-unknown-linux-musleabi install directory", +) +v( + "musl-root-armhf", + "target.arm-unknown-linux-musleabihf.musl-root", + "arm-unknown-linux-musleabihf install directory", +) +v( + "musl-root-armv5te", + "target.armv5te-unknown-linux-musleabi.musl-root", + "armv5te-unknown-linux-musleabi install directory", +) +v( + "musl-root-armv7", + "target.armv7-unknown-linux-musleabi.musl-root", + "armv7-unknown-linux-musleabi install directory", +) +v( + "musl-root-armv7hf", + "target.armv7-unknown-linux-musleabihf.musl-root", + "armv7-unknown-linux-musleabihf install directory", +) +v( + "musl-root-aarch64", + "target.aarch64-unknown-linux-musl.musl-root", + "aarch64-unknown-linux-musl install directory", +) +v( + "musl-root-mips", + "target.mips-unknown-linux-musl.musl-root", + "mips-unknown-linux-musl install directory", +) +v( + "musl-root-mipsel", + "target.mipsel-unknown-linux-musl.musl-root", + "mipsel-unknown-linux-musl install directory", +) +v( + "musl-root-mips64", + "target.mips64-unknown-linux-muslabi64.musl-root", + "mips64-unknown-linux-muslabi64 install directory", +) +v( + "musl-root-mips64el", + "target.mips64el-unknown-linux-muslabi64.musl-root", + "mips64el-unknown-linux-muslabi64 install directory", +) +v( + "musl-root-riscv32gc", + "target.riscv32gc-unknown-linux-musl.musl-root", + "riscv32gc-unknown-linux-musl install directory", +) +v( + "musl-root-riscv64gc", + "target.riscv64gc-unknown-linux-musl.musl-root", + "riscv64gc-unknown-linux-musl install directory", +) +v( + "musl-root-loongarch64", + "target.loongarch64-unknown-linux-musl.musl-root", + "loongarch64-unknown-linux-musl install directory", +) +v( + "qemu-armhf-rootfs", + "target.arm-unknown-linux-gnueabihf.qemu-rootfs", + "rootfs in qemu testing, you probably don't want to use this", +) +v( + "qemu-aarch64-rootfs", + "target.aarch64-unknown-linux-gnu.qemu-rootfs", + "rootfs in qemu testing, you probably don't want to use this", +) +v( + "qemu-riscv64-rootfs", + "target.riscv64gc-unknown-linux-gnu.qemu-rootfs", + "rootfs in qemu testing, you probably don't want to use this", +) +v( + "experimental-targets", + "llvm.experimental-targets", + "experimental LLVM targets to build", +) v("release-channel", "rust.channel", "the name of the release channel to build") -v("release-description", "rust.description", "optional descriptive string for version output") +v( + "release-description", + "rust.description", + "optional descriptive string for version output", +) v("dist-compression-formats", None, "List of compression formats to use") # Used on systems where "cc" is unavailable @@ -154,7 +294,11 @@ v("default-linker", "rust.default-linker", "the default linker") # Many of these are saved below during the "writing configuration" step # (others are conditionally saved). o("manage-submodules", "build.submodules", "let the build manage the git submodules") -o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two (not recommended except for testing reproducible builds)") +o( + "full-bootstrap", + "build.full-bootstrap", + "build three compilers instead of two (not recommended except for testing reproducible builds)", +) o("extended", "build.extended", "build an extended rust tool set") v("bootstrap-cache-path", None, "use provided path for the bootstrap cache") @@ -165,8 +309,16 @@ v("host", None, "List of GNUs ./configure syntax LLVM host triples") v("target", None, "List of GNUs ./configure syntax LLVM target triples") # Options specific to this configure script -o("option-checking", None, "complain about unrecognized options in this configure script") -o("verbose-configure", None, "don't truncate options when printing them in this configure script") +o( + "option-checking", + None, + "complain about unrecognized options in this configure script", +) +o( + "verbose-configure", + None, + "don't truncate options when printing them in this configure script", +) v("set", None, "set arbitrary key/value pairs in TOML configuration") @@ -178,39 +330,42 @@ def err(msg): print("\nconfigure: ERROR: " + msg + "\n") sys.exit(1) + def is_value_list(key): for option in options: - if option.name == key and option.desc.startswith('List of'): + if option.name == key and option.desc.startswith("List of"): return True return False -if '--help' in sys.argv or '-h' in sys.argv: - print('Usage: ./configure [options]') - print('') - print('Options') + +if "--help" in sys.argv or "-h" in sys.argv: + print("Usage: ./configure [options]") + print("") + print("Options") for option in options: - if 'android' in option.name: + if "android" in option.name: # no one needs to know about these obscure options continue if option.value: - print('\t{:30} {}'.format('--{}=VAL'.format(option.name), option.desc)) + print("\t{:30} {}".format("--{}=VAL".format(option.name), option.desc)) else: - print('\t--enable-{:25} OR --disable-{}'.format(option.name, option.name)) - print('\t\t' + option.desc) - print('') - print('This configure script is a thin configuration shim over the true') - print('configuration system, `config.toml`. You can explore the comments') - print('in `config.example.toml` next to this configure script to see') - print('more information about what each option is. Additionally you can') - print('pass `--set` as an argument to set arbitrary key/value pairs') - print('in the TOML configuration if desired') - print('') - print('Also note that all options which take `--enable` can similarly') - print('be passed with `--disable-foo` to forcibly disable the option') + print("\t--enable-{:25} OR --disable-{}".format(option.name, option.name)) + print("\t\t" + option.desc) + print("") + print("This configure script is a thin configuration shim over the true") + print("configuration system, `config.toml`. You can explore the comments") + print("in `config.example.toml` next to this configure script to see") + print("more information about what each option is. Additionally you can") + print("pass `--set` as an argument to set arbitrary key/value pairs") + print("in the TOML configuration if desired") + print("") + print("Also note that all options which take `--enable` can similarly") + print("be passed with `--disable-foo` to forcibly disable the option") sys.exit(0) VERBOSE = False + # Parse all command line arguments into one of these three lists, handling # boolean and value-based options separately def parse_args(args): @@ -222,7 +377,7 @@ def parse_args(args): while i < len(args): arg = args[i] i += 1 - if not arg.startswith('--'): + if not arg.startswith("--"): unknown_args.append(arg) continue @@ -230,7 +385,7 @@ def parse_args(args): for option in options: value = None if option.value: - keyval = arg[2:].split('=', 1) + keyval = arg[2:].split("=", 1) key = keyval[0] if option.name != key: continue @@ -244,9 +399,9 @@ def parse_args(args): need_value_args.append(arg) continue else: - if arg[2:] == 'enable-' + option.name: + if arg[2:] == "enable-" + option.name: value = True - elif arg[2:] == 'disable-' + option.name: + elif arg[2:] == "disable-" + option.name: value = False else: continue @@ -263,8 +418,9 @@ def parse_args(args): # NOTE: here and a few other places, we use [-1] to apply the *last* value # passed. But if option-checking is enabled, then the known_args loop will # also assert that options are only passed once. - option_checking = ('option-checking' not in known_args - or known_args['option-checking'][-1][1]) + option_checking = ( + "option-checking" not in known_args or known_args["option-checking"][-1][1] + ) if option_checking: if len(unknown_args) > 0: err("Option '" + unknown_args[0] + "' is not recognized") @@ -272,18 +428,18 @@ def parse_args(args): err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0])) global VERBOSE - VERBOSE = 'verbose-configure' in known_args + VERBOSE = "verbose-configure" in known_args config = {} - set('build.configure-args', args, config) + set("build.configure-args", args, config) apply_args(known_args, option_checking, config) return parse_example_config(known_args, config) def build(known_args): - if 'build' in known_args: - return known_args['build'][-1][1] + if "build" in known_args: + return known_args["build"][-1][1] return bootstrap.default_build_triple(verbose=False) @@ -291,7 +447,7 @@ def set(key, value, config): if isinstance(value, list): # Remove empty values, which value.split(',') tends to generate and # replace single quotes for double quotes to ensure correct parsing. - value = [v.replace('\'', '"') for v in value if v] + value = [v.replace("'", '"') for v in value if v] s = "{:20} := {}".format(key, value) if len(s) < 70 or VERBOSE: @@ -310,7 +466,7 @@ def set(key, value, config): for i, part in enumerate(parts): if i == len(parts) - 1: if is_value_list(part) and isinstance(value, str): - value = value.split(',') + value = value.split(",") arr[part] = value else: if part not in arr: @@ -321,9 +477,9 @@ def set(key, value, config): def apply_args(known_args, option_checking, config): for key in known_args: # The `set` option is special and can be passed a bunch of times - if key == 'set': + if key == "set": for _option, value in known_args[key]: - keyval = value.split('=', 1) + keyval = value.split("=", 1) if len(keyval) == 1 or keyval[1] == "true": value = True elif keyval[1] == "false": @@ -348,50 +504,55 @@ def apply_args(known_args, option_checking, config): # that here. build_triple = build(known_args) - if option.name == 'sccache': - set('llvm.ccache', 'sccache', config) - elif option.name == 'local-rust': - for path in os.environ['PATH'].split(os.pathsep): - if os.path.exists(path + '/rustc'): - set('build.rustc', path + '/rustc', config) + if option.name == "sccache": + set("llvm.ccache", "sccache", config) + elif option.name == "local-rust": + for path in os.environ["PATH"].split(os.pathsep): + if os.path.exists(path + "/rustc"): + set("build.rustc", path + "/rustc", config) break - for path in os.environ['PATH'].split(os.pathsep): - if os.path.exists(path + '/cargo'): - set('build.cargo', path + '/cargo', config) + for path in os.environ["PATH"].split(os.pathsep): + if os.path.exists(path + "/cargo"): + set("build.cargo", path + "/cargo", config) break - elif option.name == 'local-rust-root': - set('build.rustc', value + '/bin/rustc', config) - set('build.cargo', value + '/bin/cargo', config) - elif option.name == 'llvm-root': - set('target.{}.llvm-config'.format(build_triple), value + '/bin/llvm-config', config) - elif option.name == 'llvm-config': - set('target.{}.llvm-config'.format(build_triple), value, config) - elif option.name == 'llvm-filecheck': - set('target.{}.llvm-filecheck'.format(build_triple), value, config) - elif option.name == 'tools': - set('build.tools', value.split(','), config) - elif option.name == 'bootstrap-cache-path': - set('build.bootstrap-cache-path', value, config) - elif option.name == 'codegen-backends': - set('rust.codegen-backends', value.split(','), config) - elif option.name == 'host': - set('build.host', value.split(','), config) - elif option.name == 'target': - set('build.target', value.split(','), config) - elif option.name == 'full-tools': - set('rust.codegen-backends', ['llvm'], config) - set('rust.lld', True, config) - set('rust.llvm-tools', True, config) - set('rust.llvm-bitcode-linker', True, config) - set('build.extended', True, config) - elif option.name in ['option-checking', 'verbose-configure']: + elif option.name == "local-rust-root": + set("build.rustc", value + "/bin/rustc", config) + set("build.cargo", value + "/bin/cargo", config) + elif option.name == "llvm-root": + set( + "target.{}.llvm-config".format(build_triple), + value + "/bin/llvm-config", + config, + ) + elif option.name == "llvm-config": + set("target.{}.llvm-config".format(build_triple), value, config) + elif option.name == "llvm-filecheck": + set("target.{}.llvm-filecheck".format(build_triple), value, config) + elif option.name == "tools": + set("build.tools", value.split(","), config) + elif option.name == "bootstrap-cache-path": + set("build.bootstrap-cache-path", value, config) + elif option.name == "codegen-backends": + set("rust.codegen-backends", value.split(","), config) + elif option.name == "host": + set("build.host", value.split(","), config) + elif option.name == "target": + set("build.target", value.split(","), config) + elif option.name == "full-tools": + set("rust.codegen-backends", ["llvm"], config) + set("rust.lld", True, config) + set("rust.llvm-tools", True, config) + set("rust.llvm-bitcode-linker", True, config) + set("build.extended", True, config) + elif option.name in ["option-checking", "verbose-configure"]: # this was handled above pass - elif option.name == 'dist-compression-formats': - set('dist.compression-formats', value.split(','), config) + elif option.name == "dist-compression-formats": + set("dist.compression-formats", value.split(","), config) else: raise RuntimeError("unhandled option {}".format(option.name)) + # "Parse" the `config.example.toml` file into the various sections, and we'll # use this as a template of a `config.toml` to write out which preserves # all the various comments and whatnot. @@ -406,20 +567,22 @@ def parse_example_config(known_args, config): targets = {} top_level_keys = [] - with open(rust_dir + '/config.example.toml') as example_config: + with open(rust_dir + "/config.example.toml") as example_config: example_lines = example_config.read().split("\n") for line in example_lines: if cur_section is None: - if line.count('=') == 1: - top_level_key = line.split('=')[0] - top_level_key = top_level_key.strip(' #') + if line.count("=") == 1: + top_level_key = line.split("=")[0] + top_level_key = top_level_key.strip(" #") top_level_keys.append(top_level_key) - if line.startswith('['): + if line.startswith("["): cur_section = line[1:-1] - if cur_section.startswith('target'): - cur_section = 'target' - elif '.' in cur_section: - raise RuntimeError("don't know how to deal with section: {}".format(cur_section)) + if cur_section.startswith("target"): + cur_section = "target" + elif "." in cur_section: + raise RuntimeError( + "don't know how to deal with section: {}".format(cur_section) + ) sections[cur_section] = [line] section_order.append(cur_section) else: @@ -428,22 +591,25 @@ def parse_example_config(known_args, config): # Fill out the `targets` array by giving all configured targets a copy of the # `target` section we just loaded from the example config configured_targets = [build(known_args)] - if 'build' in config: - if 'host' in config['build']: - configured_targets += config['build']['host'] - if 'target' in config['build']: - configured_targets += config['build']['target'] - if 'target' in config: - for target in config['target']: + if "build" in config: + if "host" in config["build"]: + configured_targets += config["build"]["host"] + if "target" in config["build"]: + configured_targets += config["build"]["target"] + if "target" in config: + for target in config["target"]: configured_targets.append(target) for target in configured_targets: - targets[target] = sections['target'][:] + targets[target] = sections["target"][:] # For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target. # Avoid using quotes unless it's necessary. - targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target) + targets[target][0] = targets[target][0].replace( + "x86_64-unknown-linux-gnu", + "'{}'".format(target) if "." in target else target, + ) - if 'profile' not in config: - set('profile', 'dist', config) + if "profile" not in config: + set("profile", "dist", config) configure_file(sections, top_level_keys, targets, config) return section_order, sections, targets @@ -467,7 +633,7 @@ def to_toml(value): else: return "false" elif isinstance(value, list): - return '[' + ', '.join(map(to_toml, value)) + ']' + return "[" + ", ".join(map(to_toml, value)) + "]" elif isinstance(value, str): # Don't put quotes around numeric values if is_number(value): @@ -475,9 +641,18 @@ def to_toml(value): else: return "'" + value + "'" elif isinstance(value, dict): - return "{" + ", ".join(map(lambda a: "{} = {}".format(to_toml(a[0]), to_toml(a[1])), value.items())) + "}" + return ( + "{" + + ", ".join( + map( + lambda a: "{} = {}".format(to_toml(a[0]), to_toml(a[1])), + value.items(), + ) + ) + + "}" + ) else: - raise RuntimeError('no toml') + raise RuntimeError("no toml") def configure_section(lines, config): @@ -485,7 +660,7 @@ def configure_section(lines, config): value = config[key] found = False for i, line in enumerate(lines): - if not line.startswith('#' + key + ' = '): + if not line.startswith("#" + key + " = "): continue found = True lines[i] = "{} = {}".format(key, to_toml(value)) @@ -501,7 +676,9 @@ def configure_section(lines, config): def configure_top_level_key(lines, top_level_key, value): for i, line in enumerate(lines): - if line.startswith('#' + top_level_key + ' = ') or line.startswith(top_level_key + ' = '): + if line.startswith("#" + top_level_key + " = ") or line.startswith( + top_level_key + " = " + ): lines[i] = "{} = {}".format(top_level_key, to_toml(value)) return @@ -512,11 +689,13 @@ def configure_top_level_key(lines, top_level_key, value): def configure_file(sections, top_level_keys, targets, config): for section_key, section_config in config.items(): if section_key not in sections and section_key not in top_level_keys: - raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key)) + raise RuntimeError( + "config key {} not in sections or top_level_keys".format(section_key) + ) if section_key in top_level_keys: configure_top_level_key(sections[None], section_key, section_config) - elif section_key == 'target': + elif section_key == "target": for target in section_config: configure_section(targets[target], section_config[target]) else: @@ -536,18 +715,19 @@ def write_uncommented(target, f): block = [] is_comment = True continue - is_comment = is_comment and line.startswith('#') + is_comment = is_comment and line.startswith("#") return f def write_config_toml(writer, section_order, targets, sections): for section in section_order: - if section == 'target': + if section == "target": for target in targets: writer = write_uncommented(targets[target], writer) else: writer = write_uncommented(sections[section], writer) + def quit_if_file_exists(file): if os.path.isfile(file): msg = "Existing '{}' detected. Exiting".format(file) @@ -559,9 +739,10 @@ def quit_if_file_exists(file): err(msg) + if __name__ == "__main__": # If 'config.toml' already exists, exit the script at this point - quit_if_file_exists('config.toml') + quit_if_file_exists("config.toml") if "GITHUB_ACTIONS" in os.environ: print("::group::Configure the build") @@ -575,13 +756,13 @@ if __name__ == "__main__": # order that we read it in. p("") p("writing `config.toml` in current directory") - with bootstrap.output('config.toml') as f: + with bootstrap.output("config.toml") as f: write_config_toml(f, section_order, targets, sections) - with bootstrap.output('Makefile') as f: - contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in') + with bootstrap.output("Makefile") as f: + contents = os.path.join(rust_dir, "src", "bootstrap", "mk", "Makefile.in") contents = open(contents).read() - contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/') + contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + "/") contents = contents.replace("$(CFG_PYTHON)", sys.executable) f.write(contents) diff --git a/src/ci/cpu-usage-over-time.py b/src/ci/cpu-usage-over-time.py index adfd895ead04..3d9dc86734fc 100755 --- a/src/ci/cpu-usage-over-time.py +++ b/src/ci/cpu-usage-over-time.py @@ -40,12 +40,13 @@ import time # Python 3.3 changed the value of `sys.platform` on Linux from "linux2" to just # "linux". We check here with `.startswith` to keep compatibility with older # Python versions (especially Python 2.7). -if sys.platform.startswith('linux'): +if sys.platform.startswith("linux"): + class State: def __init__(self): - with open('/proc/stat', 'r') as file: + with open("/proc/stat", "r") as file: data = file.readline().split() - if data[0] != 'cpu': + if data[0] != "cpu": raise Exception('did not start with "cpu"') self.user = int(data[1]) self.nice = int(data[2]) @@ -69,10 +70,21 @@ if sys.platform.startswith('linux'): steal = self.steal - prev.steal guest = self.guest - prev.guest guest_nice = self.guest_nice - prev.guest_nice - total = user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice + total = ( + user + + nice + + system + + idle + + iowait + + irq + + softirq + + steal + + guest + + guest_nice + ) return float(idle) / float(total) * 100 -elif sys.platform == 'win32': +elif sys.platform == "win32": from ctypes.wintypes import DWORD from ctypes import Structure, windll, WinError, GetLastError, byref @@ -104,9 +116,10 @@ elif sys.platform == 'win32': kernel = self.kernel - prev.kernel return float(idle) / float(user + kernel) * 100 -elif sys.platform == 'darwin': +elif sys.platform == "darwin": from ctypes import * - libc = cdll.LoadLibrary('/usr/lib/libc.dylib') + + libc = cdll.LoadLibrary("/usr/lib/libc.dylib") class host_cpu_load_info_data_t(Structure): _fields_ = [("cpu_ticks", c_uint * 4)] @@ -116,7 +129,7 @@ elif sys.platform == 'darwin': c_uint, c_int, POINTER(host_cpu_load_info_data_t), - POINTER(c_int) + POINTER(c_int), ] host_statistics.restype = c_int @@ -124,13 +137,14 @@ elif sys.platform == 'darwin': CPU_STATE_SYSTEM = 1 CPU_STATE_IDLE = 2 CPU_STATE_NICE = 3 + class State: def __init__(self): stats = host_cpu_load_info_data_t() - count = c_int(4) # HOST_CPU_LOAD_INFO_COUNT + count = c_int(4) # HOST_CPU_LOAD_INFO_COUNT err = libc.host_statistics( libc.mach_host_self(), - c_int(3), # HOST_CPU_LOAD_INFO + c_int(3), # HOST_CPU_LOAD_INFO byref(stats), byref(count), ) @@ -148,7 +162,7 @@ elif sys.platform == 'darwin': return float(idle) / float(user + system + idle + nice) * 100.0 else: - print('unknown platform', sys.platform) + print("unknown platform", sys.platform) sys.exit(1) cur_state = State() diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py index 3577643ca550..4f877389fbcf 100755 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py @@ -8,78 +8,79 @@ import tempfile from pathlib import Path -TARGET_AARCH64 = 'aarch64-unknown-uefi' -TARGET_I686 = 'i686-unknown-uefi' -TARGET_X86_64 = 'x86_64-unknown-uefi' +TARGET_AARCH64 = "aarch64-unknown-uefi" +TARGET_I686 = "i686-unknown-uefi" +TARGET_X86_64 = "x86_64-unknown-uefi" + def run(*cmd, capture=False, check=True, env=None, timeout=None): """Print and run a command, optionally capturing the output.""" cmd = [str(p) for p in cmd] - print(' '.join(cmd)) - return subprocess.run(cmd, - capture_output=capture, - check=check, - env=env, - text=True, - timeout=timeout) + print(" ".join(cmd)) + return subprocess.run( + cmd, capture_output=capture, check=check, env=env, text=True, timeout=timeout + ) + def build_and_run(tmp_dir, target): if target == TARGET_AARCH64: - boot_file_name = 'bootaa64.efi' - ovmf_dir = Path('/usr/share/AAVMF') - ovmf_code = 'AAVMF_CODE.fd' - ovmf_vars = 'AAVMF_VARS.fd' - qemu = 'qemu-system-aarch64' - machine = 'virt' - cpu = 'cortex-a72' + boot_file_name = "bootaa64.efi" + ovmf_dir = Path("/usr/share/AAVMF") + ovmf_code = "AAVMF_CODE.fd" + ovmf_vars = "AAVMF_VARS.fd" + qemu = "qemu-system-aarch64" + machine = "virt" + cpu = "cortex-a72" elif target == TARGET_I686: - boot_file_name = 'bootia32.efi' - ovmf_dir = Path('/usr/share/OVMF') - ovmf_code = 'OVMF32_CODE_4M.secboot.fd' - ovmf_vars = 'OVMF32_VARS_4M.fd' + boot_file_name = "bootia32.efi" + ovmf_dir = Path("/usr/share/OVMF") + ovmf_code = "OVMF32_CODE_4M.secboot.fd" + ovmf_vars = "OVMF32_VARS_4M.fd" # The i686 target intentionally uses 64-bit qemu; the important # difference is that the OVMF code provides a 32-bit environment. - qemu = 'qemu-system-x86_64' - machine = 'q35' - cpu = 'qemu64' + qemu = "qemu-system-x86_64" + machine = "q35" + cpu = "qemu64" elif target == TARGET_X86_64: - boot_file_name = 'bootx64.efi' - ovmf_dir = Path('/usr/share/OVMF') - ovmf_code = 'OVMF_CODE.fd' - ovmf_vars = 'OVMF_VARS.fd' - qemu = 'qemu-system-x86_64' - machine = 'q35' - cpu = 'qemu64' + boot_file_name = "bootx64.efi" + ovmf_dir = Path("/usr/share/OVMF") + ovmf_code = "OVMF_CODE.fd" + ovmf_vars = "OVMF_VARS.fd" + qemu = "qemu-system-x86_64" + machine = "q35" + cpu = "qemu64" else: - raise KeyError('invalid target') + raise KeyError("invalid target") - host_artifacts = Path('/checkout/obj/build/x86_64-unknown-linux-gnu') - stage0 = host_artifacts / 'stage0/bin' - stage2 = host_artifacts / 'stage2/bin' + host_artifacts = Path("/checkout/obj/build/x86_64-unknown-linux-gnu") + stage0 = host_artifacts / "stage0/bin" + stage2 = host_artifacts / "stage2/bin" env = dict(os.environ) - env['PATH'] = '{}:{}:{}'.format(stage2, stage0, env['PATH']) + env["PATH"] = "{}:{}:{}".format(stage2, stage0, env["PATH"]) # Copy the test create into `tmp_dir`. - test_crate = Path(tmp_dir) / 'uefi_qemu_test' - shutil.copytree('/uefi_qemu_test', test_crate) + test_crate = Path(tmp_dir) / "uefi_qemu_test" + shutil.copytree("/uefi_qemu_test", test_crate) # Build the UEFI executable. - run('cargo', - 'build', - '--manifest-path', - test_crate / 'Cargo.toml', - '--target', + run( + "cargo", + "build", + "--manifest-path", + test_crate / "Cargo.toml", + "--target", target, - env=env) + env=env, + ) # Create a mock EFI System Partition in a subdirectory. - esp = test_crate / 'esp' - boot = esp / 'efi/boot' + esp = test_crate / "esp" + boot = esp / "efi/boot" os.makedirs(boot, exist_ok=True) # Copy the executable into the ESP. - src_exe_path = test_crate / 'target' / target / 'debug/uefi_qemu_test.efi' + src_exe_path = test_crate / "target" / target / "debug/uefi_qemu_test.efi" shutil.copy(src_exe_path, boot / boot_file_name) print(src_exe_path, boot / boot_file_name) @@ -89,37 +90,39 @@ def build_and_run(tmp_dir, target): # Make a writable copy of the vars file. aarch64 doesn't boot # correctly with read-only vars. - ovmf_rw_vars = Path(tmp_dir) / 'vars.fd' + ovmf_rw_vars = Path(tmp_dir) / "vars.fd" shutil.copy(ovmf_vars, ovmf_rw_vars) # Run the executable in QEMU and capture the output. - output = run(qemu, - '-machine', - machine, - '-cpu', - cpu, - '-display', - 'none', - '-serial', - 'stdio', - '-drive', - f'if=pflash,format=raw,readonly=on,file={ovmf_code}', - '-drive', - f'if=pflash,format=raw,readonly=off,file={ovmf_rw_vars}', - '-drive', - f'format=raw,file=fat:rw:{esp}', - capture=True, - check=True, - # Set a timeout to kill the VM in case something goes wrong. - timeout=60).stdout + output = run( + qemu, + "-machine", + machine, + "-cpu", + cpu, + "-display", + "none", + "-serial", + "stdio", + "-drive", + f"if=pflash,format=raw,readonly=on,file={ovmf_code}", + "-drive", + f"if=pflash,format=raw,readonly=off,file={ovmf_rw_vars}", + "-drive", + f"format=raw,file=fat:rw:{esp}", + capture=True, + check=True, + # Set a timeout to kill the VM in case something goes wrong. + timeout=60, + ).stdout - if 'Hello World!' in output: - print('VM produced expected output') + if "Hello World!" in output: + print("VM produced expected output") else: - print('unexpected VM output:') - print('---start---') + print("unexpected VM output:") + print("---start---") print(output) - print('---end---') + print("---end---") sys.exit(1) diff --git a/src/ci/docker/scripts/android-sdk-manager.py b/src/ci/docker/scripts/android-sdk-manager.py index 66cba58427ba..6356f15a8865 100755 --- a/src/ci/docker/scripts/android-sdk-manager.py +++ b/src/ci/docker/scripts/android-sdk-manager.py @@ -35,6 +35,7 @@ MIRROR_BUCKET = "rust-lang-ci-mirrors" MIRROR_BUCKET_REGION = "us-west-1" MIRROR_BASE_DIR = "rustc/android/" + class Package: def __init__(self, path, url, sha1, deps=None): if deps is None: @@ -53,18 +54,25 @@ class Package: sha1 = hashlib.sha1(f.read()).hexdigest() if sha1 != self.sha1: raise RuntimeError( - "hash mismatch for package " + self.path + ": " + - sha1 + " vs " + self.sha1 + " (known good)" + "hash mismatch for package " + + self.path + + ": " + + sha1 + + " vs " + + self.sha1 + + " (known good)" ) return file def __repr__(self): - return " Optional[WorkflowRunType]: try_build = ctx.ref in ( "refs/heads/try", "refs/heads/try-perf", - "refs/heads/automation/bors/try" + "refs/heads/automation/bors/try", ) # Unrolled branch from a rollup for testing perf @@ -135,11 +136,15 @@ def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[ continue jobs.append(job[0]) if unknown_jobs: - raise Exception(f"Custom job(s) `{unknown_jobs}` not found in auto jobs") + raise Exception( + f"Custom job(s) `{unknown_jobs}` not found in auto jobs" + ) return add_base_env(name_jobs(jobs, "try"), job_data["envs"]["try"]) elif isinstance(run_type, AutoRunType): - return add_base_env(name_jobs(job_data["auto"], "auto"), job_data["envs"]["auto"]) + return add_base_env( + name_jobs(job_data["auto"], "auto"), job_data["envs"]["auto"] + ) return [] @@ -161,7 +166,7 @@ def get_github_ctx() -> GitHubCtx: event_name=event_name, ref=os.environ["GITHUB_REF"], repository=os.environ["GITHUB_REPOSITORY"], - commit_message=commit_message + commit_message=commit_message, ) diff --git a/src/ci/scripts/upload-build-metrics.py b/src/ci/scripts/upload-build-metrics.py index a95e0949d700..23061884a39e 100644 --- a/src/ci/scripts/upload-build-metrics.py +++ b/src/ci/scripts/upload-build-metrics.py @@ -19,6 +19,7 @@ $ python3 upload-build-metrics.py `path-to-CPU-usage-CSV` is a path to a CSV generated by the `src/ci/cpu-usage-over-time.py` script. """ + import argparse import csv import os @@ -31,7 +32,7 @@ from typing import List def load_cpu_usage(path: Path) -> List[float]: usage = [] with open(path) as f: - reader = csv.reader(f, delimiter=',') + reader = csv.reader(f, delimiter=",") for row in reader: # The log might contain incomplete rows or some Python exception if len(row) == 2: @@ -50,25 +51,21 @@ def upload_datadog_measure(name: str, value: float): print(f"Metric {name}: {value:.4f}") datadog_cmd = "datadog-ci" - if os.getenv("GITHUB_ACTIONS") is not None and sys.platform.lower().startswith("win"): + if os.getenv("GITHUB_ACTIONS") is not None and sys.platform.lower().startswith( + "win" + ): # Due to weird interaction of MSYS2 and Python, we need to use an absolute path, # and also specify the ".cmd" at the end. See https://github.com/rust-lang/rust/pull/125771. datadog_cmd = "C:\\npm\\prefix\\datadog-ci.cmd" - subprocess.run([ - datadog_cmd, - "measure", - "--level", "job", - "--measures", f"{name}:{value}" - ], - check=False + subprocess.run( + [datadog_cmd, "measure", "--level", "job", "--measures", f"{name}:{value}"], + check=False, ) if __name__ == "__main__": - parser = argparse.ArgumentParser( - prog="DataDog metric uploader" - ) + parser = argparse.ArgumentParser(prog="DataDog metric uploader") parser.add_argument("cpu-usage-history-csv") args = parser.parse_args() diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py index 9264a8439bb7..791186de9c19 100755 --- a/src/etc/dec2flt_table.py +++ b/src/etc/dec2flt_table.py @@ -13,6 +13,7 @@ i.e., within 0.5 ULP of the true value. Adapted from Daniel Lemire's fast_float ``table_generation.py``, available here: . """ + from __future__ import print_function from math import ceil, floor, log from collections import deque @@ -34,6 +35,7 @@ STATIC_WARNING = """ // the final binary. """ + def main(): min_exp = minimum_exponent(10) max_exp = maximum_exponent(10) @@ -41,10 +43,10 @@ def main(): print(HEADER.strip()) print() - print('pub const SMALLEST_POWER_OF_FIVE: i32 = {};'.format(min_exp)) - print('pub const LARGEST_POWER_OF_FIVE: i32 = {};'.format(max_exp)) - print('pub const N_POWERS_OF_FIVE: usize = ', end='') - print('(LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;') + print("pub const SMALLEST_POWER_OF_FIVE: i32 = {};".format(min_exp)) + print("pub const LARGEST_POWER_OF_FIVE: i32 = {};".format(max_exp)) + print("pub const N_POWERS_OF_FIVE: usize = ", end="") + print("(LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;") print() print_proper_powers(min_exp, max_exp, bias) @@ -54,7 +56,7 @@ def minimum_exponent(base): def maximum_exponent(base): - return floor(log(1.7976931348623157e+308, base)) + return floor(log(1.7976931348623157e308, base)) def print_proper_powers(min_exp, max_exp, bias): @@ -64,46 +66,46 @@ def print_proper_powers(min_exp, max_exp, bias): # 2^(2b)/(5^−q) with b=64 + int(math.ceil(log2(5^−q))) powers = [] for q in range(min_exp, 0): - power5 = 5 ** -q + power5 = 5**-q z = 0 while (1 << z) < power5: z += 1 if q >= -27: b = z + 127 - c = 2 ** b // power5 + 1 + c = 2**b // power5 + 1 powers.append((c, q)) else: b = 2 * z + 2 * 64 - c = 2 ** b // power5 + 1 + c = 2**b // power5 + 1 # truncate - while c >= (1<<128): + while c >= (1 << 128): c //= 2 powers.append((c, q)) # Add positive exponents for q in range(0, max_exp + 1): - power5 = 5 ** q + power5 = 5**q # move the most significant bit in position - while power5 < (1<<127): + while power5 < (1 << 127): power5 *= 2 # *truncate* - while power5 >= (1<<128): + while power5 >= (1 << 128): power5 //= 2 powers.append((power5, q)) # Print the powers. print(STATIC_WARNING.strip()) - print('#[rustfmt::skip]') - typ = '[(u64, u64); N_POWERS_OF_FIVE]' - print('pub static POWER_OF_FIVE_128: {} = ['.format(typ)) + print("#[rustfmt::skip]") + typ = "[(u64, u64); N_POWERS_OF_FIVE]" + print("pub static POWER_OF_FIVE_128: {} = [".format(typ)) for c, exp in powers: - hi = '0x{:x}'.format(c // (1 << 64)) - lo = '0x{:x}'.format(c % (1 << 64)) - value = ' ({}, {}), '.format(hi, lo) - comment = '// {}^{}'.format(5, exp) - print(value.ljust(46, ' ') + comment) - print('];') + hi = "0x{:x}".format(c // (1 << 64)) + lo = "0x{:x}".format(c % (1 << 64)) + value = " ({}, {}), ".format(hi, lo) + comment = "// {}^{}".format(5, exp) + print(value.ljust(46, " ") + comment) + print("];") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/etc/gdb_load_rust_pretty_printers.py b/src/etc/gdb_load_rust_pretty_printers.py index e05039ce4744..73d1e79f9617 100644 --- a/src/etc/gdb_load_rust_pretty_printers.py +++ b/src/etc/gdb_load_rust_pretty_printers.py @@ -1,6 +1,7 @@ # Add this folder to the python sys path; GDB Python-interpreter will now find modules in this path import sys from os import path + self_dir = path.dirname(path.realpath(__file__)) sys.path.append(self_dir) diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py index f3ac9c109780..d368f7ed1ec5 100644 --- a/src/etc/gdb_lookup.py +++ b/src/etc/gdb_lookup.py @@ -6,8 +6,11 @@ from gdb_providers import * from rust_types import * -_gdb_version_matched = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION) -gdb_version = [int(num) for num in _gdb_version_matched.groups()] if _gdb_version_matched else [] +_gdb_version_matched = re.search("([0-9]+)\\.([0-9]+)", gdb.VERSION) +gdb_version = ( + [int(num) for num in _gdb_version_matched.groups()] if _gdb_version_matched else [] +) + def register_printers(objfile): objfile.pretty_printers.append(printer) diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index e8f9dee07d3e..34bb5c39909e 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -21,7 +21,7 @@ def unwrap_unique_or_non_null(unique_or_nonnull): # GDB 14 has a tag class that indicates that extension methods are ok # to call. Use of this tag only requires that printers hide local # attributes and methods by prefixing them with "_". -if hasattr(gdb, 'ValuePrinter'): +if hasattr(gdb, "ValuePrinter"): printer_base = gdb.ValuePrinter else: printer_base = object @@ -98,7 +98,7 @@ class StdStrProvider(printer_base): def _enumerate_array_elements(element_ptrs): - for (i, element_ptr) in enumerate(element_ptrs): + for i, element_ptr in enumerate(element_ptrs): key = "[{}]".format(i) element = element_ptr.dereference() @@ -173,7 +173,8 @@ class StdVecDequeProvider(printer_base): def children(self): return _enumerate_array_elements( - (self._data_ptr + ((self._head + index) % self._cap)) for index in xrange(self._size) + (self._data_ptr + ((self._head + index) % self._cap)) + for index in xrange(self._size) ) @staticmethod @@ -270,7 +271,9 @@ def children_of_btree_map(map): # Yields each key/value pair in the node and in any child nodes. def children_of_node(node_ptr, height): def cast_to_internal(node): - internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1) + internal_type_name = node.type.target().name.replace( + "LeafNode", "InternalNode", 1 + ) internal_type = gdb.lookup_type(internal_type_name) return node.cast(internal_type.pointer()) @@ -293,8 +296,16 @@ def children_of_btree_map(map): # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays. key_type_size = keys.type.sizeof val_type_size = vals.type.sizeof - key = keys[i]["value"]["value"] if key_type_size > 0 else gdb.parse_and_eval("()") - val = vals[i]["value"]["value"] if val_type_size > 0 else gdb.parse_and_eval("()") + key = ( + keys[i]["value"]["value"] + if key_type_size > 0 + else gdb.parse_and_eval("()") + ) + val = ( + vals[i]["value"]["value"] + if val_type_size > 0 + else gdb.parse_and_eval("()") + ) yield key, val if map["length"] > 0: @@ -352,7 +363,7 @@ class StdOldHashMapProvider(printer_base): self._hashes = self._table["hashes"] self._hash_uint_type = self._hashes.type self._hash_uint_size = self._hashes.type.sizeof - self._modulo = 2 ** self._hash_uint_size + self._modulo = 2**self._hash_uint_size self._data_ptr = self._hashes[ZERO_FIELD]["pointer"] self._capacity_mask = int(self._table["capacity_mask"]) @@ -382,8 +393,14 @@ class StdOldHashMapProvider(printer_base): hashes = self._hash_uint_size * self._capacity align = self._pair_type_size - len_rounded_up = (((((hashes + align) % self._modulo - 1) % self._modulo) & ~( - (align - 1) % self._modulo)) % self._modulo - hashes) % self._modulo + len_rounded_up = ( + ( + (((hashes + align) % self._modulo - 1) % self._modulo) + & ~((align - 1) % self._modulo) + ) + % self._modulo + - hashes + ) % self._modulo pairs_offset = hashes + len_rounded_up pairs_start = gdb.Value(start + pairs_offset).cast(self._pair_type.pointer()) diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index d61693460bc1..2e810d7df97b 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -12,7 +12,8 @@ import os import stat TEST_DIR = os.path.abspath( - os.path.join(os.path.dirname(__file__), '../test/ui/derives/')) + os.path.join(os.path.dirname(__file__), "../test/ui/derives/") +) TEMPLATE = """\ // This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' @@ -56,28 +57,33 @@ ENUM_TUPLE, ENUM_STRUCT, STRUCT_FIELDS, STRUCT_TUPLE = range(4) def create_test_case(type, trait, super_traits, error_count): - string = [ENUM_STRING, ENUM_STRUCT_VARIANT_STRING, STRUCT_STRING, STRUCT_TUPLE_STRING][type] - all_traits = ','.join([trait] + super_traits) - super_traits = ','.join(super_traits) - error_deriving = '#[derive(%s)]' % super_traits if super_traits else '' + string = [ + ENUM_STRING, + ENUM_STRUCT_VARIANT_STRING, + STRUCT_STRING, + STRUCT_TUPLE_STRING, + ][type] + all_traits = ",".join([trait] + super_traits) + super_traits = ",".join(super_traits) + error_deriving = "#[derive(%s)]" % super_traits if super_traits else "" - errors = '\n'.join('//~%s ERROR' % ('^' * n) for n in range(error_count)) + errors = "\n".join("//~%s ERROR" % ("^" * n) for n in range(error_count)) code = string.format(traits=all_traits, errors=errors) return TEMPLATE.format(error_deriving=error_deriving, code=code) def write_file(name, string): - test_file = os.path.join(TEST_DIR, 'derives-span-%s.rs' % name) + test_file = os.path.join(TEST_DIR, "derives-span-%s.rs" % name) # set write permission if file exists, so it can be changed if os.path.exists(test_file): os.chmod(test_file, stat.S_IWUSR) - with open(test_file, 'w') as f: + with open(test_file, "w") as f: f.write(string) # mark file read-only - os.chmod(test_file, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH) + os.chmod(test_file, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) ENUM = 1 @@ -85,29 +91,31 @@ STRUCT = 2 ALL = STRUCT | ENUM traits = { - 'Default': (STRUCT, [], 1), - 'FromPrimitive': (0, [], 0), # only works for C-like enums - - 'Decodable': (0, [], 0), # FIXME: quoting gives horrible spans - 'Encodable': (0, [], 0), # FIXME: quoting gives horrible spans + "Default": (STRUCT, [], 1), + "FromPrimitive": (0, [], 0), # only works for C-like enums + "Decodable": (0, [], 0), # FIXME: quoting gives horrible spans + "Encodable": (0, [], 0), # FIXME: quoting gives horrible spans } -for (trait, supers, errs) in [('Clone', [], 1), - ('PartialEq', [], 2), - ('PartialOrd', ['PartialEq'], 1), - ('Eq', ['PartialEq'], 1), - ('Ord', ['Eq', 'PartialOrd', 'PartialEq'], 1), - ('Debug', [], 1), - ('Hash', [], 1)]: +for trait, supers, errs in [ + ("Clone", [], 1), + ("PartialEq", [], 2), + ("PartialOrd", ["PartialEq"], 1), + ("Eq", ["PartialEq"], 1), + ("Ord", ["Eq", "PartialOrd", "PartialEq"], 1), + ("Debug", [], 1), + ("Hash", [], 1), +]: traits[trait] = (ALL, supers, errs) -for (trait, (types, super_traits, error_count)) in traits.items(): +for trait, (types, super_traits, error_count) in traits.items(): + def mk(ty, t=trait, st=super_traits, ec=error_count): return create_test_case(ty, t, st, ec) if types & ENUM: - write_file(trait + '-enum', mk(ENUM_TUPLE)) - write_file(trait + '-enum-struct-variant', mk(ENUM_STRUCT)) + write_file(trait + "-enum", mk(ENUM_TUPLE)) + write_file(trait + "-enum-struct-variant", mk(ENUM_STRUCT)) if types & STRUCT: - write_file(trait + '-struct', mk(STRUCT_FIELDS)) - write_file(trait + '-tuple-struct', mk(STRUCT_TUPLE)) + write_file(trait + "-struct", mk(STRUCT_FIELDS)) + write_file(trait + "-tuple-struct", mk(STRUCT_TUPLE)) diff --git a/src/etc/generate-keyword-tests.py b/src/etc/generate-keyword-tests.py index 77c3d2758c6d..28f932acd9d5 100755 --- a/src/etc/generate-keyword-tests.py +++ b/src/etc/generate-keyword-tests.py @@ -22,18 +22,16 @@ fn main() { } """ -test_dir = os.path.abspath( - os.path.join(os.path.dirname(__file__), '../test/ui/parser') -) +test_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../test/ui/parser")) for kw in sys.argv[1:]: - test_file = os.path.join(test_dir, 'keyword-%s-as-identifier.rs' % kw) + test_file = os.path.join(test_dir, "keyword-%s-as-identifier.rs" % kw) # set write permission if file exists, so it can be changed if os.path.exists(test_file): os.chmod(test_file, stat.S_IWUSR) - with open(test_file, 'wt') as f: + with open(test_file, "wt") as f: f.write(template % (kw, kw, kw)) # mark file read-only diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 851b01a7458f..d6b594aca71a 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -127,6 +127,7 @@ import os.path import re import shlex from collections import namedtuple + try: from html.parser import HTMLParser except ImportError: @@ -142,12 +143,28 @@ except ImportError: from htmlentitydefs import name2codepoint # "void elements" (no closing tag) from the HTML Standard section 12.1.2 -VOID_ELEMENTS = {'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', - 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'} +VOID_ELEMENTS = { + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "keygen", + "link", + "menuitem", + "meta", + "param", + "source", + "track", + "wbr", +} # Python 2 -> 3 compatibility try: - unichr # noqa: B018 FIXME: py2 + unichr # noqa: B018 FIXME: py2 except NameError: unichr = chr @@ -158,18 +175,20 @@ channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"] rust_test_path = None bless = None + class CustomHTMLParser(HTMLParser): """simplified HTML parser. this is possible because we are dealing with very regular HTML from rustdoc; we only have to deal with i) void elements and ii) empty attributes.""" + def __init__(self, target=None): HTMLParser.__init__(self) self.__builder = target or ET.TreeBuilder() def handle_starttag(self, tag, attrs): - attrs = {k: v or '' for k, v in attrs} + attrs = {k: v or "" for k, v in attrs} self.__builder.start(tag, attrs) if tag in VOID_ELEMENTS: self.__builder.end(tag) @@ -178,7 +197,7 @@ class CustomHTMLParser(HTMLParser): self.__builder.end(tag) def handle_startendtag(self, tag, attrs): - attrs = {k: v or '' for k, v in attrs} + attrs = {k: v or "" for k, v in attrs} self.__builder.start(tag, attrs) self.__builder.end(tag) @@ -189,7 +208,7 @@ class CustomHTMLParser(HTMLParser): self.__builder.data(unichr(name2codepoint[name])) def handle_charref(self, name): - code = int(name[1:], 16) if name.startswith(('x', 'X')) else int(name, 10) + code = int(name[1:], 16) if name.startswith(("x", "X")) else int(name, 10) self.__builder.data(unichr(code)) def close(self): @@ -197,7 +216,7 @@ class CustomHTMLParser(HTMLParser): return self.__builder.close() -Command = namedtuple('Command', 'negated cmd args lineno context') +Command = namedtuple("Command", "negated cmd args lineno context") class FailedCheck(Exception): @@ -216,17 +235,17 @@ def concat_multi_lines(f): concatenated.""" lastline = None # set to the last line when the last line has a backslash firstlineno = None - catenated = '' + catenated = "" for lineno, line in enumerate(f): - line = line.rstrip('\r\n') + line = line.rstrip("\r\n") # strip the common prefix from the current line if needed if lastline is not None: common_prefix = os.path.commonprefix([line, lastline]) - line = line[len(common_prefix):].lstrip() + line = line[len(common_prefix) :].lstrip() firstlineno = firstlineno or lineno - if line.endswith('\\'): + if line.endswith("\\"): if lastline is None: lastline = line[:-1] catenated += line[:-1] @@ -234,10 +253,10 @@ def concat_multi_lines(f): yield firstlineno, catenated + line lastline = None firstlineno = None - catenated = '' + catenated = "" if lastline is not None: - print_err(lineno, line, 'Trailing backslash at the end of the file') + print_err(lineno, line, "Trailing backslash at the end of the file") def get_known_directive_names(): @@ -253,12 +272,12 @@ def get_known_directive_names(): "tools/compiletest/src/directive-list.rs", ), "r", - encoding="utf8" + encoding="utf8", ) as fd: content = fd.read() return [ - line.strip().replace('",', '').replace('"', '') - for line in content.split('\n') + line.strip().replace('",', "").replace('"', "") + for line in content.split("\n") if filter_line(line) ] @@ -269,35 +288,42 @@ def get_known_directive_names(): # See . KNOWN_DIRECTIVE_NAMES = get_known_directive_names() -LINE_PATTERN = re.compile(r''' +LINE_PATTERN = re.compile( + r""" //@\s+ (?P!?)(?P[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*) (?P.*)$ -''', re.X | re.UNICODE) +""", + re.X | re.UNICODE, +) def get_commands(template): - with io.open(template, encoding='utf-8') as f: + with io.open(template, encoding="utf-8") as f: for lineno, line in concat_multi_lines(f): m = LINE_PATTERN.search(line) if not m: continue - cmd = m.group('cmd') - negated = (m.group('negated') == '!') + cmd = m.group("cmd") + negated = m.group("negated") == "!" if not negated and cmd in KNOWN_DIRECTIVE_NAMES: continue - args = m.group('args') + args = m.group("args") if args and not args[:1].isspace(): - print_err(lineno, line, 'Invalid template syntax') + print_err(lineno, line, "Invalid template syntax") continue try: args = shlex.split(args) except UnicodeEncodeError: - args = [arg.decode('utf-8') for arg in shlex.split(args.encode('utf-8'))] + args = [ + arg.decode("utf-8") for arg in shlex.split(args.encode("utf-8")) + ] except Exception as exc: raise Exception("line {}: {}".format(lineno + 1, exc)) from None - yield Command(negated=negated, cmd=cmd, args=args, lineno=lineno+1, context=line) + yield Command( + negated=negated, cmd=cmd, args=args, lineno=lineno + 1, context=line + ) def _flatten(node, acc): @@ -312,22 +338,24 @@ def _flatten(node, acc): def flatten(node): acc = [] _flatten(node, acc) - return ''.join(acc) + return "".join(acc) def make_xml(text): - xml = ET.XML('%s' % text) + xml = ET.XML("%s" % text) return xml def normalize_xpath(path): path = path.replace("{{channel}}", channel) - if path.startswith('//'): - return '.' + path # avoid warnings - elif path.startswith('.//'): + if path.startswith("//"): + return "." + path # avoid warnings + elif path.startswith(".//"): return path else: - raise InvalidCheck('Non-absolute XPath is not supported due to implementation issues') + raise InvalidCheck( + "Non-absolute XPath is not supported due to implementation issues" + ) class CachedFiles(object): @@ -338,12 +366,12 @@ class CachedFiles(object): self.last_path = None def resolve_path(self, path): - if path != '-': + if path != "-": path = os.path.normpath(path) self.last_path = path return path elif self.last_path is None: - raise InvalidCheck('Tried to use the previous path in the first command') + raise InvalidCheck("Tried to use the previous path in the first command") else: return self.last_path @@ -356,10 +384,10 @@ class CachedFiles(object): return self.files[path] abspath = self.get_absolute_path(path) - if not(os.path.exists(abspath) and os.path.isfile(abspath)): - raise FailedCheck('File does not exist {!r}'.format(path)) + if not (os.path.exists(abspath) and os.path.isfile(abspath)): + raise FailedCheck("File does not exist {!r}".format(path)) - with io.open(abspath, encoding='utf-8') as f: + with io.open(abspath, encoding="utf-8") as f: data = f.read() self.files[path] = data return data @@ -370,15 +398,15 @@ class CachedFiles(object): return self.trees[path] abspath = self.get_absolute_path(path) - if not(os.path.exists(abspath) and os.path.isfile(abspath)): - raise FailedCheck('File does not exist {!r}'.format(path)) + if not (os.path.exists(abspath) and os.path.isfile(abspath)): + raise FailedCheck("File does not exist {!r}".format(path)) - with io.open(abspath, encoding='utf-8') as f: + with io.open(abspath, encoding="utf-8") as f: try: tree = ET.fromstringlist(f.readlines(), CustomHTMLParser()) except Exception as e: - raise RuntimeError( # noqa: B904 FIXME: py2 - 'Cannot parse an HTML file {!r}: {}'.format(path, e) + raise RuntimeError( # noqa: B904 FIXME: py2 + "Cannot parse an HTML file {!r}: {}".format(path, e) ) self.trees[path] = tree return self.trees[path] @@ -386,8 +414,8 @@ class CachedFiles(object): def get_dir(self, path): path = self.resolve_path(path) abspath = self.get_absolute_path(path) - if not(os.path.exists(abspath) and os.path.isdir(abspath)): - raise FailedCheck('Directory does not exist {!r}'.format(path)) + if not (os.path.exists(abspath) and os.path.isdir(abspath)): + raise FailedCheck("Directory does not exist {!r}".format(path)) def check_string(data, pat, regexp): @@ -397,8 +425,8 @@ def check_string(data, pat, regexp): elif regexp: return re.search(pat, data, flags=re.UNICODE) is not None else: - data = ' '.join(data.split()) - pat = ' '.join(pat.split()) + data = " ".join(data.split()) + pat = " ".join(pat.split()) return pat in data @@ -444,19 +472,19 @@ def get_tree_count(tree, path): def check_snapshot(snapshot_name, actual_tree, normalize_to_text): - assert rust_test_path.endswith('.rs') - snapshot_path = '{}.{}.{}'.format(rust_test_path[:-3], snapshot_name, 'html') + assert rust_test_path.endswith(".rs") + snapshot_path = "{}.{}.{}".format(rust_test_path[:-3], snapshot_name, "html") try: - with open(snapshot_path, 'r') as snapshot_file: + with open(snapshot_path, "r") as snapshot_file: expected_str = snapshot_file.read().replace("{{channel}}", channel) except FileNotFoundError: if bless: expected_str = None else: - raise FailedCheck('No saved snapshot value') # noqa: B904 FIXME: py2 + raise FailedCheck("No saved snapshot value") # noqa: B904 FIXME: py2 if not normalize_to_text: - actual_str = ET.tostring(actual_tree).decode('utf-8') + actual_str = ET.tostring(actual_tree).decode("utf-8") else: actual_str = flatten(actual_tree) @@ -464,64 +492,66 @@ def check_snapshot(snapshot_name, actual_tree, normalize_to_text): # 1. Is --bless # 2. Are actual and expected tree different # 3. Are actual and expected text different - if not expected_str \ - or (not normalize_to_text and \ - not compare_tree(make_xml(actual_str), make_xml(expected_str), stderr)) \ - or (normalize_to_text and actual_str != expected_str): - + if ( + not expected_str + or ( + not normalize_to_text + and not compare_tree(make_xml(actual_str), make_xml(expected_str), stderr) + ) + or (normalize_to_text and actual_str != expected_str) + ): if bless: - with open(snapshot_path, 'w') as snapshot_file: + with open(snapshot_path, "w") as snapshot_file: actual_str = actual_str.replace(channel, "{{channel}}") snapshot_file.write(actual_str) else: - print('--- expected ---\n') + print("--- expected ---\n") print(expected_str) - print('\n\n--- actual ---\n') + print("\n\n--- actual ---\n") print(actual_str) print() - raise FailedCheck('Actual snapshot value is different than expected') + raise FailedCheck("Actual snapshot value is different than expected") # Adapted from https://github.com/formencode/formencode/blob/3a1ba9de2fdd494dd945510a4568a3afeddb0b2e/formencode/doctest_xml_compare.py#L72-L120 def compare_tree(x1, x2, reporter=None): if x1.tag != x2.tag: if reporter: - reporter('Tags do not match: %s and %s' % (x1.tag, x2.tag)) + reporter("Tags do not match: %s and %s" % (x1.tag, x2.tag)) return False for name, value in x1.attrib.items(): if x2.attrib.get(name) != value: if reporter: - reporter('Attributes do not match: %s=%r, %s=%r' - % (name, value, name, x2.attrib.get(name))) + reporter( + "Attributes do not match: %s=%r, %s=%r" + % (name, value, name, x2.attrib.get(name)) + ) return False for name in x2.attrib: if name not in x1.attrib: if reporter: - reporter('x2 has an attribute x1 is missing: %s' - % name) + reporter("x2 has an attribute x1 is missing: %s" % name) return False if not text_compare(x1.text, x2.text): if reporter: - reporter('text: %r != %r' % (x1.text, x2.text)) + reporter("text: %r != %r" % (x1.text, x2.text)) return False if not text_compare(x1.tail, x2.tail): if reporter: - reporter('tail: %r != %r' % (x1.tail, x2.tail)) + reporter("tail: %r != %r" % (x1.tail, x2.tail)) return False cl1 = list(x1) cl2 = list(x2) if len(cl1) != len(cl2): if reporter: - reporter('children length differs, %i != %i' - % (len(cl1), len(cl2))) + reporter("children length differs, %i != %i" % (len(cl1), len(cl2))) return False i = 0 for c1, c2 in zip(cl1, cl2): i += 1 if not compare_tree(c1, c2, reporter=reporter): if reporter: - reporter('children %i do not match: %s' - % (i, c1.tag)) + reporter("children %i do not match: %s" % (i, c1.tag)) return False return True @@ -529,14 +559,14 @@ def compare_tree(x1, x2, reporter=None): def text_compare(t1, t2): if not t1 and not t2: return True - if t1 == '*' or t2 == '*': + if t1 == "*" or t2 == "*": return True - return (t1 or '').strip() == (t2 or '').strip() + return (t1 or "").strip() == (t2 or "").strip() def stderr(*args): if sys.version_info.major < 3: - file = codecs.getwriter('utf-8')(sys.stderr) + file = codecs.getwriter("utf-8")(sys.stderr) else: file = sys.stderr @@ -556,21 +586,25 @@ def print_err(lineno, context, err, message=None): def get_nb_matching_elements(cache, c, regexp, stop_at_first): tree = cache.get_tree(c.args[0]) - pat, sep, attr = c.args[1].partition('/@') + pat, sep, attr = c.args[1].partition("/@") if sep: # attribute tree = cache.get_tree(c.args[0]) return check_tree_attr(tree, pat, attr, c.args[2], False) else: # normalized text pat = c.args[1] - if pat.endswith('/text()'): + if pat.endswith("/text()"): pat = pat[:-7] - return check_tree_text(cache.get_tree(c.args[0]), pat, c.args[2], regexp, stop_at_first) + return check_tree_text( + cache.get_tree(c.args[0]), pat, c.args[2], regexp, stop_at_first + ) def check_files_in_folder(c, cache, folder, files): files = files.strip() - if not files.startswith('[') or not files.endswith(']'): - raise InvalidCheck("Expected list as second argument of {} (ie '[]')".format(c.cmd)) + if not files.startswith("[") or not files.endswith("]"): + raise InvalidCheck( + "Expected list as second argument of {} (ie '[]')".format(c.cmd) + ) folder = cache.get_absolute_path(folder) @@ -592,12 +626,18 @@ def check_files_in_folder(c, cache, folder, files): error = 0 if len(files_set) != 0: - print_err(c.lineno, c.context, "Entries not found in folder `{}`: `{}`".format( - folder, files_set)) + print_err( + c.lineno, + c.context, + "Entries not found in folder `{}`: `{}`".format(folder, files_set), + ) error += 1 if len(folder_set) != 0: - print_err(c.lineno, c.context, "Extra entries in folder `{}`: `{}`".format( - folder, folder_set)) + print_err( + c.lineno, + c.context, + "Extra entries in folder `{}`: `{}`".format(folder, folder_set), + ) error += 1 return error == 0 @@ -608,11 +648,11 @@ ERR_COUNT = 0 def check_command(c, cache): try: cerr = "" - if c.cmd in ['has', 'hasraw', 'matches', 'matchesraw']: # string test - regexp = c.cmd.startswith('matches') + if c.cmd in ["has", "hasraw", "matches", "matchesraw"]: # string test + regexp = c.cmd.startswith("matches") # has = file existence - if len(c.args) == 1 and not regexp and 'raw' not in c.cmd: + if len(c.args) == 1 and not regexp and "raw" not in c.cmd: try: cache.get_file(c.args[0]) ret = True @@ -620,24 +660,24 @@ def check_command(c, cache): cerr = str(err) ret = False # hasraw/matchesraw = string test - elif len(c.args) == 2 and 'raw' in c.cmd: + elif len(c.args) == 2 and "raw" in c.cmd: cerr = "`PATTERN` did not match" ret = check_string(cache.get_file(c.args[0]), c.args[1], regexp) # has/matches = XML tree test - elif len(c.args) == 3 and 'raw' not in c.cmd: + elif len(c.args) == 3 and "raw" not in c.cmd: cerr = "`XPATH PATTERN` did not match" ret = get_nb_matching_elements(cache, c, regexp, True) != 0 else: - raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd)) + raise InvalidCheck("Invalid number of {} arguments".format(c.cmd)) - elif c.cmd == 'files': # check files in given folder - if len(c.args) != 2: # files + elif c.cmd == "files": # check files in given folder + if len(c.args) != 2: # files raise InvalidCheck("Invalid number of {} arguments".format(c.cmd)) elif c.negated: raise InvalidCheck("{} doesn't support negative check".format(c.cmd)) ret = check_files_in_folder(c, cache, c.args[0], c.args[1]) - elif c.cmd == 'count': # count test + elif c.cmd == "count": # count test if len(c.args) == 3: # count = count test expected = int(c.args[2]) found = get_tree_count(cache.get_tree(c.args[0]), c.args[1]) @@ -649,15 +689,15 @@ def check_command(c, cache): cerr = "Expected {} occurrences but found {}".format(expected, found) ret = found == expected else: - raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd)) + raise InvalidCheck("Invalid number of {} arguments".format(c.cmd)) - elif c.cmd == 'snapshot': # snapshot test + elif c.cmd == "snapshot": # snapshot test if len(c.args) == 3: # snapshot [snapshot_name, html_path, pattern] = c.args tree = cache.get_tree(html_path) xpath = normalize_xpath(pattern) normalize_to_text = False - if xpath.endswith('/text()'): + if xpath.endswith("/text()"): xpath = xpath[:-7] normalize_to_text = True @@ -671,13 +711,15 @@ def check_command(c, cache): cerr = str(err) ret = False elif len(subtrees) == 0: - raise FailedCheck('XPATH did not match') + raise FailedCheck("XPATH did not match") else: - raise FailedCheck('Expected 1 match, but found {}'.format(len(subtrees))) + raise FailedCheck( + "Expected 1 match, but found {}".format(len(subtrees)) + ) else: - raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd)) + raise InvalidCheck("Invalid number of {} arguments".format(c.cmd)) - elif c.cmd == 'has-dir': # has-dir test + elif c.cmd == "has-dir": # has-dir test if len(c.args) == 1: # has-dir = has-dir test try: cache.get_dir(c.args[0]) @@ -686,22 +728,22 @@ def check_command(c, cache): cerr = str(err) ret = False else: - raise InvalidCheck('Invalid number of {} arguments'.format(c.cmd)) + raise InvalidCheck("Invalid number of {} arguments".format(c.cmd)) - elif c.cmd == 'valid-html': - raise InvalidCheck('Unimplemented valid-html') + elif c.cmd == "valid-html": + raise InvalidCheck("Unimplemented valid-html") - elif c.cmd == 'valid-links': - raise InvalidCheck('Unimplemented valid-links') + elif c.cmd == "valid-links": + raise InvalidCheck("Unimplemented valid-links") else: - raise InvalidCheck('Unrecognized {}'.format(c.cmd)) + raise InvalidCheck("Unrecognized {}".format(c.cmd)) if ret == c.negated: raise FailedCheck(cerr) except FailedCheck as err: - message = '{}{} check failed'.format('!' if c.negated else '', c.cmd) + message = "{}{} check failed".format("!" if c.negated else "", c.cmd) print_err(c.lineno, c.context, str(err), message) except InvalidCheck as err: print_err(c.lineno, c.context, str(err)) @@ -713,18 +755,18 @@ def check(target, commands): check_command(c, cache) -if __name__ == '__main__': +if __name__ == "__main__": if len(sys.argv) not in [3, 4]: - stderr('Usage: {}