diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 23aeb1e06463c..ee0cef350b42f 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -22,7 +22,7 @@ use rustc_target::asm::*; use crate::builder::Builder; use crate::callee::get_fn; use crate::context::CodegenCx; -use crate::errors::{NulBytesInAsm, UnwindingInlineAsm}; +use crate::diagnostics::{NulBytesInAsm, UnwindingInlineAsm}; use crate::type_of::LayoutGccExt; // Rust asm! and GCC Extended Asm semantics differ substantially. diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 7166ad8b1f17f..98f9abdb05c4c 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -35,7 +35,7 @@ use rustc_log::tracing::info; use tempfile::{TempDir, tempdir}; use crate::back::write::{codegen, save_temp_bitcode}; -use crate::errors::LtoBitcodeFromRlib; +use crate::diagnostics::LtoBitcodeFromRlib; use crate::{GccCodegenBackend, GccContext, LtoMode, to_gcc_opt_level}; struct LtoData { diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 8fd38a2efd600..cf5514412f745 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -12,7 +12,7 @@ use rustc_session::config::OutputType; use rustc_target::spec::SplitDebuginfo; use crate::base::add_pic_option; -use crate::errors::CopyBitcode; +use crate::diagnostics::CopyBitcode; use crate::{GccContext, LtoMode}; pub(crate) fn codegen( diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 7671d2e026b03..a407362638f10 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -36,7 +36,7 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::abi::FnAbiGccExt; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; -use crate::errors; +use crate::diagnostics; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -1803,7 +1803,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _instance: Option>, ) { // FIXME: implement support for explicit tail calls like rustc_codegen_llvm. - self.tcx.dcx().emit_fatal(errors::ExplicitTailCallsUnsupported); + self.tcx.dcx().emit_fatal(diagnostics::ExplicitTailCallsUnsupported); } fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/diagnostics.rs similarity index 100% rename from compiler/rustc_codegen_gcc/src/errors.rs rename to compiler/rustc_codegen_gcc/src/diagnostics.rs diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 4cc4a2d258d14..55c721a9706a6 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -59,7 +59,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; -mod errors; +mod diagnostics; mod gcc_util; mod int; mod intrinsic; diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1f00e47a89927..a4176a8feb0f9 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -16,7 +16,7 @@ use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, Stack use smallvec::SmallVec; use crate::context::SimpleCx; -use crate::errors::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; +use crate::diagnostics::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; use crate::llvm::AttributePlace::Function; use crate::llvm::{ self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects, Value, diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index b2d22876c1858..75d9be033a5ef 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -28,7 +28,7 @@ use crate::back::write::{ self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, codegen, save_temp_bitcode, }; -use crate::errors::{LlvmError, LtoBitcodeFromRlib}; +use crate::diagnostics::{LlvmError, LtoBitcodeFromRlib}; use crate::llvm::{self, build_string}; use crate::{LlvmCodegenBackend, ModuleLlvm}; diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 65cf4cad24bd6..350d4ce9ee331 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; use rustc_data_structures::small_c_str::SmallCStr; -use crate::errors::LlvmError; +use crate::diagnostics::LlvmError; use crate::llvm; /// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions. diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6a0f4fa6d54d2..94883a94f089a 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -34,7 +34,7 @@ use crate::back::profiling::{ use crate::builder::SBuilder; use crate::builder::gpu_offload::scalar_width; use crate::common::AsCCharPtr; -use crate::errors::{ +use crate::diagnostics::{ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, ParseTargetMachineConfig, UnsupportedCompression, WithLlvmError, WriteBytecode, }; @@ -819,7 +819,7 @@ pub(crate) unsafe fn llvm_optimize( device_out_c.as_ptr(), ); if !ok || !device_out.exists() { - dcx.emit_err(crate::errors::OffloadBundleImagesFailed); + dcx.emit_err(crate::diagnostics::OffloadBundleImagesFailed); } } } @@ -837,15 +837,15 @@ pub(crate) unsafe fn llvm_optimize( { let device_pathbuf = PathBuf::from(device_path); if device_pathbuf.is_relative() { - dcx.emit_err(crate::errors::OffloadWithoutAbsPath); + dcx.emit_err(crate::diagnostics::OffloadWithoutAbsPath); } else if device_pathbuf .file_name() .and_then(|n| n.to_str()) .is_some_and(|n| n != "device.bin") { - dcx.emit_err(crate::errors::OffloadWrongFileName); + dcx.emit_err(crate::diagnostics::OffloadWrongFileName); } else if !device_pathbuf.exists() { - dcx.emit_err(crate::errors::OffloadNonexistingPath); + dcx.emit_err(crate::diagnostics::OffloadNonexistingPath); } let host_path = cgcx.output_filenames.path(OutputType::Object); let host_dir = host_path.parent().unwrap(); @@ -859,7 +859,7 @@ pub(crate) unsafe fn llvm_optimize( let ok = unsafe { llvm::LLVMRustOffloadEmbedBufferInModule(llmod2, device_bin_c.as_ptr()) }; if !ok { - dcx.emit_err(crate::errors::OffloadEmbedFailed); + dcx.emit_err(crate::diagnostics::OffloadEmbedFailed); } write_output_file( dcx, diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 8f87acaf675a4..ee752373ceca4 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -21,7 +21,7 @@ use rustc_target::spec::Arch; use tracing::{debug, instrument, trace}; use crate::common::CodegenCx; -use crate::errors::SymbolAlreadyDefined; +use crate::diagnostics::SymbolAlreadyDefined; use crate::llvm::{self, Type, Value, const_ptr_auth}; use crate::type_of::LayoutLlvmExt; use crate::{base, debuginfo}; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8f1910eaced13..89d9be451ebf4 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -238,7 +238,7 @@ pub(crate) unsafe fn create_module<'ll>( .expect("got a non-UTF8 data-layout from LLVM"); if target_data_layout != llvm_data_layout { - tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { + tcx.dcx().emit_err(crate::diagnostics::MismatchedDataLayout { rustc_target: sess.opts.target_triple.to_string().as_str(), rustc_layout: target_data_layout.as_str(), llvm_target: sess.target.llvm_target.borrow(), diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs similarity index 100% rename from compiler/rustc_codegen_llvm/src/errors.rs rename to compiler/rustc_codegen_llvm/src/diagnostics.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index edf943c81a755..4ae85af897527 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -39,7 +39,7 @@ use crate::builder::gpu_offload::{ }; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; -use crate::errors::{ +use crate::diagnostics::{ AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch, OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic, }; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1dd460c409737..3ec0495956c4c 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -59,7 +59,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; -mod errors; +mod diagnostics; mod intrinsic; mod llvm; mod llvm_util; @@ -233,10 +233,11 @@ impl CodegenBackend for LlvmCodegenBackend { match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { Ok(_) => {} Err(llvm::EnzymeLibraryError::NotFound { err }) => { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err }); + sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err }); } Err(llvm::EnzymeLibraryError::LoadFailed { err }) => { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err }); + sess.dcx() + .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err }); } } enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 87d8676cd8018..9ad14925afb14 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -21,7 +21,7 @@ use rustc_target::spec::{ use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; -use crate::{errors, llvm}; +use crate::{diagnostics, llvm}; static INIT: Once = Once::new(); @@ -636,7 +636,8 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { // -Zfixed-x18 if sess.opts.unstable_opts.fixed_x18 { if sess.target.arch != Arch::AArch64 { - sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: sess.target.arch.desc() }); + sess.dcx() + .emit_fatal(diagnostics::FixedX18InvalidArch { arch: sess.target.arch.desc() }); } else { features.push("+reserve-x18".into()); } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index b746bab643a34..19d43797a875d 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -19,7 +19,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::errors::SymbolAlreadyDefined; +use crate::diagnostics::SymbolAlreadyDefined; use crate::type_of::LayoutLlvmExt; use crate::{base, llvm}; diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4ce07ffe45ed7..5c99f903e33c0 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -41,7 +41,8 @@ use crate::ref_mut::CmCell; use crate::{ BindingKey, Decl, DeclData, DeclKind, DelayedVisResolutionError, ExternModule, ExternPreludeEntry, Finalize, IdentKey, LocalModule, Module, ModuleKind, ModuleOrUniformRoot, - ParentScope, PathResult, Res, Resolver, Segment, Used, VisResolutionError, diagnostics, + ParentScope, PathResult, Res, ResolutionTable, Resolver, Segment, Used, VisResolutionError, + diagnostics, }; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -336,7 +337,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn build_reduced_graph_external( &self, module: ExternModule<'ra>, - ) -> FxIndexMap> { + ) -> ResolutionTable<'ra> { let mut resolutions = FxIndexMap::default(); let def_id = module.def_id(); let children = self.tcx.module_children(def_id); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2dbf32dc20288..c52a07adfd6ff 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -24,7 +24,7 @@ use std::cell::Ref; use std::collections::BTreeSet; use std::ops::ControlFlow; -use std::sync::{Arc, Once}; +use std::sync::{Arc, OnceLock}; use std::{fmt, mem}; use diagnostics::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; @@ -633,7 +633,22 @@ impl BindingKey { } } -type Resolutions<'ra> = CmRefCell>>; +type ResolutionTable<'ra> = FxIndexMap>; + +enum Resolutions<'ra> { + Local(CmRefCell>), + Extern(OnceLock>>), +} + +impl<'ra> Resolutions<'ra> { + fn new(local: bool) -> Self { + if local { + Resolutions::Local(Default::default()) + } else { + Resolutions::Extern(Default::default()) + } + } +} /// One node in the tree of modules. /// @@ -655,8 +670,6 @@ struct ModuleData<'ra> { /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'ra>, - /// True if this is a module from other crate that needs to be populated on access. - populate_on_access: Once, /// Used to disambiguate underscore items (`const _: T = ...`) in the module. underscore_disambiguator: CmCell, @@ -710,6 +723,7 @@ impl<'ra> ModuleData<'ra> { vis: Visibility, arenas: &'ra ResolverArenas<'ra>, ) -> Self { + let lazy_resolutions = Resolutions::new(kind.is_local()); let self_decl = match kind { ModuleKind::Def(def_kind, def_id, ..) => { let expn_id = expansion.as_local().unwrap_or(LocalExpnId::ROOT); @@ -720,8 +734,7 @@ impl<'ra> ModuleData<'ra> { ModuleData { parent, kind, - lazy_resolutions: Default::default(), - populate_on_access: Once::new(), + lazy_resolutions, underscore_disambiguator: CmCell::new(0), unexpanded_invocations: Default::default(), no_implicit_prelude, @@ -2162,15 +2175,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.tcx.hir_arena.alloc_slice(&import_ids) } - fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { - if !module.is_local() { - // as long as 1 thread is building this external table, all other threads will wait - module.populate_on_access.call_once(|| { - *module.lazy_resolutions.borrow_mut_unchecked() = - self.build_reduced_graph_external(module.expect_extern()); - }); + fn resolutions(&self, module: Module<'ra>) -> &'ra CmRefCell> { + match &module.0.0.lazy_resolutions { + Resolutions::Local(local_res) => local_res, + Resolutions::Extern(extern_res) => { + // as long as 1 thread is building this external table, all other threads will wait + extern_res.get_or_init(|| { + CmRefCell::new(self.build_reduced_graph_external(module.expect_extern())) + }) + } } - &module.0.0.lazy_resolutions } fn resolution( @@ -2924,13 +2938,6 @@ mod ref_mut { CmRefCell(RefCell::new(value)) } - #[track_caller] - // FIXME: this should be eliminated in the process of migration - // to parallel name resolution. - pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> { - self.0.borrow_mut() - } - #[track_caller] pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { if r.assert_speculative { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 81f19529418a5..60f4ca6a8759c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -285,27 +285,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)) && (self.tcx.is_diagnostic_item(sym::From, leaf_trait_def_id) || self.tcx.is_diagnostic_item(sym::TryFrom, leaf_trait_def_id)) - { - let trait_ref = leaf_trait_predicate.skip_binder().trait_ref; - - if let Some(found_ty) = + && let Some(trait_ref) = + leaf_trait_predicate.no_bound_vars().map(|pred| pred.trait_ref) + && let Some(found_ty) = trait_ref.args.get(1).and_then(|arg| arg.as_type()) - { - let ty = main_trait_predicate.skip_binder().self_ty(); + && let Some(ty) = + main_trait_predicate.no_bound_vars().map(|pred| pred.self_ty()) + && let Some(cast_ty) = + self.find_explicit_cast_type(obligation.param_env, found_ty, ty) + { + let found_ty_str = self.tcx.short_string(found_ty, &mut long_ty_file); + let cast_ty_str = self.tcx.short_string(cast_ty, &mut long_ty_file); - if let Some(cast_ty) = - self.find_explicit_cast_type(obligation.param_env, found_ty, ty) - { - let found_ty_str = - self.tcx.short_string(found_ty, &mut long_ty_file); - let cast_ty_str = - self.tcx.short_string(cast_ty, &mut long_ty_file); - - err.help(format!( - "consider casting the `{found_ty_str}` value to `{cast_ty_str}`", - )); - } - } + err.help(format!( + "consider casting the `{found_ty_str}` value to `{cast_ty_str}`", + )); } *err.long_ty_path() = long_ty_file; diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index d29ea81c67e6d..0d3732a83a9e9 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,6 +1,7 @@ -use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; +use crate::mem::MaybeUninit; use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::hermit_abi::{ self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, @@ -12,9 +13,10 @@ use crate::sync::Arc; use crate::sys::fd::FileDesc; pub use crate::sys::fs::common::{Dir, copy, exists}; use crate::sys::helpers::run_path_with_cstr; +use crate::sys::io::DEFAULT_BUF_SIZE; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, unsupported, unsupported_err}; -use crate::{fmt, mem}; +use crate::{cmp, fmt, mem, slice}; #[derive(Debug)] pub struct File(FileDesc); @@ -33,29 +35,75 @@ impl FileAttr { // all DirEntry's will have a reference to this struct struct InnerReadDir { root: PathBuf, - dir: Vec, -} - -impl InnerReadDir { - pub fn new(root: PathBuf, dir: Vec) -> Self { - Self { root, dir } - } } pub struct ReadDir { inner: Arc, + fd: FileDesc, + buf: GetdentsBuffer, +} + +/// A buffer containing [`dirent64`]s, filled with [`getdents64`]. +/// +/// This struct is roughly modeled after the `BufReader`'s `Buffer`. +struct GetdentsBuffer { + // The buffer. + buf: Box<[MaybeUninit]>, + // The current seek offset into `buf`, must always be <= `filled`. pos: usize, + // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are + // initialized with bytes from a read. + filled: usize, } -impl ReadDir { - fn new(inner: InnerReadDir) -> Self { - Self { inner: Arc::new(inner), pos: 0 } +impl GetdentsBuffer { + /// Creates a new buffer with at least `capacity` bytes for use with dirent. + fn with_capacity(capacity: usize) -> Self { + let buf = Box::new_uninit_slice(capacity.div_ceil(size_of::())); + Self { buf, pos: 0, filled: 0 } + } + + fn buffer(&self) -> &[u8] { + // SAFETY: self.pos and self.filled are valid, and self.filled >= self.pos, and + // that region is initialized because those are all invariants of this type. + unsafe { + let ptr = self.buf.as_ptr().cast::>().add(self.pos); + slice::from_raw_parts(ptr, self.filled - self.pos).assume_init_ref() + } + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.filled); + } + + fn fill_buf(&mut self, fd: BorrowedFd<'_>) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.filled { + debug_assert!(self.pos == self.filled); + + let result = unsafe { + cvt(hermit_abi::getdents64( + fd.as_raw_fd(), + self.buf.as_mut_ptr().cast(), + self.buf.len() * size_of::(), + )) + }; + + self.pos = 0; + self.filled = 0; + + self.filled = result? as usize; + } + + Ok(self.buffer()) } } pub struct DirEntry { - /// path to the entry - root: PathBuf, + dir: Arc, /// 64-bit inode number ino: u64, /// File type @@ -185,48 +233,59 @@ impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - let mut counter: usize = 0; - let mut offset: usize = 0; - - // loop over all directory entries and search the entry for the current position loop { - // leave function, if the loop reaches the of the buffer (with all entries) - if offset >= self.inner.dir.len() { + let buf = match self.buf.fill_buf(self.fd.as_fd()) { + Ok(buf) => buf, + Err(err) => return Some(Err(err)), + }; + + if buf.len() == 0 { + // No more entries left. return None; } - let dir = unsafe { &*(self.inner.dir.as_ptr().add(offset) as *const dirent64) }; - - if counter == self.pos { - self.pos += 1; - - // After dirent64, the file name is stored. d_reclen represents the length of the dirent64 - // plus the length of the file name. Consequently, file name has a size of d_reclen minus - // the size of dirent64. The file name is always a C string and terminated by `\0`. - // Consequently, we are able to ignore the last byte. - let name_bytes = - unsafe { CStr::from_ptr(&dir.d_name as *const _ as *const c_char).to_bytes() }; - let entry = DirEntry { - root: self.inner.root.clone(), - ino: dir.d_ino, - type_: dir.d_type, - name: OsString::from_vec(name_bytes.to_vec()), - }; - - return Some(Ok(entry)); + let entry_ptr = buf.as_ptr().cast::(); + + // The dirent64 struct is a weird imaginary thing that isn't ever supposed + // to be worked with by value. Its trailing d_name field is declared + // variously as [c_char; 256] or [c_char; 1] on different systems but + // either way that size is meaningless; only the offset of d_name is + // meaningful. The dirent64 pointers that libc returns from getdents64 are + // allowed to point to allocations smaller _or_ LARGER than implied by the + // definition of the struct. + // + // As such, we need to be even more careful with dirent64 than if its + // contents were "simply" partially initialized data. + // + // Like for uninitialized contents, converting entry_ptr to `&dirent64` + // would not be legal. However, we can use `&raw const (*entry_ptr).d_name` + // to refer the fields individually, because that operation is equivalent + // to `byte_offset` and thus does not require the full extent of `*entry_ptr` + // to be in bounds of the same allocation, only the offset of the field + // being referenced. + + self.buf.consume(usize::from(unsafe { (*entry_ptr).d_reclen })); + + // d_name is guaranteed to be null-terminated. + let name = unsafe { CStr::from_ptr((&raw const (*entry_ptr).d_name).cast()) }; + let name_bytes = name.to_bytes(); + if name_bytes == b"." || name_bytes == b".." { + continue; } - counter += 1; - - // move to the next dirent64, which is directly stored after the previous one - offset = offset + usize::from(dir.d_reclen); + return Some(Ok(DirEntry { + dir: Arc::clone(&self.inner), + ino: unsafe { (*entry_ptr).d_ino }, + type_: unsafe { (*entry_ptr).d_type }, + name: OsString::from_vec(name_bytes.to_vec()), + })); } } } impl DirEntry { pub fn path(&self) -> PathBuf { - self.root.join(self.file_name_os_str()) + self.dir.root.join(self.file_name_os_str()) } pub fn file_name(&self) -> OsString { @@ -342,7 +401,7 @@ impl File { } let fd = unsafe { cvt(hermit_abi::open(path.as_ptr(), flags, mode))? }; - Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) })) + Ok(File(unsafe { FileDesc::from_raw_fd(fd) })) } pub fn file_attr(&self) -> io::Result { @@ -352,7 +411,7 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn datasync(&self) -> io::Result<()> { @@ -380,7 +439,7 @@ impl File { } pub fn truncate(&self, _size: u64) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -431,15 +490,15 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } } @@ -516,42 +575,14 @@ pub fn readdir(path: &Path) -> io::Result { let fd_raw = run_path_with_cstr(path, &|path| { cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) }) })?; - let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; - let root = path.to_path_buf(); - - // read all director entries - let mut vec: Vec = Vec::new(); - let mut sz = 512; - loop { - // reserve memory to receive all directory entries - vec.resize(sz, 0); - - let readlen = unsafe { - hermit_abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) - }; - if readlen > 0 { - // shrink down to the minimal size - vec.resize(readlen.try_into().unwrap(), 0); - break; - } - - // if the buffer is too small, getdents64 returns EINVAL - // otherwise, getdents64 returns an error number - if readlen != (-hermit_abi::errno::EINVAL).into() { - return Err(Error::from_raw_os_error(readlen.try_into().unwrap())); - } + let fd = unsafe { FileDesc::from_raw_fd(fd_raw) }; - // we don't have enough memory => try to increase the vector size - sz = sz * 2; - - // 1 MB for directory entries should be enough - // stop here to avoid an endless loop - if sz > 0x100000 { - return Err(Error::from(ErrorKind::Uncategorized)); - } - } + let root = path.to_path_buf(); + let inner = Arc::new(InnerReadDir { root }); + let buf_size = usize::max(DEFAULT_BUF_SIZE, size_of::()); + let buf = GetdentsBuffer::with_capacity(buf_size); - Ok(ReadDir::new(InnerReadDir::new(root, vec))) + Ok(ReadDir { inner, fd, buf }) } pub fn unlink(path: &Path) -> io::Result<()> { @@ -563,7 +594,7 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { } pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { @@ -571,11 +602,11 @@ pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn rmdir(path: &Path) -> io::Result<()> { diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index ba40da4035b6f..f43395ce8fd80 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -304,8 +304,8 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } + let raw = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw))) } } pub fn as_raw(&self) -> RawFd { diff --git a/library/std/src/sys/pal/windows/winsock.rs b/library/std/src/sys/pal/windows/winsock.rs index b110a43ef3aa8..7b2e7fe59171c 100644 --- a/library/std/src/sys/pal/windows/winsock.rs +++ b/library/std/src/sys/pal/windows/winsock.rs @@ -1,18 +1,17 @@ use super::c; use crate::ffi::c_int; -use crate::sync::atomic::Atomic; -use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; +use crate::sync::Once; use crate::{io, mem}; -static WSA_STARTED: Atomic = Atomic::::new(false); +static WSA_INIT: Once = Once::new(); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. #[inline] pub fn startup() { - if !WSA_STARTED.load(Relaxed) { - wsa_startup(); - } + // Make sure to only call `WSAStartup` once, because it's not thread-safe + // on Wine: https://bugs.winehq.org/show_bug.cgi?id=60084. + WSA_INIT.call_once_force(|_| wsa_startup()); } #[cold] @@ -24,11 +23,6 @@ fn wsa_startup() { &mut data, ); assert_eq!(ret, 0); - if WSA_STARTED.swap(true, AcqRel) { - // If another thread raced with us and called WSAStartup first then call - // WSACleanup so it's as though WSAStartup was only called once. - c::WSACleanup(); - } } } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 6cc2811c15f3b..b3ed7d4c6beb7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -607,7 +607,6 @@ impl Config { stack_protector: rust_stack_protector, strip: rust_strip, bootstrap_override_lld: rust_bootstrap_override_lld, - bootstrap_override_lld_legacy: rust_bootstrap_override_lld_legacy, std_features: rust_std_features, break_on_ice: rust_break_on_ice, rustflags: rust_rustflags, @@ -717,14 +716,7 @@ impl Config { let pgo_rustdoc = init_pgo(pgo_rustdoc, "rustdoc"); let pgo_cargo = init_pgo(pgo_cargo, "cargo"); - if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() { - panic!( - "Cannot use both `rust.use-lld` and `rust.bootstrap-override-lld`. Please use only `rust.bootstrap-override-lld`" - ); - } - - let bootstrap_override_lld = - rust_bootstrap_override_lld.or(rust_bootstrap_override_lld_legacy).unwrap_or_default(); + let bootstrap_override_lld = rust_bootstrap_override_lld.unwrap_or_default(); if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { eprintln!( diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index d84315d87e45a..d179d0713fcda 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -252,16 +252,6 @@ fn rust_lld() { parse("rust.bootstrap-override-lld = false").bootstrap_override_lld, BootstrapOverrideLld::None )); - - // Also check the legacy options - assert!(matches!( - parse("rust.use-lld = true").bootstrap_override_lld, - BootstrapOverrideLld::External - )); - assert!(matches!( - parse("rust.use-lld = false").bootstrap_override_lld, - BootstrapOverrideLld::None - )); } #[test] diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index fa4573ef1734f..f8f383ef18e73 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -51,8 +51,6 @@ define_config! { llvm_bitcode_linker: Option = "llvm-bitcode-linker", lld: Option = "lld", bootstrap_override_lld: Option = "bootstrap-override-lld", - // FIXME: Remove this option in Spring 2026 - bootstrap_override_lld_legacy: Option = "use-lld", llvm_tools: Option = "llvm-tools", deny_warnings: Option = "deny-warnings", backtrace_on_ice: Option = "backtrace-on-ice", @@ -385,7 +383,6 @@ pub fn check_incompatible_options_for_ci_rustc( break_on_ice: _, parallel_frontend_threads: _, bootstrap_override_lld: _, - bootstrap_override_lld_legacy: _, rustflags: _, } = ci_rust_config; diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 062310cc351a7..8892832037ee2 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -661,4 +661,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Obsolete option `build.compiletest-use-stage0-libtest` has no effect and has been removed.", }, + ChangeInfo { + change_id: 160142, + severity: ChangeSeverity::Warning, + summary: "The `rust.use-lld` option has been removed. Use `rust.bootstrap-override-lld` instead.", + }, ]; diff --git a/tests/ui/traits/explicit-reference-cast-hrtb.rs b/tests/ui/traits/explicit-reference-cast-hrtb.rs new file mode 100644 index 0000000000000..8714bff369b82 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-hrtb.rs @@ -0,0 +1,14 @@ +//! Regression test for #158967 + +struct Foo; + +fn f() +where + for<'a> Foo: From<&'a String>, +{ +} + +fn main() { + f(); + //~^ ERROR the trait bound `for<'a> Foo: From<&'a String>` is not satisfied [E0277] +} diff --git a/tests/ui/traits/explicit-reference-cast-hrtb.stderr b/tests/ui/traits/explicit-reference-cast-hrtb.stderr new file mode 100644 index 0000000000000..4921a87900051 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-hrtb.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `for<'a> Foo: From<&'a String>` is not satisfied + --> $DIR/explicit-reference-cast-hrtb.rs:12:5 + | +LL | f(); + | ^^^ unsatisfied trait bound + | +help: the trait `for<'a> From<&'a String>` is not implemented for `Foo` + --> $DIR/explicit-reference-cast-hrtb.rs:3:1 + | +LL | struct Foo; + | ^^^^^^^^^^ +note: required by a bound in `f` + --> $DIR/explicit-reference-cast-hrtb.rs:7:18 + | +LL | fn f() + | - required by a bound in this function +LL | where +LL | for<'a> Foo: From<&'a String>, + | ^^^^^^^^^^^^^^^^ required by this bound in `f` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.