diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_interface/src/errors.rs | 89 | ||||
-rw-r--r-- | compiler/rustc_interface/src/interface.rs | 117 | ||||
-rw-r--r-- | compiler/rustc_interface/src/lib.rs | 7 | ||||
-rw-r--r-- | compiler/rustc_interface/src/passes.rs | 126 | ||||
-rw-r--r-- | compiler/rustc_interface/src/proc_macro_decls.rs | 5 | ||||
-rw-r--r-- | compiler/rustc_interface/src/queries.rs | 24 | ||||
-rw-r--r-- | compiler/rustc_interface/src/tests.rs | 54 | ||||
-rw-r--r-- | compiler/rustc_interface/src/util.rs | 126 |
8 files changed, 300 insertions, 248 deletions
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs new file mode 100644 index 000000000..f5135c78d --- /dev/null +++ b/compiler/rustc_interface/src/errors.rs @@ -0,0 +1,89 @@ +use rustc_macros::Diagnostic; +use rustc_span::{Span, Symbol}; + +use std::io; +use std::path::Path; + +#[derive(Diagnostic)] +#[diag(interface_ferris_identifier)] +pub struct FerrisIdentifier { + #[primary_span] + pub spans: Vec<Span>, + #[suggestion(code = "ferris", applicability = "maybe-incorrect")] + pub first_span: Span, +} + +#[derive(Diagnostic)] +#[diag(interface_emoji_identifier)] +pub struct EmojiIdentifier { + #[primary_span] + pub spans: Vec<Span>, + pub ident: Symbol, +} + +#[derive(Diagnostic)] +#[diag(interface_mixed_bin_crate)] +pub struct MixedBinCrate; + +#[derive(Diagnostic)] +#[diag(interface_mixed_proc_macro_crate)] +pub struct MixedProcMacroCrate; + +#[derive(Diagnostic)] +#[diag(interface_proc_macro_doc_without_arg)] +pub struct ProcMacroDocWithoutArg; + +#[derive(Diagnostic)] +#[diag(interface_error_writing_dependencies)] +pub struct ErrorWritingDependencies<'a> { + pub path: &'a Path, + pub error: io::Error, +} + +#[derive(Diagnostic)] +#[diag(interface_input_file_would_be_overwritten)] +pub struct InputFileWouldBeOverWritten<'a> { + pub path: &'a Path, +} + +#[derive(Diagnostic)] +#[diag(interface_generated_file_conflicts_with_directory)] +pub struct GeneratedFileConflictsWithDirectory<'a> { + pub input_path: &'a Path, + pub dir_path: &'a Path, +} + +#[derive(Diagnostic)] +#[diag(interface_temps_dir_error)] +pub struct TempsDirError; + +#[derive(Diagnostic)] +#[diag(interface_out_dir_error)] +pub struct OutDirError; + +#[derive(Diagnostic)] +#[diag(interface_cant_emit_mir)] +pub struct CantEmitMIR { + pub error: io::Error, +} + +#[derive(Diagnostic)] +#[diag(interface_rustc_error_fatal)] +pub struct RustcErrorFatal { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(interface_rustc_error_unexpected_annotation)] +pub struct RustcErrorUnexpectedAnnotation { + #[primary_span] + pub span: Span, +} + +#[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 94f81b660..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`]. @@ -176,7 +179,7 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { let ident = arg.ident().expect("multi-segment cfg key"); names_valid.insert(ident.name.to_string()); } else { - error!("`names()` arguments must be simple identifers"); + error!("`names()` arguments must be simple identifiers"); } } continue 'specs; @@ -204,7 +207,7 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { continue 'specs; } else { error!( - "`values()` first argument must be a simple identifer" + "`values()` first argument must be a simple identifier" ); } } else if args.is_empty() { @@ -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,67 +278,60 @@ 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 -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { - tracing::trace!("run_compiler"); + trace!("run_compiler"); 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 d443057eb..a41a749ee 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,12 +1,17 @@ #![feature(box_patterns)] -#![feature(let_else)] #![feature(internal_output_capture)] #![feature(thread_spawn_unchecked)] #![feature(once_cell)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] + +#[macro_use] +extern crate tracing; mod callbacks; +mod errors; pub mod interface; mod passes; mod proc_macro_decls; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8f0835917..7f1d21bf1 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1,3 +1,8 @@ +use crate::errors::{ + CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier, + GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate, + MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError, +}; use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; @@ -8,10 +13,9 @@ use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; -use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult}; +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; @@ -25,15 +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 tracing::{info, warn}; use std::any::Any; use std::cell::RefCell; @@ -64,7 +66,7 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { } if sess.opts.unstable_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); + hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); } Ok(krate) @@ -132,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(); @@ -160,7 +159,7 @@ pub fn create_resolver( krate: &ast::Crate, crate_name: &str, ) -> BoxedResolver { - tracing::trace!("create_resolver"); + trace!("create_resolver"); BoxedResolver::new(sess, move |sess, resolver_arenas| { Resolver::new(sess, krate, crate_name, metadata_loader, resolver_arenas) }) @@ -274,7 +273,7 @@ pub fn configure_and_expand( crate_name: &str, resolver: &mut Resolver<'_>, ) -> Result<ast::Crate> { - tracing::trace!("configure_and_expand"); + trace!("configure_and_expand"); pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); @@ -374,10 +373,10 @@ pub fn configure_and_expand( if crate_types.len() > 1 { if is_executable_crate { - sess.err("cannot mix `bin` crate type with others"); + sess.emit_err(MixedBinCrate); } if is_proc_macro_crate { - sess.err("cannot mix `proc-macro` crate type with others"); + sess.emit_err(MixedProcMacroCrate); } } @@ -388,13 +387,7 @@ pub fn configure_and_expand( // However, we do emit a warning, to let such users know that they should // start passing '--crate-type proc-macro' if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate { - let mut msg = sess.diagnostic().struct_warn( - "Trying to document proc macro crate \ - without passing '--crate-type proc-macro to rustdoc", - ); - - msg.warn("The generated documentation may be incorrect"); - msg.emit(); + sess.emit_warning(ProcMacroDocWithoutArg); } else { krate = sess.time("maybe_create_a_macro_crate", || { let is_test_crate = sess.opts.test; @@ -417,7 +410,7 @@ pub fn configure_and_expand( } if sess.opts.unstable_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); + hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS", "ast-stats-2"); } resolver.resolve_crate(&krate); @@ -443,23 +436,9 @@ pub fn configure_and_expand( spans.sort(); if ident == sym::ferris { let first_span = spans[0]; - sess.diagnostic() - .struct_span_err( - MultiSpan::from(spans), - "Ferris cannot be used as an identifier", - ) - .span_suggestion( - first_span, - "try using their name instead", - "ferris", - Applicability::MaybeIncorrect, - ) - .emit(); + sess.emit_err(FerrisIdentifier { spans, first_span }); } else { - sess.diagnostic().span_err( - MultiSpan::from(spans), - &format!("identifiers cannot contain emoji: `{}`", ident), - ); + sess.emit_err(EmojiIdentifier { spans, ident }); } } }); @@ -589,13 +568,24 @@ fn write_out_deps( // Account for explicitly marked-to-track files // (e.g. accessed in proc macros). let file_depinfo = sess.parse_sess.file_depinfo.borrow(); - let extra_tracked_files = file_depinfo.iter().map(|path_sym| { - let path = PathBuf::from(path_sym.as_str()); + + let normalize_path = |path: PathBuf| { let file = FileName::from(path); escape_dep_filename(&file.prefer_local().to_string()) - }); + }; + + let extra_tracked_files = + file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))); files.extend(extra_tracked_files); + // We also need to track used PGO profile files + if let Some(ref profile_instr) = sess.opts.cg.profile_use { + files.push(normalize_path(profile_instr.as_path().to_path_buf())); + } + if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use { + files.push(normalize_path(profile_sample.as_path().to_path_buf())); + } + if sess.binary_dep_depinfo() { if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend { if backend.contains('.') { @@ -662,11 +652,9 @@ fn write_out_deps( .emit_artifact_notification(&deps_filename, "dep-info"); } } - Err(e) => sess.fatal(&format!( - "error writing dependencies to `{}`: {}", - deps_filename.display(), - e - )), + Err(error) => { + sess.emit_fatal(ErrorWritingDependencies { path: &deps_filename, error }); + } } } @@ -696,20 +684,12 @@ pub fn prepare_outputs( if let Some(ref input_path) = compiler.input_path { if sess.opts.will_create_output_file() { if output_contains_path(&output_paths, input_path) { - let reported = sess.err(&format!( - "the input file \"{}\" would be overwritten by the generated \ - executable", - input_path.display() - )); + let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path }); return Err(reported); } - if let Some(dir_path) = output_conflicts_with_dir(&output_paths) { - let reported = sess.err(&format!( - "the generated executable for the input file \"{}\" conflicts with the \ - existing directory \"{}\"", - input_path.display(), - dir_path.display() - )); + if let Some(ref dir_path) = output_conflicts_with_dir(&output_paths) { + let reported = + sess.emit_err(GeneratedFileConflictsWithDirectory { input_path, dir_path }); return Err(reported); } } @@ -717,8 +697,7 @@ pub fn prepare_outputs( if let Some(ref dir) = compiler.temps_dir { if fs::create_dir_all(dir).is_err() { - let reported = - sess.err("failed to find or create the directory specified by `--temps-dir`"); + let reported = sess.emit_err(TempsDirError); return Err(reported); } } @@ -731,8 +710,7 @@ pub fn prepare_outputs( if !only_dep_info { if let Some(ref dir) = compiler.output_dir { if fs::create_dir_all(dir).is_err() { - let reported = - sess.err("failed to find or create the directory specified by `--out-dir`"); + let reported = sess.emit_err(OutDirError); return Err(reported); } } @@ -753,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); @@ -806,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); @@ -834,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), @@ -897,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!( @@ -907,13 +881,13 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { }); }, { - sess.time("liveness_and_intrinsic_checking", || { - tcx.hir().par_for_each_module(|module| { + sess.time("liveness_checking", || { + tcx.hir().par_body_owners(|def_id| { // this must run before MIR dump, because // "not all control paths return a value" is reported here. // // maybe move the check to a MIR pass? - tcx.ensure().check_mod_liveness(module); + tcx.ensure().check_liveness(def_id.to_def_id()); }); }); } @@ -953,7 +927,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { sess.time("misc_checking_3", || { parallel!( { - tcx.ensure().privacy_access_levels(()); + tcx.ensure().effective_visibilities(()); parallel!( { @@ -1015,8 +989,8 @@ pub fn start_codegen<'tcx>( info!("Post-codegen\n{:?}", tcx.debug_stats()); if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(e) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) { - tcx.sess.err(&format!("could not emit MIR: {}", e)); + if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) { + tcx.sess.emit_err(CantEmitMIR { error }); tcx.sess.abort_if_errors(); } } 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 73402ae08..91d180e1e 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -1,3 +1,4 @@ +use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation}; use crate::interface::{Compiler, Result}; use crate::passes::{self, BoxedResolver, QueryContext}; @@ -165,7 +166,7 @@ impl<'tcx> Queries<'tcx> { pub fn expansion( &self, ) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> { - tracing::trace!("expansion"); + trace!("expansion"); self.expansion.compute(|| { let crate_name = self.crate_name()?.peek().clone(); let (krate, lint_store) = self.register_plugins()?.take(); @@ -245,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); @@ -274,18 +279,14 @@ impl<'tcx> Queries<'tcx> { // Bare `#[rustc_error]`. None => { - tcx.sess.span_fatal( - tcx.def_span(def_id), - "fatal error triggered by #[rustc_error]", - ); + tcx.sess.emit_fatal(RustcErrorFatal { span: tcx.def_span(def_id) }); } // Some other attribute. Some(_) => { - tcx.sess.span_warn( - tcx.def_span(def_id), - "unexpected annotation used with `#[rustc_error(...)]!", - ); + tcx.sess.emit_warning(RustcErrorUnexpectedAnnotation { + span: tcx.def_span(def_id), + }); } } } @@ -360,9 +361,8 @@ impl Linker { if sess.opts.unstable_opts.no_link { let encoded = CodegenResults::serialize_rlink(&codegen_results); let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); - std::fs::write(&rlink_file, encoded).map_err(|err| { - sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err)); - })?; + std::fs::write(&rlink_file, encoded) + .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; return Ok(()); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a9fdfa241..eb8e65a6d 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#![allow(rustc::bad_opt_access)] use crate::interface::parse_cfgspecs; use rustc_data_structures::fx::FxHashSet; @@ -17,14 +17,12 @@ 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; -use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}; -use rustc_target::spec::{ - RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, -}; +use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel}; +use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel}; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; @@ -42,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) } @@ -542,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); @@ -552,12 +541,13 @@ fn test_codegen_options_tracking_hash() { untracked!(link_args, vec![String::from("abc"), String::from("def")]); untracked!(link_self_contained, Some(true)); untracked!(linker, Some(PathBuf::from("linker"))); - untracked!(linker_flavor, Some(LinkerFlavor::Gcc)); + untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc)); untracked!(no_stack_check, true); untracked!(remark, Passes::Some(vec![String::from("pass1"), String::from("pass2")])); untracked!(rpath, true); untracked!(save_temps, true); untracked!(strip, Strip::Debuginfo); + // tidy-alphabetical-end macro_rules! tracked { ($name: ident, $non_default_value: expr) => { @@ -569,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)); @@ -579,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")]); @@ -601,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] @@ -621,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] @@ -643,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); @@ -656,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); @@ -680,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)); @@ -694,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); @@ -704,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) => { @@ -715,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); @@ -736,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))); @@ -760,13 +753,13 @@ 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); tracked!(panic_abort_tests, true); tracked!(panic_in_drop, PanicStrategy::Abort); tracked!(pick_stable_methods_before_any_unstable, false); @@ -776,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"))); @@ -806,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 5e5596f13..519b8a7fc 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,23 +1,17 @@ +use info; 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; @@ -25,13 +19,10 @@ 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; use std::thread; -use tracing::info; /// Function pointer type that constructs a new CodegenBackend. pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>; @@ -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() }) }) } @@ -559,7 +555,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C // command line, then reuse the empty `base` Vec to hold the types that // will be found in crate attributes. // JUSTIFICATION: before wrapper fn is available - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] let mut base = session.opts.crate_types.clone(); if base.is_empty() { base.extend(attr_types); |