diff options
Diffstat (limited to 'compiler/rustc_interface/src')
| -rw-r--r-- | compiler/rustc_interface/src/callbacks.rs | 43 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/errors.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/interface.rs | 164 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/lib.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/passes.rs | 366 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/proc_macro_decls.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/queries.rs | 168 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/tests.rs | 143 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/util.rs | 147 |
9 files changed, 640 insertions, 399 deletions
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index bc6d7c20997..45b1aeb4a5c 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -10,8 +10,10 @@ //! origin crate when the `TyCtxt` is not present in TLS. use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; -use rustc_middle::dep_graph::TaskDepsRef; +use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef}; use rustc_middle::ty::tls; +use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug; +use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode}; use std::fmt; fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { @@ -59,10 +61,49 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> write!(f, ")") } +/// This is a callback from `rustc_query_system` as it cannot access the implicit state +/// in `rustc_middle` otherwise. +pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + write!(f, "{}", tcx.dep_kind_info(kind).name) + } else { + default_dep_kind_debug(kind, f) + } + }) +} + +/// This is a callback from `rustc_query_system` as it cannot access the implicit state +/// in `rustc_middle` otherwise. +pub fn dep_node_debug(node: DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}(", node.kind)?; + + tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = node.extract_def_id(tcx) { + write!(f, "{}", tcx.def_path_debug_str(def_id))?; + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(node) { + write!(f, "{s}")?; + } else { + write!(f, "{}", node.hash)?; + } + } else { + write!(f, "{}", node.hash)?; + } + Ok(()) + })?; + + write!(f, ")") +} + /// Sets up the callbacks in prior crates which we want to refer to the /// TyCtxt in. pub fn setup_callbacks() { rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + rustc_query_system::dep_graph::dep_node::DEP_KIND_DEBUG + .swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); + rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG + .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _)); } diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index 0eedee25026..a9ab2720d89 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -108,3 +108,7 @@ pub struct IgnoringExtraFilename; #[derive(Diagnostic)] #[diag(interface_ignoring_out_dir)] pub struct IgnoringOutDir; + +#[derive(Diagnostic)] +#[diag(interface_multiple_output_types_to_stdout)] +pub struct MultipleOutputTypesToStdout; diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index be7fa9378ca..1c330c064ab 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -3,20 +3,22 @@ use crate::util; use rustc_ast::token; use rustc_ast::{self as ast, LitKind, MetaItemKind}; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::defer; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::OnDrop; use rustc_errors::registry::Registry; use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_lint::LintStore; -use rustc_middle::ty; +use rustc_middle::util::Providers; +use rustc_middle::{bug, ty}; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; -use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames}; -use rustc_session::lint; +use rustc_query_system::query::print_query_stack; +use rustc_session::config::{self, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames}; use rustc_session::parse::{CrateConfig, ParseSess}; +use rustc_session::CompilerIO; use rustc_session::Session; -use rustc_session::{early_error, CompilerIO}; +use rustc_session::{lint, EarlyErrorHandler}; use rustc_span::source_map::{FileLoader, FileName}; use rustc_span::symbol::sym; use std::path::PathBuf; @@ -33,17 +35,16 @@ pub type Result<T> = result::Result<T, ErrorGuaranteed>; /// Created by passing [`Config`] to [`run_compiler`]. pub struct Compiler { pub(crate) sess: Lrc<Session>, - codegen_backend: Lrc<Box<dyn CodegenBackend>>, + codegen_backend: Lrc<dyn CodegenBackend>, pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>, - pub(crate) override_queries: - Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>, + pub(crate) override_queries: Option<fn(&Session, &mut Providers)>, } impl Compiler { pub fn session(&self) -> &Lrc<Session> { &self.sess } - pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> { + pub fn codegen_backend(&self) -> &Lrc<dyn CodegenBackend> { &self.codegen_backend } pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> { @@ -59,7 +60,10 @@ impl Compiler { } /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. -pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> { +pub fn parse_cfgspecs( + handler: &EarlyErrorHandler, + cfgspecs: Vec<String>, +) -> FxHashSet<(String, Option<String>)> { rustc_span::create_default_session_if_not_set_then(move |_| { let cfg = cfgspecs .into_iter() @@ -71,10 +75,10 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String macro_rules! error { ($reason: expr) => { - early_error( - ErrorOutputType::default(), - &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s), - ); + handler.early_error(format!( + concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), + s + )); }; } @@ -118,11 +122,11 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String } /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. -pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { +pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg { rustc_span::create_default_session_if_not_set_then(move |_| { - let mut cfg = CheckCfg::default(); + let mut check_cfg = CheckCfg::default(); - 'specs: for s in specs { + for s in specs { let sess = ParseSess::with_silent_emitter(Some(format!( "this error occurred on the command line: `--check-cfg={s}`" ))); @@ -130,46 +134,67 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { macro_rules! error { ($reason: expr) => { - early_error( - ErrorOutputType::default(), - &format!( - concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), - s - ), - ); + handler.early_error(format!( + concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), + s + )) }; } + let expected_error = || { + error!( + "expected `names(name1, name2, ... nameN)` or \ + `values(name, \"value1\", \"value2\", ... \"valueN\")`" + ) + }; + match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if let Some(args) = meta_item.meta_item_list() { if meta_item.has_name(sym::names) { - let names_valid = - cfg.names_valid.get_or_insert_with(|| FxHashSet::default()); + check_cfg.exhaustive_names = true; for arg in args { if arg.is_word() && arg.ident().is_some() { let ident = arg.ident().expect("multi-segment cfg key"); - names_valid.insert(ident.name.to_string()); + check_cfg + .expecteds + .entry(ident.name.to_string()) + .or_insert(ExpectedValues::Any); } else { error!("`names()` arguments must be simple identifiers"); } } - continue 'specs; } else if meta_item.has_name(sym::values) { if let Some((name, values)) = args.split_first() { if name.is_word() && name.ident().is_some() { let ident = name.ident().expect("multi-segment cfg key"); - let ident_values = cfg - .values_valid + let expected_values = check_cfg + .expecteds .entry(ident.name.to_string()) - .or_insert_with(|| FxHashSet::default()); + .and_modify(|expected_values| match expected_values { + ExpectedValues::Some(_) => {} + ExpectedValues::Any => { + // handle the case where names(...) was done + // before values by changing to a list + *expected_values = + ExpectedValues::Some(FxHashSet::default()); + } + }) + .or_insert_with(|| { + ExpectedValues::Some(FxHashSet::default()) + }); + + let ExpectedValues::Some(expected_values) = expected_values + else { + bug!("`expected_values` should be a list a values") + }; for val in values { if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) { - ident_values.insert(s.to_string()); + expected_values.insert(Some(s.to_string())); } else { error!( "`values()` arguments must be string literals" @@ -177,35 +202,40 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { } } - continue 'specs; + if values.is_empty() { + expected_values.insert(None); + } } else { error!( "`values()` first argument must be a simple identifier" ); } } else if args.is_empty() { - cfg.well_known_values = true; - continue 'specs; + check_cfg.exhaustive_values = true; + } else { + expected_error(); } + } else { + expected_error(); } + } else { + expected_error(); } } - Ok(..) => {} - Err(err) => err.cancel(), + Ok(..) => expected_error(), + Err(err) => { + err.cancel(); + expected_error(); + } }, - Err(errs) => drop(errs), + Err(errs) => { + drop(errs); + expected_error(); + } } - - error!( - "expected `names(name1, name2, ... nameN)` or \ - `values(name, \"value1\", \"value2\", ... \"valueN\")`" - ); } - if let Some(names_valid) = &mut cfg.names_valid { - names_valid.extend(cfg.values_valid.keys().cloned()); - } - cfg + check_cfg }) } @@ -220,7 +250,8 @@ pub struct Config { pub input: Input, pub output_dir: Option<PathBuf>, - pub output_file: Option<PathBuf>, + pub output_file: Option<OutFileName>, + pub ice_file: Option<PathBuf>, pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>, pub locale_resources: &'static [&'static str], @@ -240,8 +271,7 @@ pub struct Config { /// the list of queries. /// /// The second parameter is local providers and the third parameter is external providers. - pub override_queries: - Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>, + pub override_queries: Option<fn(&Session, &mut Providers)>, /// This is a callback from the driver that is called to create a codegen backend. pub make_codegen_backend: @@ -249,12 +279,22 @@ pub struct Config { /// Registry of diagnostics codes. pub registry: Registry, + + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub expanded_args: Vec<String>, } // 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 { trace!("run_compiler"); + + // Set parallel mode before thread pool creation, which will create `Lock`s. + rustc_data_structures::sync::set_dyn_thread_safe_mode(config.opts.unstable_opts.threads > 1); + util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.unstable_opts.threads, @@ -263,8 +303,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se let registry = &config.registry; + let handler = EarlyErrorHandler::new(config.opts.error_format); + let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let (mut sess, codegen_backend) = util::create_session( + &handler, config.opts, config.crate_cfg, config.crate_check_cfg, @@ -279,6 +322,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.lint_caps, config.make_codegen_backend, registry.clone(), + config.ice_file, + config.expanded_args, ); if let Some(parse_sess_created) = config.parse_sess_created { @@ -287,14 +332,14 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se let compiler = Compiler { sess: Lrc::new(sess), - codegen_backend: Lrc::new(codegen_backend), + codegen_backend: Lrc::from(codegen_backend), register_lints: config.register_lints, override_queries: config.override_queries, }; rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || { let r = { - let _sess_abort_error = OnDrop(|| { + let _sess_abort_error = defer(|| { compiler.sess.finish_diagnostics(registry); }); @@ -302,6 +347,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se }; let prof = compiler.sess.prof.clone(); + prof.generic_activity("drop_compiler").run(move || drop(compiler)); r }) @@ -309,7 +355,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se ) } -pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) { +pub fn try_print_query_stack( + handler: &Handler, + num_frames: Option<usize>, + file: Option<std::fs::File>, +) { eprintln!("query stack during panic:"); // Be careful relying on global state here: this code is called from @@ -317,7 +367,13 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) { // state if it was responsible for triggering the panic. let i = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { - QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames) + ty::print::with_no_queries!(print_query_stack( + QueryCtxt::new(icx.tcx), + icx.query, + handler, + num_frames, + file, + )) } else { 0 } diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 51bd8381e93..76131c1ad69 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -25,7 +25,7 @@ pub mod util; pub use callbacks::setup_callbacks; pub use interface::{run_compiler, Config}; -pub use passes::{DEFAULT_EXTERN_QUERY_PROVIDERS, DEFAULT_QUERY_PROVIDERS}; +pub use passes::DEFAULT_QUERY_PROVIDERS; pub use queries::Queries; #[cfg(test)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 0e4e20c7cd1..718dbaaafcc 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -8,24 +8,25 @@ use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; +use rustc_data_structures::sync::{Lrc, OnceLock, WorkerLocal}; use rustc_errors::PResult; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; +use rustc_feature::Features; use rustc_fs_util::try_canonicalize; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; +use rustc_middle::util::Providers; use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; -use rustc_passes::{self, hir_stats, layout_test}; +use rustc_passes::{self, abi_test, hir_stats, layout_test}; use rustc_plugin_impl as plugin; -use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::Resolver; -use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType}; +use rustc_session::code_stats::VTableSizeInfo; +use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::{MetadataLoader, Untracked}; use rustc_session::output::filename_for_input; use rustc_session::search_paths::PathKind; @@ -72,42 +73,16 @@ fn count_nodes(krate: &ast::Crate) -> usize { counter.count } -pub fn register_plugins<'a>( - sess: &'a Session, - metadata_loader: &'a dyn MetadataLoader, - register_lints: impl Fn(&Session, &mut LintStore), +pub(crate) fn create_lint_store( + sess: &Session, + metadata_loader: &dyn MetadataLoader, + register_lints: Option<impl Fn(&Session, &mut LintStore)>, pre_configured_attrs: &[ast::Attribute], - crate_name: Symbol, -) -> Result<LintStore> { - // these need to be set "early" so that expansion sees `quote` if enabled. - let features = rustc_expand::config::features(sess, pre_configured_attrs); - sess.init_features(features); - - let crate_types = util::collect_crate_types(sess, pre_configured_attrs); - sess.init_crate_types(crate_types); - - let stable_crate_id = StableCrateId::new( - crate_name, - sess.crate_types().contains(&CrateType::Executable), - sess.opts.cg.metadata.clone(), - ); - sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized"); - rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?; - - if sess.opts.incremental.is_some() { - sess.time("incr_comp_garbage_collect_session_directories", || { - if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { - warn!( - "Error while trying to garbage collect incremental \ - compilation cache directory: {}", - e - ); - } - }); - } - +) -> LintStore { let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints()); - register_lints(sess, &mut lint_store); + if let Some(register_lints) = register_lints { + register_lints(sess, &mut lint_store); + } let registrars = sess.time("plugin_loading", || { plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs) @@ -119,11 +94,12 @@ pub fn register_plugins<'a>( } }); - Ok(lint_store) + lint_store } fn pre_expansion_lint<'a>( sess: &Session, + features: &Features, lint_store: &LintStore, registered_tools: &RegisteredTools, check_node: impl EarlyCheckNode<'a>, @@ -133,6 +109,7 @@ fn pre_expansion_lint<'a>( || { rustc_lint::check_ast_node( sess, + features, true, lint_store, registered_tools, @@ -151,13 +128,14 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> { fn pre_expansion_lint( &self, sess: &Session, + features: &Features, registered_tools: &RegisteredTools, node_id: ast::NodeId, attrs: &[ast::Attribute], items: &[rustc_ast::ptr::P<ast::Item>], name: Symbol, ) { - pre_expansion_lint(sess, self.0, registered_tools, (node_id, attrs, items), name); + pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, attrs, items), name); } } @@ -173,10 +151,18 @@ fn configure_and_expand( ) -> ast::Crate { let tcx = resolver.tcx(); let sess = tcx.sess; + let features = tcx.features(); let lint_store = unerased_lint_store(tcx); let crate_name = tcx.crate_name(LOCAL_CRATE); let lint_check_node = (&krate, pre_configured_attrs); - pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), lint_check_node, crate_name); + pre_expansion_lint( + sess, + features, + lint_store, + tcx.registered_tools(()), + lint_check_node, + crate_name, + ); rustc_builtin_macros::register_builtin_macros(resolver); let num_standard_library_imports = sess.time("crate_injection", || { @@ -185,6 +171,7 @@ fn configure_and_expand( pre_configured_attrs, resolver, sess, + features, ) }); @@ -224,16 +211,15 @@ fn configure_and_expand( } // Create the config for macro expansion - let features = sess.features_untracked(); let recursion_limit = get_recursion_limit(pre_configured_attrs, sess); let cfg = rustc_expand::expand::ExpansionConfig { - features: Some(features), + crate_name: crate_name.to_string(), + features, recursion_limit, trace_mac: sess.opts.unstable_opts.trace_macros, should_test: sess.is_test_crate(), span_debug: sess.opts.unstable_opts.span_debug, proc_macro_backtrace: sess.opts.unstable_opts.proc_macro_backtrace, - ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; let lint_store = LintStoreExpandImpl(lint_store); @@ -267,14 +253,19 @@ fn configure_and_expand( }); sess.time("maybe_building_test_harness", || { - rustc_builtin_macros::test_harness::inject(&mut krate, sess, resolver) + rustc_builtin_macros::test_harness::inject(&mut krate, sess, features, resolver) }); let has_proc_macro_decls = sess.time("AST_validation", || { - rustc_ast_passes::ast_validation::check_crate(sess, &krate, resolver.lint_buffer()) + rustc_ast_passes::ast_validation::check_crate( + sess, + features, + &krate, + resolver.lint_buffer(), + ) }); - let crate_types = sess.crate_types(); + let crate_types = tcx.crate_types(); let is_executable_crate = crate_types.contains(&CrateType::Executable); let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); @@ -296,6 +287,7 @@ fn configure_and_expand( rustc_builtin_macros::proc_macro_harness::inject( &mut krate, sess, + features, resolver, is_proc_macro_crate, has_proc_macro_decls, @@ -326,7 +318,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { // Needs to go *after* expansion to be able to check the results of macro expansion. sess.time("complete_gated_feature_checking", || { - rustc_ast_passes::feature_gate::check_crate(&krate, sess); + rustc_ast_passes::feature_gate::check_crate(&krate, sess, tcx.features()); }); // Add all buffered lints from the `ParseSess` to the `Session`. @@ -355,6 +347,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let lint_store = unerased_lint_store(tcx); rustc_lint::check_ast_node( sess, + tcx.features(), false, lint_store, tcx.registered_tools(()), @@ -366,26 +359,31 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { // Returns all the paths that correspond to generated files. fn generated_output_paths( - sess: &Session, + tcx: TyCtxt<'_>, outputs: &OutputFilenames, exact_name: bool, crate_name: Symbol, ) -> Vec<PathBuf> { + let sess = tcx.sess; let mut out_filenames = Vec::new(); for output_type in sess.opts.output_types.keys() { - let file = outputs.path(*output_type); + let out_filename = outputs.path(*output_type); + let file = out_filename.as_path().to_path_buf(); match *output_type { // If the filename has been overridden using `-o`, it will not be modified // by appending `.rlib`, `.exe`, etc., so we can skip this transformation. OutputType::Exe if !exact_name => { - for crate_type in sess.crate_types().iter() { + for crate_type in tcx.crate_types().iter() { let p = filename_for_input(sess, *crate_type, crate_name, outputs); - out_filenames.push(p); + out_filenames.push(p.as_path().to_path_buf()); } } OutputType::DepInfo if sess.opts.unstable_opts.dep_info_omit_d_target => { // Don't add the dep-info output when omitting it from dep-info targets } + OutputType::DepInfo if out_filename.is_stdout() => { + // Don't add the dep-info output when it goes to stdout + } _ => { out_filenames.push(file); } @@ -452,7 +450,8 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { return; } - let deps_filename = outputs.path(OutputType::DepInfo); + let deps_output = outputs.path(OutputType::DepInfo); + let deps_filename = deps_output.as_path(); let result: io::Result<()> = try { // Build a list of files used to compile the output and @@ -487,6 +486,11 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P files.push(normalize_path(profile_sample.as_path().to_path_buf())); } + // Debugger visualizer files + for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) { + files.push(normalize_path(debugger_visualizer.path.clone().unwrap())); + } + if sess.binary_dep_depinfo() { if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend { if backend.contains('.') { @@ -510,33 +514,47 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P } } - let mut file = BufWriter::new(fs::File::create(&deps_filename)?); - for path in out_filenames { - writeln!(file, "{}: {}\n", path.display(), files.join(" "))?; - } + let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> { + for path in out_filenames { + writeln!(file, "{}: {}\n", path.display(), files.join(" "))?; + } - // Emit a fake target for each input file to the compilation. This - // prevents `make` from spitting out an error if a file is later - // deleted. For more info see #28735 - for path in files { - writeln!(file, "{path}:")?; - } + // Emit a fake target for each input file to the compilation. This + // prevents `make` from spitting out an error if a file is later + // deleted. For more info see #28735 + for path in files { + writeln!(file, "{path}:")?; + } - // Emit special comments with information about accessed environment variables. - let env_depinfo = sess.parse_sess.env_depinfo.borrow(); - if !env_depinfo.is_empty() { - let mut envs: Vec<_> = env_depinfo - .iter() - .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env))) - .collect(); - envs.sort_unstable(); - writeln!(file)?; - for (k, v) in envs { - write!(file, "# env-dep:{k}")?; - if let Some(v) = v { - write!(file, "={v}")?; - } + // Emit special comments with information about accessed environment variables. + let env_depinfo = sess.parse_sess.env_depinfo.borrow(); + if !env_depinfo.is_empty() { + let mut envs: Vec<_> = env_depinfo + .iter() + .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env))) + .collect(); + envs.sort_unstable(); writeln!(file)?; + for (k, v) in envs { + write!(file, "# env-dep:{k}")?; + if let Some(v) = v { + write!(file, "={v}")?; + } + writeln!(file)?; + } + } + + Ok(()) + }; + + match deps_output { + OutFileName::Stdout => { + let mut file = BufWriter::new(io::stdout()); + write_deps_to_file(&mut file)?; + } + OutFileName::Real(ref path) => { + let mut file = BufWriter::new(fs::File::create(path)?); + write_deps_to_file(&mut file)?; } } }; @@ -566,7 +584,7 @@ fn resolver_for_lowering<'tcx>( let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver); // Make sure we don't mutate the cstore from here on. - tcx.untracked().cstore.leak(); + tcx.untracked().cstore.freeze(); let ty::ResolverOutputs { global_ctxt: untracked_resolutions, @@ -588,7 +606,7 @@ fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> { let outputs = util::build_output_filenames(&krate.attrs, sess); let output_paths = - generated_output_paths(sess, &outputs, sess.io.output_file.is_some(), crate_name); + generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name); // Ensure the source file isn't accidentally overwritten during compilation. if let Some(ref input_path) = sess.io.input.opt_path() { @@ -657,20 +675,14 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { *providers }); -pub static DEFAULT_EXTERN_QUERY_PROVIDERS: LazyLock<ExternProviders> = LazyLock::new(|| { - let mut extern_providers = ExternProviders::default(); - rustc_metadata::provide_extern(&mut extern_providers); - rustc_codegen_ssa::provide_extern(&mut extern_providers); - extern_providers -}); - pub fn create_global_ctxt<'tcx>( compiler: &'tcx Compiler, + crate_types: Vec<CrateType>, + stable_crate_id: StableCrateId, lint_store: Lrc<LintStore>, dep_graph: DepGraph, untracked: Untracked, - queries: &'tcx OnceCell<TcxQueries<'tcx>>, - gcx_cell: &'tcx OnceCell<GlobalCtxt<'tcx>>, + gcx_cell: &'tcx OnceLock<GlobalCtxt<'tcx>>, arena: &'tcx WorkerLocal<Arena<'tcx>>, hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>, ) -> &'tcx GlobalCtxt<'tcx> { @@ -683,49 +695,50 @@ pub fn create_global_ctxt<'tcx>( let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); let codegen_backend = compiler.codegen_backend(); - let mut local_providers = *DEFAULT_QUERY_PROVIDERS; - codegen_backend.provide(&mut local_providers); - - let mut extern_providers = *DEFAULT_EXTERN_QUERY_PROVIDERS; - codegen_backend.provide_extern(&mut extern_providers); + let mut providers = *DEFAULT_QUERY_PROVIDERS; + codegen_backend.provide(&mut providers); if let Some(callback) = compiler.override_queries { - callback(sess, &mut local_providers, &mut extern_providers); + callback(sess, &mut providers); } - let queries = queries.get_or_init(|| { - TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache) - }); + let incremental = dep_graph.is_fully_enabled(); sess.time("setup_global_ctxt", || { gcx_cell.get_or_init(move || { TyCtxt::create_global_ctxt( sess, + crate_types, + stable_crate_id, lint_store, arena, hir_arena, untracked, dep_graph, - queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), - queries.as_dyn(), rustc_query_impl::query_callbacks(arena), + rustc_query_impl::query_system( + providers.queries, + providers.extern_queries, + query_result_on_disk_cache, + incremental, + ), + providers.hooks, ) }) }) } -/// Runs the resolution, type-checking, region checking and other -/// miscellaneous analysis passes on the crate. +/// Runs the type-checking, region checking and other miscellaneous analysis +/// passes on the crate. fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { rustc_passes::hir_id_validator::check_crate(tcx); let sess = tcx.sess; - let mut entry_point = None; sess.time("misc_checking_1", || { parallel!( { - entry_point = sess.time("looking_for_entry_point", || tcx.entry_fn(())); + sess.time("looking_for_entry_point", || tcx.ensure().entry_fn(())); sess.time("looking_for_derive_registrar", || { tcx.ensure().proc_macro_decls_static(()) @@ -761,27 +774,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // passes are timed inside typeck rustc_hir_analysis::check_crate(tcx)?; - sess.time("misc_checking_2", || { - parallel!( - { - sess.time("match_checking", || { - tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id)) - }); - }, - { - 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_liveness(def_id.to_def_id()); - }); - }); - } - ); - }); - sess.time("MIR_borrow_checking", || { tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); }); @@ -794,23 +786,27 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } tcx.ensure().has_ffi_unwind_calls(def_id); - if tcx.hir().body_const_context(def_id).is_some() { - tcx.ensure() - .mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(def_id)); + // If we need to codegen, ensure that we emit all errors from + // `mir_drops_elaborated_and_const_checked` now, to avoid discovering + // them later during codegen. + if tcx.sess.opts.output_types.should_codegen() + || tcx.hir().body_const_context(def_id).is_some() + { + tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); + tcx.ensure().unused_generic_params(ty::InstanceDef::Item(def_id.to_def_id())); } } }); - if tcx.sess.opts.unstable_opts.drop_tracking_mir { - tcx.hir().par_body_owners(|def_id| { - if let rustc_hir::def::DefKind::Generator = tcx.def_kind(def_id) { - tcx.ensure().mir_generator_witnesses(def_id); - tcx.ensure().check_generator_obligations(def_id); - } - }); - } + tcx.hir().par_body_owners(|def_id| { + if let rustc_hir::def::DefKind::Generator = tcx.def_kind(def_id) { + tcx.ensure().mir_generator_witnesses(def_id); + tcx.ensure().check_generator_obligations(def_id); + } + }); sess.time("layout_testing", || layout_test::test_layout(tcx)); + sess.time("abi_testing", || abi_test::test_abi(tcx)); // Avoid overwhelming user with errors if borrow checking failed. // I'm not sure how helpful this is, to be honest, but it avoids a @@ -836,10 +832,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { }, { sess.time("lint_checking", || { - rustc_lint::check_crate(tcx, || { - rustc_lint::BuiltinCombinedLateLintPass::new() - }); + rustc_lint::check_crate(tcx); }); + }, + { + tcx.ensure().clashing_extern_declarations(()); } ); }, @@ -854,9 +851,95 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // This check has to be run after all lints are done processing. We don't // define a lint filter, as all lint checks should have finished at this point. - sess.time("check_lint_expectations", || tcx.check_expectations(None)); + sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None)); }); + if sess.opts.unstable_opts.print_vtable_sizes { + let traits = tcx.traits(LOCAL_CRATE); + + for &tr in traits { + if !tcx.check_is_object_safe(tr) { + continue; + } + + let name = ty::print::with_no_trimmed_paths!(tcx.def_path_str(tr)); + + let mut first_dsa = true; + + // Number of vtable entries, if we didn't have upcasting + let mut entries_ignoring_upcasting = 0; + // Number of vtable entries needed solely for upcasting + let mut entries_for_upcasting = 0; + + let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr)); + + // A slightly edited version of the code in `rustc_trait_selection::traits::vtable::vtable_entries`, + // that works without self type and just counts number of entries. + // + // Note that this is technically wrong, for traits which have associated types in supertraits: + // + // trait A: AsRef<Self::T> + AsRef<()> { type T; } + // + // Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>` and + // `AsRef<()>` are the same trait, thus we assume that those are different, and potentially + // over-estimate how many vtable entries there are. + // + // Similarly this is wrong for traits that have methods with possibly-impossible bounds. + // For example: + // + // trait B<T> { fn f(&self) where T: Copy; } + // + // Here `dyn B<u8>` will have 4 entries, while `dyn B<String>` will only have 3. + // However, since we don't know `T`, we can't know if `T: Copy` holds or not, + // thus we lean on the bigger side and say it has 4 entries. + traits::vtable::prepare_vtable_segments(tcx, trait_ref, |segment| { + match segment { + traits::vtable::VtblSegment::MetadataDSA => { + // If this is the first dsa, it would be included either way, + // otherwise it's needed for upcasting + if std::mem::take(&mut first_dsa) { + entries_ignoring_upcasting += 3; + } else { + entries_for_upcasting += 3; + } + } + + traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { + // Lookup the shape of vtable for the trait. + let own_existential_entries = + tcx.own_existential_vtable_entries(trait_ref.def_id()); + + // The original code here ignores the method if its predicates are impossible. + // We can't really do that as, for example, all not trivial bounds on generic + // parameters are impossible (since we don't know the parameters...), + // see the comment above. + entries_ignoring_upcasting += own_existential_entries.len(); + + if emit_vptr { + entries_for_upcasting += 1; + } + } + } + + std::ops::ControlFlow::Continue::<std::convert::Infallible>(()) + }); + + sess.code_stats.record_vtable_size( + tr, + &name, + VTableSizeInfo { + trait_name: name.clone(), + entries: entries_ignoring_upcasting + entries_for_upcasting, + entries_ignoring_upcasting, + entries_for_upcasting, + upcasting_cost_percent: entries_for_upcasting as f64 + / entries_ignoring_upcasting as f64 + * 100., + }, + ) + } + } + Ok(()) } @@ -874,10 +957,9 @@ pub fn start_codegen<'tcx>( codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) }); - // Don't run these test assertions when not doing codegen. Compiletest tries to build + // Don't run this test assertions when not doing codegen. Compiletest tries to build // build-fail tests in check mode first and expects it to not give an error in that case. if tcx.sess.opts.output_types.should_codegen() { - rustc_incremental::assert_module_sources::assert_module_sources(tcx); rustc_symbol_mangling::test::report_symbol_names(tcx); } diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 1c58caa0353..2c8014d8b3a 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -1,6 +1,6 @@ use rustc_ast::attr; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 818f450a58c..fe253febfc7 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -1,27 +1,24 @@ use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation}; use crate::interface::{Compiler, Result}; -use crate::passes; +use crate::{passes, util}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{AppendOnlyIndexVec, Lrc, OnceCell, RwLock, WorkerLocal}; -use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, Lrc, OnceLock, WorkerLocal}; +use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; -use rustc_incremental::DepGraphFuture; -use rustc_lint::LintStore; +use rustc_incremental::setup_dep_graph; use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::{GlobalCtxt, TyCtxt}; -use rustc_query_impl::Queries as TcxQueries; -use rustc_session::config::{self, OutputFilenames, OutputType}; +use rustc_session::config::{self, CrateType, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; use rustc_session::{output::find_crate_name, Session}; use rustc_span::symbol::sym; -use rustc_span::Symbol; use std::any::Any; use std::cell::{RefCell, RefMut}; use std::sync::Arc; @@ -80,61 +77,43 @@ impl<T> Default for Query<T> { pub struct Queries<'tcx> { compiler: &'tcx Compiler, - gcx_cell: OnceCell<GlobalCtxt<'tcx>>, - queries: OnceCell<TcxQueries<'tcx>>, + gcx_cell: OnceLock<GlobalCtxt<'tcx>>, arena: WorkerLocal<Arena<'tcx>>, hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>, - dep_graph_future: Query<Option<DepGraphFuture>>, parse: Query<ast::Crate>, pre_configure: Query<(ast::Crate, ast::AttrVec)>, - crate_name: Query<Symbol>, - register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>, - dep_graph: Query<DepGraph>, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, - ongoing_codegen: Query<Box<dyn Any>>, } impl<'tcx> Queries<'tcx> { pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> { Queries { compiler, - gcx_cell: OnceCell::new(), - queries: OnceCell::new(), + gcx_cell: OnceLock::new(), arena: WorkerLocal::new(|_| Arena::default()), hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), - dep_graph_future: Default::default(), parse: Default::default(), pre_configure: Default::default(), - crate_name: Default::default(), - register_plugins: Default::default(), - dep_graph: Default::default(), gcx: Default::default(), - ongoing_codegen: Default::default(), } } fn session(&self) -> &Lrc<Session> { &self.compiler.sess } - fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> { + fn codegen_backend(&self) -> &Lrc<dyn CodegenBackend> { self.compiler.codegen_backend() } - fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> { - self.dep_graph_future.compute(|| { - let sess = self.session(); - Ok(sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess))) - }) - } - pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> { self.parse .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())) } + #[deprecated = "pre_configure may be made private in the future. If you need it please open an issue with your use case."] pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> { self.pre_configure.compute(|| { let mut krate = self.parse()?.steal(); @@ -152,69 +131,34 @@ impl<'tcx> Queries<'tcx> { }) } - pub fn register_plugins( - &self, - ) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> { - self.register_plugins.compute(|| { - let crate_name = *self.crate_name()?.borrow(); - let (krate, pre_configured_attrs) = self.pre_configure()?.steal(); - - let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; - let lint_store = passes::register_plugins( - self.session(), - &*self.codegen_backend().metadata_loader(), - self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), - &pre_configured_attrs, - crate_name, - )?; - - // Compute the dependency graph (in the background). We want to do - // this as early as possible, to give the DepGraph maximum time to - // load before dep_graph() is called, but it also can't happen - // until after rustc_incremental::prepare_session_directory() is - // called, which happens within passes::register_plugins(). - self.dep_graph_future().ok(); - - Ok((krate, pre_configured_attrs, Lrc::new(lint_store))) - }) - } - - fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> { - self.crate_name.compute(|| { - Ok({ - let pre_configure_result = self.pre_configure()?; - let (_, pre_configured_attrs) = &*pre_configure_result.borrow(); - // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. - find_crate_name(self.session(), pre_configured_attrs) - }) - }) - } - - fn dep_graph(&self) -> Result<QueryResult<'_, DepGraph>> { - self.dep_graph.compute(|| { - let sess = self.session(); - let future_opt = self.dep_graph_future()?.steal(); - let dep_graph = future_opt - .and_then(|future| { - let (prev_graph, prev_work_products) = - sess.time("blocked_on_dep_graph_loading", || future.open().open(sess)); - - rustc_incremental::build_dep_graph(sess, prev_graph, prev_work_products) - }) - .unwrap_or_else(DepGraph::new_disabled); - Ok(dep_graph) - }) - } - pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> { self.gcx.compute(|| { - let crate_name = *self.crate_name()?.borrow(); - let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal(); - let sess = self.session(); + #[allow(deprecated)] + let (krate, pre_configured_attrs) = self.pre_configure()?.steal(); - let cstore = RwLock::new(Box::new(CStore::new(sess)) as _); - let definitions = RwLock::new(Definitions::new(sess.local_stable_crate_id())); + // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. + let crate_name = find_crate_name(sess, &pre_configured_attrs); + let crate_types = util::collect_crate_types(sess, &pre_configured_attrs); + let stable_crate_id = StableCrateId::new( + crate_name, + crate_types.contains(&CrateType::Executable), + sess.opts.cg.metadata.clone(), + sess.cfg_version, + ); + let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?; + + let lint_store = Lrc::new(passes::create_lint_store( + sess, + &*self.codegen_backend().metadata_loader(), + self.compiler.register_lints.as_deref(), + &pre_configured_attrs, + )); + let cstore = FreezeLock::new(Box::new(CStore::new( + self.codegen_backend().metadata_loader(), + stable_crate_id, + )) as _); + let definitions = FreezeLock::new(Definitions::new(stable_crate_id)); let source_span = AppendOnlyIndexVec::new(); let _id = source_span.push(krate.spans.inner_span); debug_assert_eq!(_id, CRATE_DEF_ID); @@ -222,10 +166,11 @@ impl<'tcx> Queries<'tcx> { let qcx = passes::create_global_ctxt( self.compiler, + crate_types, + stable_crate_id, lint_store, - self.dep_graph()?.steal(), + dep_graph, untracked, - &self.queries, &self.gcx_cell, &self.arena, &self.hir_arena, @@ -236,33 +181,28 @@ impl<'tcx> Queries<'tcx> { feed.crate_name(crate_name); let feed = tcx.feed_unit_query(); - feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); - feed.metadata_loader( - tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())), + feed.features_query( + tcx.arena.alloc(rustc_expand::config::features(sess, &pre_configured_attrs)), ); - feed.features_query(tcx.sess.features_untracked()); + feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); }); Ok(qcx) }) } - pub fn ongoing_codegen(&'tcx self) -> Result<QueryResult<'_, Box<dyn Any>>> { - self.ongoing_codegen.compute(|| { - self.global_ctxt()?.enter(|tcx| { - tcx.analysis(()).ok(); - - // Don't do code generation if there were any errors - self.session().compile_status()?; + pub fn ongoing_codegen(&'tcx self) -> Result<Box<dyn Any>> { + self.global_ctxt()?.enter(|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(); + // 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); + // Hook for UI tests. + Self::check_for_rustc_errors_attr(tcx); - Ok(passes::start_codegen(&***self.codegen_backend(), tcx)) - }) + Ok(passes::start_codegen(&**self.codegen_backend(), tcx)) }) } @@ -300,18 +240,17 @@ impl<'tcx> Queries<'tcx> { } } - pub fn linker(&'tcx self) -> Result<Linker> { + pub fn linker(&'tcx self, ongoing_codegen: Box<dyn Any>) -> Result<Linker> { let sess = self.session().clone(); let codegen_backend = self.codegen_backend().clone(); let (crate_hash, prepare_outputs, dep_graph) = self.global_ctxt()?.enter(|tcx| { ( - if tcx.sess.needs_crate_hash() { Some(tcx.crate_hash(LOCAL_CRATE)) } else { None }, + if tcx.needs_crate_hash() { Some(tcx.crate_hash(LOCAL_CRATE)) } else { None }, tcx.output_filenames(()).clone(), tcx.dep_graph.clone(), ) }); - let ongoing_codegen = self.ongoing_codegen()?.steal(); Ok(Linker { sess, @@ -328,7 +267,7 @@ impl<'tcx> Queries<'tcx> { pub struct Linker { // compilation inputs sess: Lrc<Session>, - codegen_backend: Lrc<Box<dyn CodegenBackend>>, + codegen_backend: Lrc<dyn CodegenBackend>, // compilation outputs dep_graph: DepGraph, @@ -372,9 +311,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) + CodegenResults::serialize_rlink(sess, &rlink_file, &codegen_results) .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 10dfd32d418..7799af37008 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,10 +8,12 @@ use rustc_session::config::rustc_optgroups; use rustc_session::config::DebugInfo; use rustc_session::config::Input; use rustc_session::config::InstrumentXRay; +use rustc_session::config::LinkSelfContained; +use rustc_session::config::Polonius; use rustc_session::config::TraitSolver; use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; use rustc_session::config::{ - BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet, + BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel, }; use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; @@ -21,8 +23,8 @@ use rustc_session::config::{InstrumentCoverage, Passes}; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; -use rustc_session::CompilerIO; use rustc_session::{build_session, getopts, Session}; +use rustc_session::{CompilerIO, EarlyErrorHandler}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_span::FileName; @@ -36,15 +38,18 @@ use std::path::{Path, PathBuf}; type CfgSpecs = FxHashSet<(String, Option<String>)>; -fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options, CfgSpecs) { - let sessopts = build_session_options(&matches); - let cfg = parse_cfgspecs(matches.opt_strs("cfg")); +fn build_session_options_and_crate_config( + handler: &mut EarlyErrorHandler, + matches: getopts::Matches, +) -> (Options, CfgSpecs) { + let sessopts = build_session_options(handler, &matches); + let cfg = parse_cfgspecs(handler, matches.opt_strs("cfg")); (sessopts, cfg) } -fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { +fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, CfgSpecs) { let registry = registry::Registry::new(&[]); - let (sessopts, cfg) = build_session_options_and_crate_config(matches); + let (sessopts, cfg) = build_session_options_and_crate_config(handler, matches); let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let io = CompilerIO { input: Input::Str { name: FileName::Custom(String::new()), input: String::new() }, @@ -52,7 +57,20 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { output_file: None, temps_dir, }; - let sess = build_session(sessopts, io, None, registry, vec![], Default::default(), None, None); + let sess = build_session( + handler, + sessopts, + io, + None, + registry, + vec![], + Default::default(), + None, + None, + "", + None, + Default::default(), + ); (sess, cfg) } @@ -69,6 +87,7 @@ where is_private_dep: false, add_prelude: true, nounused_dep: false, + force: false, } } @@ -118,7 +137,8 @@ fn assert_non_crate_hash_different(x: &Options, y: &Options) { fn test_switch_implies_cfg_test() { rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["--test".to_string()]).unwrap(); - let (sess, cfg) = mk_session(matches); + let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); + let (sess, cfg) = mk_session(&mut handler, matches); let cfg = build_configuration(&sess, to_crate_config(cfg)); assert!(cfg.contains(&(sym::test, None))); }); @@ -129,7 +149,8 @@ fn test_switch_implies_cfg_test() { fn test_switch_implies_cfg_test_unless_cfg_test() { rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap(); - let (sess, cfg) = mk_session(matches); + let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); + let (sess, cfg) = mk_session(&mut handler, matches); let cfg = build_configuration(&sess, to_crate_config(cfg)); let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test); assert!(test_items.next().is_some()); @@ -141,20 +162,23 @@ fn test_switch_implies_cfg_test_unless_cfg_test() { fn test_can_print_warnings() { rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap(); - let (sess, _) = mk_session(matches); + let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); + let (sess, _) = mk_session(&mut handler, matches); assert!(!sess.diagnostic().can_emit_warnings()); }); rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap(); - let (sess, _) = mk_session(matches); + let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); + let (sess, _) = mk_session(&mut handler, matches); assert!(sess.diagnostic().can_emit_warnings()); }); rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap(); - let (sess, _) = mk_session(matches); + let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); + let (sess, _) = mk_session(&mut handler, matches); assert!(sess.diagnostic().can_emit_warnings()); }); } @@ -165,8 +189,14 @@ fn test_output_types_tracking_hash_different_paths() { let mut v2 = Options::default(); let mut v3 = Options::default(); - v1.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]); - v2.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]); + v1.output_types = OutputTypes::new(&[( + OutputType::Exe, + Some(OutFileName::Real(PathBuf::from("./some/thing"))), + )]); + v2.output_types = OutputTypes::new(&[( + OutputType::Exe, + Some(OutFileName::Real(PathBuf::from("/some/thing"))), + )]); v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); assert_non_crate_hash_different(&v1, &v2); @@ -180,13 +210,13 @@ fn test_output_types_tracking_hash_different_construction_order() { let mut v2 = Options::default(); v1.output_types = OutputTypes::new(&[ - (OutputType::Exe, Some(PathBuf::from("./some/thing"))), - (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))), + (OutputType::Exe, Some(OutFileName::Real(PathBuf::from("./some/thing")))), + (OutputType::Bitcode, Some(OutFileName::Real(PathBuf::from("./some/thing.bc")))), ]); v2.output_types = OutputTypes::new(&[ - (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))), - (OutputType::Exe, Some(PathBuf::from("./some/thing"))), + (OutputType::Bitcode, Some(OutFileName::Real(PathBuf::from("./some/thing.bc")))), + (OutputType::Exe, Some(OutFileName::Real(PathBuf::from("./some/thing")))), ]); assert_same_hash(&v1, &v2); @@ -294,35 +324,36 @@ fn test_search_paths_tracking_hash_different_order() { let mut v3 = Options::default(); let mut v4 = Options::default(); + let handler = EarlyErrorHandler::new(JSON); const JSON: ErrorOutputType = ErrorOutputType::Json { pretty: false, json_rendered: HumanReadableErrorType::Default(ColorConfig::Never), }; // Reference - v1.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON)); - v1.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON)); - v1.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON)); - v1.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON)); - v1.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON)); - - v2.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON)); - v2.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON)); - v2.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON)); - v2.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON)); - v2.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON)); - - v3.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON)); - v3.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON)); - v3.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON)); - v3.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON)); - v3.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON)); - - v4.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON)); - v4.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON)); - v4.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON)); - v4.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON)); - v4.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON)); + v1.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc")); + v1.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def")); + v1.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi")); + v1.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl")); + v1.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno")); + + v2.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc")); + v2.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi")); + v2.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def")); + v2.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl")); + v2.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno")); + + v3.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def")); + v3.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl")); + v3.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc")); + v3.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi")); + v3.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno")); + + v4.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno")); + v4.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc")); + v4.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def")); + v4.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi")); + v4.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl")); assert_same_hash(&v1, &v2); assert_same_hash(&v1, &v3); @@ -547,11 +578,12 @@ fn test_codegen_options_tracking_hash() { untracked!(ar, String::from("abc")); untracked!(codegen_units, Some(42)); untracked!(default_linker_libraries, true); + untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe"))); untracked!(extra_filename, String::from("extra-filename")); untracked!(incremental, Some(String::from("abc"))); // `link_arg` is omitted because it just forwards to `link_args`. untracked!(link_args, vec![String::from("abc"), String::from("def")]); - untracked!(link_self_contained, Some(true)); + untracked!(link_self_contained, LinkSelfContained::on()); untracked!(linker, Some(PathBuf::from("linker"))); untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc)); untracked!(no_stack_check, true); @@ -651,10 +683,8 @@ fn test_unstable_options_tracking_hash() { untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(deduplicate_diagnostics, false); untracked!(dep_tasks, true); - untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe"))); untracked!(dont_buffer_diagnostics, true); untracked!(dump_dep_graph, true); - untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string())); untracked!(dump_mir, Some(String::from("abc"))); untracked!(dump_mir_dataflow, true); untracked!(dump_mir_dir, String::from("abc")); @@ -674,10 +704,10 @@ fn test_unstable_options_tracking_hash() { untracked!(keep_hygiene_data, true); untracked!(link_native_libraries, false); untracked!(llvm_time_trace, true); - untracked!(ls, true); + untracked!(ls, vec!["all".to_owned()]); untracked!(macro_backtrace, true); untracked!(meta_stats, true); - untracked!(mir_pretty_relative_line_numbers, true); + untracked!(mir_include_spans, true); untracked!(nll_facts, true); untracked!(no_analysis, true); untracked!(no_leak_check, true); @@ -686,6 +716,7 @@ 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!(print_codegen_stats, true); untracked!(print_llvm_passes, true); untracked!(print_mono_items, Some(String::from("abc"))); untracked!(print_type_sizes, true); @@ -710,6 +741,7 @@ fn test_unstable_options_tracking_hash() { untracked!(unstable_options, true); untracked!(validate_mir, true); untracked!(verbose, true); + untracked!(write_long_types_to_disk, false); // tidy-alphabetical-end macro_rules! tracked { @@ -741,13 +773,12 @@ fn test_unstable_options_tracking_hash() { tracked!(debug_info_for_profiling, true); tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); - tracked!(drop_tracking, 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!(flatten_format_args, true); + tracked!(flatten_format_args, false); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); tracked!(function_sections, Some(false)); @@ -768,6 +799,7 @@ fn test_unstable_options_tracking_hash() { tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(mir_emit_retag, true); tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]); + tracked!(mir_keep_place_mention, true); tracked!(mir_opt_level, Some(4)); tracked!(move_size_limit, Some(4096)); tracked!(mutable_noalias, false); @@ -775,6 +807,7 @@ fn test_unstable_options_tracking_hash() { tracked!(no_jump_tables, true); tracked!(no_link, true); tracked!(no_profiler_runtime, true); + tracked!(no_trait_vptr, true); tracked!(no_unique_section_names, true); tracked!(oom, OomStrategy::Panic); tracked!(osx_rpath_install_name, true); @@ -782,7 +815,7 @@ fn test_unstable_options_tracking_hash() { tracked!(panic_abort_tests, true); tracked!(panic_in_drop, PanicStrategy::Abort); tracked!(plt, Some(true)); - tracked!(polonius, true); + tracked!(polonius, Polonius::Legacy); tracked!(precise_enum_drop_elaboration, false); tracked!(print_fuel, Some("abc".to_string())); tracked!(profile, true); @@ -794,12 +827,16 @@ fn test_unstable_options_tracking_hash() { tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); tracked!(report_delayed_bugs, true); tracked!(sanitizer, SanitizerSet::ADDRESS); + tracked!(sanitizer_cfi_canonical_jump_tables, None); + tracked!(sanitizer_cfi_generalize_pointers, Some(true)); + tracked!(sanitizer_cfi_normalize_integers, Some(true)); tracked!(sanitizer_memory_track_origins, 2); tracked!(sanitizer_recover, SanitizerSet::ADDRESS); tracked!(saturating_float_casts, Some(true)); tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc"))); + tracked!(split_lto_unit, Some(true)); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); tracked!(stack_protector, StackProtector::All); tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); @@ -808,7 +845,7 @@ fn test_unstable_options_tracking_hash() { tracked!(thir_unsafeck, true); tracked!(tiny_const_eval_limit, true); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); - tracked!(trait_solver, TraitSolver::Chalk); + tracked!(trait_solver, TraitSolver::NextCoherence); tracked!(translate_remapped_path_to_local_path, false); tracked!(trap_unreachable, Some(false)); tracked!(treat_err_as_bug, NonZeroUsize::new(1)); @@ -838,7 +875,9 @@ fn test_edition_parsing() { let options = Options::default(); assert!(options.edition == DEFAULT_EDITION); + let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); + let matches = optgroups().parse(&["--edition=2018".to_string()]).unwrap(); - let (sessopts, _) = build_session_options_and_crate_config(matches); + let (sessopts, _) = build_session_options_and_crate_config(&mut handler, matches); assert!(sessopts.edition == Edition::Edition2018) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 612903810d2..0634e44c562 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -4,21 +4,23 @@ 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::sync; use rustc_errors::registry::Registry; use rustc_parse::validate_attr; use rustc_session as session; use rustc_session::config::CheckCfg; use rustc_session::config::{self, CrateType}; -use rustc_session::config::{ErrorOutputType, OutputFilenames}; +use rustc_session::config::{OutFileName, OutputFilenames, OutputTypes}; use rustc_session::filesearch::sysroot_candidates; use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::parse::CrateConfig; -use rustc_session::{early_error, filesearch, output, Session}; +use rustc_session::{filesearch, output, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::source_map::FileLoader; use rustc_span::symbol::{sym, Symbol}; -use session::CompilerIO; +use session::{CompilerIO, EarlyErrorHandler}; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::mem; @@ -56,6 +58,7 @@ pub fn add_configuration( } pub fn create_session( + handler: &EarlyErrorHandler, sopts: config::Options, cfg: FxHashSet<(String, Option<String>)>, check_cfg: CheckCfg, @@ -67,11 +70,17 @@ pub fn create_session( Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, >, descriptions: Registry, + ice_file: Option<PathBuf>, + expanded_args: Vec<String>, ) -> (Session, Box<dyn CodegenBackend>) { let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { make_codegen_backend(&sopts) } else { - get_codegen_backend(&sopts.maybe_sysroot, sopts.unstable_opts.codegen_backend.as_deref()) + get_codegen_backend( + handler, + &sopts.maybe_sysroot, + sopts.unstable_opts.codegen_backend.as_deref(), + ) }; // target_override is documented to be called before init(), so this is okay @@ -86,7 +95,7 @@ pub fn create_session( ) { Ok(bundle) => bundle, Err(e) => { - early_error(sopts.error_format, &format!("failed to load fluent bundle: {e}")); + handler.early_error(format!("failed to load fluent bundle: {e}")); } }; @@ -94,6 +103,7 @@ pub fn create_session( locale_resources.push(codegen_backend.locale_resource()); let mut sess = session::build_session( + handler, sopts, io, bundle, @@ -102,6 +112,9 @@ pub fn create_session( lint_caps, file_loader, target_override, + rustc_version_str().unwrap_or("unknown"), + ice_file, + expanded_args, ); codegen_backend.init(&sess); @@ -126,10 +139,8 @@ fn get_stack_size() -> Option<usize> { env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE) } -#[cfg(not(parallel_compiler))] -pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( +pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>( edition: Edition, - _threads: usize, f: F, ) -> R { // The "thread pool" is a single spawned thread in the non-parallel @@ -160,15 +171,36 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( }) } +#[cfg(not(parallel_compiler))] +pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( + edition: Edition, + _threads: usize, + f: F, +) -> R { + run_in_thread_with_globals(edition, f) +} + #[cfg(parallel_compiler)] pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( edition: Edition, threads: usize, f: F, ) -> R { - use rustc_data_structures::jobserver; + use rustc_data_structures::{jobserver, sync::FromDyn}; use rustc_middle::ty::tls; - use rustc_query_impl::{deadlock, QueryContext, QueryCtxt}; + use rustc_query_impl::QueryCtxt; + use rustc_query_system::query::{deadlock, QueryContext}; + + let registry = sync::Registry::new(threads); + + if !sync::is_dyn_thread_safe() { + return run_in_thread_with_globals(edition, || { + // Register the thread for use with the `WorkerLocal` type. + registry.register(); + + f() + }); + } let mut builder = rayon::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) @@ -178,13 +210,13 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( .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) + let query_map = FromDyn::from(tls::with(|tcx| { + QueryCtxt::new(tcx) .try_collect_active_jobs() .expect("active jobs shouldn't be locked in deadlock handler") - }); + })); let registry = rayon_core::Registry::current(); - thread::spawn(move || deadlock(query_map, ®istry)); + thread::spawn(move || deadlock(query_map.into_inner(), ®istry)); }); if let Some(size) = get_stack_size() { builder = builder.stack_size(size); @@ -196,11 +228,17 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( // `Send` in the parallel compiler. rustc_span::create_session_globals_then(edition, || { rustc_span::with_session_globals(|session_globals| { + let session_globals = FromDyn::from(session_globals); builder .build_scoped( // Initialize each new worker thread when created. move |thread: rayon::ThreadBuilder| { - rustc_span::set_session_globals_then(session_globals, || thread.run()) + // Register the thread for use with the `WorkerLocal` type. + registry.register(); + + rustc_span::set_session_globals_then(session_globals.into_inner(), || { + thread.run() + }) }, // Run `f` on the first thread in the thread pool. move |pool: &rayon::ThreadPool| pool.install(f), @@ -210,16 +248,16 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( }) } -fn load_backend_from_dylib(path: &Path) -> MakeBackendFn { +fn load_backend_from_dylib(handler: &EarlyErrorHandler, path: &Path) -> MakeBackendFn { let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| { let err = format!("couldn't load codegen backend {path:?}: {err}"); - early_error(ErrorOutputType::default(), &err); + handler.early_error(err); }); let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") } .unwrap_or_else(|e| { let err = format!("couldn't load codegen backend: {e}"); - early_error(ErrorOutputType::default(), &err); + handler.early_error(err); }); // Intentionally leak the dynamic library. We can't ever unload it @@ -234,6 +272,7 @@ fn load_backend_from_dylib(path: &Path) -> MakeBackendFn { /// /// A name of `None` indicates that the default backend should be used. pub fn get_codegen_backend( + handler: &EarlyErrorHandler, maybe_sysroot: &Option<PathBuf>, backend_name: Option<&str>, ) -> Box<dyn CodegenBackend> { @@ -243,10 +282,12 @@ pub fn get_codegen_backend( let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm"); match backend_name.unwrap_or(default_codegen_backend) { - filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), + filename if filename.contains('.') => { + load_backend_from_dylib(handler, filename.as_ref()) + } #[cfg(feature = "llvm")] "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, - backend_name => get_codegen_sysroot(maybe_sysroot, backend_name), + backend_name => get_codegen_sysroot(handler, maybe_sysroot, backend_name), } }); @@ -278,7 +319,11 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> { }) } -fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn { +fn get_codegen_sysroot( + handler: &EarlyErrorHandler, + maybe_sysroot: &Option<PathBuf>, + backend_name: &str, +) -> MakeBackendFn { // For now we only allow this function to be called once as it'll dlopen a // few things, which seems to work best if we only do that once. In // general this assertion never trips due to the once guard in `get_codegen_backend`, @@ -313,7 +358,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M "failed to find a `codegen-backends` folder \ in the sysroot candidates:\n* {candidates}" ); - early_error(ErrorOutputType::default(), &err); + handler.early_error(err); }); info!("probing {} for a codegen backend", sysroot.display()); @@ -324,7 +369,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M sysroot.display(), e ); - early_error(ErrorOutputType::default(), &err); + handler.early_error(err); }); let mut file: Option<PathBuf> = None; @@ -352,16 +397,16 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M prev.display(), path.display() ); - early_error(ErrorOutputType::default(), &err); + handler.early_error(err); } file = Some(path.clone()); } match file { - Some(ref s) => load_backend_from_dylib(s), + Some(ref s) => load_backend_from_dylib(handler, s), None => { let err = format!("unsupported builtin codegen backend `{backend_name}`"); - early_error(ErrorOutputType::default(), &err); + handler.early_error(err); } } } @@ -492,7 +537,44 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C base } +fn multiple_output_types_to_stdout( + output_types: &OutputTypes, + single_output_file_is_stdout: bool, +) -> bool { + use std::io::IsTerminal; + if std::io::stdout().is_terminal() { + // If stdout is a tty, check if multiple text output types are + // specified by `--emit foo=- --emit bar=-` or `-o - --emit foo,bar` + let named_text_types = output_types + .iter() + .filter(|(f, o)| f.is_text_output() && *o == &Some(OutFileName::Stdout)) + .count(); + let unnamed_text_types = + output_types.iter().filter(|(f, o)| f.is_text_output() && o.is_none()).count(); + named_text_types > 1 || unnamed_text_types > 1 && single_output_file_is_stdout + } else { + // Otherwise, all the output types should be checked + let named_types = + output_types.values().filter(|o| *o == &Some(OutFileName::Stdout)).count(); + let unnamed_types = output_types.values().filter(|o| o.is_none()).count(); + named_types > 1 || unnamed_types > 1 && single_output_file_is_stdout + } +} + pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> OutputFilenames { + if multiple_output_types_to_stdout( + &sess.opts.output_types, + sess.io.output_file == Some(OutFileName::Stdout), + ) { + sess.emit_fatal(errors::MultipleOutputTypesToStdout); + } + + let crate_name = sess + .opts + .crate_name + .clone() + .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string())); + match sess.io.output_file { None => { // "-" as input file will cause the parser to read from stdin so we @@ -501,15 +583,11 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu let dirpath = sess.io.output_dir.clone().unwrap_or_default(); // If a crate name is present, we use it as the link name - let stem = sess - .opts - .crate_name - .clone() - .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string())) - .unwrap_or_else(|| sess.io.input.filestem().to_owned()); + let stem = crate_name.clone().unwrap_or_else(|| sess.io.input.filestem().to_owned()); OutputFilenames::new( dirpath, + crate_name.unwrap_or_else(|| stem.replace('-', "_")), stem, None, sess.io.temps_dir.clone(), @@ -534,9 +612,12 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu sess.emit_warning(errors::IgnoringOutDir); } + let out_filestem = + out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(); OutputFilenames::new( out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), - out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(), + crate_name.unwrap_or_else(|| out_filestem.replace('-', "_")), + out_filestem, ofile, sess.io.temps_dir.clone(), sess.opts.cg.extra_filename.clone(), |
