diff options
Diffstat (limited to 'compiler/rustc_interface/src')
-rw-r--r-- | compiler/rustc_interface/src/errors.rs | 58 | ||||
-rw-r--r-- | compiler/rustc_interface/src/interface.rs | 109 | ||||
-rw-r--r-- | compiler/rustc_interface/src/lib.rs | 1 | ||||
-rw-r--r-- | compiler/rustc_interface/src/passes.rs | 23 | ||||
-rw-r--r-- | compiler/rustc_interface/src/proc_macro_decls.rs | 5 | ||||
-rw-r--r-- | compiler/rustc_interface/src/queries.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_interface/src/tests.rs | 43 | ||||
-rw-r--r-- | compiler/rustc_interface/src/util.rs | 122 |
8 files changed, 172 insertions, 193 deletions
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index 6a497aed4..f5135c78d 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -1,11 +1,11 @@ -use rustc_macros::SessionDiagnostic; +use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; use std::io; use std::path::Path; -#[derive(SessionDiagnostic)] -#[diag(interface::ferris_identifier)] +#[derive(Diagnostic)] +#[diag(interface_ferris_identifier)] pub struct FerrisIdentifier { #[primary_span] pub spans: Vec<Span>, @@ -13,76 +13,76 @@ pub struct FerrisIdentifier { pub first_span: Span, } -#[derive(SessionDiagnostic)] -#[diag(interface::emoji_identifier)] +#[derive(Diagnostic)] +#[diag(interface_emoji_identifier)] pub struct EmojiIdentifier { #[primary_span] pub spans: Vec<Span>, pub ident: Symbol, } -#[derive(SessionDiagnostic)] -#[diag(interface::mixed_bin_crate)] +#[derive(Diagnostic)] +#[diag(interface_mixed_bin_crate)] pub struct MixedBinCrate; -#[derive(SessionDiagnostic)] -#[diag(interface::mixed_proc_macro_crate)] +#[derive(Diagnostic)] +#[diag(interface_mixed_proc_macro_crate)] pub struct MixedProcMacroCrate; -#[derive(SessionDiagnostic)] -#[diag(interface::proc_macro_doc_without_arg)] +#[derive(Diagnostic)] +#[diag(interface_proc_macro_doc_without_arg)] pub struct ProcMacroDocWithoutArg; -#[derive(SessionDiagnostic)] -#[diag(interface::error_writing_dependencies)] +#[derive(Diagnostic)] +#[diag(interface_error_writing_dependencies)] pub struct ErrorWritingDependencies<'a> { pub path: &'a Path, pub error: io::Error, } -#[derive(SessionDiagnostic)] -#[diag(interface::input_file_would_be_overwritten)] +#[derive(Diagnostic)] +#[diag(interface_input_file_would_be_overwritten)] pub struct InputFileWouldBeOverWritten<'a> { pub path: &'a Path, } -#[derive(SessionDiagnostic)] -#[diag(interface::generated_file_conflicts_with_directory)] +#[derive(Diagnostic)] +#[diag(interface_generated_file_conflicts_with_directory)] pub struct GeneratedFileConflictsWithDirectory<'a> { pub input_path: &'a Path, pub dir_path: &'a Path, } -#[derive(SessionDiagnostic)] -#[diag(interface::temps_dir_error)] +#[derive(Diagnostic)] +#[diag(interface_temps_dir_error)] pub struct TempsDirError; -#[derive(SessionDiagnostic)] -#[diag(interface::out_dir_error)] +#[derive(Diagnostic)] +#[diag(interface_out_dir_error)] pub struct OutDirError; -#[derive(SessionDiagnostic)] -#[diag(interface::cant_emit_mir)] +#[derive(Diagnostic)] +#[diag(interface_cant_emit_mir)] pub struct CantEmitMIR { pub error: io::Error, } -#[derive(SessionDiagnostic)] -#[diag(interface::rustc_error_fatal)] +#[derive(Diagnostic)] +#[diag(interface_rustc_error_fatal)] pub struct RustcErrorFatal { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(interface::rustc_error_unexpected_annotation)] +#[derive(Diagnostic)] +#[diag(interface_rustc_error_unexpected_annotation)] pub struct RustcErrorUnexpectedAnnotation { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(interface::failed_writing_file)] +#[derive(Diagnostic)] +#[diag(interface_failed_writing_file)] pub struct FailedWritingFile<'a> { pub path: &'a Path, pub error: io::Error, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 949bd02ad..89aaa0b95 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -17,7 +17,7 @@ use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilena use rustc_session::early_error; use rustc_session::lint; use rustc_session::parse::{CrateConfig, ParseSess}; -use rustc_session::{DiagnosticOutput, Session}; +use rustc_session::Session; use rustc_span::source_map::{FileLoader, FileName}; use rustc_span::symbol::sym; use std::path::PathBuf; @@ -25,7 +25,10 @@ use std::result; pub type Result<T> = result::Result<T, ErrorGuaranteed>; -/// Represents a compiler session. +/// Represents a compiler session. Note that every `Compiler` contains a +/// `Session`, but `Compiler` also contains some things that cannot be in +/// `Session`, due to `Session` being in a crate that has many fewer +/// dependencies than this crate. /// /// Can be used to run `rustc_interface` queries. /// Created by passing [`Config`] to [`run_compiler`]. @@ -247,7 +250,6 @@ pub struct Config { pub output_dir: Option<PathBuf>, pub output_file: Option<PathBuf>, pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>, - pub diagnostic_output: DiagnosticOutput, pub lint_caps: FxHashMap<lint::LintId, lint::Level>, @@ -276,59 +278,6 @@ pub struct Config { pub registry: Registry, } -pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R { - crate::callbacks::setup_callbacks(); - - let registry = &config.registry; - let (mut sess, codegen_backend) = util::create_session( - config.opts, - config.crate_cfg, - config.crate_check_cfg, - config.diagnostic_output, - config.file_loader, - config.input_path.clone(), - config.lint_caps, - config.make_codegen_backend, - registry.clone(), - ); - - if let Some(parse_sess_created) = config.parse_sess_created { - parse_sess_created( - &mut Lrc::get_mut(&mut sess) - .expect("create_session() should never share the returned session") - .parse_sess, - ); - } - - let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); - - let compiler = Compiler { - sess, - codegen_backend, - input: config.input, - input_path: config.input_path, - output_dir: config.output_dir, - output_file: config.output_file, - temps_dir, - register_lints: config.register_lints, - override_queries: config.override_queries, - }; - - rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { - let r = { - let _sess_abort_error = OnDrop(|| { - compiler.sess.finish_diagnostics(registry); - }); - - f(&compiler) - }; - - let prof = compiler.sess.prof.clone(); - prof.generic_activity("drop_compiler").run(move || drop(compiler)); - r - }) -} - // JUSTIFICATION: before session exists, only config #[allow(rustc::bad_opt_access)] pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { @@ -336,7 +285,53 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.unstable_opts.threads, - || create_compiler_and_run(config, f), + || { + crate::callbacks::setup_callbacks(); + + let registry = &config.registry; + let (mut sess, codegen_backend) = util::create_session( + config.opts, + config.crate_cfg, + config.crate_check_cfg, + config.file_loader, + config.input_path.clone(), + config.lint_caps, + config.make_codegen_backend, + registry.clone(), + ); + + if let Some(parse_sess_created) = config.parse_sess_created { + parse_sess_created(&mut sess.parse_sess); + } + + let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); + + let compiler = Compiler { + sess: Lrc::new(sess), + codegen_backend: Lrc::new(codegen_backend), + input: config.input, + input_path: config.input_path, + output_dir: config.output_dir, + output_file: config.output_file, + temps_dir, + register_lints: config.register_lints, + override_queries: config.override_queries, + }; + + rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { + let r = { + let _sess_abort_error = OnDrop(|| { + compiler.sess.finish_diagnostics(registry); + }); + + f(&compiler) + }; + + let prof = compiler.sess.prof.clone(); + prof.generic_activity("drop_compiler").run(move || drop(compiler)); + r + }) + }, ) } diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 41cd7b0e9..a41a749ee 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,5 +1,4 @@ #![feature(box_patterns)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(internal_output_capture)] #![feature(thread_spawn_unchecked)] #![feature(once_cell)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c41b154c3..7f1d21bf1 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -16,7 +16,6 @@ use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::{ErrorGuaranteed, PResult}; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand}; use rustc_hir::def_id::StableCrateId; -use rustc_hir::definitions::Definitions; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; @@ -30,14 +29,13 @@ use rustc_plugin_impl as plugin; use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType}; -use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn}; +use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn}; use rustc_session::output::filename_for_input; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::FileName; use rustc_trait_selection::traits; -use rustc_typeck as typeck; use std::any::Any; use std::cell::RefCell; @@ -136,10 +134,7 @@ mod boxed_resolver { f((&mut *resolver).as_mut().unwrap()) } - pub fn to_resolver_outputs( - resolver: Rc<RefCell<BoxedResolver>>, - ) -> (Definitions, Box<CrateStoreDyn>, ty::ResolverOutputs, ty::ResolverAstLowering) - { + pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ty::ResolverOutputs { match Rc::try_unwrap(resolver) { Ok(resolver) => { let mut resolver = resolver.into_inner(); @@ -736,11 +731,11 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { rustc_mir_transform::provide(providers); rustc_monomorphize::provide(providers); rustc_privacy::provide(providers); - typeck::provide(providers); + rustc_hir_analysis::provide(providers); + rustc_hir_typeck::provide(providers); ty::provide(providers); traits::provide(providers); rustc_passes::provide(providers); - rustc_resolve::provide(providers); rustc_traits::provide(providers); rustc_ty_utils::provide(providers); rustc_metadata::provide(providers); @@ -789,8 +784,7 @@ pub fn create_global_ctxt<'tcx>( // incr. comp. yet. dep_graph.assert_ignored(); - let (definitions, cstore, resolver_outputs, resolver_for_lowering) = - BoxedResolver::to_resolver_outputs(resolver); + let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver); let sess = &compiler.session(); let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); @@ -817,10 +811,7 @@ pub fn create_global_ctxt<'tcx>( lint_store, arena, hir_arena, - definitions, - cstore, resolver_outputs, - resolver_for_lowering, krate, dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), @@ -880,7 +871,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { }); // passes are timed inside typeck - typeck::check_crate(tcx)?; + rustc_hir_analysis::check_crate(tcx)?; sess.time("misc_checking_2", || { parallel!( @@ -936,7 +927,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { sess.time("misc_checking_3", || { parallel!( { - tcx.ensure().privacy_access_levels(()); + tcx.ensure().effective_visibilities(()); parallel!( { diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 5371c513d..4c236c693 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -1,4 +1,3 @@ -use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -10,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> { for id in tcx.hir().items() { let attrs = finder.tcx.hir().attrs(id.hir_id()); if finder.tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) { - finder.decls = Some(id.def_id); + finder.decls = Some(id.owner_id.def_id); } } @@ -19,7 +18,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> { struct Finder<'tcx> { tcx: TyCtxt<'tcx>, - decls: Option<hir::def_id::LocalDefId>, + decls: Option<LocalDefId>, } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 6c725a01b..91d180e1e 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -246,6 +246,10 @@ impl<'tcx> Queries<'tcx> { // Don't do code generation if there were any errors self.session().compile_status()?; + // If we have any delayed bugs, for example because we created TyKind::Error earlier, + // it's likely that codegen will only cause more ICEs, obscuring the original problem + self.session().diagnostic().flush_delayed(); + // Hook for UI tests. Self::check_for_rustc_errors_attr(tcx); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index c7615a577..eb8e65a6d 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -17,7 +17,7 @@ use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, Switc use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; -use rustc_session::{build_session, getopts, DiagnosticOutput, Session}; +use rustc_session::{build_session, getopts, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_span::SourceFileHashAlgorithm; @@ -40,16 +40,7 @@ fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { let registry = registry::Registry::new(&[]); let (sessopts, cfg) = build_session_options_and_crate_config(matches); - let sess = build_session( - sessopts, - None, - None, - registry, - DiagnosticOutput::Default, - Default::default(), - None, - None, - ); + let sess = build_session(sessopts, None, None, registry, Default::default(), None, None); (sess, cfg) } @@ -540,7 +531,7 @@ fn test_codegen_options_tracking_hash() { } // Make sure that changing an [UNTRACKED] option leaves the hash unchanged. - // This list is in alphabetical order. + // tidy-alphabetical-start untracked!(ar, String::from("abc")); untracked!(codegen_units, Some(42)); untracked!(default_linker_libraries, true); @@ -556,6 +547,7 @@ fn test_codegen_options_tracking_hash() { untracked!(rpath, true); untracked!(save_temps, true); untracked!(strip, Strip::Debuginfo); + // tidy-alphabetical-end macro_rules! tracked { ($name: ident, $non_default_value: expr) => { @@ -567,7 +559,7 @@ fn test_codegen_options_tracking_hash() { } // Make sure that changing a [TRACKED] option changes the hash. - // This list is in alphabetical order. + // tidy-alphabetical-start tracked!(code_model, Some(CodeModel::Large)); tracked!(control_flow_guard, CFGuard::Checks); tracked!(debug_assertions, Some(true)); @@ -577,8 +569,8 @@ fn test_codegen_options_tracking_hash() { tracked!(force_unwind_tables, Some(true)); tracked!(inline_threshold, Some(0xf007ba11)); tracked!(instrument_coverage, Some(InstrumentCoverage::All)); - tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto); tracked!(link_dead_code, Some(true)); + tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto); tracked!(llvm_args, vec![String::from("1"), String::from("2")]); tracked!(lto, LtoCli::Fat); tracked!(metadata, vec![String::from("A"), String::from("B")]); @@ -599,6 +591,7 @@ fn test_codegen_options_tracking_hash() { tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(target_cpu, Some(String::from("abc"))); tracked!(target_feature, String::from("all the features, all of them")); + // tidy-alphabetical-end } #[test] @@ -619,12 +612,13 @@ fn test_top_level_options_tracked_no_crate() { } // Make sure that changing a [TRACKED_NO_CRATE_HASH] option leaves the crate hash unchanged but changes the incremental hash. - // This list is in alphabetical order. - tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]); + // tidy-alphabetical-start tracked!( real_rust_source_base_dir, Some("/home/bors/rust/.rustup/toolchains/nightly/lib/rustlib/src/rust".into()) ); + tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]); + // tidy-alphabetical-end } #[test] @@ -641,7 +635,7 @@ fn test_unstable_options_tracking_hash() { } // Make sure that changing an [UNTRACKED] option leaves the hash unchanged. - // This list is in alphabetical order. + // tidy-alphabetical-start untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(deduplicate_diagnostics, false); untracked!(dep_tasks, true); @@ -654,6 +648,7 @@ fn test_unstable_options_tracking_hash() { untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_graphviz, true); + untracked!(dylib_lto, true); untracked!(emit_stack_sizes, true); untracked!(future_incompat_test, true); untracked!(hir_stats, true); @@ -678,12 +673,12 @@ fn test_unstable_options_tracking_hash() { untracked!(perf_stats, true); // `pre_link_arg` is omitted because it just forwards to `pre_link_args`. untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]); - untracked!(profile_closures, true); untracked!(print_llvm_passes, true); untracked!(print_mono_items, Some(String::from("abc"))); untracked!(print_type_sizes, true); untracked!(proc_macro_backtrace, true); untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread); + untracked!(profile_closures, true); untracked!(query_dep_graph, true); untracked!(save_analysis, true); untracked!(self_profile, SwitchWithOptPath::Enabled(None)); @@ -692,7 +687,6 @@ fn test_unstable_options_tracking_hash() { untracked!(span_free_formats, true); untracked!(temps_dir, Some(String::from("abc"))); untracked!(threads, 99); - untracked!(time, true); untracked!(time_llvm_passes, true); untracked!(time_passes, true); untracked!(trace_macros, true); @@ -702,6 +696,7 @@ fn test_unstable_options_tracking_hash() { untracked!(unstable_options, true); untracked!(validate_mir, true); untracked!(verbose, true); + // tidy-alphabetical-end macro_rules! tracked { ($name: ident, $non_default_value: expr) => { @@ -713,7 +708,7 @@ fn test_unstable_options_tracking_hash() { } // Make sure that changing a [TRACKED] option changes the hash. - // This list is in alphabetical order. + // tidy-alphabetical-start tracked!(allow_features, Some(vec![String::from("lang_items")])); tracked!(always_encode_mir, true); tracked!(asm_comments, true); @@ -734,10 +729,10 @@ fn test_unstable_options_tracking_hash() { tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); tracked!(drop_tracking, true); - tracked!(export_executable_symbols, true); tracked!(dual_proc_macros, true); tracked!(dwarf_version, Some(5)); tracked!(emit_thin_lto, false); + tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); @@ -758,11 +753,10 @@ fn test_unstable_options_tracking_hash() { tracked!(mir_opt_level, Some(4)); tracked!(move_size_limit, Some(4096)); tracked!(mutable_noalias, Some(true)); - tracked!(new_llvm_pass_manager, Some(true)); tracked!(no_generate_arange_section, true); tracked!(no_link, true); - tracked!(no_unique_section_names, true); tracked!(no_profiler_runtime, true); + tracked!(no_unique_section_names, true); tracked!(oom, OomStrategy::Panic); tracked!(osx_rpath_install_name, true); tracked!(packed_bundled_libs, true); @@ -775,8 +769,8 @@ fn test_unstable_options_tracking_hash() { tracked!(print_fuel, Some("abc".to_string())); tracked!(profile, true); tracked!(profile_emit, Some(PathBuf::from("abc"))); - tracked!(profiler_runtime, "abc".to_string()); tracked!(profile_sample_use, Some(PathBuf::from("abc"))); + tracked!(profiler_runtime, "abc".to_string()); tracked!(relax_elf_relocations, Some(true)); tracked!(relro_level, Some(RelroLevel::Full)); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); @@ -805,6 +799,7 @@ fn test_unstable_options_tracking_hash() { tracked!(verify_llvm_ir, true); tracked!(virtual_function_elimination, true); tracked!(wasi_exec_model, Some(WasiExecModel::Reactor)); + // tidy-alphabetical-end macro_rules! tracked_no_crate_hash { ($name: ident, $non_default_value: expr) => { diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f7e70d355..519b8a7fc 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -3,22 +3,15 @@ use libloading::Library; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -#[cfg(parallel_compiler)] -use rustc_data_structures::jobserver; -use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; -#[cfg(parallel_compiler)] -use rustc_middle::ty::tls; use rustc_parse::validate_attr; -#[cfg(parallel_compiler)] -use rustc_query_impl::{QueryContext, QueryCtxt}; use rustc_session as session; use rustc_session::config::CheckCfg; use rustc_session::config::{self, CrateType}; use rustc_session::config::{ErrorOutputType, Input, OutputFilenames}; use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::parse::CrateConfig; -use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session}; +use rustc_session::{early_error, filesearch, output, Session}; use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::FileLoader; @@ -26,8 +19,6 @@ use rustc_span::symbol::{sym, Symbol}; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::mem; -#[cfg(not(parallel_compiler))] -use std::panic; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; @@ -65,7 +56,6 @@ pub fn create_session( sopts: config::Options, cfg: FxHashSet<(String, Option<String>)>, check_cfg: CheckCfg, - diagnostic_output: DiagnosticOutput, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, input_path: Option<PathBuf>, lint_caps: FxHashMap<lint::LintId, lint::Level>, @@ -73,7 +63,7 @@ pub fn create_session( Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, >, descriptions: Registry, -) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>) { +) -> (Session, Box<dyn CodegenBackend>) { let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { make_codegen_backend(&sopts) } else { @@ -104,7 +94,6 @@ pub fn create_session( input_path, bundle, descriptions, - diagnostic_output, lint_caps, file_loader, target_override, @@ -121,7 +110,7 @@ pub fn create_session( sess.parse_sess.config = cfg; sess.parse_sess.check_config = check_cfg; - (Lrc::new(sess), Lrc::new(codegen_backend)) + (sess, codegen_backend) } const STACK_SIZE: usize = 8 * 1024 * 1024; @@ -132,79 +121,86 @@ fn get_stack_size() -> Option<usize> { env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE) } -/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need -/// for `'static` bounds. -#[cfg(not(parallel_compiler))] -fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { - // SAFETY: join() is called immediately, so any closure captures are still - // alive. - match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { - Ok(v) => v, - Err(e) => panic::resume_unwind(e), - } -} - #[cfg(not(parallel_compiler))] -pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( edition: Edition, _threads: usize, f: F, ) -> R { - let mut cfg = thread::Builder::new().name("rustc".to_string()); - + // The "thread pool" is a single spawned thread in the non-parallel + // compiler. We run on a spawned thread instead of the main thread (a) to + // provide control over the stack size, and (b) to increase similarity with + // the parallel compiler, in particular to ensure there is no accidental + // sharing of data between the main thread and the compilation thread + // (which might cause problems for the parallel compiler). + let mut builder = thread::Builder::new().name("rustc".to_string()); if let Some(size) = get_stack_size() { - cfg = cfg.stack_size(size); + builder = builder.stack_size(size); } - let main_handler = move || rustc_span::create_session_globals_then(edition, f); - - scoped_thread(cfg, main_handler) -} - -/// Creates a new thread and forwards information in thread locals to it. -/// The new thread runs the deadlock handler. -/// Must only be called when a deadlock is about to happen. -#[cfg(parallel_compiler)] -unsafe fn handle_deadlock() { - let registry = rustc_rayon_core::Registry::current(); - - let query_map = tls::with(|tcx| { - QueryCtxt::from_tcx(tcx) - .try_collect_active_jobs() - .expect("active jobs shouldn't be locked in deadlock handler") - }); - thread::spawn(move || rustc_query_impl::deadlock(query_map, ®istry)); + // We build the session globals and run `f` on the spawned thread, because + // `SessionGlobals` does not impl `Send` in the non-parallel compiler. + thread::scope(|s| { + // `unwrap` is ok here because `spawn_scoped` only panics if the thread + // name contains null bytes. + let r = builder + .spawn_scoped(s, move || rustc_span::create_session_globals_then(edition, f)) + .unwrap() + .join(); + + match r { + Ok(v) => v, + Err(e) => std::panic::resume_unwind(e), + } + }) } #[cfg(parallel_compiler)] -pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( edition: Edition, threads: usize, f: F, ) -> R { - let mut config = rayon::ThreadPoolBuilder::new() + use rustc_data_structures::jobserver; + use rustc_middle::ty::tls; + use rustc_query_impl::{deadlock, QueryContext, QueryCtxt}; + + let mut builder = rayon::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) .acquire_thread_handler(jobserver::acquire_thread) .release_thread_handler(jobserver::release_thread) .num_threads(threads) - .deadlock_handler(|| unsafe { handle_deadlock() }); - + .deadlock_handler(|| { + // On deadlock, creates a new thread and forwards information in thread + // locals to it. The new thread runs the deadlock handler. + let query_map = tls::with(|tcx| { + QueryCtxt::from_tcx(tcx) + .try_collect_active_jobs() + .expect("active jobs shouldn't be locked in deadlock handler") + }); + let registry = rustc_rayon_core::Registry::current(); + thread::spawn(move || deadlock(query_map, ®istry)); + }); if let Some(size) = get_stack_size() { - config = config.stack_size(size); + builder = builder.stack_size(size); } - let with_pool = move |pool: &rayon::ThreadPool| pool.install(f); - + // We create the session globals on the main thread, then create the thread + // pool. Upon creation, each worker thread created gets a copy of the + // session globals in TLS. This is possible because `SessionGlobals` impls + // `Send` in the parallel compiler. rustc_span::create_session_globals_then(edition, || { rustc_span::with_session_globals(|session_globals| { - // The main handler runs for each Rayon worker thread and sets up - // the thread local rustc uses. `session_globals` is captured and set - // on the new threads. - let main_handler = move |thread: rayon::ThreadBuilder| { - rustc_span::set_session_globals_then(session_globals, || thread.run()) - }; - - config.build_scoped(main_handler, with_pool).unwrap() + builder + .build_scoped( + // Initialize each new worker thread when created. + move |thread: rayon::ThreadBuilder| { + rustc_span::set_session_globals_then(session_globals, || thread.run()) + }, + // Run `f` on the first thread in the thread pool. + move |pool: &rayon::ThreadPool| pool.install(f), + ) + .unwrap() }) }) } |