1
Fork 0

Auto merge of #117584 - bjorn3:eager_output_filenames, r=b-naber

Eagerly compute output_filenames

It can be computed before creating TyCtxt. Previously the query would also write the dep info file, which meant that the output filenames couldn't be accessed before macro expansion is done. The dep info file writing is now done as a separate non-query function. The old query was always executed again anyways due to depending on the HIR.

Also encode the output_filenames in rlink files to ensure `#![crate_name]` affects the linking stage when doing separate compiling and linking using `-Zno-link`/`-Zlink-only`.
This commit is contained in:
bors 2023-11-27 00:03:51 +00:00
commit ac9b308133
6 changed files with 46 additions and 53 deletions

View file

@ -216,6 +216,7 @@ impl CodegenResults {
sess: &Session, sess: &Session,
rlink_file: &Path, rlink_file: &Path,
codegen_results: &CodegenResults, codegen_results: &CodegenResults,
outputs: &OutputFilenames,
) -> Result<usize, io::Error> { ) -> Result<usize, io::Error> {
let mut encoder = FileEncoder::new(rlink_file)?; let mut encoder = FileEncoder::new(rlink_file)?;
encoder.emit_raw_bytes(RLINK_MAGIC); encoder.emit_raw_bytes(RLINK_MAGIC);
@ -224,10 +225,14 @@ impl CodegenResults {
encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()); encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes());
encoder.emit_str(sess.cfg_version); encoder.emit_str(sess.cfg_version);
Encodable::encode(codegen_results, &mut encoder); Encodable::encode(codegen_results, &mut encoder);
Encodable::encode(outputs, &mut encoder);
encoder.finish().map_err(|(_path, err)| err) encoder.finish().map_err(|(_path, err)| err)
} }
pub fn deserialize_rlink(sess: &Session, data: Vec<u8>) -> Result<Self, CodegenErrors> { pub fn deserialize_rlink(
sess: &Session,
data: Vec<u8>,
) -> Result<(Self, OutputFilenames), CodegenErrors> {
// The Decodable machinery is not used here because it panics if the input data is invalid // The Decodable machinery is not used here because it panics if the input data is invalid
// and because its internal representation may change. // and because its internal representation may change.
if !data.starts_with(RLINK_MAGIC) { if !data.starts_with(RLINK_MAGIC) {
@ -256,6 +261,7 @@ impl CodegenResults {
} }
let codegen_results = CodegenResults::decode(&mut decoder); let codegen_results = CodegenResults::decode(&mut decoder);
Ok(codegen_results) let outputs = OutputFilenames::decode(&mut decoder);
Ok((codegen_results, outputs))
} }
} }

View file

@ -401,9 +401,7 @@ fn run_compiler(
Ok(()) Ok(())
})?; })?;
// Make sure the `output_filenames` query is run for its side queries.write_dep_info()?;
// effects of writing the dep-info and reporting errors.
queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
} else { } else {
let krate = queries.parse()?; let krate = queries.parse()?;
pretty::print( pretty::print(
@ -431,9 +429,7 @@ fn run_compiler(
return early_exit(); return early_exit();
} }
// Make sure the `output_filenames` query is run for its side queries.write_dep_info()?;
// effects of writing the dep-info and reporting errors.
queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
if sess.opts.output_types.contains_key(&OutputType::DepInfo) if sess.opts.output_types.contains_key(&OutputType::DepInfo)
&& sess.opts.output_types.len() == 1 && sess.opts.output_types.len() == 1
@ -648,12 +644,11 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
fn process_rlink(sess: &Session, compiler: &interface::Compiler) { fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
assert!(sess.opts.unstable_opts.link_only); assert!(sess.opts.unstable_opts.link_only);
if let Input::File(file) = &sess.io.input { if let Input::File(file) = &sess.io.input {
let outputs = compiler.build_output_filenames(sess, &[]);
let rlink_data = fs::read(file).unwrap_or_else(|err| { let rlink_data = fs::read(file).unwrap_or_else(|err| {
sess.emit_fatal(RlinkUnableToRead { err }); sess.emit_fatal(RlinkUnableToRead { err });
}); });
let codegen_results = match CodegenResults::deserialize_rlink(sess, rlink_data) { let (codegen_results, outputs) = match CodegenResults::deserialize_rlink(sess, rlink_data) {
Ok(codegen) => codegen, Ok((codegen, outputs)) => (codegen, outputs),
Err(err) => { Err(err) => {
match err { match err {
CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType), CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType),

View file

@ -1,7 +1,7 @@
use crate::util; use crate::util;
use rustc_ast::token; use rustc_ast::token;
use rustc_ast::{self as ast, LitKind, MetaItemKind}; use rustc_ast::{LitKind, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::defer; use rustc_data_structures::defer;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -15,9 +15,7 @@ use rustc_middle::{bug, ty};
use rustc_parse::maybe_new_parser_from_source_str; use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt; use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack; use rustc_query_system::query::print_query_stack;
use rustc_session::config::{ use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName};
self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames,
};
use rustc_session::filesearch::sysroot_candidates; use rustc_session::filesearch::sysroot_candidates;
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_session::{lint, CompilerIO, EarlyErrorHandler, Session}; use rustc_session::{lint, CompilerIO, EarlyErrorHandler, Session};
@ -43,16 +41,6 @@ pub struct Compiler {
pub(crate) override_queries: Option<fn(&Session, &mut Providers)>, pub(crate) override_queries: Option<fn(&Session, &mut Providers)>,
} }
impl Compiler {
pub fn build_output_filenames(
&self,
sess: &Session,
attrs: &[ast::Attribute],
) -> OutputFilenames {
util::build_output_filenames(attrs, sess)
}
}
/// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg { pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg {
cfgs.into_iter() cfgs.into_iter()

View file

@ -39,7 +39,7 @@ use std::any::Any;
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{self, BufWriter, Write}; use std::io::{self, BufWriter, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::{Arc, LazyLock}; use std::sync::LazyLock;
use std::{env, fs, iter}; use std::{env, fs, iter};
pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> { pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
@ -553,13 +553,17 @@ fn resolver_for_lowering<'tcx>(
tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, Lrc::new(krate)))) tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, Lrc::new(krate))))
} }
fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> { pub(crate) fn write_dep_info(tcx: TyCtxt<'_>) {
// Make sure name resolution and macro expansion is run for
// the side-effect of providing a complete set of all
// accessed files and env vars.
let _ = tcx.resolver_for_lowering(());
let sess = tcx.sess; let sess = tcx.sess;
let _timer = sess.timer("prepare_outputs"); let _timer = sess.timer("write_dep_info");
let (_, krate) = &*tcx.resolver_for_lowering(()).borrow();
let crate_name = tcx.crate_name(LOCAL_CRATE); let crate_name = tcx.crate_name(LOCAL_CRATE);
let outputs = util::build_output_filenames(&krate.attrs, sess); let outputs = tcx.output_filenames(());
let output_paths = let output_paths =
generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name); generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name);
@ -596,15 +600,12 @@ fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> {
} }
} }
} }
outputs.into()
} }
pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
let providers = &mut Providers::default(); let providers = &mut Providers::default();
providers.analysis = analysis; providers.analysis = analysis;
providers.hir_crate = rustc_ast_lowering::lower_to_hir; providers.hir_crate = rustc_ast_lowering::lower_to_hir;
providers.output_filenames = output_filenames;
providers.resolver_for_lowering = resolver_for_lowering; providers.resolver_for_lowering = resolver_for_lowering;
providers.early_lint_checks = early_lint_checks; providers.early_lint_checks = early_lint_checks;
proc_macro_decls::provide(providers); proc_macro_decls::provide(providers);

View file

@ -85,7 +85,6 @@ pub struct Queries<'tcx> {
hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>, hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>,
parse: Query<ast::Crate>, parse: Query<ast::Crate>,
pre_configure: Query<(ast::Crate, ast::AttrVec)>,
// This just points to what's in `gcx_cell`. // This just points to what's in `gcx_cell`.
gcx: Query<&'tcx GlobalCtxt<'tcx>>, gcx: Query<&'tcx GlobalCtxt<'tcx>>,
} }
@ -98,7 +97,6 @@ impl<'tcx> Queries<'tcx> {
arena: WorkerLocal::new(|_| Arena::default()), arena: WorkerLocal::new(|_| Arena::default()),
hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
parse: Default::default(), parse: Default::default(),
pre_configure: Default::default(),
gcx: Default::default(), gcx: Default::default(),
} }
} }
@ -113,12 +111,12 @@ impl<'tcx> Queries<'tcx> {
}) })
} }
#[deprecated = "pre_configure may be made private in the future. If you need it please open an issue with your use case."] pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> { self.gcx.compute(|| {
self.pre_configure.compute(|| { let sess = &self.compiler.sess;
let mut krate = self.parse()?.steal(); let mut krate = self.parse()?.steal();
let sess = &self.compiler.sess;
rustc_builtin_macros::cmdline_attrs::inject( rustc_builtin_macros::cmdline_attrs::inject(
&mut krate, &mut krate,
&sess.parse_sess, &sess.parse_sess,
@ -127,15 +125,6 @@ impl<'tcx> Queries<'tcx> {
let pre_configured_attrs = let pre_configured_attrs =
rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
Ok((krate, pre_configured_attrs))
})
}
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
self.gcx.compute(|| {
let sess = &self.compiler.sess;
#[allow(deprecated)]
let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
// parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. // 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_name = find_crate_name(sess, &pre_configured_attrs);
@ -146,6 +135,7 @@ impl<'tcx> Queries<'tcx> {
sess.opts.cg.metadata.clone(), sess.opts.cg.metadata.clone(),
sess.cfg_version, sess.cfg_version,
); );
let outputs = util::build_output_filenames(&pre_configured_attrs, sess);
let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?; let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?;
let cstore = FreezeLock::new(Box::new(CStore::new( let cstore = FreezeLock::new(Box::new(CStore::new(
@ -180,11 +170,19 @@ impl<'tcx> Queries<'tcx> {
crate_name, crate_name,
))); )));
feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
feed.output_filenames(Arc::new(outputs));
}); });
Ok(qcx) Ok(qcx)
}) })
} }
pub fn write_dep_info(&'tcx self) -> Result<()> {
self.global_ctxt()?.enter(|tcx| {
passes::write_dep_info(tcx);
});
Ok(())
}
/// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
/// to write UI tests that actually test that compilation succeeds without reporting /// to write UI tests that actually test that compilation succeeds without reporting
/// an error. /// an error.
@ -284,7 +282,12 @@ impl Linker {
if sess.opts.unstable_opts.no_link { if sess.opts.unstable_opts.no_link {
let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT); let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT);
CodegenResults::serialize_rlink(sess, &rlink_file, &codegen_results) CodegenResults::serialize_rlink(
sess,
&rlink_file,
&codegen_results,
&*self.output_filenames,
)
.map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?;
return Ok(()); return Ok(());
} }

View file

@ -580,7 +580,7 @@ pub enum ResolveDocLinks {
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
/// dependency tracking for command-line arguments. Also only hash keys, since tracking /// dependency tracking for command-line arguments. Also only hash keys, since tracking
/// should only depend on the output types, not the paths they're written to. /// should only depend on the output types, not the paths they're written to.
#[derive(Clone, Debug, Hash, HashStable_Generic)] #[derive(Clone, Debug, Hash, HashStable_Generic, Encodable, Decodable)]
pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>); pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>);
impl OutputTypes { impl OutputTypes {
@ -818,7 +818,7 @@ impl Input {
} }
} }
#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq)] #[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq, Encodable, Decodable)]
pub enum OutFileName { pub enum OutFileName {
Real(PathBuf), Real(PathBuf),
Stdout, Stdout,
@ -890,7 +890,7 @@ impl OutFileName {
} }
} }
#[derive(Clone, Hash, Debug, HashStable_Generic)] #[derive(Clone, Hash, Debug, HashStable_Generic, Encodable, Decodable)]
pub struct OutputFilenames { pub struct OutputFilenames {
pub out_directory: PathBuf, pub out_directory: PathBuf,
/// Crate name. Never contains '-'. /// Crate name. Never contains '-'.