diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index debed38361a14..67fd8eef95c8c 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -151,7 +151,10 @@ impl fmt::Debug for DefId { ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { - write!(f, " ~ {}", tcx.def_path_debug_str(*self))?; + // Only print the path after HIR lowering is done + if tcx.is_hir_lowered() { + write!(f, " ~ {}", tcx.def_path_debug_str(*self))?; + } } Ok(()) })?; diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 5c5aea76cadb3..55d95034d59da 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -31,6 +31,12 @@ use syntax_pos::symbol::InternedString; // as they will raise an fatal error on query cycles instead. rustc_queries! { Other { + query expand_macros(_: ()) -> Result, ErrorReported> { + no_hash + eval_always + desc { "expanding macros" } + } + query prepare_outputs(_: ()) -> Result, ErrorReported> { no_hash eval_always diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 456d603cea8ce..c4f338272d783 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -53,7 +53,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableVec}; use arena::SyncDroplessArena; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal, AtomicOnce, OneThread}; +use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal, AtomicOnce, Once, OneThread}; use std::any::Any; use std::borrow::Borrow; use std::cmp::Ordering; @@ -1009,15 +1009,20 @@ pub struct GlobalCtxt<'tcx> { pub io: InputsAndOutputs, - pub ast_crate: Steal, + /// This stores a `Lrc`, but that type depends on + /// rustc_metadata, so it cannot be used here. + pub cstore_rc: OneThread>>, - /// This stores a `Lrc>>)>`, but that type depends on - /// librustc_resolve, so it cannot be used here. - pub boxed_resolver: Steal>>, + pub sess_rc: Lrc, + + /// The AST after registering plugins. + pub ast_crate: Steal<(ast::Crate, ty::PluginInfo)>, lowered_hir: AtomicOnce<&'tcx hir::LoweredHir>, hir_map: AtomicOnce<&'tcx hir_map::Map<'tcx>>, + metadata_dep_nodes: Once<()>, + pub queries: query::Queries<'tcx>, // Internal cache for metadata decoding. No need to track deps on this. @@ -1075,10 +1080,19 @@ impl<'tcx> TyCtxt<'tcx> { self.lowered_hir.get_or_init(|| { // FIXME: The ignore here is only sound because all queries // used to compute LoweredHir are eval_always - self.dep_graph.with_ignore(|| self.lower_ast_to_hir(()).unwrap()) + self.dep_graph.with_ignore(|| { + let map = self.lower_ast_to_hir(()).unwrap(); + self.lowered_hir.init(map); + self.allocate_metadata_dep_nodes(); + map + }) }) } + pub fn is_hir_lowered(self) -> bool { + self.lowered_hir.is_initalized() + } + #[inline(always)] pub fn hir(self) -> &'tcx hir_map::Map<'tcx> { self.hir_map.get_or_init(|| { @@ -1163,14 +1177,15 @@ impl<'tcx> TyCtxt<'tcx> { /// value (types, substs, etc.) can only be used while `ty::tls` has a valid /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( - s: &'tcx Session, + s: &'tcx Lrc, cstore: &'tcx CrateStoreDyn, + cstore_rc: Box, local_providers: ty::query::Providers<'tcx>, extern_providers: ty::query::Providers<'tcx>, arenas: &'tcx AllArenas, dep_graph: DepGraph, ast_crate: ast::Crate, - boxed_resolver: Box, + plugin_info: ty::PluginInfo, on_disk_query_result_cache: query::OnDiskCache<'tcx>, crate_name: &str, tx: mpsc::Sender>, @@ -1194,19 +1209,21 @@ impl<'tcx> TyCtxt<'tcx> { providers[LOCAL_CRATE] = local_providers; GlobalCtxt { - sess: s, - cstore, + sess: &**s, arena: WorkerLocal::new(|_| Arena::default()), + cstore, + cstore_rc: OneThread::new(Steal::new(cstore_rc)), + sess_rc: s.clone(), interners, dep_graph, common, types: common_types, lifetimes: common_lifetimes, consts: common_consts, - ast_crate: Steal::new(ast_crate), - boxed_resolver: Steal::new(OneThread::new(boxed_resolver)), + ast_crate: Steal::new((ast_crate, plugin_info)), lowered_hir: AtomicOnce::new(), hir_map: AtomicOnce::new(), + metadata_dep_nodes: Once::new(), queries: query::Queries::new( providers, extern_providers, @@ -1381,18 +1398,24 @@ impl<'tcx> TyCtxt<'tcx> { // With full-fledged red/green, the method will probably become unnecessary // as this will be done on-demand. pub fn allocate_metadata_dep_nodes(self) { - // We cannot use the query versions of crates() and crate_hash(), since - // those would need the DepNodes that we are allocating here. - for cnum in self.cstore.crates_untracked() { - let dep_node = DepNode::new(self, DepConstructor::CrateMetadata(cnum)); - let crate_hash = self.cstore.crate_hash_untracked(cnum); - self.dep_graph.with_task(dep_node, - self, - crate_hash, - |_, x| x, // No transformation needed - Some(dep_graph::hash_result), - ); + if !self.dep_graph.is_fully_enabled() { + return } + + self.metadata_dep_nodes.init_locking(|| { + // We cannot use the query versions of crates() and crate_hash(), since + // those would need the DepNodes that we are allocating here. + for cnum in self.cstore.crates_untracked() { + let dep_node = DepNode::new(self, DepConstructor::CrateMetadata(cnum)); + let crate_hash = self.cstore.crate_hash_untracked(cnum); + self.dep_graph.with_task(dep_node, + self, + crate_hash, + |_, x| x, // No transformation needed + Some(dep_graph::hash_result), + ); + } + }); } pub fn serialize_query_result_cache(self, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6701c20b0a366..1578de632f858 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -38,13 +38,16 @@ use std::cmp::{self, Ordering}; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; -use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; +use std::any::Any; +use rustc_data_structures::sync::{self, Lrc, OneThread, ParallelIterator, par_iter}; use std::slice; use std::{mem, ptr}; use std::ops::Range; use syntax::ast::{self, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; +use syntax::ext::base::NamedSyntaxExtension; +use syntax::feature_gate::AttributeType; use syntax::symbol::{kw, sym, Symbol, LocalInternedString, InternedString}; use syntax_pos::Span; @@ -119,6 +122,19 @@ mod sty; // Data types +pub struct PluginInfo { + pub syntax_exts: Vec, + pub attributes: Vec<(Symbol, AttributeType)>, +} + +pub struct ExpansionResult { + pub ast_crate: steal::Steal, + + /// This stores a `Lrc>>)>`, but that type depends on + /// librustc_resolve, so it cannot be used here. + pub boxed_resolver: steal::Steal>>, +} + #[derive(Clone)] pub struct Resolutions { pub trait_map: TraitMap, diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 469f778551239..60085441fcfec 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -600,6 +600,16 @@ impl AtomicOnce { value.unwrap() } } + + #[inline] + pub fn init(&self, value: T) { + self.0.store(Some(value)); + } + + #[inline] + pub fn is_initalized(&self) -> bool { + self.0.load().is_some() + } } #[derive(Debug)] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index c6a1b216accb2..9a2d3218fac17 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -268,10 +268,11 @@ pub fn run_compiler( if ppm.needs_ast_map(&opt_uii) { pretty::visit_crate(sess, &mut compiler.parse()?.peek_mut(), ppm); compiler.global_ctxt()?.peek_mut().enter(|tcx| { + let expansion_result = tcx.expand_macros(())?; pretty::print_after_hir_lowering( tcx, compiler.input(), - &tcx.ast_crate.borrow(), + &expansion_result.ast_crate.borrow(), ppm, opt_uii.clone(), compiler.output_file().as_ref().map(|p| &**p), @@ -334,13 +335,14 @@ pub fn run_compiler( if sess.opts.debugging_opts.save_analysis { compiler.global_ctxt()?.peek_mut().enter(|tcx| { + let expansion_result = tcx.expand_macros(())?; let result = tcx.analysis(LOCAL_CRATE); let crate_name = &tcx.crate_name.as_str(); time(sess, "save analysis", || { save::process_crate( tcx, - &tcx.ast_crate.borrow(), + &expansion_result.ast_crate.borrow(), crate_name, &compiler.input(), None, @@ -355,7 +357,7 @@ pub fn run_compiler( } else { compiler.global_ctxt()?.peek_mut().enter(|tcx| { // Drop AST after lowering HIR to free memory - mem::drop(tcx.ast_crate.steal()); + mem::drop(tcx.expand_macros(()).unwrap().ast_crate.steal()); }); } @@ -368,7 +370,7 @@ pub fn run_compiler( if sess.opts.debugging_opts.save_analysis { compiler.global_ctxt()?.peek_mut().enter(|tcx| { // Drop AST after lowering HIR to free memory - mem::drop(tcx.ast_crate.steal()); + mem::drop(tcx.expand_macros(()).unwrap().ast_crate.steal()); }); } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 569aa78c9d4b3..226171929cadb 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -22,7 +22,6 @@ pub mod assert_module_sources; mod persist; pub use assert_dep_graph::assert_dep_graph; -pub use persist::dep_graph_tcx_init; pub use persist::{DepGraphFuture, load_dep_graph}; pub use persist::load_query_result_cache; pub use persist::LoadResult; diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 90aefb0f32416..792705abea3b4 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; use rustc::session::Session; -use rustc::ty::TyCtxt; use rustc::ty::query::OnDiskCache; use rustc::util::common::time_ext; use rustc_serialize::Decodable as RustcDecodable; @@ -15,14 +14,6 @@ use super::fs::*; use super::file_format; use super::work_product; -pub fn dep_graph_tcx_init(tcx: TyCtxt<'_>) { - if !tcx.dep_graph.is_fully_enabled() { - return - } - - tcx.allocate_metadata_dep_nodes(); -} - type WorkProductMap = FxHashMap; pub enum LoadResult { diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index bf404140f18d5..99acfb166e9e0 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -15,7 +15,6 @@ pub use fs::garbage_collect_session_directories; pub use fs::in_incr_comp_dir; pub use fs::in_incr_comp_dir_sess; pub use fs::prepare_session_directory; -pub use load::dep_graph_tcx_init; pub use load::{DepGraphFuture, load_dep_graph}; pub use load::load_query_result_cache; pub use load::LoadResult; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 64aff184addfb..5dc1b16c42e9b 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -118,26 +118,21 @@ declare_box_region_type!( (&mut Resolver<'_>) -> (Result, ExpansionResult) ); -/// Runs the "early phases" of the compiler: initial `cfg` processing, -/// loading compiler plugins (including those from `addl_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( - sess: Lrc, - cstore: Lrc, - krate: ast::Crate, - crate_name: &str, - plugin_info: PluginInfo, -) -> Result<(ast::Crate, BoxedResolver)> { +fn expand_macros( + tcx: TyCtxt<'_>, + _: (), +) -> Result> { + let (krate, plugin_info) = tcx.ast_crate.steal(); + let sess = tcx.sess_rc.clone(); + let cstore_rc: Box = tcx.cstore_rc.steal(); + let cstore = cstore_rc.downcast::>().unwrap(); + // 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(); + let crate_name = tcx.crate_name.to_string(); let (result, resolver) = BoxedResolver::new(static move || { let sess = &*sess; let mut crate_loader = CrateLoader::new(sess, &*cstore, &crate_name); @@ -164,7 +159,11 @@ pub fn configure_and_expand( box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver)); ExpansionResult::from_owned_resolver(resolver) }); - result.map(|k| (k, resolver)) + + result.map(|k| Lrc::new(ty::ExpansionResult { + ast_crate: Steal::new(k), + boxed_resolver: Steal::new(OneThread::new(Box::new(Lrc::new(Some(Lock::new(resolver)))))), + })) } pub struct ExpansionResult { @@ -224,18 +223,13 @@ impl BoxedResolver { } } -pub struct PluginInfo { - syntax_exts: Vec, - attributes: Vec<(Symbol, AttributeType)>, -} - pub fn register_plugins<'a>( compiler: &Compiler, sess: &'a Session, cstore: &'a CStore, mut krate: ast::Crate, crate_name: &str, -) -> Result<(ast::Crate, PluginInfo)> { +) -> Result<(ast::Crate, ty::PluginInfo)> { krate = time(sess, "attributes injection", || { syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) }); @@ -339,7 +333,7 @@ pub fn register_plugins<'a>( *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; *sess.plugin_attributes.borrow_mut() = attributes.clone(); - Ok((krate, PluginInfo { + Ok((krate, ty::PluginInfo { syntax_exts, attributes, })) @@ -352,7 +346,7 @@ fn configure_and_expand_inner<'a>( crate_name: &str, resolver_arenas: &'a ResolverArenas<'a>, crate_loader: &'a mut CrateLoader<'a>, - plugin_info: PluginInfo, + plugin_info: ty::PluginInfo, ) -> Result<(ast::Crate, Resolver<'a>)> { let attributes = plugin_info.attributes; time(sess, "pre ast expansion lint checks", || { @@ -555,8 +549,8 @@ fn lower_ast_to_hir( tcx.prepare_outputs(())?; let sess = tcx.sess; - - let boxed_resolver: Box = OneThread::into_inner(tcx.boxed_resolver.steal()); + let expansion_result = tcx.expand_macros(())?; + let boxed_resolver = OneThread::into_inner(expansion_result.boxed_resolver.steal()); let mut boxed_resolver: Box>>> = boxed_resolver.downcast().unwrap(); @@ -567,7 +561,7 @@ fn lower_ast_to_hir( sess, tcx.cstore, &tcx.dep_graph, - &tcx.ast_crate.borrow(), + &expansion_result.ast_crate.borrow(), resolver, ); @@ -582,7 +576,7 @@ fn lower_ast_to_hir( time(sess, "early lint checks", || { lint::check_ast_crate( sess, - &tcx.ast_crate.borrow(), + &expansion_result.ast_crate.borrow(), false,rustc_lint::BuiltinCombinedEarlyLintPass::new() ) }); @@ -792,7 +786,7 @@ fn prepare_outputs( &tcx.io.input, &tcx.io.output_dir, &tcx.io.output_file, - &tcx.ast_crate.borrow().attrs, + &tcx.expand_macros(())?.ast_crate.borrow().attrs, tcx.sess ); @@ -848,6 +842,7 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) { providers.hir_map = hir_map; providers.lower_ast_to_hir = lower_ast_to_hir; providers.prepare_outputs = prepare_outputs; + providers.expand_macros = expand_macros; proc_macro_decls::provide(providers); plugin::build::provide(providers); hir::provide(providers); @@ -895,7 +890,7 @@ pub fn create_global_ctxt( compiler: &Compiler, dep_graph: DepGraph, ast_krate: ast::Crate, - boxed_resolver: Box>>>, + plugin_info: ty::PluginInfo, io: InputsAndOutputs, tx: mpsc::Sender>, crate_name: &str, @@ -906,8 +901,8 @@ pub fn create_global_ctxt( let crate_name = crate_name.to_string(); let ((), result) = BoxedGlobalCtxt::new(static move || { - let sess = &*sess; - let cstore = &*cstore; + let sess = &sess; + let cstore = &cstore; let global_ctxt: Option>; let arenas = AllArenas::new(); @@ -924,15 +919,18 @@ pub fn create_global_ctxt( default_provide_extern(&mut extern_providers); codegen_backend.provide_extern(&mut extern_providers); + let cstore_rc: Lrc = cstore.clone(); + let gcx = TyCtxt::create_global_ctxt( sess, - cstore, + &**cstore, + Box::new(cstore_rc), local_providers, extern_providers, &arenas, dep_graph, ast_krate, - boxed_resolver, + plugin_info, query_result_on_disk_cache, &crate_name, tx, @@ -942,12 +940,6 @@ pub fn create_global_ctxt( global_ctxt = Some(gcx); let gcx = global_ctxt.as_ref().unwrap(); - ty::tls::enter_global(gcx, |tcx| { - // Do some initialization of the DepGraph that can only be done with the - // tcx available. - time(tcx.sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx)); - }); - yield BoxedGlobalCtxt::initial_yield(()); box_region_allow_access!(for('tcx), (&'tcx GlobalCtxt<'tcx>), (gcx)); diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 113e28035d758..20db751cf9daa 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -1,5 +1,5 @@ use crate::interface::{Compiler, Result}; -use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo}; +use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt}; use rustc_incremental::DepGraphFuture; use rustc_data_structures::sync::{Lrc, Lock}; @@ -87,8 +87,7 @@ pub(crate) struct Queries { dep_graph_future: Query>, parse: Query, crate_name: Query, - register_plugins: Query<(ast::Crate, PluginInfo)>, - expansion: Query<(ast::Crate, Lrc>>)>, + register_plugins: Query<(ast::Crate, ty::PluginInfo)>, dep_graph: Query, codegen_channel: Query<(Steal>>, Steal>>)>, @@ -119,7 +118,7 @@ impl Compiler { }) } - pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> { + pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, ty::PluginInfo)>> { self.queries.register_plugins.compute(|| { let crate_name = self.crate_name()?.peek().clone(); let krate = self.parse()?.take(); @@ -150,22 +149,6 @@ impl Compiler { }) } - pub fn expansion( - &self - ) -> Result<&Query<(ast::Crate, Lrc>>)>> { - self.queries.expansion.compute(|| { - let crate_name = self.crate_name()?.peek().clone(); - let (krate, plugin_info) = self.register_plugins()?.take(); - passes::configure_and_expand( - self.sess.clone(), - self.cstore().clone(), - krate, - &crate_name, - plugin_info, - ).map(|(krate, resolver)| (krate, Lrc::new(Some(Lock::new(resolver))))) - }) - } - pub fn dep_graph(&self) -> Result<&Query> { self.queries.dep_graph.compute(|| { Ok(match self.dep_graph_future()?.take() { @@ -194,14 +177,13 @@ impl Compiler { pub fn global_ctxt(&self) -> Result<&Query> { self.queries.global_ctxt.compute(|| { let crate_name = self.crate_name()?.peek().clone(); - let expansion_result = self.expansion()?; - let (krate, resolver) = expansion_result.take(); + let (krate, plugin_info) = self.register_plugins()?.take(); let tx = self.codegen_channel()?.peek().0.steal(); Ok(passes::create_global_ctxt( self, self.dep_graph()?.peek().clone(), krate, - Box::new(resolver), + plugin_info, self.io.clone(), tx, &crate_name)) @@ -262,7 +244,7 @@ impl Compiler { self.global_ctxt()?.peek_mut().enter(|tcx| { tcx.lower_ast_to_hir(())?; // Drop AST after lowering HIR to free memory - mem::drop(tcx.ast_crate.steal()); + mem::drop(tcx.expand_macros(()).unwrap().ast_crate.steal()); Ok(()) })?; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index e3bafd3435019..359d604b1c1c5 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -9,7 +9,7 @@ use rustc::lint::{self, LintPass}; use rustc::session::config::ErrorOutputType; use rustc::session::DiagnosticOutput; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_interface::interface; +use rustc_interface::interface::{self, BoxedResolver}; use rustc_driver::abort_on_err; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; @@ -27,6 +27,7 @@ use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc, Lock}; use std::sync::Arc; +use std::any::Any; use crate::visit_ast::RustdocVisitor; use crate::config::{Options as RustdocOptions, RenderOptions}; @@ -338,20 +339,22 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }; interface::run_compiler_in_existing_thread_pool(config, |compiler| { - let sess = compiler.session(); - - // We need to hold on to the complete resolver, so we cause everything to be - // cloned for the analysis passes to use. Suboptimal, but necessary in the - // current architecture. - let resolver = abort_on_err(compiler.expansion(), sess).peek().1.clone(); - - if sess.has_errors() { - sess.fatal("Compilation failed, aborting rustdoc"); - } + abort_on_err(compiler.global_ctxt(), compiler.session()).take().enter(|tcx| { + let sess = compiler.session(); + + // We need to hold on to the complete resolver, so we cause everything to be + // cloned for the analysis passes to use. Suboptimal, but necessary in the + // current architecture. + let resolver = { + let expanded = abort_on_err(tcx.expand_macros(()), sess); + let resolver: &Box = &**expanded.boxed_resolver.borrow(); + resolver.downcast_ref::>>>().unwrap().clone() + }; - let mut global_ctxt = abort_on_err(compiler.global_ctxt(), sess).take(); + if sess.has_errors() { + sess.fatal("Compilation failed, aborting rustdoc"); + } - global_ctxt.enter(|tcx| { tcx.analysis(LOCAL_CRATE).ok(); // Abort if there were any errors so far