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};
use rustc_expand::base::ExtCtxt;
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
use rustc_hir::Crate;
use rustc_lint::LintStore;
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::middle;
-use rustc_middle::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn};
+use rustc_middle::middle::cstore::{MetadataLoader, MetadataLoaderDyn};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_mir as mir;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
use rustc_passes::{self, hir_stats, layout_test};
use rustc_plugin_impl as plugin;
-use rustc_query_impl::Queries as TcxQueries;
+use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
use rustc_resolve::{Resolver, ResolverArenas};
+use rustc_serialize::json;
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode};
use rustc_session::lint;
use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind;
use rustc_session::Session;
use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::FileName;
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
-use tracing::{info, warn};
-
-use rustc_serialize::json;
use tempfile::Builder as TempFileBuilder;
+use tracing::{info, warn};
use std::any::Any;
use std::cell::RefCell;
}
// 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();
}
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()),
// 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))
}
}
}
}
-/// 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)
})
}
let crate_types = util::collect_crate_types(sess, &krate.attrs);
sess.init_crate_types(crate_types);
- let disambiguator = util::compute_crate_disambiguator(sess);
- sess.crate_disambiguator.set(disambiguator).expect("not yet initialized");
- rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator)?;
+ 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", || {
});
}
- sess.time("recursion_limit", || {
- middle::limits::update_limits(sess, &krate);
- });
-
let mut lint_store = rustc_lint::new_lint_store(
sess.opts.debugging_opts.no_interleave_lints,
sess.unstable_options(),
});
}
-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());
// Create the config for macro expansion
let features = sess.features_untracked();
+ let recursion_limit =
+ rustc_middle::middle::limits::get_recursion_limit(&krate.attrs, &sess);
let cfg = rustc_expand::expand::ExpansionConfig {
features: Some(&features),
- recursion_limit: sess.recursion_limit(),
+ recursion_limit,
trace_mac: sess.opts.debugging_opts.trace_macros,
should_test: sess.opts.test,
span_debug: sess.opts.debugging_opts.span_debug,
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));
})?;
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();
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,
}
});
- 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,
)
});
+ // 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();
fn escape_dep_filename(filename: &String) -> String {
// Apparently clang and gcc *only* escape spaces:
- // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
+ // https://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
filename.replace(" ", "\\ ")
}
fn write_out_deps(
sess: &Session,
- boxed_resolver: &Steal<Rc<RefCell<BoxedResolver>>>,
+ boxed_resolver: &RefCell<BoxedResolver>,
outputs: &OutputFilenames,
out_filenames: &[PathBuf],
) {
.map(|fmap| escape_dep_filename(&fmap.name.prefer_local().to_string()))
.collect();
+ // Account for explicitly marked-to-track files
+ // (e.g. accessed in proc macros).
+ let file_depinfo = sess.parse_sess.file_depinfo.borrow();
+ let extra_tracked_files = file_depinfo.iter().map(|path_sym| {
+ let path = PathBuf::from(&*path_sym.as_str());
+ let file = FileName::from(path);
+ escape_dep_filename(&file.prefer_local().to_string())
+ });
+ files.extend(extra_tracked_files);
+
if let Some(ref backend) = sess.opts.debugging_opts.codegen_backend {
files.push(backend.to_string());
}
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 {
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");
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);
callback(sess, &mut local_providers, &mut extern_providers);
}
- let queries = queries.get_or_init(|| TcxQueries::new(local_providers, extern_providers));
+ let queries = queries.get_or_init(|| {
+ TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache)
+ });
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,
resolver_outputs,
krate,
dep_graph,
- query_result_on_disk_cache,
+ queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
queries.as_dyn(),
&crate_name,
outputs,
tcx.ensure().proc_macro_decls_static(())
});
- let cstore = tcx
- .cstore_as_any()
- .downcast_ref::<CStore>()
- .expect("`tcx.cstore` is not a `CStore`");
- cstore.report_unused_deps(tcx);
+ CStore::from_tcx(tcx).report_unused_deps(tcx);
},
{
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
tcx.ensure().check_mod_unstable_api_usage(module);
tcx.ensure().check_mod_const_bodies(module);
});
+ },
+ {
+ // We force these querie to run,
+ // since they might not otherwise get called.
+ // This marks the corresponding crate-level attributes
+ // as used, and ensures that their values are valid.
+ tcx.ensure().limits(());
}
);
});