From b9746ce03901fc39707c8c2d0405caf5384b4e97 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 3 Mar 2023 10:14:57 +0800 Subject: [PATCH 1/7] introduce `DynSend` and `DynSync` auto trait --- Cargo.lock | 1 + compiler/rustc_ast/src/tokenstream.rs | 13 +- compiler/rustc_codegen_ssa/src/base.rs | 17 +- .../rustc_codegen_ssa/src/traits/backend.rs | 5 +- compiler/rustc_data_structures/Cargo.toml | 1 + compiler/rustc_data_structures/src/lib.rs | 5 +- compiler/rustc_data_structures/src/marker.rs | 268 ++++++++++++++++++ compiler/rustc_data_structures/src/sync.rs | 233 ++++++++++++--- compiler/rustc_driver_impl/src/lib.rs | 3 + compiler/rustc_error_messages/src/lib.rs | 13 +- compiler/rustc_errors/src/lib.rs | 6 +- compiler/rustc_errors/src/tests.rs | 8 +- compiler/rustc_expand/src/base.rs | 12 +- compiler/rustc_interface/src/interface.rs | 5 + compiler/rustc_lint/src/context.rs | 16 +- compiler/rustc_lint/src/late.rs | 4 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 +- compiler/rustc_middle/src/hir/map/mod.rs | 11 +- compiler/rustc_middle/src/hir/mod.rs | 10 +- compiler/rustc_middle/src/ty/context.rs | 4 +- compiler/rustc_middle/src/ty/context/tls.rs | 4 +- compiler/rustc_middle/src/ty/list.rs | 6 + compiler/rustc_middle/src/ty/query.rs | 5 +- compiler/rustc_session/src/cstore.rs | 4 +- compiler/rustc_span/src/source_map.rs | 6 +- src/librustdoc/lib.rs | 3 + 26 files changed, 555 insertions(+), 112 deletions(-) create mode 100644 compiler/rustc_data_structures/src/marker.rs diff --git a/Cargo.lock b/Cargo.lock index d24a4271aa166..6812932d67866 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3299,6 +3299,7 @@ dependencies = [ "rustc-hash", "rustc-rayon", "rustc-rayon-core", + "rustc_arena", "rustc_graphviz", "rustc_index", "rustc_macros", diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f0a6a5e072586..3b47ebef2fd3f 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -48,14 +48,15 @@ pub enum TokenTree { Delimited(DelimSpan, Delimiter, TokenStream), } -// Ensure all fields of `TokenTree` is `Send` and `Sync`. +// Ensure all fields of `TokenTree` is `DynSend` and `DynSync`. #[cfg(parallel_compiler)] fn _dummy() where - Token: Send + Sync, - DelimSpan: Send + Sync, - Delimiter: Send + Sync, - TokenStream: Send + Sync, + Token: sync::DynSend + sync::DynSync, + Spacing: sync::DynSend + sync::DynSync, + DelimSpan: sync::DynSend + sync::DynSync, + Delimiter: sync::DynSend + sync::DynSync, + TokenStream: sync::DynSend + sync::DynSync, { } @@ -118,7 +119,7 @@ where } } -pub trait ToAttrTokenStream: sync::Send + sync::Sync { +pub trait ToAttrTokenStream: sync::DynSend + sync::DynSync { fn to_attr_token_stream(&self) -> AttrTokenStream; } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index ae45ae9d802c8..1805c6fabdff9 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -17,10 +17,7 @@ use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; - -use rustc_data_structures::sync::par_iter; -#[cfg(parallel_compiler)] -use rustc_data_structures::sync::ParallelIterator; +use rustc_data_structures::sync::par_map; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -689,7 +686,7 @@ pub fn codegen_crate( // This likely is a temporary measure. Once we don't have to support the // non-parallel compiler anymore, we can compile CGUs end-to-end in // parallel and get rid of the complicated scheduling logic. - let mut pre_compiled_cgus = if cfg!(parallel_compiler) { + let mut pre_compiled_cgus = if tcx.sess.threads() > 1 { tcx.sess.time("compile_first_CGU_batch", || { // Try to find one CGU to compile per thread. let cgus: Vec<_> = cgu_reuse @@ -702,12 +699,10 @@ pub fn codegen_crate( // Compile the found CGUs in parallel. let start_time = Instant::now(); - let pre_compiled_cgus = par_iter(cgus) - .map(|(i, _)| { - let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); - (i, module) - }) - .collect(); + let pre_compiled_cgus = par_map(cgus, |(i, _)| { + let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); + (i, module) + }); total_codegen_time += start_time.elapsed(); diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 64bebe50ddbf2..684598eebe6eb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -22,6 +22,7 @@ use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; +use rustc_data_structures::sync::{DynSend, DynSync}; use std::any::Any; pub trait BackendTypes { @@ -117,7 +118,9 @@ pub trait CodegenBackend { ) -> Result<(), ErrorGuaranteed>; } -pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync { +pub trait ExtraBackendMethods: + CodegenBackend + WriteBackendMethods + Sized + Send + Sync + DynSend + DynSync +{ fn codegen_allocator<'tcx>( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 5e05fe463ed2b..fcbe5e945d226 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -16,6 +16,7 @@ libc = "0.2" measureme = "10.0.0" rustc-rayon-core = { version = "0.5.0", optional = true } rustc-rayon = { version = "0.5.0", optional = true } +rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } rustc-hash = "1.1.0" rustc_index = { path = "../rustc_index", package = "rustc_index" } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 004017ec5f31a..f543e0d4a7add 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -26,9 +26,11 @@ #![feature(test)] #![feature(thread_id_value)] #![feature(vec_into_raw_parts)] +#![feature(allocator_api)] #![feature(get_mut_unchecked)] #![feature(lint_reasons)] -#![feature(unwrap_infallible)] +#![feature(unwrap_infallible)]#![feature(const_mut_refs)] +#![feature(const_trait_impl)] #![feature(strict_provenance)] #![feature(ptr_alignment_type)] #![feature(macro_metavar_expr)] @@ -77,6 +79,7 @@ pub mod sorted_map; pub mod stable_hasher; mod atomic_ref; pub mod fingerprint; +pub mod marker; pub mod profiling; pub mod sharded; pub mod stack; diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs new file mode 100644 index 0000000000000..fef8177214ba1 --- /dev/null +++ b/compiler/rustc_data_structures/src/marker.rs @@ -0,0 +1,268 @@ +cfg_if!( + if #[cfg(not(parallel_compiler))] { + pub auto trait DynSend {} + pub auto trait DynSync {} + + impl DynSend for T {} + impl DynSync for T {} + } else { + #[rustc_on_unimplemented( + message = "`{Self}` doesn't implement `DynSend`. \ + Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Send`", + label = "`{Self}` doesn't implement `DynSend`. \ + Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Send`" + )] + // Ensure data structures is `Send` if `sync::active()` is true. + // `sync::active()` should be checked before using these data structures. + // Note: Ensure that the data structure **will not break** + // thread safety after being created. + // + // `sync::active()` should be checked when downcasting these data structures + // to `Send` via `FromDyn`. + pub unsafe auto trait DynSend {} + + #[rustc_on_unimplemented( + message = "`{Self}` doesn't implement `DynSync`. \ + Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Sync`", + label = "`{Self}` doesn't implement `DynSync`. \ + Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Sync`" + )] + // Ensure data structures is `Sync` if `sync::active()` is true. + // Note: Ensure that the data structure **will not break** + // thread safety after being checked. + // + // `sync::active()` should be checked when downcasting these data structures + // to `Send` via `FromDyn`. + pub unsafe auto trait DynSync {} + + // Same with `Sync` and `Send`. + unsafe impl DynSend for &T {} + + macro_rules! impls_dyn_send_neg { + ($([$t1: ty $(where $($generics1: tt)*)?])*) => { + $(impl$(<$($generics1)*>)? !DynSend for $t1 {})* + }; + } + + // Consistent with `std` + impls_dyn_send_neg!( + [std::env::Args] + [std::env::ArgsOs] + [*const T where T: ?Sized] + [*mut T where T: ?Sized] + [std::ptr::NonNull where T: ?Sized] + [std::rc::Rc where T: ?Sized] + [std::rc::Weak where T: ?Sized] + [std::sync::MutexGuard<'_, T> where T: ?Sized] + [std::sync::RwLockReadGuard<'_, T> where T: ?Sized] + [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized] + [std::io::StdoutLock<'_>] + [std::io::StderrLock<'_>] + ); + cfg_if!( + // Consistent with `std` + // `os_imp::Env` is `!Send` in these platforms + if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] { + impl !DynSend for std::env::VarsOs {} + } + ); + + macro_rules! already_send { + ($([$ty: ty])*) => { + $(unsafe impl DynSend for $ty where $ty: Send {})* + }; + } + + // These structures are already `Send`. + already_send!( + [std::backtrace::Backtrace] + [std::io::Stdout] + [std::io::Stderr] + [std::io::Error] + [std::fs::File] + [rustc_arena::DroplessArena] + [crate::memmap::Mmap] + [crate::profiling::SelfProfiler] + ); + + macro_rules! impl_dyn_send { + ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => { + $(unsafe impl<$($generics2)*> DynSend for $ty {})* + }; + } + + impl_dyn_send!( + [std::sync::atomic::AtomicPtr where T] + [std::sync::Mutex where T: ?Sized+ DynSend] + [std::sync::mpsc::Sender where T: DynSend] + [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::LazyLock where T: DynSend, F: DynSend] + [std::collections::HashSet where K: DynSend, S: DynSend] + [std::collections::HashMap where K: DynSend, V: DynSend, S: DynSend] + [std::collections::BTreeMap where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend] + [Vec where T: DynSend, A: std::alloc::Allocator + DynSend] + [Box where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend] + [crate::sync::Lock where T: DynSend] + [crate::sync::RwLock where T: DynSend] + [rustc_arena::TypedArena where T: DynSend] + [indexmap::IndexSet where V: DynSend, S: DynSend] + [indexmap::IndexMap where K: DynSend, V: DynSend, S: DynSend] + [thin_vec::ThinVec where T: DynSend] + [smallvec::SmallVec where A: smallvec::Array + DynSend] + + // We use `Send` here to omit some extra code, since they are only + // used in `Send` situations now. + [crate::owning_ref::OwningRef where O: Send, T: ?Sized + Send] + [crate::owning_ref::OwningRefMut where O: Send, T: ?Sized + Send] + ); + + macro_rules! impls_dyn_sync_neg { + ($([$t1: ty $(where $($generics1: tt)*)?])*) => { + $(impl$(<$($generics1)*>)? !DynSync for $t1 {})* + }; + } + + // Consistent with `std` + impls_dyn_sync_neg!( + [std::env::Args] + [std::env::ArgsOs] + [*const T where T: ?Sized] + [*mut T where T: ?Sized] + [std::cell::Cell where T: ?Sized] + [std::cell::RefCell where T: ?Sized] + [std::cell::UnsafeCell where T: ?Sized] + [std::ptr::NonNull where T: ?Sized] + [std::rc::Rc where T: ?Sized] + [std::rc::Weak where T: ?Sized] + [std::cell::OnceCell where T] + [std::sync::mpsc::Receiver where T] + [std::sync::mpsc::Sender where T] + ); + cfg_if!( + // Consistent with `std` + // `os_imp::Env` is `!Sync` in these platforms + if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] { + impl !DynSync for std::env::VarsOs {} + } + ); + + macro_rules! already_sync { + ($([$ty: ty])*) => { + $(unsafe impl DynSync for $ty where $ty: Sync {})* + }; + } + + // These structures are already `Sync`. + already_sync!( + [std::sync::atomic::AtomicBool] + [std::sync::atomic::AtomicUsize] + [std::sync::atomic::AtomicU8] + [std::sync::atomic::AtomicU32] + [std::sync::atomic::AtomicU64] + [std::backtrace::Backtrace] + [std::io::Error] + [std::fs::File] + [jobserver_crate::Client] + [crate::memmap::Mmap] + [crate::profiling::SelfProfiler] + ); + + macro_rules! impl_dyn_sync { + ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => { + $(unsafe impl<$($generics2)*> DynSync for $ty {})* + }; + } + + impl_dyn_sync!( + [std::sync::atomic::AtomicPtr where T] + [std::sync::OnceLock where T: DynSend + DynSync] + [std::sync::Mutex where T: ?Sized + DynSend] + [std::sync::Arc where T: ?Sized + DynSync + DynSend] + [std::sync::LazyLock where T: DynSend + DynSync, F: DynSend] + [std::collections::HashSet where K: DynSync, S: DynSync] + [std::collections::HashMap where K: DynSync, V: DynSync, S: DynSync] + [std::collections::BTreeMap where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync] + [Vec where T: DynSync, A: std::alloc::Allocator + DynSync] + [Box where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync] + [crate::sync::Lock where T: DynSend] + [crate::sync::RwLock where T: DynSend + DynSync] + [crate::sync::OneThread where T] + [crate::sync::WorkerLocal where T: DynSend] + [crate::intern::Interned<'a, T> where 'a, T: DynSync] + [parking_lot::lock_api::Mutex where R: DynSync, T: ?Sized + DynSend] + [parking_lot::lock_api::RwLock where R: DynSync, T: ?Sized + DynSend + DynSync] + [indexmap::IndexSet where V: DynSync, S: DynSync] + [indexmap::IndexMap where K: DynSync, V: DynSync, S: DynSync] + [smallvec::SmallVec where A: smallvec::Array + DynSync] + [thin_vec::ThinVec where T: DynSync] + + // We use `Sync` here to omit some extra code, since they are only + // used in `Sync` situations now. + [crate::owning_ref::OwningRef where O: Sync, T: ?Sized + Sync] + [crate::owning_ref::OwningRefMut where O: Sync, T: ?Sized + Sync] + ); + } +); + +pub fn assert_dyn_sync() {} +pub fn assert_dyn_send() {} +pub fn assert_dyn_send_val(_t: &T) {} +pub fn assert_dyn_send_sync_val(_t: &T) {} + +#[derive(Copy, Clone)] +pub struct FromDyn(T); + +impl FromDyn { + // Check `sync::active()` when creating this structure + // and downcasting to `Send`. So we can ensure it is + // thread-safe. + #[inline(always)] + pub fn from(val: T) -> Self { + #[cfg(parallel_compiler)] + assert!(crate::sync::active()); + FromDyn(val) + } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0 + } +} + +// `FromDyn` is `Send` if `T` is `DynSend`, since it check when created. +#[cfg(parallel_compiler)] +unsafe impl Send for FromDyn {} + +// `FromDyn` is `Sync` if `T` is `DynSync`, since it check when created. +#[cfg(parallel_compiler)] +unsafe impl Sync for FromDyn {} + +impl const std::ops::Deref for FromDyn { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Copy, Clone)] +pub struct IntoDyn(pub T); + +#[cfg(parallel_compiler)] +unsafe impl DynSend for IntoDyn {} +#[cfg(parallel_compiler)] +unsafe impl DynSync for IntoDyn {} + +impl const std::ops::Deref for IntoDyn { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl const std::ops::DerefMut for IntoDyn { + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index e73ca56efa037..5f865486880ea 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -39,6 +39,7 @@ //! //! [^2] `MTLockRef` is a typedef. +pub use crate::marker::*; use crate::owned_slice::OwnedSlice; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; @@ -55,6 +56,37 @@ pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; +mod mode { + use super::Ordering; + use std::sync::atomic::AtomicU8; + + const UNINITIALIZED: u8 = 0; + const INACTIVE: u8 = 1; + const ACTIVE: u8 = 2; + + static MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); + + #[inline] + pub fn active() -> bool { + match MODE.load(Ordering::Relaxed) { + INACTIVE => false, + ACTIVE => true, + _ => panic!("uninitialized parallel mode!"), + } + } + + // Only set by the `-Z threads` compile option + pub fn set(parallel: bool) { + let set: u8 = if parallel { ACTIVE } else { INACTIVE }; + let previous = + MODE.compare_exchange(UNINITIALIZED, set, Ordering::Relaxed, Ordering::Relaxed); + + // Check that the mode was either uninitialized or was already set to the requested mode. + assert!(previous.is_ok() || previous == Err(set)); + } +} + +pub use mode::{active, set}; cfg_if! { if #[cfg(not(parallel_compiler))] { pub unsafe auto trait Send {} @@ -149,7 +181,7 @@ cfg_if! { #[macro_export] macro_rules! parallel { - ($($blocks:tt),*) => { + ($($blocks:block),*) => {{ // We catch panics here ensuring that all the blocks execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; @@ -165,13 +197,7 @@ cfg_if! { if let Some(panic) = panic { ::std::panic::resume_unwind(panic); } - } - } - - pub use Iterator as ParallelIterator; - - pub fn par_iter(t: T) -> T::IntoIter { - t.into_iter() + }} } pub fn par_for_each_in(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) { @@ -190,6 +216,29 @@ cfg_if! { } } + pub fn par_map>( + t: T, + mut map: impl FnMut(<::IntoIter as Iterator>::Item) -> R, + ) -> C { + // We catch panics here ensuring that all the loop iterations execute. + let mut panic = None; + let r = t.into_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + if panic.is_none() { + panic = Some(p); + } + None + } + } + }).collect(); + if let Some(panic) = panic { + resume_unwind(panic); + } + r + } + pub type MetadataRef = OwnedSlice; pub use std::rc::Rc as Lrc; @@ -302,46 +351,159 @@ cfg_if! { use parking_lot::RwLock as InnerRwLock; use std::thread; - pub use rayon::{join, scope}; + + #[inline] + pub fn join(oper_a: A, oper_b: B) -> (RA, RB) + where + A: FnOnce() -> RA + DynSend, + B: FnOnce() -> RB + DynSend, + { + if mode::active() { + let oper_a = FromDyn::from(oper_a); + let oper_b = FromDyn::from(oper_b); + let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()())); + (a.into_inner(), b.into_inner()) + } else { + (oper_a(), oper_b()) + } + } + + pub fn scope<'scope, OP, R>(op: OP) -> R + where + OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, + R: DynSend, + { + let op = FromDyn::from(op); + rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() + } /// Runs a list of blocks in parallel. The first block is executed immediately on /// the current thread. Use that for the longest running block. #[macro_export] macro_rules! parallel { - (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => { - parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) + ($fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => { + parallel!($fblock [$block, $($c,)*] [$($rest),*]) + }; + ($fblock:block [$($blocks:expr,)*] []) => { + { + ::rustc_data_structures::sync::scope(|s| { + $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks); + s.spawn(move |_| block.into_inner()());)* + (|| $fblock)(); + }); + } }; - (impl $fblock:tt [$($blocks:tt,)*] []) => { - ::rustc_data_structures::sync::scope(|s| { + ($fblock:block, $($blocks:block),*) => { + if rustc_data_structures::sync::active() { + // Reverse the order of the later blocks since Rayon executes them in reverse order + // when using a single thread. This ensures the execution order matches that + // of a single threaded rustc + parallel!($fblock [] [$($blocks),*]); + } else { + // We catch panics here ensuring that all the blocks execute. + // This makes behavior consistent with the parallel compiler. + let mut panic = None; $( - s.spawn(|_| $blocks); + if let Err(p) = ::std::panic::catch_unwind( + ::std::panic::AssertUnwindSafe(|| $blocks) + ) { + if panic.is_none() { + panic = Some(p); + } + } )* - $fblock; - }) - }; - ($fblock:tt, $($blocks:tt),*) => { - // Reverse the order of the later blocks since Rayon executes them in reverse order - // when using a single thread. This ensures the execution order matches that - // of a single threaded rustc - parallel!(impl $fblock [] [$($blocks),*]); + if let Some(panic) = panic { + ::std::panic::resume_unwind(panic); + } + } }; } - pub use rayon::iter::ParallelIterator; - use rayon::iter::IntoParallelIterator; + use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator}; - pub fn par_iter(t: T) -> T::Iter { - t.into_par_iter() + pub fn par_for_each_in + IntoParallelIterator>( + t: T, + for_each: impl Fn(I) + DynSync + DynSend + ) { + if mode::active() { + let for_each = FromDyn::from(for_each); + let panic: Lock> = Lock::new(None); + t.into_par_iter().for_each(|i| if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) { + let mut l = panic.lock(); + if l.is_none() { + *l = Some(p) + } + }); + + if let Some(panic) = panic.into_inner() { + resume_unwind(panic); + } + } else { + // We catch panics here ensuring that all the loop iterations execute. + // This makes behavior consistent with the parallel compiler. + let mut panic = None; + t.into_iter().for_each(|i| { + if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) { + if panic.is_none() { + panic = Some(p); + } + } + }); + if let Some(panic) = panic { + resume_unwind(panic); + } + } } - pub fn par_for_each_in( + pub fn par_map< + I, + T: IntoIterator + IntoParallelIterator, + R: std::marker::Send, + C: FromIterator + FromParallelIterator + >( t: T, - for_each: impl Fn(T::Item) + Sync + Send, - ) { - let ps: Vec<_> = t.into_par_iter().map(|i| catch_unwind(AssertUnwindSafe(|| for_each(i)))).collect(); - ps.into_iter().for_each(|p| if let Err(panic) = p { - resume_unwind(panic) - }); + map: impl Fn(I) -> R + DynSync + DynSend + ) -> C { + if mode::active() { + let panic: Lock> = Lock::new(None); + let map = FromDyn::from(map); + // We catch panics here ensuring that all the loop iterations execute. + let r = t.into_par_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + let mut l = panic.lock(); + if l.is_none() { + *l = Some(p); + } + None + }, + } + }).collect(); + + if let Some(panic) = panic.into_inner() { + resume_unwind(panic); + } + r + } else { + // We catch panics here ensuring that all the loop iterations execute. + let mut panic = None; + let r = t.into_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + if panic.is_none() { + panic = Some(p); + } + None + } + } + }).collect(); + if let Some(panic) = panic { + resume_unwind(panic); + } + r + } } pub type MetadataRef = OwnedSlice; @@ -352,11 +514,6 @@ cfg_if! { } } -pub fn assert_sync() {} -pub fn assert_send() {} -pub fn assert_send_val(_t: &T) {} -pub fn assert_send_sync_val(_t: &T) {} - #[derive(Default)] #[cfg_attr(parallel_compiler, repr(align(64)))] pub struct CacheAligned(pub T); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 5fac485de6417..353f49e66199c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -255,6 +255,9 @@ fn run_compiler( let sopts = config::build_session_options(&matches); + // Set parallel mode before thread pool creation as the session will already create locks. + interface::set_parallel_mode(&sopts.unstable_opts); + if let Some(ref code) = matches.opt_str("explain") { handle_explain(diagnostics_registry(), code, sopts.error_format); return Ok(()); diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 6c3f677ab8e69..2b7c8dc5f3dac 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -11,7 +11,7 @@ extern crate tracing; use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{IntoDyn, Lrc}; use rustc_fluent_macro::fluent_messages; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; @@ -37,16 +37,17 @@ pub use unic_langid::{langid, LanguageIdentifier}; fluent_messages! { "../messages.ftl" } -pub type FluentBundle = fluent_bundle::bundle::FluentBundle; +pub type FluentBundle = + IntoDyn>; -#[cfg(parallel_compiler)] +#[cfg(not(parallel_compiler))] fn new_bundle(locales: Vec) -> FluentBundle { - FluentBundle::new_concurrent(locales) + IntoDyn(fluent_bundle::bundle::FluentBundle::new(locales)) } -#[cfg(not(parallel_compiler))] +#[cfg(parallel_compiler)] fn new_bundle(locales: Vec) -> FluentBundle { - FluentBundle::new(locales) + IntoDyn(fluent_bundle::bundle::FluentBundle::new_concurrent(locales)) } #[derive(Debug)] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index f9c062d3a2176..f57bb8d8bdc48 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -32,7 +32,7 @@ use emitter::{is_case_difference, Emitter, EmitterWriter}; use registry::Registry; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::{self, Lock, Lrc}; +use rustc_data_structures::sync::{self, IntoDyn, Lock, Lrc}; use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, @@ -409,7 +409,7 @@ struct HandlerInner { err_count: usize, warn_count: usize, deduplicated_err_count: usize, - emitter: Box, + emitter: IntoDyn>, delayed_span_bugs: Vec, delayed_good_path_bugs: Vec, /// This flag indicates that an expected diagnostic was emitted and suppressed. @@ -605,7 +605,7 @@ impl Handler { warn_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, - emitter, + emitter: IntoDyn(emitter), delayed_span_bugs: Vec::new(), delayed_good_path_bugs: Vec::new(), suppressed_expected_diag: false, diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 52103e4609770..08b3281d9a59f 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -2,7 +2,7 @@ use crate::error::{TranslateError, TranslateErrorKind}; use crate::fluent_bundle::*; use crate::translation::Translate; use crate::FluentBundle; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{IntoDyn, Lrc}; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::langid; use rustc_error_messages::DiagnosticMessage; @@ -27,10 +27,12 @@ fn make_dummy(ftl: &'static str) -> Dummy { let langid_en = langid!("en-US"); #[cfg(parallel_compiler)] - let mut bundle = FluentBundle::new_concurrent(vec![langid_en]); + let mut bundle: FluentBundle = + IntoDyn(crate::fluent_bundle::bundle::FluentBundle::new_concurrent(vec![langid_en])); #[cfg(not(parallel_compiler))] - let mut bundle = FluentBundle::new(vec![langid_en]); + let mut bundle: FluentBundle = + IntoDyn(crate::fluent_bundle::bundle::FluentBundle::new(vec![langid_en])); bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle."); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c1cca89df8ca5..e03576c55f436 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -653,13 +653,13 @@ pub enum SyntaxExtensionKind { /// A token-based function-like macro. Bang( /// An expander with signature TokenStream -> TokenStream. - Box, + Box, ), /// An AST-based function-like macro. LegacyBang( /// An expander with signature TokenStream -> AST. - Box, + Box, ), /// A token-based attribute macro. @@ -667,7 +667,7 @@ pub enum SyntaxExtensionKind { /// An expander with signature (TokenStream, TokenStream) -> TokenStream. /// The first TokenSteam is the attribute itself, the second is the annotated item. /// The produced TokenSteam replaces the input TokenSteam. - Box, + Box, ), /// An AST-based attribute macro. @@ -675,7 +675,7 @@ pub enum SyntaxExtensionKind { /// An expander with signature (AST, AST) -> AST. /// The first AST fragment is the attribute itself, the second is the annotated item. /// The produced AST fragment replaces the input AST fragment. - Box, + Box, ), /// A trivial attribute "macro" that does nothing, @@ -692,14 +692,14 @@ pub enum SyntaxExtensionKind { /// is handled identically to `LegacyDerive`. It should be migrated to /// a token-based representation like `Bang` and `Attr`, instead of /// using `MultiItemModifier`. - Box, + Box, ), /// An AST-based derive macro. LegacyDerive( /// An expander with signature AST -> AST. /// The produced AST fragment is appended to the input AST fragment. - Box, + Box, ), } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 9d9f4ee13f402..2a091077700a8 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -60,6 +60,11 @@ impl Compiler { } } +#[allow(rustc::bad_opt_access)] +pub fn set_parallel_mode(sopts: &config::UnstableOptions) { + rustc_data_structures::sync::set(sopts.threads > 1); +} + /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option)> { rustc_span::create_default_session_if_not_set_then(move |_| { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 53d7cf74cde53..1d0c43e95e085 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -49,9 +49,9 @@ use std::cell::Cell; use std::iter; use std::slice; -type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync; +type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync; type LateLintPassFactory = - dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync; + dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync; /// Information about the registered lints. /// @@ -169,7 +169,7 @@ impl LintStore { pub fn register_early_pass( &mut self, - pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync, ) { self.early_passes.push(Box::new(pass)); } @@ -182,7 +182,7 @@ impl LintStore { /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518) pub fn register_pre_expansion_pass( &mut self, - pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync, ) { self.pre_expansion_passes.push(Box::new(pass)); } @@ -191,8 +191,8 @@ impl LintStore { &mut self, pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + 'static - + sync::Send - + sync::Sync, + + sync::DynSend + + sync::DynSync, ) { self.late_passes.push(Box::new(pass)); } @@ -201,8 +201,8 @@ impl LintStore { &mut self, pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + 'static - + sync::Send - + sync::Sync, + + sync::DynSend + + sync::DynSync, ) { self.late_module_passes.push(Box::new(pass)); } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b42878a02ee02..c9781a72704f4 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -16,7 +16,7 @@ use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; use rustc_ast as ast; -use rustc_data_structures::sync::join; +use rustc_data_structures::sync::{join, DynSend}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit as hir_visit; @@ -429,7 +429,7 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>( /// Performs lint checking on a crate. pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>( tcx: TyCtxt<'tcx>, - builtin_lints: impl FnOnce() -> T + Send, + builtin_lints: impl FnOnce() -> T + Send + DynSend, ) { join( || { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 82c66b9dfb9f6..a155c71bc9801 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; -use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator}; +use rustc_data_structures::sync::{join, par_for_each_in, Lrc}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -2125,7 +2125,7 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { return; } - par_iter(tcx.mir_keys(())).for_each(|&def_id| { + par_for_each_in(tcx.mir_keys(()), |&def_id| { let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); if encode_const { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 15d672c1408f5..5bf0938d51869 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -5,7 +5,7 @@ use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; +use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; @@ -150,11 +150,6 @@ impl<'hir> Map<'hir> { self.tcx.hir_module_items(module).items() } - #[inline] - pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) { - par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id)); - } - pub fn def_key(self, def_id: LocalDefId) -> DefKey { // Accessing the DefKey is ok, since it is part of DefPathHash. self.tcx.definitions_untracked().def_key(def_id) @@ -502,7 +497,7 @@ impl<'hir> Map<'hir> { } #[inline] - pub fn par_body_owners(self, f: impl Fn(LocalDefId) + Sync + Send) { + pub fn par_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); } @@ -640,7 +635,7 @@ impl<'hir> Map<'hir> { } #[inline] - pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync + Send) { + pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { let crate_items = self.tcx.hir_crate_items(()); par_for_each_in(&crate_items.submodules[..], |module| f(module.def_id)) } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 7770a5e476418..a867a13e061ea 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -9,7 +9,7 @@ pub mod place; use crate::ty::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; +use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; @@ -77,19 +77,19 @@ impl ModuleItems { self.owners().map(|id| id.def_id) } - pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) { + pub fn par_items(&self, f: impl Fn(ItemId) + DynSend + DynSync) { par_for_each_in(&self.items[..], |&id| f(id)) } - pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + Send + Sync) { + pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + DynSend + DynSync) { par_for_each_in(&self.trait_items[..], |&id| f(id)) } - pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + Send + Sync) { + pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + DynSend + DynSync) { par_for_each_in(&self.impl_items[..], |&id| f(id)) } - pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + Send + Sync) { + pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + DynSend + DynSync) { par_for_each_in(&self.foreign_items[..], |&id| f(id)) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c62254cd79cb1..f34de7d838e0f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -496,7 +496,7 @@ pub struct GlobalCtxt<'tcx> { /// /// FIXME(Centril): consider `dyn LintStoreMarker` once /// we can upcast to `Any` for some additional type safety. - pub lint_store: Lrc, + pub lint_store: Lrc, pub dep_graph: DepGraph, @@ -648,7 +648,7 @@ impl<'tcx> TyCtxt<'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( s: &'tcx Session, - lint_store: Lrc, + lint_store: Lrc, arena: &'tcx WorkerLocal>, hir_arena: &'tcx WorkerLocal>, untracked: Untracked, diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index fb0d909307e78..bf9806f64069f 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -94,8 +94,8 @@ where f(None) } else { // We could get an `ImplicitCtxt` pointer from another thread. - // Ensure that `ImplicitCtxt` is `Sync`. - sync::assert_sync::>(); + // Ensure that `ImplicitCtxt` is `DynSync`. + sync::assert_dyn_sync::>(); unsafe { f(Some(downcast(context))) } } diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 30f036e471c42..8f99a0513283f 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -199,6 +199,12 @@ impl<'a, T: Copy> IntoIterator for &'a List { unsafe impl Sync for List {} +// We need this since `List` uses extern type `OpaqueListContents` +#[cfg(parallel_compiler)] +use rustc_data_structures::sync::DynSync; +#[cfg(parallel_compiler)] +unsafe impl DynSync for List {} + // Safety: // Layouts of `Equivalent` and `List` are the same, modulo opaque tail, // thus aligns of `Equivalent` and `List` must be the same. diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 07d47cae5ee93..1d09a62ca17c9 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -52,9 +52,8 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::AtomicU64; -use rustc_data_structures::sync::Lrc; -use rustc_data_structures::sync::WorkerLocal; +use rustc_data_structures::sync::AtomicU64;use rustc_data_structures::sync::WorkerLocal; +use rustc_data_structures::sync::{self, Lrc}; use rustc_data_structures::unord::UnordSet; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index dd1721801f37f..8089d81cc22c9 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -207,7 +207,7 @@ pub trait MetadataLoader: std::fmt::Debug { fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result; } -pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync; +pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync; /// A store of Rust crates, through which their metadata can be accessed. /// @@ -252,7 +252,7 @@ pub trait CrateStore: std::fmt::Debug { fn import_source_files(&self, sess: &Session, cnum: CrateNum); } -pub type CrateStoreDyn = dyn CrateStore + sync::Sync + sync::Send; +pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend; pub struct Untracked { pub cstore: RwLock>, diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 1294a8b8e6b83..e0a2733a46401 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -14,7 +14,7 @@ pub use crate::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock}; +use rustc_data_structures::sync::{AtomicU32, IntoDyn, Lrc, MappedReadGuard, ReadGuard, RwLock}; use std::cmp; use std::hash::Hash; use std::path::{self, Path, PathBuf}; @@ -176,7 +176,7 @@ pub struct SourceMap { used_address_space: AtomicU32, files: RwLock, - file_loader: Box, + file_loader: IntoDyn>, // This is used to apply the file path remapping as specified via // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`. path_mapping: FilePathMapping, @@ -202,7 +202,7 @@ impl SourceMap { SourceMap { used_address_space: AtomicU32::new(0), files: Default::default(), - file_loader, + file_loader: IntoDyn(file_loader), path_mapping, hash_kind, } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 263ce3d93b9fd..ba71d0372a775 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -730,6 +730,9 @@ fn main_args(at_args: &[String]) -> MainResult { } }; + // Set parallel mode early as the error handler will already create locks. + interface::set_parallel_mode(&options.unstable_opts); + let diag = core::new_handler( options.error_format, None, From 261b727d7626506f0eabb88e99c9d6a27b2a4f24 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Mon, 13 Mar 2023 10:04:56 +0800 Subject: [PATCH 2/7] fix some nits --- compiler/rustc_data_structures/src/marker.rs | 41 +++++++------------- compiler/rustc_data_structures/src/sync.rs | 25 ++++++------ 2 files changed, 27 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index fef8177214ba1..2af7bc917c2a0 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -8,31 +8,20 @@ cfg_if!( } else { #[rustc_on_unimplemented( message = "`{Self}` doesn't implement `DynSend`. \ - Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Send`", - label = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Send`" )] - // Ensure data structures is `Send` if `sync::active()` is true. - // `sync::active()` should be checked before using these data structures. - // Note: Ensure that the data structure **will not break** - // thread safety after being created. - // - // `sync::active()` should be checked when downcasting these data structures - // to `Send` via `FromDyn`. + // This is an auto trait for types which can be sent across threads if `sync::active()` + // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a + // `Send` type in `IntoDyn` will create a `DynSend` type. pub unsafe auto trait DynSend {} #[rustc_on_unimplemented( message = "`{Self}` doesn't implement `DynSync`. \ - Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Sync`", - label = "`{Self}` doesn't implement `DynSync`. \ Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Sync`" )] - // Ensure data structures is `Sync` if `sync::active()` is true. - // Note: Ensure that the data structure **will not break** - // thread safety after being checked. - // - // `sync::active()` should be checked when downcasting these data structures - // to `Send` via `FromDyn`. + // This is an auto trait for types which can be shared across threads if `sync::active()` + // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a + // `Sync` type in `IntoDyn` will create a `DynSync` type. pub unsafe auto trait DynSync {} // Same with `Sync` and `Send`. @@ -110,8 +99,8 @@ cfg_if!( [thin_vec::ThinVec where T: DynSend] [smallvec::SmallVec where A: smallvec::Array + DynSend] - // We use `Send` here to omit some extra code, since they are only - // used in `Send` situations now. + // We use `Send` here, since they are only used in `Send` situations now. + // In this case we don't need copy or change the codes in `crate::owning_ref`. [crate::owning_ref::OwningRef where O: Send, T: ?Sized + Send] [crate::owning_ref::OwningRefMut where O: Send, T: ?Sized + Send] ); @@ -196,8 +185,8 @@ cfg_if!( [smallvec::SmallVec where A: smallvec::Array + DynSync] [thin_vec::ThinVec where T: DynSync] - // We use `Sync` here to omit some extra code, since they are only - // used in `Sync` situations now. + // We use `Sync` here, since they are only used in `Sync` situations now. + // In this case we don't need copy or change the codes in `crate::owning_ref`. [crate::owning_ref::OwningRef where O: Sync, T: ?Sized + Sync] [crate::owning_ref::OwningRefMut where O: Sync, T: ?Sized + Sync] ); @@ -213,11 +202,11 @@ pub fn assert_dyn_send_sync_val(_t: &T) {} pub struct FromDyn(T); impl FromDyn { - // Check `sync::active()` when creating this structure - // and downcasting to `Send`. So we can ensure it is - // thread-safe. #[inline(always)] pub fn from(val: T) -> Self { + // Check that `sync::active()` is true on creation so we can + // implement `Send` and `Sync` for this structure when `T` + // implements `DynSend` and `DynSync` respectively. #[cfg(parallel_compiler)] assert!(crate::sync::active()); FromDyn(val) @@ -229,11 +218,11 @@ impl FromDyn { } } -// `FromDyn` is `Send` if `T` is `DynSend`, since it check when created. +// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::active() is true. #[cfg(parallel_compiler)] unsafe impl Send for FromDyn {} -// `FromDyn` is `Sync` if `T` is `DynSync`, since it check when created. +// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::active() is true. #[cfg(parallel_compiler)] unsafe impl Sync for FromDyn {} diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 5f865486880ea..bffb98630c835 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -181,7 +181,7 @@ cfg_if! { #[macro_export] macro_rules! parallel { - ($($blocks:block),*) => {{ + ($($blocks:block),*) => { // We catch panics here ensuring that all the blocks execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; @@ -197,7 +197,7 @@ cfg_if! { if let Some(panic) = panic { ::std::panic::resume_unwind(panic); } - }} + } } pub fn par_for_each_in(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) { @@ -368,6 +368,7 @@ cfg_if! { } } + // This function only works when `mode::active()`. pub fn scope<'scope, OP, R>(op: OP) -> R where OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, @@ -381,24 +382,22 @@ cfg_if! { /// the current thread. Use that for the longest running block. #[macro_export] macro_rules! parallel { - ($fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => { - parallel!($fblock [$block, $($c,)*] [$($rest),*]) + (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => { + parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) }; - ($fblock:block [$($blocks:expr,)*] []) => { - { - ::rustc_data_structures::sync::scope(|s| { - $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks); - s.spawn(move |_| block.into_inner()());)* - (|| $fblock)(); - }); - } + (impl $fblock:block [$($blocks:expr,)*] []) => { + ::rustc_data_structures::sync::scope(|s| { + $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks); + s.spawn(move |_| block.into_inner()());)* + (|| $fblock)(); + }); }; ($fblock:block, $($blocks:block),*) => { if rustc_data_structures::sync::active() { // Reverse the order of the later blocks since Rayon executes them in reverse order // when using a single thread. This ensures the execution order matches that // of a single threaded rustc - parallel!($fblock [] [$($blocks),*]); + parallel!(impl $fblock [] [$($blocks),*]); } else { // We catch panics here ensuring that all the blocks execute. // This makes behavior consistent with the parallel compiler. From f196e27d87cf2be019098c7562b4c2cf26566680 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Tue, 14 Mar 2023 20:31:58 +0800 Subject: [PATCH 3/7] fix `parallel!` --- compiler/rustc_data_structures/src/sync.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index bffb98630c835..f30235572d01f 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -402,6 +402,13 @@ cfg_if! { // We catch panics here ensuring that all the blocks execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; + if let Err(p) = ::std::panic::catch_unwind( + ::std::panic::AssertUnwindSafe(|| $fblock) + ) { + if panic.is_none() { + panic = Some(p); + } + } $( if let Err(p) = ::std::panic::catch_unwind( ::std::panic::AssertUnwindSafe(|| $blocks) From 9f8ab2a8d361c537d5f0e3c27df9e3f630daecd3 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Tue, 4 Apr 2023 16:26:00 +0800 Subject: [PATCH 4/7] rename relative names in `sync` --- compiler/rustc_data_structures/src/marker.rs | 12 +++--- compiler/rustc_data_structures/src/sync.rs | 39 +++++++++++--------- compiler/rustc_interface/src/interface.rs | 2 +- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 2af7bc917c2a0..62e65209d7225 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -10,7 +10,7 @@ cfg_if!( message = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Send`" )] - // This is an auto trait for types which can be sent across threads if `sync::active()` + // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a // `Send` type in `IntoDyn` will create a `DynSend` type. pub unsafe auto trait DynSend {} @@ -19,7 +19,7 @@ cfg_if!( message = "`{Self}` doesn't implement `DynSync`. \ Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Sync`" )] - // This is an auto trait for types which can be shared across threads if `sync::active()` + // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()` // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a // `Sync` type in `IntoDyn` will create a `DynSync` type. pub unsafe auto trait DynSync {} @@ -204,11 +204,11 @@ pub struct FromDyn(T); impl FromDyn { #[inline(always)] pub fn from(val: T) -> Self { - // Check that `sync::active()` is true on creation so we can + // Check that `sync::is_dyn_thread_safe()` is true on creation so we can // implement `Send` and `Sync` for this structure when `T` // implements `DynSend` and `DynSync` respectively. #[cfg(parallel_compiler)] - assert!(crate::sync::active()); + assert!(crate::sync::is_dyn_thread_safe()); FromDyn(val) } @@ -218,11 +218,11 @@ impl FromDyn { } } -// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::active() is true. +// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true. #[cfg(parallel_compiler)] unsafe impl Send for FromDyn {} -// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::active() is true. +// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true. #[cfg(parallel_compiler)] unsafe impl Sync for FromDyn {} diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index f30235572d01f..41aad2ff4e424 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -61,32 +61,37 @@ mod mode { use std::sync::atomic::AtomicU8; const UNINITIALIZED: u8 = 0; - const INACTIVE: u8 = 1; - const ACTIVE: u8 = 2; + const DYN_NOT_SYNC: u8 = 1; + const DYN_SYNC: u8 = 2; - static MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); + static DYN_SYNC_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); + // Weather control thread safety dynamically #[inline] - pub fn active() -> bool { - match MODE.load(Ordering::Relaxed) { - INACTIVE => false, - ACTIVE => true, + pub fn is_dyn_thread_safe() -> bool { + match DYN_SYNC_MODE.load(Ordering::Relaxed) { + DYN_NOT_SYNC => false, + DYN_SYNC => true, _ => panic!("uninitialized parallel mode!"), } } // Only set by the `-Z threads` compile option - pub fn set(parallel: bool) { - let set: u8 = if parallel { ACTIVE } else { INACTIVE }; - let previous = - MODE.compare_exchange(UNINITIALIZED, set, Ordering::Relaxed, Ordering::Relaxed); + pub fn set_dyn_thread_safe_mode(parallel: bool) { + let set: u8 = if parallel { DYN_SYNC } else { DYN_NOT_SYNC }; + let previous = DYN_SYNC_MODE.compare_exchange( + UNINITIALIZED, + set, + Ordering::Relaxed, + Ordering::Relaxed, + ); // Check that the mode was either uninitialized or was already set to the requested mode. assert!(previous.is_ok() || previous == Err(set)); } } -pub use mode::{active, set}; +pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; cfg_if! { if #[cfg(not(parallel_compiler))] { pub unsafe auto trait Send {} @@ -358,7 +363,7 @@ cfg_if! { A: FnOnce() -> RA + DynSend, B: FnOnce() -> RB + DynSend, { - if mode::active() { + if mode::is_dyn_thread_safe() { let oper_a = FromDyn::from(oper_a); let oper_b = FromDyn::from(oper_b); let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()())); @@ -368,7 +373,7 @@ cfg_if! { } } - // This function only works when `mode::active()`. + // This function only works when `mode::is_dyn_thread_safe()`. pub fn scope<'scope, OP, R>(op: OP) -> R where OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, @@ -393,7 +398,7 @@ cfg_if! { }); }; ($fblock:block, $($blocks:block),*) => { - if rustc_data_structures::sync::active() { + if rustc_data_structures::sync::is_dyn_thread_safe() { // Reverse the order of the later blocks since Rayon executes them in reverse order // when using a single thread. This ensures the execution order matches that // of a single threaded rustc @@ -431,7 +436,7 @@ cfg_if! { t: T, for_each: impl Fn(I) + DynSync + DynSend ) { - if mode::active() { + if mode::is_dyn_thread_safe() { let for_each = FromDyn::from(for_each); let panic: Lock> = Lock::new(None); t.into_par_iter().for_each(|i| if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) { @@ -470,7 +475,7 @@ cfg_if! { t: T, map: impl Fn(I) -> R + DynSync + DynSend ) -> C { - if mode::active() { + if mode::is_dyn_thread_safe() { let panic: Lock> = Lock::new(None); let map = FromDyn::from(map); // We catch panics here ensuring that all the loop iterations execute. diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 2a091077700a8..fb6c273e929f7 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -62,7 +62,7 @@ impl Compiler { #[allow(rustc::bad_opt_access)] pub fn set_parallel_mode(sopts: &config::UnstableOptions) { - rustc_data_structures::sync::set(sopts.threads > 1); + rustc_data_structures::sync::set_dyn_thread_safe_mode(sopts.threads > 1); } /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. From 089a38880b6e3b05a2c59644469233dbda411158 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 7 Apr 2023 21:20:26 +0800 Subject: [PATCH 5/7] correct literals for dyn thread safe --- compiler/rustc_ast/src/tokenstream.rs | 2 +- compiler/rustc_data_structures/src/marker.rs | 21 +++++++++-------- compiler/rustc_data_structures/src/sync.rs | 24 ++++++++++---------- compiler/rustc_driver_impl/src/lib.rs | 4 ++-- compiler/rustc_error_messages/src/lib.rs | 8 +++---- compiler/rustc_errors/src/lib.rs | 6 ++--- compiler/rustc_errors/src/tests.rs | 8 ++++--- compiler/rustc_interface/src/interface.rs | 2 +- compiler/rustc_middle/src/ty/list.rs | 2 +- compiler/rustc_span/src/source_map.rs | 8 ++++--- src/librustdoc/lib.rs | 4 ++-- 11 files changed, 48 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 3b47ebef2fd3f..3f0b1627afa56 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -48,7 +48,7 @@ pub enum TokenTree { Delimited(DelimSpan, Delimiter, TokenStream), } -// Ensure all fields of `TokenTree` is `DynSend` and `DynSync`. +// Ensure all fields of `TokenTree` are `DynSend` and `DynSync`. #[cfg(parallel_compiler)] fn _dummy() where diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 62e65209d7225..6dad2bac58aec 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -8,20 +8,20 @@ cfg_if!( } else { #[rustc_on_unimplemented( message = "`{Self}` doesn't implement `DynSend`. \ - Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Send`" + Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`" )] // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a - // `Send` type in `IntoDyn` will create a `DynSend` type. + // `Send` type in `IntoDynSyncSend` will create a `DynSend` type. pub unsafe auto trait DynSend {} #[rustc_on_unimplemented( message = "`{Self}` doesn't implement `DynSync`. \ - Add it to `rustc_data_structures::marker` or use `IntoDyn` if it's already `Sync`" + Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`" )] // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()` // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a - // `Sync` type in `IntoDyn` will create a `DynSync` type. + // `Sync` type in `IntoDynSyncSend` will create a `DynSync` type. pub unsafe auto trait DynSync {} // Same with `Sync` and `Send`. @@ -234,15 +234,18 @@ impl const std::ops::Deref for FromDyn { } } +// A wrapper to convert a struct that is already a `Send` or `Sync` into +// an instance of `DynSend` and `DynSync`, since the compiler cannot infer +// it automatically in some cases. (e.g. Box) #[derive(Copy, Clone)] -pub struct IntoDyn(pub T); +pub struct IntoDynSyncSend(pub T); #[cfg(parallel_compiler)] -unsafe impl DynSend for IntoDyn {} +unsafe impl DynSend for IntoDynSyncSend {} #[cfg(parallel_compiler)] -unsafe impl DynSync for IntoDyn {} +unsafe impl DynSync for IntoDynSyncSend {} -impl const std::ops::Deref for IntoDyn { +impl const std::ops::Deref for IntoDynSyncSend { type Target = T; fn deref(&self) -> &T { @@ -250,7 +253,7 @@ impl const std::ops::Deref for IntoDyn { } } -impl const std::ops::DerefMut for IntoDyn { +impl const std::ops::DerefMut for IntoDynSyncSend { fn deref_mut(&mut self) -> &mut T { &mut self.0 } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 41aad2ff4e424..8a778866a77e2 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -61,25 +61,25 @@ mod mode { use std::sync::atomic::AtomicU8; const UNINITIALIZED: u8 = 0; - const DYN_NOT_SYNC: u8 = 1; - const DYN_SYNC: u8 = 2; + const DYN_NOT_THREAD_SAFE: u8 = 1; + const DYN_THREAD_SAFE: u8 = 2; - static DYN_SYNC_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); + static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); - // Weather control thread safety dynamically + // Whether thread safety is enabled (due to running under multiple threads). #[inline] pub fn is_dyn_thread_safe() -> bool { - match DYN_SYNC_MODE.load(Ordering::Relaxed) { - DYN_NOT_SYNC => false, - DYN_SYNC => true, - _ => panic!("uninitialized parallel mode!"), + match DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) { + DYN_NOT_THREAD_SAFE => false, + DYN_THREAD_SAFE => true, + _ => panic!("uninitialized dyn_thread_safe mode!"), } } // Only set by the `-Z threads` compile option - pub fn set_dyn_thread_safe_mode(parallel: bool) { - let set: u8 = if parallel { DYN_SYNC } else { DYN_NOT_SYNC }; - let previous = DYN_SYNC_MODE.compare_exchange( + pub fn set_dyn_thread_safe_mode(mode: bool) { + let set: u8 = if mode { DYN_THREAD_SAFE } else { DYN_NOT_THREAD_SAFE }; + let previous = DYN_THREAD_SAFE_MODE.compare_exchange( UNINITIALIZED, set, Ordering::Relaxed, @@ -401,7 +401,7 @@ cfg_if! { if rustc_data_structures::sync::is_dyn_thread_safe() { // Reverse the order of the later blocks since Rayon executes them in reverse order // when using a single thread. This ensures the execution order matches that - // of a single threaded rustc + // of a single threaded rustc. parallel!(impl $fblock [] [$($blocks),*]); } else { // We catch panics here ensuring that all the blocks execute. diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 353f49e66199c..b94fb335a4ef0 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -255,8 +255,8 @@ fn run_compiler( let sopts = config::build_session_options(&matches); - // Set parallel mode before thread pool creation as the session will already create locks. - interface::set_parallel_mode(&sopts.unstable_opts); + // Set parallel mode before thread pool creation, which will create `Lock`s. + interface::set_thread_safe_mode(&sopts.unstable_opts); if let Some(ref code) = matches.opt_str("explain") { handle_explain(diagnostics_registry(), code, sopts.error_format); diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 2b7c8dc5f3dac..0accb4ab96f59 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -11,7 +11,7 @@ extern crate tracing; use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; -use rustc_data_structures::sync::{IntoDyn, Lrc}; +use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_fluent_macro::fluent_messages; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; @@ -38,16 +38,16 @@ pub use unic_langid::{langid, LanguageIdentifier}; fluent_messages! { "../messages.ftl" } pub type FluentBundle = - IntoDyn>; + IntoDynSyncSend>; #[cfg(not(parallel_compiler))] fn new_bundle(locales: Vec) -> FluentBundle { - IntoDyn(fluent_bundle::bundle::FluentBundle::new(locales)) + IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new(locales)) } #[cfg(parallel_compiler)] fn new_bundle(locales: Vec) -> FluentBundle { - IntoDyn(fluent_bundle::bundle::FluentBundle::new_concurrent(locales)) + IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new_concurrent(locales)) } #[derive(Debug)] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index f57bb8d8bdc48..64fbf22c26241 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -32,7 +32,7 @@ use emitter::{is_case_difference, Emitter, EmitterWriter}; use registry::Registry; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::{self, IntoDyn, Lock, Lrc}; +use rustc_data_structures::sync::{self, IntoDynSyncSend, Lock, Lrc}; use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, @@ -409,7 +409,7 @@ struct HandlerInner { err_count: usize, warn_count: usize, deduplicated_err_count: usize, - emitter: IntoDyn>, + emitter: IntoDynSyncSend>, delayed_span_bugs: Vec, delayed_good_path_bugs: Vec, /// This flag indicates that an expected diagnostic was emitted and suppressed. @@ -605,7 +605,7 @@ impl Handler { warn_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, - emitter: IntoDyn(emitter), + emitter: IntoDynSyncSend(emitter), delayed_span_bugs: Vec::new(), delayed_good_path_bugs: Vec::new(), suppressed_expected_diag: false, diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 08b3281d9a59f..0e729b716803f 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -2,7 +2,7 @@ use crate::error::{TranslateError, TranslateErrorKind}; use crate::fluent_bundle::*; use crate::translation::Translate; use crate::FluentBundle; -use rustc_data_structures::sync::{IntoDyn, Lrc}; +use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::langid; use rustc_error_messages::DiagnosticMessage; @@ -28,11 +28,13 @@ fn make_dummy(ftl: &'static str) -> Dummy { #[cfg(parallel_compiler)] let mut bundle: FluentBundle = - IntoDyn(crate::fluent_bundle::bundle::FluentBundle::new_concurrent(vec![langid_en])); + IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new_concurrent(vec![ + langid_en, + ])); #[cfg(not(parallel_compiler))] let mut bundle: FluentBundle = - IntoDyn(crate::fluent_bundle::bundle::FluentBundle::new(vec![langid_en])); + IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new(vec![langid_en])); bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle."); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index fb6c273e929f7..ee373f72ee9ce 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -61,7 +61,7 @@ impl Compiler { } #[allow(rustc::bad_opt_access)] -pub fn set_parallel_mode(sopts: &config::UnstableOptions) { +pub fn set_thread_safe_mode(sopts: &config::UnstableOptions) { rustc_data_structures::sync::set_dyn_thread_safe_mode(sopts.threads > 1); } diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 8f99a0513283f..71911a5a61877 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -199,7 +199,7 @@ impl<'a, T: Copy> IntoIterator for &'a List { unsafe impl Sync for List {} -// We need this since `List` uses extern type `OpaqueListContents` +// We need this since `List` uses extern type `OpaqueListContents`. #[cfg(parallel_compiler)] use rustc_data_structures::sync::DynSync; #[cfg(parallel_compiler)] diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index e0a2733a46401..8238a16969d9b 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -14,7 +14,9 @@ pub use crate::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, IntoDyn, Lrc, MappedReadGuard, ReadGuard, RwLock}; +use rustc_data_structures::sync::{ + AtomicU32, IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock, +}; use std::cmp; use std::hash::Hash; use std::path::{self, Path, PathBuf}; @@ -176,7 +178,7 @@ pub struct SourceMap { used_address_space: AtomicU32, files: RwLock, - file_loader: IntoDyn>, + file_loader: IntoDynSyncSend>, // This is used to apply the file path remapping as specified via // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`. path_mapping: FilePathMapping, @@ -202,7 +204,7 @@ impl SourceMap { SourceMap { used_address_space: AtomicU32::new(0), files: Default::default(), - file_loader: IntoDyn(file_loader), + file_loader: IntoDynSyncSend(file_loader), path_mapping, hash_kind, } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ba71d0372a775..70b6ba1aced13 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -730,8 +730,8 @@ fn main_args(at_args: &[String]) -> MainResult { } }; - // Set parallel mode early as the error handler will already create locks. - interface::set_parallel_mode(&options.unstable_opts); + // Set parallel mode before error handler creation, which will create `Lock`s. + interface::set_thread_safe_mode(&options.unstable_opts); let diag = core::new_handler( options.error_format, From bffccddac3470f68efe15a3e81257869be562568 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Mon, 10 Apr 2023 09:53:50 +0800 Subject: [PATCH 6/7] correct import of owned_slice --- compiler/rustc_data_structures/src/lib.rs | 3 ++- compiler/rustc_data_structures/src/marker.rs | 12 ++---------- .../rustc_data_structures/src/owned_slice/tests.rs | 4 ++-- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index f543e0d4a7add..579f54c5f715b 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -29,7 +29,8 @@ #![feature(allocator_api)] #![feature(get_mut_unchecked)] #![feature(lint_reasons)] -#![feature(unwrap_infallible)]#![feature(const_mut_refs)] +#![feature(unwrap_infallible)] +#![feature(const_mut_refs)] #![feature(const_trait_impl)] #![feature(strict_provenance)] #![feature(ptr_alignment_type)] diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 6dad2bac58aec..e23a10839ee17 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -72,6 +72,7 @@ cfg_if!( [rustc_arena::DroplessArena] [crate::memmap::Mmap] [crate::profiling::SelfProfiler] + [crate::owned_slice::OwnedSlice] ); macro_rules! impl_dyn_send { @@ -98,11 +99,6 @@ cfg_if!( [indexmap::IndexMap where K: DynSend, V: DynSend, S: DynSend] [thin_vec::ThinVec where T: DynSend] [smallvec::SmallVec where A: smallvec::Array + DynSend] - - // We use `Send` here, since they are only used in `Send` situations now. - // In this case we don't need copy or change the codes in `crate::owning_ref`. - [crate::owning_ref::OwningRef where O: Send, T: ?Sized + Send] - [crate::owning_ref::OwningRefMut where O: Send, T: ?Sized + Send] ); macro_rules! impls_dyn_sync_neg { @@ -154,6 +150,7 @@ cfg_if!( [jobserver_crate::Client] [crate::memmap::Mmap] [crate::profiling::SelfProfiler] + [crate::owned_slice::OwnedSlice] ); macro_rules! impl_dyn_sync { @@ -184,11 +181,6 @@ cfg_if!( [indexmap::IndexMap where K: DynSync, V: DynSync, S: DynSync] [smallvec::SmallVec where A: smallvec::Array + DynSync] [thin_vec::ThinVec where T: DynSync] - - // We use `Sync` here, since they are only used in `Sync` situations now. - // In this case we don't need copy or change the codes in `crate::owning_ref`. - [crate::owning_ref::OwningRef where O: Sync, T: ?Sized + Sync] - [crate::owning_ref::OwningRefMut where O: Sync, T: ?Sized + Sync] ); } ); diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs index e715fb55362dd..e151b8c2de04e 100644 --- a/compiler/rustc_data_structures/src/owned_slice/tests.rs +++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs @@ -69,6 +69,6 @@ fn drop_drops() { #[test] fn send_sync() { - crate::sync::assert_send::(); - crate::sync::assert_sync::(); + crate::sync::assert_dyn_send::(); + crate::sync::assert_dyn_sync::(); } From d7e3e5bede187d113fa01c4d8b8c16a2bd4f721c Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Sat, 6 May 2023 10:23:51 +0800 Subject: [PATCH 7/7] add `DynSend / DynSync` for `CopyTaggedPtr` --- compiler/rustc_data_structures/src/lib.rs | 2 -- compiler/rustc_data_structures/src/marker.rs | 11 ++++++++--- compiler/rustc_middle/src/ty/query.rs | 5 +++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 579f54c5f715b..5b9b0e106d254 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -30,8 +30,6 @@ #![feature(get_mut_unchecked)] #![feature(lint_reasons)] #![feature(unwrap_infallible)] -#![feature(const_mut_refs)] -#![feature(const_trait_impl)] #![feature(strict_provenance)] #![feature(ptr_alignment_type)] #![feature(macro_metavar_expr)] diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index e23a10839ee17..f8c06f9a8145e 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -94,6 +94,7 @@ cfg_if!( [Box where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend] [crate::sync::Lock where T: DynSend] [crate::sync::RwLock where T: DynSend] + [crate::tagged_ptr::CopyTaggedPtr where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool] [rustc_arena::TypedArena where T: DynSend] [indexmap::IndexSet where V: DynSend, S: DynSend] [indexmap::IndexMap where K: DynSend, V: DynSend, S: DynSend] @@ -175,6 +176,7 @@ cfg_if!( [crate::sync::OneThread where T] [crate::sync::WorkerLocal where T: DynSend] [crate::intern::Interned<'a, T> where 'a, T: DynSync] + [crate::tagged_ptr::CopyTaggedPtr where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool] [parking_lot::lock_api::Mutex where R: DynSync, T: ?Sized + DynSend] [parking_lot::lock_api::RwLock where R: DynSync, T: ?Sized + DynSend + DynSync] [indexmap::IndexSet where V: DynSync, S: DynSync] @@ -218,9 +220,10 @@ unsafe impl Send for FromDyn {} #[cfg(parallel_compiler)] unsafe impl Sync for FromDyn {} -impl const std::ops::Deref for FromDyn { +impl std::ops::Deref for FromDyn { type Target = T; + #[inline(always)] fn deref(&self) -> &Self::Target { &self.0 } @@ -237,15 +240,17 @@ unsafe impl DynSend for IntoDynSyncSend {} #[cfg(parallel_compiler)] unsafe impl DynSync for IntoDynSyncSend {} -impl const std::ops::Deref for IntoDynSyncSend { +impl std::ops::Deref for IntoDynSyncSend { type Target = T; + #[inline(always)] fn deref(&self) -> &T { &self.0 } } -impl const std::ops::DerefMut for IntoDynSyncSend { +impl std::ops::DerefMut for IntoDynSyncSend { + #[inline(always)] fn deref_mut(&mut self) -> &mut T { &mut self.0 } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 1d09a62ca17c9..07d47cae5ee93 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -52,8 +52,9 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::AtomicU64;use rustc_data_structures::sync::WorkerLocal; -use rustc_data_structures::sync::{self, Lrc}; +use rustc_data_structures::sync::AtomicU64; +use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::WorkerLocal; use rustc_data_structures::unord::UnordSet; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir;