Auto merge of #86489 - cjgillot:lower, r=petrochenkov

Simplify early compilation interface

* separate resolver creation and AST configuration.
* bundle lowering with global_ctxt creation.
This commit is contained in:
bors 2021-06-30 22:20:36 +00:00
commit e6f450bcfe
7 changed files with 106 additions and 173 deletions

View File

@ -296,7 +296,7 @@ pub fn lower_crate<'a, 'hir>(
resolver: &'a mut dyn ResolverAstLowering,
nt_to_tokenstream: NtToTokenstream,
arena: &'hir Arena<'hir>,
) -> hir::Crate<'hir> {
) -> &'hir hir::Crate<'hir> {
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
LoweringContext {
@ -403,7 +403,7 @@ enum AnonymousLifetimeMode {
}
impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_crate(mut self, c: &Crate) -> hir::Crate<'hir> {
fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
/// Full-crate AST visitor that inserts into a fresh
/// `LoweringContext` any information that may be
/// needed from arbitrary locations in the crate,
@ -530,7 +530,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
hir::Crate {
let krate = hir::Crate {
item: module,
exported_macros: self.arena.alloc_from_iter(self.exported_macros),
non_exported_macro_attrs: self.arena.alloc_from_iter(self.non_exported_macro_attrs),
@ -545,7 +545,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
proc_macros,
trait_map,
attrs: self.attrs,
}
};
self.arena.alloc(krate)
}
fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {

View File

@ -46,7 +46,6 @@ use std::ffi::OsString;
use std::fs;
use std::io::{self, Read, Write};
use std::lazy::SyncLazy;
use std::mem;
use std::panic::{self, catch_unwind};
use std::path::PathBuf;
use std::process::{self, Command, Stdio};
@ -316,12 +315,12 @@ fn run_compiler(
if let Some(ppm) = &sess.opts.pretty {
if ppm.needs_ast_map() {
let expanded_crate = queries.expansion()?.peek().0.clone();
queries.global_ctxt()?.peek_mut().enter(|tcx| {
let expanded_crate = queries.expansion()?.take().0;
pretty::print_after_hir_lowering(
tcx,
compiler.input(),
&expanded_crate,
&*expanded_crate,
*ppm,
compiler.output_file().as_ref().map(|p| &**p),
);
@ -377,12 +376,6 @@ fn run_compiler(
queries.global_ctxt()?;
// Drop AST after creating GlobalCtxt to free memory
{
let _timer = sess.prof.generic_activity("drop_ast");
mem::drop(queries.expansion()?.take());
}
if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json {
return early_exit();
}

View File

@ -21,8 +21,8 @@ pub enum LoadResult<T> {
Error { message: String },
}
impl LoadResult<(SerializedDepGraph, WorkProductMap)> {
pub fn open(self, sess: &Session) -> (SerializedDepGraph, WorkProductMap) {
impl<T: Default> LoadResult<T> {
pub fn open(self, sess: &Session) -> T {
match self {
LoadResult::Error { message } => {
sess.warn(&message);
@ -74,11 +74,14 @@ pub enum MaybeAsync<T> {
Sync(T),
Async(std::thread::JoinHandle<T>),
}
impl<T> MaybeAsync<T> {
pub fn open(self) -> std::thread::Result<T> {
impl<T> MaybeAsync<LoadResult<T>> {
pub fn open(self) -> LoadResult<T> {
match self {
MaybeAsync::Sync(result) => Ok(result),
MaybeAsync::Async(handle) => handle.join(),
MaybeAsync::Sync(result) => result,
MaybeAsync::Async(handle) => handle.join().unwrap_or_else(|e| LoadResult::Error {
message: format!("could not decode incremental cache: {:?}", e),
}),
}
}
}

View File

@ -7,7 +7,6 @@ use rustc_ast::{self as ast, visit};
use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::parallel;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{ErrorReported, PResult};
@ -101,7 +100,7 @@ mod boxed_resolver {
}
// Note: Drop order is important to prevent dangling references. Resolver must be dropped first,
// then resolver_arenas and finally session.
// then resolver_arenas and session.
impl Drop for BoxedResolverInner {
fn drop(&mut self) {
self.resolver.take();
@ -110,13 +109,10 @@ mod boxed_resolver {
}
impl BoxedResolver {
pub(super) fn new<F>(session: Lrc<Session>, make_resolver: F) -> Result<(ast::Crate, Self)>
where
F: for<'a> FnOnce(
&'a Session,
&'a ResolverArenas<'a>,
) -> Result<(ast::Crate, Resolver<'a>)>,
{
pub(super) fn new(
session: Lrc<Session>,
make_resolver: impl for<'a> FnOnce(&'a Session, &'a ResolverArenas<'a>) -> Resolver<'a>,
) -> BoxedResolver {
let mut boxed_resolver = Box::new(BoxedResolverInner {
session,
resolver_arenas: Some(Resolver::arenas()),
@ -127,14 +123,14 @@ mod boxed_resolver {
// returns a resolver with the same lifetime as the arena. We ensure that the arena
// outlives the resolver in the drop impl and elsewhere so these transmutes are sound.
unsafe {
let (crate_, resolver) = make_resolver(
let resolver = make_resolver(
std::mem::transmute::<&Session, &Session>(&boxed_resolver.session),
std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>(
boxed_resolver.resolver_arenas.as_ref().unwrap(),
),
)?;
);
boxed_resolver.resolver = Some(resolver);
Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver))))
BoxedResolver(Pin::new_unchecked(boxed_resolver))
}
}
@ -165,35 +161,15 @@ mod boxed_resolver {
}
}
/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
/// syntax expansion, secondary `cfg` expansion, synthesis of a test
/// harness if one is to be provided, injection of a dependency on the
/// standard library and prelude, and name resolution.
///
/// Returns [`None`] if we're aborting after handling -W help.
pub fn configure_and_expand(
pub fn create_resolver(
sess: Lrc<Session>,
lint_store: Lrc<LintStore>,
metadata_loader: Box<MetadataLoaderDyn>,
krate: ast::Crate,
krate: &ast::Crate,
crate_name: &str,
) -> Result<(ast::Crate, BoxedResolver)> {
tracing::trace!("configure_and_expand");
// Currently, we ignore the name resolution data structures for the purposes of dependency
// tracking. Instead we will run name resolution and include its output in the hash of each
// item, much like we do for macro expansion. In other words, the hash reflects not just
// its contents but the results of name resolution on those contents. Hopefully we'll push
// this back at some point.
let crate_name = crate_name.to_string();
) -> BoxedResolver {
tracing::trace!("create_resolver");
BoxedResolver::new(sess, move |sess, resolver_arenas| {
configure_and_expand_inner(
sess,
&lint_store,
krate,
&crate_name,
&resolver_arenas,
metadata_loader,
)
Resolver::new(sess, &krate, &crate_name, metadata_loader, &resolver_arenas)
})
}
@ -278,28 +254,24 @@ fn pre_expansion_lint(
});
}
fn configure_and_expand_inner<'a>(
sess: &'a Session,
/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
/// syntax expansion, secondary `cfg` expansion, synthesis of a test
/// harness if one is to be provided, injection of a dependency on the
/// standard library and prelude, and name resolution.
pub fn configure_and_expand(
sess: &Session,
lint_store: &LintStore,
mut krate: ast::Crate,
crate_name: &str,
resolver_arenas: &'a ResolverArenas<'a>,
metadata_loader: Box<MetadataLoaderDyn>,
) -> Result<(ast::Crate, Resolver<'a>)> {
tracing::trace!("configure_and_expand_inner");
resolver: &mut Resolver<'_>,
) -> Result<ast::Crate> {
tracing::trace!("configure_and_expand");
pre_expansion_lint(sess, lint_store, &krate, crate_name);
let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas);
rustc_builtin_macros::register_builtin_macros(&mut resolver);
rustc_builtin_macros::register_builtin_macros(resolver);
krate = sess.time("crate_injection", || {
let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
rustc_builtin_macros::standard_library_imports::inject(
krate,
&mut resolver,
&sess,
alt_std_name,
)
rustc_builtin_macros::standard_library_imports::inject(krate, resolver, &sess, alt_std_name)
});
util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer());
@ -354,7 +326,7 @@ fn configure_and_expand_inner<'a>(
pre_expansion_lint(sess, lint_store, &krate, &ident.name.as_str());
(krate.attrs, krate.items)
};
let mut ecx = ExtCtxt::new(&sess, cfg, &mut resolver, Some(&extern_mod_loaded));
let mut ecx = ExtCtxt::new(&sess, cfg, resolver, Some(&extern_mod_loaded));
// Expand macros now!
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
@ -396,16 +368,16 @@ fn configure_and_expand_inner<'a>(
})?;
sess.time("maybe_building_test_harness", || {
rustc_builtin_macros::test_harness::inject(&sess, &mut resolver, &mut krate)
rustc_builtin_macros::test_harness::inject(&sess, resolver, &mut krate)
});
if let Some(PpMode::Source(PpSourceMode::EveryBodyLoops)) = sess.opts.pretty {
tracing::debug!("replacing bodies with loop {{}}");
util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
util::ReplaceBodyWithLoop::new(resolver).visit_crate(&mut krate);
}
let has_proc_macro_decls = sess.time("AST_validation", || {
rustc_ast_passes::ast_validation::check_crate(sess, &krate, &mut resolver.lint_buffer())
rustc_ast_passes::ast_validation::check_crate(sess, &krate, resolver.lint_buffer())
});
let crate_types = sess.crate_types();
@ -431,7 +403,7 @@ fn configure_and_expand_inner<'a>(
let is_test_crate = sess.opts.test;
rustc_builtin_macros::proc_macro_harness::inject(
&sess,
&mut resolver,
resolver,
krate,
is_proc_macro_crate,
has_proc_macro_decls,
@ -471,26 +443,20 @@ fn configure_and_expand_inner<'a>(
}
});
Ok((krate, resolver))
Ok(krate)
}
pub fn lower_to_hir<'res, 'tcx>(
sess: &'tcx Session,
lint_store: &LintStore,
resolver: &'res mut Resolver<'_>,
dep_graph: &'res DepGraph,
krate: &'res ast::Crate,
krate: Rc<ast::Crate>,
arena: &'tcx rustc_ast_lowering::Arena<'tcx>,
) -> Crate<'tcx> {
// We're constructing the HIR here; we don't care what we will
// read, since we haven't even constructed the *input* to
// incr. comp. yet.
dep_graph.assert_ignored();
) -> &'tcx Crate<'tcx> {
// Lower AST to HIR.
let hir_crate = rustc_ast_lowering::lower_crate(
sess,
&krate,
&*krate,
resolver,
rustc_parse::nt_to_tokenstream,
arena,
@ -511,6 +477,9 @@ pub fn lower_to_hir<'res, 'tcx>(
)
});
// Drop AST to free memory
sess.time("drop_ast", || std::mem::drop(krate));
// Discard hygiene data, which isn't required after lowering to HIR.
if !sess.opts.debugging_opts.keep_hygiene_data {
rustc_span::hygiene::clear_syntax_context_map();
@ -603,7 +572,7 @@ fn escape_dep_env(symbol: Symbol) -> String {
fn write_out_deps(
sess: &Session,
boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
boxed_resolver: &RefCell<BoxedResolver>,
outputs: &OutputFilenames,
out_filenames: &[PathBuf],
) {
@ -630,7 +599,7 @@ fn write_out_deps(
}
if sess.binary_dep_depinfo() {
boxed_resolver.borrow().borrow_mut().access(|resolver| {
boxed_resolver.borrow_mut().access(|resolver| {
for cnum in resolver.cstore().crates_untracked() {
let source = resolver.cstore().crate_source_untracked(cnum);
if let Some((path, _)) = source.dylib {
@ -699,7 +668,7 @@ pub fn prepare_outputs(
sess: &Session,
compiler: &Compiler,
krate: &ast::Crate,
boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
boxed_resolver: &RefCell<BoxedResolver>,
crate_name: &str,
) -> Result<OutputFilenames> {
let _timer = sess.timer("prepare_outputs");
@ -803,16 +772,26 @@ impl<'tcx> QueryContext<'tcx> {
pub fn create_global_ctxt<'tcx>(
compiler: &'tcx Compiler,
lint_store: Lrc<LintStore>,
krate: &'tcx Crate<'tcx>,
krate: Rc<ast::Crate>,
dep_graph: DepGraph,
resolver_outputs: ResolverOutputs,
resolver: Rc<RefCell<BoxedResolver>>,
outputs: OutputFilenames,
crate_name: &str,
queries: &'tcx OnceCell<TcxQueries<'tcx>>,
global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>,
arena: &'tcx WorkerLocal<Arena<'tcx>>,
hir_arena: &'tcx WorkerLocal<rustc_ast_lowering::Arena<'tcx>>,
) -> QueryContext<'tcx> {
// We're constructing the HIR here; we don't care what we will
// read, since we haven't even constructed the *input* to
// incr. comp. yet.
dep_graph.assert_ignored();
let sess = &compiler.session();
let krate = resolver
.borrow_mut()
.access(|resolver| lower_to_hir(sess, &lint_store, resolver, krate, hir_arena));
let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver);
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
@ -831,7 +810,7 @@ pub fn create_global_ctxt<'tcx>(
let queries = queries.get_or_init(|| TcxQueries::new(local_providers, extern_providers));
let gcx = sess.time("setup_global_ctxt", || {
global_ctxt.get_or_init(|| {
global_ctxt.get_or_init(move || {
TyCtxt::create_global_ctxt(
sess,
lint_store,

View File

@ -3,17 +3,15 @@ use crate::passes::{self, BoxedResolver, QueryContext};
use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_errors::ErrorReported;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::Crate;
use rustc_incremental::DepGraphFuture;
use rustc_lint::LintStore;
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_middle::ty::{GlobalCtxt, TyCtxt};
use rustc_query_impl::Queries as TcxQueries;
use rustc_serialize::json;
use rustc_session::config::{self, OutputFilenames, OutputType};
@ -81,9 +79,8 @@ pub struct Queries<'tcx> {
parse: Query<ast::Crate>,
crate_name: Query<String>,
register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
expansion: Query<(Rc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>,
dep_graph: Query<DepGraph>,
lower_to_hir: Query<(&'tcx Crate<'tcx>, Steal<ResolverOutputs>)>,
prepare_outputs: Query<OutputFilenames>,
global_ctxt: Query<QueryContext<'tcx>>,
ongoing_codegen: Query<Box<dyn Any>>,
@ -103,7 +100,6 @@ impl<'tcx> Queries<'tcx> {
register_plugins: Default::default(),
expansion: Default::default(),
dep_graph: Default::default(),
lower_to_hir: Default::default(),
prepare_outputs: Default::default(),
global_ctxt: Default::default(),
ongoing_codegen: Default::default(),
@ -117,13 +113,10 @@ impl<'tcx> Queries<'tcx> {
&self.compiler.codegen_backend()
}
pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
self.dep_graph_future.compute(|| {
Ok(self
.session()
.opts
.build_dep_graph()
.then(|| rustc_incremental::load_dep_graph(self.session())))
let sess = self.session();
Ok(sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess)))
})
}
@ -174,83 +167,51 @@ impl<'tcx> Queries<'tcx> {
pub fn expansion(
&self,
) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
) -> Result<&Query<(Rc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> {
tracing::trace!("expansion");
self.expansion.compute(|| {
let crate_name = self.crate_name()?.peek().clone();
let (krate, lint_store) = self.register_plugins()?.take();
let _timer = self.session().timer("configure_and_expand");
passes::configure_and_expand(
self.session().clone(),
lint_store.clone(),
let sess = self.session();
let mut resolver = passes::create_resolver(
sess.clone(),
self.codegen_backend().metadata_loader(),
krate,
&crate_name,
)
.map(|(krate, resolver)| {
(krate, Steal::new(Rc::new(RefCell::new(resolver))), lint_store)
})
})
}
pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
self.dep_graph.compute(|| {
Ok(match self.dep_graph_future()?.take() {
None => DepGraph::new_disabled(),
Some(future) => {
let (prev_graph, prev_work_products) =
self.session().time("blocked_on_dep_graph_loading", || {
future
.open()
.unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
message: format!("could not decode incremental cache: {:?}", e),
})
.open(self.session())
});
rustc_incremental::build_dep_graph(
self.session(),
prev_graph,
prev_work_products,
)
.unwrap_or_else(DepGraph::new_disabled)
}
})
})
}
pub fn lower_to_hir(&'tcx self) -> Result<&Query<(&'tcx Crate<'tcx>, Steal<ResolverOutputs>)>> {
self.lower_to_hir.compute(|| {
let expansion_result = self.expansion()?;
let peeked = expansion_result.peek();
let krate = &peeked.0;
let resolver = peeked.1.steal();
let lint_store = &peeked.2;
let hir = resolver.borrow_mut().access(|resolver| {
Ok(passes::lower_to_hir(
self.session(),
lint_store,
resolver,
&*self.dep_graph()?.peek(),
&krate,
&self.hir_arena,
))
&crate_name,
);
let krate = resolver.access(|resolver| {
passes::configure_and_expand(&sess, &lint_store, krate, &crate_name, resolver)
})?;
let hir = self.hir_arena.alloc(hir);
Ok((hir, Steal::new(BoxedResolver::to_resolver_outputs(resolver))))
Ok((Rc::new(krate), Rc::new(RefCell::new(resolver)), lint_store))
})
}
fn dep_graph(&self) -> Result<&Query<DepGraph>> {
self.dep_graph.compute(|| {
let sess = self.session();
let future_opt = self.dep_graph_future()?.take();
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 prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
self.prepare_outputs.compute(|| {
let expansion_result = self.expansion()?;
let (krate, boxed_resolver, _) = &*expansion_result.peek();
let (krate, boxed_resolver, _) = &*self.expansion()?.peek();
let crate_name = self.crate_name()?.peek();
passes::prepare_outputs(
self.session(),
self.compiler,
&krate,
&boxed_resolver,
krate,
&*boxed_resolver,
&crate_name,
)
})
@ -260,22 +221,20 @@ impl<'tcx> Queries<'tcx> {
self.global_ctxt.compute(|| {
let crate_name = self.crate_name()?.peek().clone();
let outputs = self.prepare_outputs()?.peek().clone();
let lint_store = self.expansion()?.peek().2.clone();
let hir = self.lower_to_hir()?.peek();
let dep_graph = self.dep_graph()?.peek().clone();
let (ref krate, ref resolver_outputs) = &*hir;
let _timer = self.session().timer("create_global_ctxt");
let (krate, resolver, lint_store) = self.expansion()?.take();
Ok(passes::create_global_ctxt(
self.compiler,
lint_store,
krate,
dep_graph,
resolver_outputs.steal(),
resolver,
outputs,
&crate_name,
&self.queries,
&self.gcx,
&self.arena,
&self.hir_arena,
))
})
}

View File

@ -303,9 +303,8 @@ crate fn create_resolver<'a>(
queries: &Queries<'a>,
sess: &Session,
) -> Rc<RefCell<interface::BoxedResolver>> {
let parts = abort_on_err(queries.expansion(), sess).peek();
let (krate, resolver, _) = &*parts;
let resolver = resolver.borrow().clone();
let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
let resolver = resolver.clone();
let mut loader = crate::passes::collect_intra_doc_links::IntraLinkCrateLoader::new(resolver);
ast::visit::walk_crate(&mut loader, krate);

View File

@ -112,7 +112,6 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
let res = interface::run_compiler(config, |compiler| {
compiler.enter(|queries| {
let _lower_to_hir = queries.lower_to_hir()?;
let mut global_ctxt = queries.global_ctxt()?.take();
let collector = global_ctxt.enter(|tcx| {