From 51938c61f6f1b26e463f9071716f543543486e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 8 Dec 2018 20:30:23 +0100 Subject: [PATCH] Make the rustc driver and interface demand driven --- src/librustc/ich/impls_ty.rs | 5 - src/librustc/session/config.rs | 36 +- src/librustc/session/mod.rs | 18 +- src/librustc/ty/context.rs | 87 +- src/librustc/ty/mod.rs | 2 +- src/librustc_codegen_llvm/lib.rs | 5 +- src/librustc_codegen_utils/codegen_backend.rs | 7 +- src/librustc_data_structures/box_region.rs | 172 +++ src/librustc_data_structures/lib.rs | 3 + src/librustc_driver/driver.rs | 1244 ----------------- src/librustc_driver/lib.rs | 729 ++++------ src/librustc_driver/pretty.rs | 273 ++-- src/librustc_driver/test.rs | 142 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_incremental/persist/load.rs | 6 +- src/librustc_incremental/persist/mod.rs | 2 +- src/librustc_interface/interface.rs | 155 ++ src/librustc_interface/lib.rs | 11 +- src/librustc_interface/passes.rs | 756 +++++++++- src/librustc_interface/queries.rs | 302 ++++ src/librustc_interface/util.rs | 159 ++- src/librustdoc/clean/auto_trait.rs | 8 +- src/librustdoc/clean/blanket_impl.rs | 8 +- src/librustdoc/clean/def_ctor.rs | 4 +- src/librustdoc/clean/inline.rs | 38 +- src/librustdoc/clean/mod.rs | 214 +-- src/librustdoc/clean/simplify.rs | 4 +- src/librustdoc/config.rs | 2 +- src/librustdoc/core.rs | 207 +-- src/librustdoc/lib.rs | 11 +- src/librustdoc/markdown.rs | 4 +- .../passes/calculate_doc_coverage.rs | 2 +- .../passes/check_code_block_syntax.rs | 10 +- src/librustdoc/passes/collapse_docs.rs | 2 +- .../passes/collect_intra_doc_links.rs | 62 +- src/librustdoc/passes/collect_trait_impls.rs | 12 +- src/librustdoc/passes/mod.rs | 8 +- .../passes/private_items_doc_tests.rs | 12 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 2 +- src/librustdoc/passes/strip_priv_imports.rs | 2 +- src/librustdoc/passes/strip_private.rs | 2 +- src/librustdoc/passes/unindent_comments.rs | 2 +- src/librustdoc/test.rs | 294 ++-- src/librustdoc/visit_ast.rs | 12 +- src/librustdoc/visit_lib.rs | 10 +- src/rustc/rustc.rs | 11 - .../hotplug_codegen_backend/the_backend.rs | 5 +- src/test/run-make-fulldeps/issue-19371/foo.rs | 74 +- src/test/run-pass-fulldeps/compiler-calls.rs | 81 +- .../deny-intra-link-resolution-failure.stderr | 2 + .../rustdoc-ui/deny-missing-docs-crate.stderr | 2 +- .../rustdoc-ui/deny-missing-docs-macro.stderr | 2 +- .../rustdoc-ui/doc-without-codeblock.stderr | 2 + .../rustdoc-ui/failed-doctest-output.stdout | 7 +- .../rustdoc-ui/intra-doc-alias-ice.stderr | 2 + .../intra-link-span-ice-55723.stderr | 2 + src/test/rustdoc-ui/lint-group.stderr | 2 + .../rustdoc-ui/private-item-doc-test.stderr | 2 + src/tools/rustdoc/main.rs | 12 - 60 files changed, 2511 insertions(+), 2745 deletions(-) create mode 100644 src/librustc_data_structures/box_region.rs delete mode 100644 src/librustc_driver/driver.rs create mode 100644 src/librustc_interface/interface.rs create mode 100644 src/librustc_interface/queries.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 21988de90183a..7e0abf7523031 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -946,11 +946,6 @@ impl_stable_hash_for!(struct ty::CrateInherentImpls { inherent_impls }); -impl_stable_hash_for!(enum crate::session::CompileIncomplete { - Stopped, - Errored(error_reported) -}); - impl_stable_hash_for!(struct crate::util::common::ErrorReported {}); impl_stable_hash_for!(tuple_struct crate::middle::reachable::ReachableSet { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a44d815025e92..55c4b0e54b822 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -11,6 +11,7 @@ use rustc_target::spec::{Target, TargetTriple}; use crate::lint; use crate::middle::cstore; +use syntax; use syntax::ast::{self, IntTy, UintTy, MetaItemKind}; use syntax::source_map::{FileName, FilePathMapping}; use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION}; @@ -1494,6 +1495,15 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { ret } +/// Converts the crate cfg! configuration from String to Symbol. +/// `rustc_interface::interface::Config` accepts this in the compiler configuration, +/// but the symbol interner is not yet set up then, so we must convert it later. +pub fn to_crate_config(cfg: FxHashSet<(String, Option)>) -> ast::CrateConfig { + cfg.into_iter() + .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))) + .collect() +} + pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig { // Combine the configuration requested by the session (command line) with // some default and generated configuration items @@ -1800,10 +1810,9 @@ pub fn rustc_optgroups() -> Vec { } // Convert strings provided as --cfg [cfgspec] into a crate_cfg -pub fn parse_cfgspecs(cfgspecs: Vec) -> ast::CrateConfig { - cfgspecs - .into_iter() - .map(|s| { +pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option)> { + syntax::with_globals(move || { + let cfg = cfgspecs.into_iter().map(|s| { let sess = parse::ParseSess::new(FilePathMapping::empty()); let filename = FileName::cfg_spec_source_code(&s); let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string()); @@ -1835,8 +1844,11 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> ast::CrateConfig { } error!(r#"expected `key` or `key="value"`"#); - }) - .collect::() + }).collect::(); + cfg.into_iter().map(|(a, b)| { + (a.to_string(), b.map(|b| b.to_string())) + }).collect() + }) } pub fn get_cmd_lint_options(matches: &getopts::Matches, @@ -1864,7 +1876,7 @@ pub fn get_cmd_lint_options(matches: &getopts::Matches, pub fn build_session_options_and_crate_config( matches: &getopts::Matches, -) -> (Options, ast::CrateConfig) { +) -> (Options, FxHashSet<(String, Option)>) { let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) { Some("auto") => ColorConfig::Auto, Some("always") => ColorConfig::Always, @@ -2590,7 +2602,11 @@ mod tests { use getopts; use crate::lint; use crate::middle::cstore; - use crate::session::config::{build_configuration, build_session_options_and_crate_config}; + use crate::session::config::{ + build_configuration, + build_session_options_and_crate_config, + to_crate_config + }; use crate::session::config::{LtoCli, LinkerPluginLto}; use crate::session::build_session; use crate::session::search_paths::SearchPath; @@ -2631,7 +2647,7 @@ mod tests { let registry = errors::registry::Registry::new(&[]); let (sessopts, cfg) = build_session_options_and_crate_config(matches); let sess = build_session(sessopts, None, registry); - let cfg = build_configuration(&sess, cfg); + let cfg = build_configuration(&sess, to_crate_config(cfg)); assert!(cfg.contains(&(Symbol::intern("test"), None))); }); } @@ -2649,7 +2665,7 @@ mod tests { let registry = errors::registry::Registry::new(&[]); let (sessopts, cfg) = build_session_options_and_crate_config(matches); let sess = build_session(sessopts, None, registry); - let cfg = build_configuration(&sess, cfg); + let cfg = build_configuration(&sess, to_crate_config(cfg)); let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test"); assert!(test_items.next().is_some()); assert!(test_items.next().is_none()); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 751fa7e95e3a8..75a0a8195bc2e 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -311,7 +311,7 @@ impl Session { pub fn abort_if_errors(&self) { self.diagnostic().abort_if_errors(); } - pub fn compile_status(&self) -> Result<(), CompileIncomplete> { + pub fn compile_status(&self) -> Result<(), ErrorReported> { compile_result_from_err_count(self.err_count()) } pub fn track_errors(&self, f: F) -> Result @@ -1124,7 +1124,7 @@ pub fn build_session_with_source_map( build_session_(sopts, local_crate_source_file, diagnostic_handler, source_map, lint_caps) } -pub fn build_session_( +fn build_session_( sopts: config::Options, local_crate_source_file: Option, span_diagnostic: errors::Handler, @@ -1334,22 +1334,12 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { handler.emit(&MultiSpan::new(), msg, errors::Level::Warning); } -#[derive(Copy, Clone, Debug)] -pub enum CompileIncomplete { - Stopped, - Errored(ErrorReported), -} -impl From for CompileIncomplete { - fn from(err: ErrorReported) -> CompileIncomplete { - CompileIncomplete::Errored(err) - } -} -pub type CompileResult = Result<(), CompileIncomplete>; +pub type CompileResult = Result<(), ErrorReported>; pub fn compile_result_from_err_count(err_count: usize) -> CompileResult { if err_count == 0 { Ok(()) } else { - Err(CompileIncomplete::Errored(ErrorReported)) + Err(ErrorReported) } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 04d503d993db7..b705968ce8aed 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -78,7 +78,6 @@ use crate::hir; pub struct AllArenas<'tcx> { pub global: WorkerLocal>, pub interner: SyncDroplessArena, - global_ctxt: Option>, } impl<'tcx> AllArenas<'tcx> { @@ -86,7 +85,6 @@ impl<'tcx> AllArenas<'tcx> { AllArenas { global: WorkerLocal::new(|_| GlobalArenas::default()), interner: SyncDroplessArena::default(), - global_ctxt: None, } } } @@ -1182,20 +1180,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// to the context. The closure enforces that the type context and any interned /// 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_and_enter(s: &'tcx Session, - cstore: &'tcx CrateStoreDyn, - local_providers: ty::query::Providers<'tcx>, - extern_providers: ty::query::Providers<'tcx>, - arenas: &'tcx mut AllArenas<'tcx>, - resolutions: ty::Resolutions, - hir: hir_map::Map<'tcx>, - on_disk_query_result_cache: query::OnDiskCache<'tcx>, - crate_name: &str, - tx: mpsc::Sender>, - output_filenames: &OutputFilenames, - f: F) -> R - where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R - { + pub fn create_global_ctxt( + s: &'tcx Session, + cstore: &'tcx CrateStoreDyn, + local_providers: ty::query::Providers<'tcx>, + extern_providers: ty::query::Providers<'tcx>, + arenas: &'tcx AllArenas<'tcx>, + resolutions: ty::Resolutions, + hir: hir_map::Map<'tcx>, + on_disk_query_result_cache: query::OnDiskCache<'tcx>, + crate_name: &str, + tx: mpsc::Sender>, + output_filenames: &OutputFilenames, + ) -> GlobalCtxt<'tcx> { let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| { s.fatal(&err); }); @@ -1247,7 +1244,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Lrc::new(StableVec::new(v))); } - arenas.global_ctxt = Some(GlobalCtxt { + GlobalCtxt { sess: s, cstore, global_arenas: &arenas.global, @@ -1293,15 +1290,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { alloc_map: Lock::new(interpret::AllocMap::new()), tx_to_llvm_workers: Lock::new(tx), output_filenames: Arc::new(output_filenames.clone()), - }); - - let gcx = arenas.global_ctxt.as_ref().unwrap(); - - let r = tls::enter_global(gcx, f); - - gcx.queries.record_computed_queries(s); - - r + } } pub fn consider_optimizing String>(&self, msg: T) -> bool { @@ -1985,31 +1974,29 @@ pub mod tls { pub fn enter_global<'gcx, F, R>(gcx: &'gcx GlobalCtxt<'gcx>, f: F) -> R where F: FnOnce(TyCtxt<'gcx, 'gcx, 'gcx>) -> R { - with_thread_locals(|| { - // Update GCX_PTR to indicate there's a GlobalCtxt available - GCX_PTR.with(|lock| { - *lock.lock() = gcx as *const _ as usize; - }); - // Set GCX_PTR back to 0 when we exit - let _on_drop = OnDrop(move || { - GCX_PTR.with(|lock| *lock.lock() = 0); - }); + // Update GCX_PTR to indicate there's a GlobalCtxt available + GCX_PTR.with(|lock| { + *lock.lock() = gcx as *const _ as usize; + }); + // Set GCX_PTR back to 0 when we exit + let _on_drop = OnDrop(move || { + GCX_PTR.with(|lock| *lock.lock() = 0); + }); - let tcx = TyCtxt { - gcx, - interners: &gcx.global_interners, - dummy: PhantomData, - }; - let icx = ImplicitCtxt { - tcx, - query: None, - diagnostics: None, - layout_depth: 0, - task_deps: None, - }; - enter_context(&icx, |_| { - f(tcx) - }) + let tcx = TyCtxt { + gcx, + interners: &gcx.global_interners, + dummy: PhantomData, + }; + let icx = ImplicitCtxt { + tcx, + query: None, + diagnostics: None, + layout_depth: 0, + task_deps: None, + }; + enter_context(&icx, |_| { + f(tcx) }) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1629f1dc6302a..1a44dbdbb61ae 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -71,7 +71,7 @@ pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local}; -pub use self::context::{Lift, TypeckTables, CtxtInterners}; +pub use self::context::{Lift, TypeckTables, CtxtInterners, GlobalCtxt}; pub use self::context::{ UserTypeAnnotationIndex, UserType, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy, diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 258391ba8360f..7b2b9ec24ea0f 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -63,11 +63,12 @@ use std::sync::{mpsc, Arc}; use rustc::dep_graph::DepGraph; use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; -use rustc::session::{Session, CompileIncomplete}; +use rustc::session::Session; use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel}; use rustc::ty::{self, TyCtxt}; use rustc::util::time_graph; use rustc::util::profiling::ProfileCategory; +use rustc::util::common::ErrorReported; use rustc_mir::monomorphize; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_utils::codegen_backend::CodegenBackend; @@ -311,7 +312,7 @@ impl CodegenBackend for LlvmCodegenBackend { sess: &Session, dep_graph: &DepGraph, outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete>{ + ) -> Result<(), ErrorReported>{ use rustc::util::common::time; let (codegen_results, work_products) = ongoing_codegen.downcast:: diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 28d7d18422841..29bcb4f2e6446 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -21,7 +21,8 @@ use flate2::write::DeflateEncoder; use syntax::symbol::Symbol; use rustc::hir::def_id::LOCAL_CRATE; -use rustc::session::{Session, CompileIncomplete}; +use rustc::session::Session; +use rustc::util::common::ErrorReported; use rustc::session::config::{CrateType, OutputFilenames, PrintRequest}; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; @@ -61,7 +62,7 @@ pub trait CodegenBackend { sess: &Session, dep_graph: &DepGraph, outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete>; + ) -> Result<(), ErrorReported>; } pub struct NoLlvmMetadataLoader; @@ -163,7 +164,7 @@ impl CodegenBackend for MetadataOnlyCodegenBackend { sess: &Session, _dep_graph: &DepGraph, outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete> { + ) -> Result<(), ErrorReported> { let ongoing_codegen = ongoing_codegen.downcast::() .expect("Expected MetadataOnlyCodegenBackend's OngoingCodegen, found Box"); for &crate_type in sess.opts.crate_types.iter() { diff --git a/src/librustc_data_structures/box_region.rs b/src/librustc_data_structures/box_region.rs new file mode 100644 index 0000000000000..278dcdf2bee42 --- /dev/null +++ b/src/librustc_data_structures/box_region.rs @@ -0,0 +1,172 @@ +use std::cell::Cell; +use std::marker::PhantomData; +use std::pin::Pin; +use std::ops::{Generator, GeneratorState}; + +#[derive(Copy, Clone)] +pub struct AccessAction(*mut dyn FnMut()); + +impl AccessAction { + pub fn get(self) -> *mut dyn FnMut() { + self.0 + } +} + +#[derive(Copy, Clone)] +pub enum Action { + Access(AccessAction), + Complete, +} + +thread_local!(pub static BOX_REGION_ARG: Cell = Cell::new(Action::Complete)); + +pub struct PinnedGenerator { + generator: Pin, Return = R>>> +} + +impl PinnedGenerator { + pub fn new< + T: Generator, Return = R> + 'static + >(generator: T) -> (I, Self) { + let mut result = PinnedGenerator { + generator: Box::pin(generator) + }; + + // Run it to the first yield to set it up + let init = match Pin::new(&mut result.generator).resume() { + GeneratorState::Yielded( + YieldType::Initial(y) + ) => y, + _ => panic!() + }; + + (init, result) + } + + pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { + BOX_REGION_ARG.with(|i| { + i.set(Action::Access(AccessAction(closure))); + }); + + // Call the generator, which in turn will call the closure in BOX_REGION_ARG + if let GeneratorState::Complete(_) = Pin::new(&mut self.generator).resume() { + panic!() + } + } + + pub fn complete(&mut self) -> R { + // Tell the generator we want it to complete, consuming it and yielding a result + BOX_REGION_ARG.with(|i| { + i.set(Action::Complete) + }); + + let result = Pin::new(&mut self.generator).resume(); + if let GeneratorState::Complete(r) = result { + r + } else { + panic!() + } + } +} + +#[derive(PartialEq)] +pub struct Marker(PhantomData); + +impl Marker { + pub unsafe fn new() -> Self { + Marker(PhantomData) + } +} + +pub enum YieldType { + Initial(I), + Accessor(Marker), +} + +#[macro_export] +#[allow_internal_unstable(fn_traits)] +macro_rules! declare_box_region_type { + (impl $v:vis + $name: ident, + $yield_type:ty, + for($($lifetimes:tt)*), + ($($args:ty),*) -> ($reti:ty, $retc:ty) + ) => { + $v struct $name($crate::box_region::PinnedGenerator< + $reti, + for<$($lifetimes)*> fn(($($args,)*)), + $retc + >); + + impl $name { + fn new + 'static>( + generator: T + ) -> ($reti, Self) { + let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator); + (initial, $name(pinned)) + } + + $v fn access FnOnce($($args,)*) -> R, R>(&mut self, f: F) -> R { + // Turn the FnOnce closure into *mut dyn FnMut() + // so we can pass it in to the generator using the BOX_REGION_ARG thread local + let mut r = None; + let mut f = Some(f); + let mut_f: &mut dyn for<$($lifetimes)*> FnMut(($($args,)*)) = + &mut |args| { + let f = f.take().unwrap(); + r = Some(FnOnce::call_once(f, args)); + }; + let mut_f = mut_f as *mut dyn for<$($lifetimes)*> FnMut(($($args,)*)); + + // Get the generator to call our closure + unsafe { + self.0.access(::std::mem::transmute(mut_f)); + } + + // Unwrap the result + r.unwrap() + } + + $v fn complete(mut self) -> $retc { + self.0.complete() + } + + fn initial_yield(value: $reti) -> $yield_type { + $crate::box_region::YieldType::Initial(value) + } + } + }; + + ($v:vis $name: ident, for($($lifetimes:tt)*), ($($args:ty),*) -> ($reti:ty, $retc:ty)) => { + declare_box_region_type!( + impl $v $name, + $crate::box_region::YieldType<$reti, for<$($lifetimes)*> fn(($($args,)*))>, + for($($lifetimes)*), + ($($args),*) -> ($reti, $retc) + ); + }; +} + +#[macro_export] +#[allow_internal_unstable(fn_traits)] +macro_rules! box_region_allow_access { + (for($($lifetimes:tt)*), ($($args:ty),*), ($($exprs:expr),*) ) => { + loop { + match $crate::box_region::BOX_REGION_ARG.with(|i| i.get()) { + $crate::box_region::Action::Access(accessor) => { + let accessor: &mut dyn for<$($lifetimes)*> FnMut($($args),*) = unsafe { + ::std::mem::transmute(accessor.get()) + }; + (*accessor)(($($exprs),*)); + unsafe { + let marker = $crate::box_region::Marker::< + for<$($lifetimes)*> fn(($($args,)*)) + >::new(); + yield $crate::box_region::YieldType::Accessor(marker) + }; + } + $crate::box_region::Action::Complete => break, + } + } + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 09482340b1a1d..a1d7ab8856daa 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -10,6 +10,8 @@ #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] +#![feature(generators)] +#![feature(generator_trait)] #![feature(fn_traits)] #![feature(unsize)] #![feature(specialization)] @@ -71,6 +73,7 @@ pub mod macros; pub mod svh; pub mod base_n; pub mod bit_set; +pub mod box_region; pub mod const_cstr; pub mod flock; pub mod fx; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs deleted file mode 100644 index d3e295607c2b3..0000000000000 --- a/src/librustc_driver/driver.rs +++ /dev/null @@ -1,1244 +0,0 @@ -use rustc::dep_graph::DepGraph; -use rustc::hir; -use rustc::hir::lowering::lower_crate; -use rustc::hir::map as hir_map; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::lint; -use rustc::middle::{self, reachable, resolve_lifetime, stability}; -use rustc::ty::{self, AllArenas, Resolutions, TyCtxt}; -use rustc::traits; -use rustc::util::common::{install_panic_hook, time, ErrorReported}; -use rustc::util::profiling::ProfileCategory; -use rustc::session::{CompileResult, Session}; -use rustc::session::CompileIncomplete; -use rustc::session::config::{self, Input, OutputFilenames, OutputType}; -use rustc::session::search_paths::PathKind; -use rustc_allocator as allocator; -use rustc_borrowck as borrowck; -use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_data_structures::sync::{self, Lock}; -#[cfg(parallel_compiler)] -use rustc_data_structures::jobserver; -use rustc_incremental; -use rustc_metadata::creader::CrateLoader; -use rustc_metadata::cstore::{self, CStore}; -use rustc_mir as mir; -use rustc_passes::{self, ast_validation, hir_stats}; -use rustc_plugin as plugin; -use rustc_plugin::registry::Registry; -use rustc_privacy; -use rustc_resolve::{Resolver, ResolverArenas}; -use rustc_traits; -use rustc_typeck as typeck; -use syntax::{self, ast, diagnostics, visit}; -use syntax::early_buffered_lints::BufferedEarlyLint; -use syntax::ext::base::ExtCtxt; -use syntax::mut_visit::MutVisitor; -use syntax::parse::{self, PResult}; -use syntax::util::node_count::NodeCounter; -use syntax_pos::hygiene; -use syntax_ext; - -use serialize::json; - -use std::any::Any; -use std::env; -use std::ffi::OsString; -use std::fs; -use std::iter; -use std::path::{Path, PathBuf}; -use std::sync::mpsc; - -use rustc_interface::{util, profile, passes}; -use super::Compilation; - -#[cfg(not(parallel_compiler))] -pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( - opts: config::Options, - f: F -) -> R { - ty::tls::GCX_PTR.set(&Lock::new(0), || { - f(opts) - }) -} - -#[cfg(parallel_compiler)] -pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( - opts: config::Options, - f: F -) -> R { - use syntax; - use syntax_pos; - use rayon::{ThreadPoolBuilder, ThreadPool}; - - let gcx_ptr = &Lock::new(0); - - let config = ThreadPoolBuilder::new() - .acquire_thread_handler(jobserver::acquire_thread) - .release_thread_handler(jobserver::release_thread) - .num_threads(Session::threads_from_count(opts.debugging_opts.threads)) - .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }) - .stack_size(::STACK_SIZE); - - let with_pool = move |pool: &ThreadPool| { - pool.install(move || f(opts)) - }; - - syntax::GLOBALS.with(|syntax_globals| { - syntax_pos::GLOBALS.with(|syntax_pos_globals| { - // The main handler run for each Rayon worker thread and sets up - // the thread local rustc uses. syntax_globals and syntax_pos_globals are - // captured and set on the new threads. ty::tls::with_thread_locals sets up - // thread local callbacks from libsyntax - let main_handler = move |worker: &mut dyn FnMut()| { - syntax::GLOBALS.set(syntax_globals, || { - syntax_pos::GLOBALS.set(syntax_pos_globals, || { - ty::tls::with_thread_locals(|| { - ty::tls::GCX_PTR.set(gcx_ptr, || { - worker() - }) - }) - }) - }) - }; - - ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap() - }) - }) -} - -pub fn compile_input( - codegen_backend: Box, - sess: &Session, - cstore: &CStore, - input_path: &Option, - input: &Input, - outdir: &Option, - output: &Option, - addl_plugins: Option>, - control: &CompileController, -) -> CompileResult { - macro_rules! controller_entry_point { - ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ - let state = &mut $make_state; - let phase_result: &CompileResult = &$phase_result; - if phase_result.is_ok() || control.$point.run_callback_on_error { - (control.$point.callback)(state); - } - - if control.$point.stop == Compilation::Stop { - // FIXME: shouldn't this return Err(CompileIncomplete::Stopped) - // if there are no errors? - return $tsess.compile_status(); - } - }} - } - - if sess.profile_queries() { - profile::begin(sess); - } - - // We need nested scopes here, because the intermediate results can keep - // large chunks of memory alive and we want to free them as soon as - // possible to keep the peak memory usage low - let (outputs, ongoing_codegen, dep_graph) = { - let krate = match phase_1_parse_input(control, sess, input) { - Ok(krate) => krate, - Err(mut parse_error) => { - parse_error.emit(); - return Err(CompileIncomplete::Errored(ErrorReported)); - } - }; - - let (krate, registry) = { - let mut compile_state = - CompileState::state_after_parse(input, sess, outdir, output, krate, &cstore); - controller_entry_point!(after_parse, sess, compile_state, Ok(())); - - (compile_state.krate.unwrap(), compile_state.registry) - }; - - let outputs = util::build_output_filenames(input, outdir, output, &krate.attrs, sess); - let crate_name = - ::rustc_codegen_utils::link::find_crate_name(Some(sess), &krate.attrs, input); - install_panic_hook(); - - let ExpansionResult { - expanded_crate, - defs, - resolutions, - mut hir_forest, - } = { - phase_2_configure_and_expand( - sess, - &cstore, - krate, - registry, - &crate_name, - addl_plugins, - |expanded_crate| { - let mut state = CompileState::state_after_expand( - input, - sess, - outdir, - output, - &cstore, - expanded_crate, - &crate_name, - ); - controller_entry_point!(after_expand, sess, state, Ok(())); - Ok(()) - }, - )? - }; - - let output_paths = passes::generated_output_paths( - sess, - &outputs, - output.is_some(), - &crate_name - ); - - // Ensure the source file isn't accidentally overwritten during compilation. - if let Some(ref input_path) = *input_path { - if sess.opts.will_create_output_file() { - if passes::output_contains_path(&output_paths, input_path) { - sess.err(&format!( - "the input file \"{}\" would be overwritten by the generated \ - executable", - input_path.display() - )); - return Err(CompileIncomplete::Stopped); - } - if let Some(dir_path) = passes::output_conflicts_with_dir(&output_paths) { - sess.err(&format!( - "the generated executable for the input file \"{}\" conflicts with the \ - existing directory \"{}\"", - input_path.display(), - dir_path.display() - )); - return Err(CompileIncomplete::Stopped); - } - } - } - - passes::write_out_deps(sess, &outputs, &output_paths); - if sess.opts.output_types.contains_key(&OutputType::DepInfo) - && sess.opts.output_types.len() == 1 - { - return Ok(()); - } - - if let &Some(ref dir) = outdir { - if fs::create_dir_all(dir).is_err() { - sess.err("failed to find or create the directory specified by --out-dir"); - return Err(CompileIncomplete::Stopped); - } - } - - // Construct the HIR map - let hir_map = time(sess, "indexing hir", || { - hir_map::map_crate(sess, cstore, &mut hir_forest, &defs) - }); - - { - hir_map.dep_graph.assert_ignored(); - controller_entry_point!( - after_hir_lowering, - sess, - CompileState::state_after_hir_lowering( - input, - sess, - outdir, - output, - &cstore, - &hir_map, - &resolutions, - &expanded_crate, - &hir_map.krate(), - &outputs, - &crate_name - ), - Ok(()) - ); - } - - let opt_crate = if control.keep_ast { - Some(&expanded_crate) - } else { - drop(expanded_crate); - None - }; - - let mut arenas = AllArenas::new(); - - phase_3_run_analysis_passes( - &*codegen_backend, - control, - sess, - cstore, - hir_map, - resolutions, - &mut arenas, - &crate_name, - &outputs, - |tcx, rx, result| { - { - // Eventually, we will want to track plugins. - tcx.dep_graph.with_ignore(|| { - let mut state = CompileState::state_after_analysis( - input, - sess, - outdir, - output, - opt_crate, - tcx.hir().krate(), - tcx, - &crate_name, - ); - (control.after_analysis.callback)(&mut state); - }); - - // Plugins like clippy and rust-semverver stop the analysis early, - // but want to still return an error if errors during the analysis - // happened: - tcx.sess.compile_status()?; - - if control.after_analysis.stop == Compilation::Stop { - return result.and_then(|_| Err(CompileIncomplete::Stopped)); - } - } - - result?; - - if log_enabled!(::log::Level::Info) { - println!("Pre-codegen"); - tcx.print_debug_stats(); - } - - let ongoing_codegen = phase_4_codegen(&*codegen_backend, tcx, rx); - - if log_enabled!(::log::Level::Info) { - println!("Post-codegen"); - tcx.print_debug_stats(); - } - - if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) { - sess.err(&format!("could not emit MIR: {}", e)); - sess.abort_if_errors(); - } - } - - if tcx.sess.opts.debugging_opts.query_stats { - tcx.queries.print_stats(); - } - - Ok((outputs.clone(), ongoing_codegen, tcx.dep_graph.clone())) - }, - )? - }; - - if sess.opts.debugging_opts.print_type_sizes { - sess.code_stats.borrow().print_type_sizes(); - } - - codegen_backend.join_codegen_and_link(ongoing_codegen, sess, &dep_graph, &outputs)?; - - if sess.opts.debugging_opts.perf_stats { - sess.print_perf_stats(); - } - - controller_entry_point!( - compilation_done, - sess, - CompileState::state_when_compilation_done(input, sess, outdir, output), - Ok(()) - ); - - Ok(()) -} - -/// CompileController is used to customize compilation, it allows compilation to -/// be stopped and/or to call arbitrary code at various points in compilation. -/// It also allows for various flags to be set to influence what information gets -/// collected during compilation. -/// -/// This is a somewhat higher level controller than a Session - the Session -/// controls what happens in each phase, whereas the CompileController controls -/// whether a phase is run at all and whether other code (from outside the -/// compiler) is run between phases. -/// -/// Note that if compilation is set to stop and a callback is provided for a -/// given entry point, the callback is called before compilation is stopped. -/// -/// Expect more entry points to be added in the future. -pub struct CompileController<'a> { - pub after_parse: PhaseController<'a>, - pub after_expand: PhaseController<'a>, - pub after_hir_lowering: PhaseController<'a>, - pub after_analysis: PhaseController<'a>, - pub compilation_done: PhaseController<'a>, - - // FIXME we probably want to group the below options together and offer a - // better API, rather than this ad-hoc approach. - // Whether the compiler should keep the ast beyond parsing. - pub keep_ast: bool, - // -Zcontinue-parse-after-error - pub continue_parse_after_error: bool, - - /// Allows overriding default rustc query providers, - /// after `default_provide` has installed them. - pub provide: Box, - /// Same as `provide`, but only for non-local crates, - /// applied after `default_provide_extern`. - pub provide_extern: Box, -} - -impl<'a> CompileController<'a> { - pub fn basic() -> CompileController<'a> { - sync::assert_send::(); - CompileController { - after_parse: PhaseController::basic(), - after_expand: PhaseController::basic(), - after_hir_lowering: PhaseController::basic(), - after_analysis: PhaseController::basic(), - compilation_done: PhaseController::basic(), - keep_ast: false, - continue_parse_after_error: false, - provide: box |_| {}, - provide_extern: box |_| {}, - } - } -} - -/// This implementation makes it easier to create a custom driver when you only want to hook -/// into callbacks from `CompileController`. -/// -/// # Example -/// -/// ```no_run -/// # extern crate rustc_driver; -/// # use rustc_driver::driver::CompileController; -/// let mut controller = CompileController::basic(); -/// controller.after_analysis.callback = Box::new(move |_state| {}); -/// rustc_driver::run_compiler(&[], Box::new(controller), None, None); -/// ``` -impl<'a> ::CompilerCalls<'a> for CompileController<'a> { - fn early_callback( - &mut self, - matches: &::getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - descriptions: &::errors::registry::Registry, - output: ::ErrorOutputType, - ) -> Compilation { - ::RustcDefaultCalls.early_callback( - matches, - sopts, - cfg, - descriptions, - output, - ) - } - fn no_input( - &mut self, - matches: &::getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &::errors::registry::Registry, - ) -> Option<(Input, Option)> { - ::RustcDefaultCalls.no_input( - matches, - sopts, - cfg, - odir, - ofile, - descriptions, - ) - } - fn late_callback( - &mut self, - codegen_backend: &dyn (::CodegenBackend), - matches: &::getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option, - ofile: &Option, - ) -> Compilation { - ::RustcDefaultCalls - .late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) - } - fn build_controller( - self: Box, - _: &Session, - _: &::getopts::Matches - ) -> CompileController<'a> { - *self - } -} - -pub struct PhaseController<'a> { - pub stop: Compilation, - // If true then the compiler will try to run the callback even if the phase - // ends with an error. Note that this is not always possible. - pub run_callback_on_error: bool, - pub callback: Box, -} - -impl<'a> PhaseController<'a> { - pub fn basic() -> PhaseController<'a> { - PhaseController { - stop: Compilation::Continue, - run_callback_on_error: false, - callback: box |_| {}, - } - } -} - -/// State that is passed to a callback. What state is available depends on when -/// during compilation the callback is made. See the various constructor methods -/// (`state_*`) in the impl to see which data is provided for any given entry point. -pub struct CompileState<'a, 'tcx: 'a> { - pub input: &'a Input, - pub session: &'tcx Session, - pub krate: Option, - pub registry: Option>, - pub cstore: Option<&'tcx CStore>, - pub crate_name: Option<&'a str>, - pub output_filenames: Option<&'a OutputFilenames>, - pub out_dir: Option<&'a Path>, - pub out_file: Option<&'a Path>, - pub expanded_crate: Option<&'a ast::Crate>, - pub hir_crate: Option<&'a hir::Crate>, - pub hir_map: Option<&'a hir_map::Map<'tcx>>, - pub resolutions: Option<&'a Resolutions>, - pub tcx: Option>, -} - -impl<'a, 'tcx> CompileState<'a, 'tcx> { - fn empty(input: &'a Input, session: &'tcx Session, out_dir: &'a Option) -> Self { - CompileState { - input, - session, - out_dir: out_dir.as_ref().map(|s| &**s), - out_file: None, - krate: None, - registry: None, - cstore: None, - crate_name: None, - output_filenames: None, - expanded_crate: None, - hir_crate: None, - hir_map: None, - resolutions: None, - tcx: None, - } - } - - fn state_after_parse( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - krate: ast::Crate, - cstore: &'tcx CStore, - ) -> Self { - CompileState { - // Initialize the registry before moving `krate` - registry: Some(Registry::new(&session, krate.span)), - krate: Some(krate), - cstore: Some(cstore), - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } - - fn state_after_expand( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - cstore: &'tcx CStore, - expanded_crate: &'a ast::Crate, - crate_name: &'a str, - ) -> Self { - CompileState { - crate_name: Some(crate_name), - cstore: Some(cstore), - expanded_crate: Some(expanded_crate), - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } - - fn state_after_hir_lowering( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - cstore: &'tcx CStore, - hir_map: &'a hir_map::Map<'tcx>, - resolutions: &'a Resolutions, - krate: &'a ast::Crate, - hir_crate: &'a hir::Crate, - output_filenames: &'a OutputFilenames, - crate_name: &'a str, - ) -> Self { - CompileState { - crate_name: Some(crate_name), - cstore: Some(cstore), - hir_map: Some(hir_map), - resolutions: Some(resolutions), - expanded_crate: Some(krate), - hir_crate: Some(hir_crate), - output_filenames: Some(output_filenames), - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } - - fn state_after_analysis( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - krate: Option<&'a ast::Crate>, - hir_crate: &'a hir::Crate, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - crate_name: &'a str, - ) -> Self { - CompileState { - tcx: Some(tcx), - expanded_crate: krate, - hir_crate: Some(hir_crate), - crate_name: Some(crate_name), - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } - - fn state_when_compilation_done( - input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option, - out_file: &'a Option, - ) -> Self { - CompileState { - out_file: out_file.as_ref().map(|s| &**s), - ..CompileState::empty(input, session, out_dir) - } - } -} - -pub fn phase_1_parse_input<'a>( - control: &CompileController, - sess: &'a Session, - input: &Input, -) -> PResult<'a, ast::Crate> { - sess.diagnostic() - .set_continue_after_error(control.continue_parse_after_error); - hygiene::set_default_edition(sess.edition()); - - if sess.profile_queries() { - profile::begin(sess); - } - - sess.profiler(|p| p.start_activity(ProfileCategory::Parsing)); - let krate = time(sess, "parsing", || match *input { - Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), - Input::Str { - ref input, - ref name, - } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), - })?; - sess.profiler(|p| p.end_activity(ProfileCategory::Parsing)); - - sess.diagnostic().set_continue_after_error(true); - - if sess.opts.debugging_opts.ast_json_noexpand { - println!("{}", json::as_json(&krate)); - } - - if sess.opts.debugging_opts.input_stats { - println!( - "Lines of code: {}", - sess.source_map().count_lines() - ); - println!("Pre-expansion node count: {}", count_nodes(&krate)); - } - - if let Some(ref s) = sess.opts.debugging_opts.show_span { - syntax::show_span::run(sess.diagnostic(), s, &krate); - } - - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); - } - - Ok(krate) -} - -fn count_nodes(krate: &ast::Crate) -> usize { - let mut counter = NodeCounter::new(); - visit::walk_crate(&mut counter, krate); - counter.count -} - -// For continuing compilation after a parsed crate has been -// modified - -pub struct ExpansionResult { - pub expanded_crate: ast::Crate, - pub defs: hir_map::Definitions, - pub resolutions: Resolutions, - pub hir_forest: hir_map::Forest, -} - -pub struct InnerExpansionResult<'a> { - pub expanded_crate: ast::Crate, - pub resolver: Resolver<'a>, - pub hir_forest: hir_map::Forest, -} - -/// 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 phase_2_configure_and_expand( - sess: &Session, - cstore: &CStore, - krate: ast::Crate, - registry: Option, - crate_name: &str, - addl_plugins: Option>, - after_expand: F, -) -> Result -where - F: FnOnce(&ast::Crate) -> CompileResult, -{ - // 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 mut crate_loader = CrateLoader::new(sess, &cstore, &crate_name); - let resolver_arenas = Resolver::arenas(); - let result = phase_2_configure_and_expand_inner( - sess, - cstore, - krate, - registry, - crate_name, - addl_plugins, - &resolver_arenas, - &mut crate_loader, - after_expand, - ); - match result { - Ok(InnerExpansionResult { - expanded_crate, - resolver, - hir_forest, - }) => Ok(ExpansionResult { - expanded_crate, - defs: resolver.definitions, - hir_forest, - resolutions: Resolutions { - freevars: resolver.freevars, - export_map: resolver.export_map, - trait_map: resolver.trait_map, - glob_map: resolver.glob_map, - maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, - maybe_unused_extern_crates: resolver.maybe_unused_extern_crates, - extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { - (ident.name, entry.introduced_by_item) - }).collect(), - }, - }), - Err(x) => Err(x), - } -} - -/// Same as phase_2_configure_and_expand, but doesn't let you keep the resolver -/// around -pub fn phase_2_configure_and_expand_inner<'a, F>( - sess: &'a Session, - cstore: &'a CStore, - mut krate: ast::Crate, - registry: Option, - crate_name: &str, - addl_plugins: Option>, - resolver_arenas: &'a ResolverArenas<'a>, - crate_loader: &'a mut CrateLoader<'a>, - after_expand: F, -) -> Result, CompileIncomplete> -where - F: FnOnce(&ast::Crate) -> CompileResult, -{ - krate = time(sess, "attributes injection", || { - syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) - }); - - let (mut krate, features) = syntax::config::features( - krate, - &sess.parse_sess, - sess.edition(), - ); - // these need to be set "early" so that expansion sees `quote` if enabled. - sess.init_features(features); - - let crate_types = util::collect_crate_types(sess, &krate.attrs); - sess.crate_types.set(crate_types); - - let disambiguator = util::compute_crate_disambiguator(sess); - sess.crate_disambiguator.set(disambiguator); - rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); - - if sess.opts.incremental.is_some() { - time(sess, "garbage collect incremental cache directory", || { - if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { - warn!( - "Error while trying to garbage collect incremental \ - compilation cache directory: {}", - e - ); - } - }); - } - - // If necessary, compute the dependency graph (in the background). - let future_dep_graph = if sess.opts.build_dep_graph() { - Some(rustc_incremental::load_dep_graph(sess)) - } else { - None - }; - - time(sess, "recursion limit", || { - middle::recursion_limit::update_limits(sess, &krate); - }); - - krate = time(sess, "crate injection", || { - let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s); - syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition()) - }); - - let mut addl_plugins = Some(addl_plugins); - let registrars = time(sess, "plugin loading", || { - plugin::load::load_plugins( - sess, - &cstore, - &krate, - crate_name, - addl_plugins.take().unwrap(), - ) - }); - - let mut registry = registry.unwrap_or_else(|| Registry::new(sess, krate.span)); - - time(sess, "plugin registration", || { - if sess.features_untracked().rustc_diagnostic_macros { - registry.register_macro( - "__diagnostic_used", - diagnostics::plugin::expand_diagnostic_used, - ); - registry.register_macro( - "__register_diagnostic", - diagnostics::plugin::expand_register_diagnostic, - ); - registry.register_macro( - "__build_diagnostic_array", - diagnostics::plugin::expand_build_diagnostic_array, - ); - } - - for registrar in registrars { - registry.args_hidden = Some(registrar.args); - (registrar.fun)(&mut registry); - } - }); - - let Registry { - syntax_exts, - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - - sess.track_errors(|| { - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, false, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } - - for (name, (to, deprecated_name)) in lint_groups { - ls.register_group(Some(sess), true, name, deprecated_name, to); - } - - *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; - *sess.plugin_attributes.borrow_mut() = attributes.clone(); - })?; - - // Lint plugins are registered; now we can process command line flags. - if sess.opts.describe_lints { - super::describe_lints(&sess, &sess.lint_store.borrow(), true); - return Err(CompileIncomplete::Stopped); - } - - time(sess, "pre ast expansion lint checks", || { - lint::check_ast_crate( - sess, - &krate, - true, - rustc_lint::BuiltinCombinedPreExpansionLintPass::new()); - }); - - let mut resolver = Resolver::new( - sess, - cstore, - &krate, - crate_name, - crate_loader, - &resolver_arenas, - ); - syntax_ext::register_builtins(&mut resolver, syntax_exts); - - // Expand all macros - sess.profiler(|p| p.start_activity(ProfileCategory::Expansion)); - krate = time(sess, "expansion", || { - // Windows dlls do not have rpaths, so they don't know how to find their - // dependencies. It's up to us to tell the system where to find all the - // dependent dlls. Note that this uses cfg!(windows) as opposed to - // targ_cfg because syntax extensions are always loaded for the host - // compiler, not for the target. - // - // This is somewhat of an inherently racy operation, however, as - // multiple threads calling this function could possibly continue - // extending PATH far beyond what it should. To solve this for now we - // just don't add any new elements to PATH which are already there - // within PATH. This is basically a targeted fix at #17360 for rustdoc - // which runs rustc in parallel but has been seen (#33844) to cause - // problems with PATH becoming too long. - let mut old_path = OsString::new(); - if cfg!(windows) { - old_path = env::var_os("PATH").unwrap_or(old_path); - let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs(); - for path in env::split_paths(&old_path) { - if !new_path.contains(&path) { - new_path.push(path); - } - } - env::set_var( - "PATH", - &env::join_paths( - new_path - .iter() - .filter(|p| env::join_paths(iter::once(p)).is_ok()), - ).unwrap(), - ); - } - - // Create the config for macro expansion - let features = sess.features_untracked(); - let cfg = syntax::ext::expand::ExpansionConfig { - features: Some(&features), - recursion_limit: *sess.recursion_limit.get(), - trace_mac: sess.opts.debugging_opts.trace_macros, - should_test: sess.opts.test, - ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) - }; - - let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); - - // Expand macros now! - let krate = time(sess, "expand crate", || { - ecx.monotonic_expander().expand_crate(krate) - }); - - // The rest is error reporting - - time(sess, "check unused macros", || { - ecx.check_unused_macros(); - }); - - let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess - .missing_fragment_specifiers - .borrow() - .iter() - .cloned() - .collect(); - missing_fragment_specifiers.sort(); - - for span in missing_fragment_specifiers { - let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; - let msg = "missing fragment specifier"; - sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg); - } - if cfg!(windows) { - env::set_var("PATH", &old_path); - } - krate - }); - sess.profiler(|p| p.end_activity(ProfileCategory::Expansion)); - - time(sess, "maybe building test harness", || { - syntax::test::modify_for_testing( - &sess.parse_sess, - &mut resolver, - sess.opts.test, - &mut krate, - sess.diagnostic(), - &sess.features_untracked(), - ) - }); - - // If we're actually rustdoc then there's no need to actually compile - // anything, so switch everything to just looping - if sess.opts.actually_rustdoc { - util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate); - } - - let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || { - ast_validation::check_crate(sess, &krate) - }); - - // If we're in rustdoc we're always compiling as an rlib, but that'll trip a - // bunch of checks in the `modify` function below. For now just skip this - // step entirely if we're rustdoc as it's not too useful anyway. - if !sess.opts.actually_rustdoc { - krate = time(sess, "maybe creating a macro crate", || { - let crate_types = sess.crate_types.borrow(); - let num_crate_types = crate_types.len(); - let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro); - let is_test_crate = sess.opts.test; - syntax_ext::proc_macro_decls::modify( - &sess.parse_sess, - &mut resolver, - krate, - is_proc_macro_crate, - has_proc_macro_decls, - is_test_crate, - num_crate_types, - sess.diagnostic(), - ) - }); - } - - if has_global_allocator { - // Expand global allocators, which are treated as an in-tree proc macro - time(sess, "creating allocators", || { - allocator::expand::modify( - &sess.parse_sess, - &mut resolver, - &mut krate, - crate_name.to_string(), - sess.diagnostic(), - ) - }); - } - - // Done with macro expansion! - - after_expand(&krate)?; - - if sess.opts.debugging_opts.input_stats { - println!("Post-expansion node count: {}", count_nodes(&krate)); - } - - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); - } - - if sess.opts.debugging_opts.ast_json { - println!("{}", json::as_json(&krate)); - } - - time(sess, "name resolution", || { - resolver.resolve_crate(&krate); - }); - - // Needs to go *after* expansion to be able to check the results of macro expansion. - time(sess, "complete gated feature checking", || { - syntax::feature_gate::check_crate( - &krate, - &sess.parse_sess, - &sess.features_untracked(), - &attributes, - sess.opts.unstable_features, - ); - }); - - // Add all buffered lints from the `ParseSess` to the `Session`. - sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { - info!("{} parse sess buffered_lints", buffered_lints.len()); - for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) { - let lint = lint::Lint::from_parser_lint_id(lint_id); - sess.buffer_lint(lint, id, span, &msg); - } - }); - - // Lower ast -> hir. - // First, we need to collect the dep_graph. - let dep_graph = match future_dep_graph { - None => DepGraph::new_disabled(), - Some(future) => { - let (prev_graph, prev_work_products) = - time(sess, "blocked while dep-graph loading finishes", || { - future - .open() - .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { - message: format!("could not decode incremental cache: {:?}", e), - }) - .open(sess) - }); - DepGraph::new(prev_graph, prev_work_products) - } - }; - let hir_forest = time(sess, "lowering ast -> hir", || { - let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver); - - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_hir_stats(&hir_crate); - } - - hir_map::Forest::new(hir_crate, &dep_graph) - }); - - time(sess, "early lint checks", || { - lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new()) - }); - - // Discard hygiene data, which isn't required after lowering to HIR. - if !sess.opts.debugging_opts.keep_hygiene_data { - syntax::ext::hygiene::clear_markings(); - } - - Ok(InnerExpansionResult { - expanded_crate: krate, - resolver, - hir_forest, - }) -} - -pub fn default_provide(providers: &mut ty::query::Providers) { - rustc_interface::passes::provide(providers); - plugin::build::provide(providers); - hir::provide(providers); - borrowck::provide(providers); - mir::provide(providers); - reachable::provide(providers); - resolve_lifetime::provide(providers); - rustc_privacy::provide(providers); - typeck::provide(providers); - ty::provide(providers); - traits::provide(providers); - stability::provide(providers); - middle::intrinsicck::provide(providers); - middle::liveness::provide(providers); - reachable::provide(providers); - rustc_passes::provide(providers); - rustc_traits::provide(providers); - middle::region::provide(providers); - middle::entry::provide(providers); - cstore::provide(providers); - lint::provide(providers); -} - -pub fn default_provide_extern(providers: &mut ty::query::Providers) { - cstore::provide_extern(providers); -} - -/// Runs the resolution, type-checking, region checking and other -/// miscellaneous analysis passes on the crate. Return various -/// structures carrying the results of the analysis. -pub fn phase_3_run_analysis_passes<'tcx, F, R>( - codegen_backend: &dyn CodegenBackend, - control: &CompileController, - sess: &'tcx Session, - cstore: &'tcx CStore, - hir_map: hir_map::Map<'tcx>, - resolutions: Resolutions, - arenas: &'tcx mut AllArenas<'tcx>, - name: &str, - output_filenames: &OutputFilenames, - f: F, -) -> R -where - F: for<'a> FnOnce( - TyCtxt<'a, 'tcx, 'tcx>, - mpsc::Receiver>, - CompileResult, - ) -> R, -{ - let query_result_on_disk_cache = time(sess, "load query result cache", || { - rustc_incremental::load_query_result_cache(sess) - }); - - let mut local_providers = ty::query::Providers::default(); - default_provide(&mut local_providers); - codegen_backend.provide(&mut local_providers); - (control.provide)(&mut local_providers); - - let mut extern_providers = local_providers; - default_provide_extern(&mut extern_providers); - codegen_backend.provide_extern(&mut extern_providers); - (control.provide_extern)(&mut extern_providers); - - let (tx, rx) = mpsc::channel(); - - TyCtxt::create_and_enter( - sess, - cstore, - local_providers, - extern_providers, - arenas, - resolutions, - hir_map, - query_result_on_disk_cache, - name, - tx, - output_filenames, - |tcx| { - // Do some initialization of the DepGraph that can only be done with the - // tcx available. - time(sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx)); - - tcx.analysis(LOCAL_CRATE).ok(); - - f(tcx, rx, tcx.sess.compile_status()) - }, - ) -} - -/// Runs the codegen backend, after which the AST and analysis can -/// be discarded. -pub fn phase_4_codegen<'a, 'tcx>( - codegen_backend: &dyn CodegenBackend, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver>, -) -> Box { - time(tcx.sess, "resolving dependency formats", || { - ::rustc::middle::dependency_format::calculate(tcx) - }); - - tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen)); - let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx)); - tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen)); - if tcx.sess.profile_queries() { - profile::dump(&tcx.sess, "profile_queries".to_string()) - } - - codegen -} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 656d8e463dbd0..2b75a607f1681 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -51,45 +51,42 @@ extern crate syntax; extern crate syntax_ext; extern crate syntax_pos; -use driver::CompileController; use pretty::{PpMode, UserIdentifiedItem}; +//use rustc_resolve as resolve; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; -use rustc_data_structures::sync::{self, Lrc, Ordering::SeqCst}; -use rustc_data_structures::OnDrop; -use rustc::session::{self, config, Session, build_session, CompileResult, DiagnosticOutput}; -use rustc::session::CompileIncomplete; -use rustc::session::config::{Input, PrintRequest, ErrorOutputType}; +use rustc::session::{config, Session, DiagnosticOutput}; +use rustc::session::config::{Input, PrintRequest, ErrorOutputType, OutputType}; use rustc::session::config::nightly_options; use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::util::common::{time, ErrorReported, install_panic_hook}; use rustc_metadata::locator; use rustc_metadata::cstore::CStore; -use rustc::util::common::{time, ErrorReported}; use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_interface::util::{self, get_codegen_sysroot}; +use rustc_interface::interface; +use rustc_interface::util::get_codegen_sysroot; +use rustc_data_structures::sync::SeqCst; use serialize::json::ToJson; -use std::any::Any; use std::borrow::Cow; use std::cmp::max; use std::default::Default; use std::env; -use std::error::Error; use std::ffi::OsString; -use std::fmt::{self, Display}; use std::io::{self, Read, Write}; -use std::panic; +use std::panic::{self, catch_unwind}; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; -use std::thread; +use std::mem; use syntax::ast; -use syntax::source_map::{SourceMap, FileLoader, RealFileLoader}; +use syntax::source_map::FileLoader; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; @@ -97,14 +94,13 @@ use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; #[cfg(test)] mod test; -pub mod driver; pub mod pretty; /// Exit status code used for successful compilation and help output. -pub const EXIT_SUCCESS: isize = 0; +pub const EXIT_SUCCESS: i32 = 0; /// Exit status code used for compilation failures and invalid flags. -pub const EXIT_FAILURE: isize = 1; +pub const EXIT_FAILURE: i32 = 1; const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ md#bug-reports"; @@ -115,172 +111,290 @@ const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"]; -pub fn abort_on_err(result: Result, sess: &Session) -> T { +pub fn source_name(input: &Input) -> FileName { + match *input { + Input::File(ref ifile) => ifile.clone().into(), + Input::Str { ref name, .. } => name.clone(), + } +} + +pub fn abort_on_err(result: Result, sess: &Session) -> T { match result { - Err(CompileIncomplete::Errored(ErrorReported)) => { + Err(..) => { sess.abort_if_errors(); panic!("error reported but abort_if_errors didn't abort???"); } - Err(CompileIncomplete::Stopped) => { - sess.fatal("compilation terminated"); - } Ok(x) => x, } } -pub fn run(run_compiler: F) -> isize - where F: FnOnce() -> (CompileResult, Option) + Send + 'static -{ - let result = monitor(move || { - syntax::with_globals(|| { - let (result, session) = run_compiler(); - if let Err(CompileIncomplete::Errored(_)) = result { - match session { - Some(sess) => { - sess.abort_if_errors(); - panic!("error reported but abort_if_errors didn't abort???"); - } - None => { - let emitter = - errors::emitter::EmitterWriter::stderr( - errors::ColorConfig::Auto, - None, - true, - false - ); - let handler = errors::Handler::with_emitter(true, None, Box::new(emitter)); - handler.emit(&MultiSpan::new(), - "aborting due to previous error(s)", - errors::Level::Fatal); - panic::resume_unwind(Box::new(errors::FatalErrorMarker)); - } - } - } - }); - }); - - match result { - Ok(()) => EXIT_SUCCESS, - Err(_) => EXIT_FAILURE, +pub trait Callbacks { + /// Called before creating the compiler instance + fn config(&mut self, _config: &mut interface::Config) {} + /// Called after parsing and returns true to continue execution + fn after_parsing(&mut self, _compiler: &interface::Compiler) -> bool { + true + } + /// Called after analysis and returns true to continue execution + fn after_analysis(&mut self, _compiler: &interface::Compiler) -> bool { + true } } +pub struct DefaultCallbacks; + +impl Callbacks for DefaultCallbacks {} + // Parse args and run the compiler. This is the primary entry point for rustc. // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. -pub fn run_compiler<'a>(args: &[String], - callbacks: Box + sync::Send + 'a>, - file_loader: Option>, - emitter_dest: Option>) - -> (CompileResult, Option) -{ +pub fn run_compiler( + args: &[String], + callbacks: &mut (dyn Callbacks + Send), + file_loader: Option>, + emitter: Option> +) -> interface::Result<()> { + let diagnostic_output = emitter.map(|emitter| DiagnosticOutput::Raw(emitter)) + .unwrap_or(DiagnosticOutput::Default); let matches = match handle_options(args) { Some(matches) => matches, - None => return (Ok(()), None), + None => return Ok(()), }; - let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); - - driver::spawn_thread_pool(sopts, |sopts| { - run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest) - }) -} + install_panic_hook(); -fn run_compiler_with_pool<'a>( - matches: getopts::Matches, - sopts: config::Options, - cfg: ast::CrateConfig, - mut callbacks: Box + sync::Send + 'a>, - file_loader: Option>, - emitter_dest: Option> -) -> (CompileResult, Option) { - macro_rules! do_or_return {($expr: expr, $sess: expr) => { - match $expr { - Compilation::Stop => return (Ok(()), $sess), - Compilation::Continue => {} - } - }} + let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); - let descriptions = diagnostics_registry(); + let mut dummy_config = |sopts, cfg, diagnostic_output| { + let mut config = interface::Config { + opts: sopts, + crate_cfg: cfg, + input: Input::File(PathBuf::new()), + input_path: None, + output_file: None, + output_dir: None, + file_loader: None, + diagnostic_output, + stderr: None, + crate_name: None, + lint_caps: Default::default(), + }; + callbacks.config(&mut config); + config + }; - do_or_return!(callbacks.early_callback(&matches, - &sopts, - &cfg, - &descriptions, - sopts.error_format), - None); + if let Some(ref code) = matches.opt_str("explain") { + handle_explain(code, sopts.error_format); + return Ok(()); + } let (odir, ofile) = make_output(&matches); let (input, input_file_path, input_err) = match make_input(&matches.free) { - Some((input, input_file_path, input_err)) => { - let (input, input_file_path) = callbacks.some_input(input, input_file_path); - (input, input_file_path, input_err) - }, - None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) { - Some((input, input_file_path)) => (input, input_file_path, None), - None => return (Ok(()), None), - }, - }; + Some(v) => v, + None => { + match matches.free.len() { + 0 => { + let config = dummy_config(sopts, cfg, diagnostic_output); + interface::run_compiler(config, |compiler| { + let sopts = &compiler.session().opts; + if sopts.describe_lints { + describe_lints( + compiler.session(), + &*compiler.session().lint_store.borrow(), + false + ); + return; + } + let should_stop = RustcDefaultCalls::print_crate_info( + &***compiler.codegen_backend(), + compiler.session(), + None, + &odir, + &ofile + ); - let loader = file_loader.unwrap_or(box RealFileLoader); - let source_map = Lrc::new(SourceMap::with_file_loader(loader, sopts.file_path_mapping())); - let mut sess = session::build_session_with_source_map( - sopts, - input_file_path.clone(), - descriptions, - source_map, - emitter_dest.map(|e| DiagnosticOutput::Raw(e)).unwrap_or(DiagnosticOutput::Default), - Default::default(), - ); + if should_stop == Compilation::Stop { + return; + } + early_error(sopts.error_format, "no input filename given") + }); + return Ok(()); + } + 1 => panic!("make_input should have provided valid inputs"), + _ => early_error(sopts.error_format, &format!( + "multiple input filenames provided (first two filenames are `{}` and `{}`)", + matches.free[0], + matches.free[1], + )), + } + } + }; if let Some(err) = input_err { // Immediately stop compilation if there was an issue reading // the input (for example if the input stream is not UTF-8). - sess.err(&err.to_string()); - return (Err(CompileIncomplete::Stopped), Some(sess)); + interface::run_compiler(dummy_config(sopts, cfg, diagnostic_output), |compiler| { + compiler.session().err(&err.to_string()); + }); + return Err(ErrorReported); } - let codegen_backend = util::get_codegen_backend(&sess); + let mut config = interface::Config { + opts: sopts, + crate_cfg: cfg, + input, + input_path: input_file_path, + output_file: ofile, + output_dir: odir, + file_loader, + diagnostic_output, + stderr: None, + crate_name: None, + lint_caps: Default::default(), + }; + + callbacks.config(&mut config); + + interface::run_compiler(config, |compiler| { + let sess = compiler.session(); + let should_stop = RustcDefaultCalls::print_crate_info( + &***compiler.codegen_backend(), + sess, + Some(compiler.input()), + compiler.output_dir(), + compiler.output_file(), + ).and_then(|| RustcDefaultCalls::list_metadata( + sess, + compiler.cstore(), + &matches, + compiler.input() + )); + + if should_stop == Compilation::Stop { + return sess.compile_status(); + } + + let pretty_info = parse_pretty(sess, &matches); + + compiler.parse()?; - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + if let Some((ppm, opt_uii)) = pretty_info { + 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 expanded_crate = compiler.expansion()?.take().0; + pretty::print_after_hir_lowering( + tcx, + compiler.input(), + &expanded_crate, + ppm, + opt_uii.clone(), + compiler.output_file().as_ref().map(|p| &**p), + ); + Ok(()) + })?; + return sess.compile_status(); + } else { + let mut krate = compiler.parse()?.take(); + pretty::visit_crate(sess, &mut krate, ppm); + pretty::print_after_parsing( + sess, + &compiler.input(), + &krate, + ppm, + compiler.output_file().as_ref().map(|p| &**p), + ); + return sess.compile_status(); + } + } - let mut cfg = config::build_configuration(&sess, cfg); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; + if !callbacks.after_parsing(compiler) { + return sess.compile_status(); + } - let result = { - let plugins = sess.opts.debugging_opts.extra_plugins.clone(); + if sess.opts.debugging_opts.parse_only || + sess.opts.debugging_opts.show_span.is_some() || + sess.opts.debugging_opts.ast_json_noexpand { + return sess.compile_status(); + } - let cstore = CStore::new(codegen_backend.metadata_loader()); + compiler.register_plugins()?; - do_or_return!(callbacks.late_callback(&*codegen_backend, - &matches, - &sess, - &cstore, - &input, - &odir, - &ofile), Some(sess)); + // Lint plugins are registered; now we can process command line flags. + if sess.opts.describe_lints { + describe_lints(&sess, &sess.lint_store.borrow(), true); + return sess.compile_status(); + } - let _sess_abort_error = OnDrop(|| sess.diagnostic().print_error_count()); + compiler.prepare_outputs()?; - let control = callbacks.build_controller(&sess, &matches); + if sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1 + { + return sess.compile_status(); + } - driver::compile_input(codegen_backend, - &sess, - &cstore, - &input_file_path, - &input, - &odir, - &ofile, - Some(plugins), - &control) - }; + compiler.global_ctxt()?; - if sess.opts.debugging_opts.self_profile { - sess.profiler(|p| p.dump_raw_events(&sess.opts)); - } + if sess.opts.debugging_opts.no_analysis || + sess.opts.debugging_opts.ast_json { + return sess.compile_status(); + } + + if sess.opts.debugging_opts.save_analysis { + let expanded_crate = compiler.expansion()?.take().0; + + let crate_name = compiler.crate_name()?.peek().clone(); + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + let result = tcx.analysis(LOCAL_CRATE); + + time(sess, "save analysis", || { + // FIXME: Should this run even with analysis errors? + save::process_crate( + tcx, + &expanded_crate, + &crate_name, + &compiler.input(), + None, + DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), &crate_name) + ) + }); + + result + })?; + } else { + // Drop AST after creating GlobalCtxt to free memory + mem::drop(compiler.expansion()?.take()); + } + compiler.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?; + + if !callbacks.after_analysis(compiler) { + return sess.compile_status(); + } + + compiler.ongoing_codegen()?; + + // Drop GlobalCtxt after starting codegen to free memory + mem::drop(compiler.global_ctxt()?.take()); + + if sess.opts.debugging_opts.print_type_sizes { + sess.code_stats.borrow().print_type_sizes(); + } + + compiler.link()?; + + if sess.opts.debugging_opts.perf_stats { + sess.print_perf_stats(); + } + + if sess.print_fuel_crate.is_some() { + eprintln!("Fuel used by {}: {}", + sess.print_fuel_crate.as_ref().unwrap(), + sess.print_fuel.load(SeqCst)); + } - (result, Some(sess)) + Ok(()) + }) } #[cfg(unix)] @@ -363,72 +477,6 @@ impl Compilation { } } -/// A trait for customizing the compilation process. Offers a number of hooks for -/// executing custom code or customizing input. -pub trait CompilerCalls<'a> { - /// Hook for a callback early in the process of handling arguments. This will - /// be called straight after options have been parsed but before anything - /// else (e.g., selecting input and output). - fn early_callback(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &errors::registry::Registry, - _: ErrorOutputType) - -> Compilation { - Compilation::Continue - } - - /// Hook for a callback late in the process of handling arguments. This will - /// be called just before actual compilation starts (and before build_controller - /// is called), after all arguments etc. have been completely handled. - fn late_callback(&mut self, - _: &dyn CodegenBackend, - _: &getopts::Matches, - _: &Session, - _: &CStore, - _: &Input, - _: &Option, - _: &Option) - -> Compilation { - Compilation::Continue - } - - /// Called after we extract the input from the arguments. Gives the implementer - /// an opportunity to change the inputs or to add some custom input handling. - /// The default behaviour is to simply pass through the inputs. - fn some_input(&mut self, - input: Input, - input_path: Option) - -> (Input, Option) { - (input, input_path) - } - - /// Called after we extract the input from the arguments if there is no valid - /// input. Gives the implementer an opportunity to supply alternate input (by - /// returning a Some value) or to add custom behaviour for this error such as - /// emitting error messages. Returning None will cause compilation to stop - /// at this point. - fn no_input(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &Option, - _: &Option, - _: &errors::registry::Registry) - -> Option<(Input, Option)> { - None - } - - // Create a CompilController struct for controlling the behaviour of - // compilation. - fn build_controller( - self: Box, - _: &Session, - _: &getopts::Matches - ) -> CompileController<'a>; -} - /// CompilerCalls instance for a regular rustc build. #[derive(Copy, Clone)] pub struct RustcDefaultCalls; @@ -532,178 +580,6 @@ fn show_content_with_pager(content: &String) { } } -impl<'a> CompilerCalls<'a> for RustcDefaultCalls { - fn early_callback(&mut self, - matches: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &errors::registry::Registry, - output: ErrorOutputType) - -> Compilation { - if let Some(ref code) = matches.opt_str("explain") { - handle_explain(code, output); - return Compilation::Stop; - } - - Compilation::Continue - } - - fn no_input(&mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &errors::registry::Registry) - -> Option<(Input, Option)> { - match matches.free.len() { - 0 => { - let mut sess = build_session(sopts.clone(), - None, - descriptions.clone()); - if sopts.describe_lints { - let mut ls = lint::LintStore::new(); - rustc_lint::register_builtins(&mut ls, Some(&sess)); - describe_lints(&sess, &ls, false); - return None; - } - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let mut cfg = config::build_configuration(&sess, cfg.clone()); - let codegen_backend = util::get_codegen_backend(&sess); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; - let should_stop = RustcDefaultCalls::print_crate_info( - &*codegen_backend, - &sess, - None, - odir, - ofile - ); - - if should_stop == Compilation::Stop { - return None; - } - early_error(sopts.error_format, "no input filename given"); - } - 1 => panic!("make_input should have provided valid inputs"), - _ => - early_error( - sopts.error_format, - &format!( - "multiple input filenames provided (first two filenames are `{}` and `{}`)", - matches.free[0], - matches.free[1], - ), - ) - } - } - - fn late_callback(&mut self, - codegen_backend: &dyn CodegenBackend, - matches: &getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option, - ofile: &Option) - -> Compilation { - RustcDefaultCalls::print_crate_info(codegen_backend, sess, Some(input), odir, ofile) - .and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input)) - } - - fn build_controller(self: Box, - sess: &Session, - matches: &getopts::Matches) - -> CompileController<'a> { - let mut control = CompileController::basic(); - - control.keep_ast = sess.opts.debugging_opts.keep_ast; - control.continue_parse_after_error = sess.opts.debugging_opts.continue_parse_after_error; - - if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) { - if ppm.needs_ast_map(&opt_uii) { - control.after_hir_lowering.stop = Compilation::Stop; - - control.after_parse.callback = box move |state| { - let mut krate = state.krate.take().unwrap(); - pretty::visit_crate(state.session, &mut krate, ppm); - state.krate = Some(krate); - }; - control.after_hir_lowering.callback = box move |state| { - pretty::print_after_hir_lowering(state.session, - state.cstore.unwrap(), - state.hir_map.unwrap(), - state.resolutions.unwrap(), - state.input, - &state.expanded_crate.take().unwrap(), - state.crate_name.unwrap(), - ppm, - state.output_filenames.unwrap(), - opt_uii.clone(), - state.out_file); - }; - } else { - control.after_parse.stop = Compilation::Stop; - - control.after_parse.callback = box move |state| { - let mut krate = state.krate.take().unwrap(); - pretty::visit_crate(state.session, &mut krate, ppm); - pretty::print_after_parsing(state.session, - state.input, - &krate, - ppm, - state.out_file); - }; - } - - return control; - } - - if sess.opts.debugging_opts.parse_only || - sess.opts.debugging_opts.show_span.is_some() || - sess.opts.debugging_opts.ast_json_noexpand { - control.after_parse.stop = Compilation::Stop; - } - - if sess.opts.debugging_opts.no_analysis || - sess.opts.debugging_opts.ast_json { - control.after_hir_lowering.stop = Compilation::Stop; - } - - if sess.opts.debugging_opts.save_analysis { - enable_save_analysis(&mut control); - } - - if sess.print_fuel_crate.is_some() { - let old_callback = control.compilation_done.callback; - control.compilation_done.callback = box move |state| { - old_callback(state); - let sess = state.session; - eprintln!("Fuel used by {}: {}", - sess.print_fuel_crate.as_ref().unwrap(), - sess.print_fuel.load(SeqCst)); - } - } - control - } -} - -pub fn enable_save_analysis(control: &mut CompileController) { - control.keep_ast = true; - control.after_analysis.callback = box |state| { - time(state.session, "save analysis", || { - save::process_crate(state.tcx.unwrap(), - state.expanded_crate.unwrap(), - state.crate_name.unwrap(), - state.input, - None, - DumpHandler::new(state.out_dir, - state.crate_name.unwrap())) - }); - }; - control.after_analysis.run_callback_on_error = true; -} - impl RustcDefaultCalls { pub fn list_metadata(sess: &Session, cstore: &CStore, @@ -1199,49 +1075,6 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec(name: String, f: F) -> Result> - where F: FnOnce() -> R + Send + 'static, - R: Send + 'static, -{ - // We need a thread for soundness of thread local storage in rustc. For debugging purposes - // we allow an escape hatch where everything runs on the main thread. - if env::var_os("RUSTC_UNSTABLE_NO_MAIN_THREAD").is_none() { - let mut cfg = thread::Builder::new().name(name); - - // If the env is trying to override the stack size then *don't* set it explicitly. - // The libstd thread impl will fetch the `RUST_MIN_STACK` env var itself. - if env::var_os("RUST_MIN_STACK").is_none() { - cfg = cfg.stack_size(STACK_SIZE); - } - - let thread = cfg.spawn(f); - thread.unwrap().join() - } else { - let f = panic::AssertUnwindSafe(f); - panic::catch_unwind(f) - } -} - -/// Runs `f` in a suitable thread for running `rustc`; returns a -/// `Result` with either the return value of `f` or -- if a panic -/// occurs -- the panic value. -pub fn in_rustc_thread(f: F) -> Result> - where F: FnOnce() -> R + Send + 'static, - R: Send + 'static, -{ - in_named_rustc_thread("rustc".to_string(), f) -} - /// Gets a list of extra command-line flags provided by the user, as strings. /// /// This function is used during ICEs to show more information useful for @@ -1296,28 +1129,15 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> { } } -#[derive(Debug)] -pub struct CompilationFailure; - -impl Error for CompilationFailure {} - -impl Display for CompilationFailure { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "compilation had errors") - } -} - /// Runs a procedure which will detect panics in the compiler and print nicer /// error messages rather than just failing the test. /// /// The diagnostic emitter yielded to the procedure should be used for reporting /// errors of the compiler. -pub fn monitor(f: F) -> Result<(), CompilationFailure> { - in_rustc_thread(move || { - f() - }).map_err(|value| { +pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result { + catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { if value.is::() { - CompilationFailure + ErrorReported } else { // Thread panicked without emitting a fatal diagnostic eprintln!(""); @@ -1364,25 +1184,6 @@ pub fn monitor(f: F) -> Result<(), CompilationFail }) } -pub fn diagnostics_registry() -> errors::registry::Registry { - use errors::registry::Registry; - - let mut all_errors = Vec::new(); - all_errors.extend_from_slice(&rustc::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); - // FIXME: need to figure out a way to get these back in here - // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics()); - all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_mir::DIAGNOSTICS); - all_errors.extend_from_slice(&syntax::DIAGNOSTICS); - - Registry::new(&all_errors) -} - /// This allows tools to enable rust logging without having to magically match rustc's /// log crate version pub fn init_rustc_env_logger() { @@ -1391,17 +1192,17 @@ pub fn init_rustc_env_logger() { pub fn main() { init_rustc_env_logger(); - let result = run(|| { + let result = report_ices_to_stderr_if_any(|| { let args = env::args_os().enumerate() .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { early_error(ErrorOutputType::default(), &format!("Argument {} is not valid Unicode: {:?}", i, arg)) })) .collect::>(); - run_compiler(&args, - Box::new(RustcDefaultCalls), - None, - None) + run_compiler(&args, &mut DefaultCallbacks, None, None) + }).and_then(|result| result); + process::exit(match result { + Ok(_) => EXIT_SUCCESS, + Err(_) => EXIT_FAILURE, }); - process::exit(result as i32); } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 1750aa62dd5e0..3182b2ce30c6d 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -6,13 +6,14 @@ use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::map::blocks; use rustc::hir::print as pprust_hir; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::session::Session; -use rustc::session::config::{Input, OutputFilenames}; -use rustc::ty::{self, TyCtxt, Resolutions, AllArenas}; -use rustc_interface::util; +use rustc::session::config::Input; +use rustc::ty::{self, TyCtxt}; +use rustc::util::common::ErrorReported; +use rustc_interface::util::ReplaceBodyWithLoop; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; -use rustc_metadata::cstore::CStore; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; use syntax::ast; @@ -35,7 +36,8 @@ pub use self::PpSourceMode::*; pub use self::PpMode::*; use self::NodesMatchingUII::*; use abort_on_err; -use driver; + +use source_name; #[derive(Copy, Clone, PartialEq, Debug)] pub enum PpSourceMode { @@ -154,7 +156,7 @@ impl PpSourceMode { /// Constructs a `PrinterSupport` object and passes it to `f`. fn call_with_pp_support<'tcx, A, F>(&self, sess: &'tcx Session, - hir_map: Option<&hir_map::Map<'tcx>>, + tcx: Option>, f: F) -> A where F: FnOnce(&dyn PrinterSupport) -> A @@ -163,7 +165,7 @@ impl PpSourceMode { PpmNormal | PpmEveryBodyLoops | PpmExpanded => { let annotation = NoAnn { sess, - hir_map: hir_map.map(|m| m.clone()), + tcx, }; f(&annotation) } @@ -171,7 +173,7 @@ impl PpSourceMode { PpmIdentified | PpmExpandedIdentified => { let annotation = IdentifiedAnnotation { sess, - hir_map: hir_map.map(|m| m.clone()), + tcx, }; f(&annotation) } @@ -186,12 +188,7 @@ impl PpSourceMode { } fn call_with_pp_support_hir<'tcx, A, F>( &self, - sess: &'tcx Session, - cstore: &'tcx CStore, - hir_map: &hir_map::Map<'tcx>, - resolutions: &Resolutions, - output_filenames: &OutputFilenames, - id: &str, + tcx: TyCtxt<'tcx, 'tcx, 'tcx>, f: F ) -> A where F: FnOnce(&dyn HirPrinterSupport, &hir::Crate) -> A @@ -199,42 +196,29 @@ impl PpSourceMode { match *self { PpmNormal => { let annotation = NoAnn { - sess, - hir_map: Some(hir_map.clone()), + sess: tcx.sess, + tcx: Some(tcx), }; - f(&annotation, hir_map.forest.krate()) + f(&annotation, tcx.hir().forest.krate()) } PpmIdentified => { let annotation = IdentifiedAnnotation { - sess, - hir_map: Some(hir_map.clone()), + sess: tcx.sess, + tcx: Some(tcx), }; - f(&annotation, hir_map.forest.krate()) + f(&annotation, tcx.hir().forest.krate()) } PpmTyped => { - let control = &driver::CompileController::basic(); - let codegen_backend = util::get_codegen_backend(sess); - let mut arenas = AllArenas::new(); - driver::phase_3_run_analysis_passes(&*codegen_backend, - control, - sess, - cstore, - hir_map.clone(), - resolutions.clone(), - &mut arenas, - id, - output_filenames, - |tcx, _, result| { - abort_on_err(result, tcx.sess); - let empty_tables = ty::TypeckTables::empty(None); - let annotation = TypedAnnotation { - tcx, - tables: Cell::new(&empty_tables) - }; - tcx.dep_graph.with_ignore(|| { - f(&annotation, hir_map.forest.krate()) - }) + abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess); + + let empty_tables = ty::TypeckTables::empty(None); + let annotation = TypedAnnotation { + tcx, + tables: Cell::new(&empty_tables) + }; + tcx.dep_graph.with_ignore(|| { + f(&annotation, tcx.hir().forest.krate()) }) } _ => panic!("Should use call_with_pp_support"), @@ -283,7 +267,7 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { struct NoAnn<'hir> { sess: &'hir Session, - hir_map: Option>, + tcx: Option>, } impl<'hir> PrinterSupport for NoAnn<'hir> { @@ -302,7 +286,7 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { } fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { - self.hir_map.as_ref() + self.tcx.map(|tcx| tcx.hir()) } fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { @@ -314,8 +298,8 @@ impl<'hir> pprust::PpAnn for NoAnn<'hir> {} impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) -> io::Result<()> { - if let Some(ref map) = self.hir_map { - pprust_hir::PpAnn::nested(map, state, nested) + if let Some(tcx) = self.tcx { + pprust_hir::PpAnn::nested(tcx.hir(), state, nested) } else { Ok(()) } @@ -324,7 +308,7 @@ impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { struct IdentifiedAnnotation<'hir> { sess: &'hir Session, - hir_map: Option>, + tcx: Option>, } impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { @@ -380,7 +364,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { } fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { - self.hir_map.as_ref() + self.tcx.map(|tcx| tcx.hir()) } fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { @@ -391,8 +375,8 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) -> io::Result<()> { - if let Some(ref map) = self.hir_map { - pprust_hir::PpAnn::nested(map, state, nested) + if let Some(ref tcx) = self.tcx { + pprust_hir::PpAnn::nested(tcx.hir(), state, nested) } else { Ok(()) } @@ -691,12 +675,12 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) { if let PpmSource(PpmEveryBodyLoops) = ppm { - util::ReplaceBodyWithLoop::new(sess).visit_crate(krate); + ReplaceBodyWithLoop::new(sess).visit_crate(krate); } } fn get_source(input: &Input, sess: &Session) -> (Vec, FileName) { - let src_name = input.source_name(); + let src_name = source_name(input); let src = sess.source_map() .get_source_file(&src_name) .unwrap() @@ -752,31 +736,24 @@ pub fn print_after_parsing(sess: &Session, write_output(out, ofile); } -pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'tcx CStore, - hir_map: &hir_map::Map<'tcx>, - resolutions: &Resolutions, - input: &Input, - krate: &ast::Crate, - crate_name: &str, - ppm: PpMode, - output_filenames: &OutputFilenames, - opt_uii: Option, - ofile: Option<&Path>) { +pub fn print_after_hir_lowering<'tcx>( + tcx: TyCtxt<'tcx, 'tcx, 'tcx>, + input: &Input, + krate: &ast::Crate, + ppm: PpMode, + opt_uii: Option, + ofile: Option<&Path>) { if ppm.needs_analysis() { - print_with_analysis(sess, - cstore, - hir_map, - resolutions, - crate_name, - output_filenames, - ppm, - opt_uii, - ofile); + abort_on_err(print_with_analysis( + tcx, + ppm, + opt_uii, + ofile + ), tcx.sess); return; } - let (src, src_name) = get_source(input, sess); + let (src, src_name) = get_source(input, tcx.sess); let mut rdr = &src[..]; let mut out = Vec::new(); @@ -785,7 +762,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmSource(s), _) => { // Silently ignores an identified node. let out: &mut dyn Write = &mut out; - s.call_with_pp_support(sess, Some(hir_map), move |annotation| { + s.call_with_pp_support(tcx.sess, Some(tcx), move |annotation| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust::print_crate(sess.source_map(), @@ -801,13 +778,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmHir(s), None) => { let out: &mut dyn Write = &mut out; - s.call_with_pp_support_hir(sess, - cstore, - hir_map, - resolutions, - output_filenames, - crate_name, - move |annotation, krate| { + s.call_with_pp_support_hir(tcx, move |annotation, krate| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust_hir::print_crate(sess.source_map(), @@ -823,13 +794,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmHirTree(s), None) => { let out: &mut dyn Write = &mut out; - s.call_with_pp_support_hir(sess, - cstore, - hir_map, - resolutions, - output_filenames, - crate_name, - move |_annotation, krate| { + s.call_with_pp_support_hir(tcx, move |_annotation, krate| { debug!("pretty printing source code {:?}", s); write!(out, "{:#?}", krate) }) @@ -837,13 +802,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmHir(s), Some(uii)) => { let out: &mut dyn Write = &mut out; - s.call_with_pp_support_hir(sess, - cstore, - hir_map, - resolutions, - output_filenames, - crate_name, - move |annotation, _| { + s.call_with_pp_support_hir(tcx, move |annotation, _| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); let hir_map = annotation.hir_map().expect("-Z unpretty missing HIR map"); @@ -869,16 +828,10 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, (PpmHirTree(s), Some(uii)) => { let out: &mut dyn Write = &mut out; - s.call_with_pp_support_hir(sess, - cstore, - hir_map, - resolutions, - output_filenames, - crate_name, - move |_annotation, _krate| { + s.call_with_pp_support_hir(tcx, move |_annotation, _krate| { debug!("pretty printing source code {:?}", s); - for node_id in uii.all_matching_node_ids(hir_map) { - let node = hir_map.get(node_id); + for node_id in uii.all_matching_node_ids(tcx.hir()) { + let node = tcx.hir().get(node_id); write!(out, "{:#?}", node)?; } Ok(()) @@ -896,18 +849,15 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, // analysis is performed. However, we want to call `phase_3_run_analysis_passes` // with a different callback than the standard driver, so that isn't easy. // Instead, we call that function ourselves. -fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'a CStore, - hir_map: &hir_map::Map<'tcx>, - resolutions: &Resolutions, - crate_name: &str, - output_filenames: &OutputFilenames, - ppm: PpMode, - uii: Option, - ofile: Option<&Path>) { +fn print_with_analysis<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + ppm: PpMode, + uii: Option, + ofile: Option<&Path> +) -> Result<(), ErrorReported> { let nodeid = if let Some(uii) = uii { debug!("pretty printing for {:?}", uii); - Some(uii.to_one_node_id("-Z unpretty", sess, &hir_map)) + Some(uii.to_one_node_id("-Z unpretty", tcx.sess, tcx.hir())) } else { debug!("pretty printing for whole crate"); None @@ -915,66 +865,57 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, let mut out = Vec::new(); - let control = &driver::CompileController::basic(); - let codegen_backend = util::get_codegen_backend(sess); - let mut arenas = AllArenas::new(); - driver::phase_3_run_analysis_passes(&*codegen_backend, - control, - sess, - cstore, - hir_map.clone(), - resolutions.clone(), - &mut arenas, - crate_name, - output_filenames, - |tcx, _, result| { - abort_on_err(result, tcx.sess); - match ppm { - PpmMir | PpmMirCFG => { - if let Some(nodeid) = nodeid { - let def_id = tcx.hir().local_def_id(nodeid); - match ppm { - PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out), - PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out), - _ => unreachable!(), - }?; - } else { - match ppm { - PpmMir => write_mir_pretty(tcx, None, &mut out), - PpmMirCFG => write_mir_graphviz(tcx, None, &mut out), - _ => unreachable!(), - }?; - } - Ok(()) + tcx.analysis(LOCAL_CRATE)?; + + let mut print = || match ppm { + PpmMir | PpmMirCFG => { + if let Some(nodeid) = nodeid { + let def_id = tcx.hir().local_def_id(nodeid); + match ppm { + PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out), + PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out), + _ => unreachable!(), + }?; + } else { + match ppm { + PpmMir => write_mir_pretty(tcx, None, &mut out), + PpmMirCFG => write_mir_graphviz(tcx, None, &mut out), + _ => unreachable!(), + }?; } - PpmFlowGraph(mode) => { - let nodeid = - nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \ - suffix (b::c::d)"); - let node = tcx.hir().find(nodeid).unwrap_or_else(|| { - tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) - }); + Ok(()) + } + PpmFlowGraph(mode) => { + let nodeid = + nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \ + suffix (b::c::d)"); + let node = tcx.hir().find(nodeid).unwrap_or_else(|| { + tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) + }); - match blocks::Code::from_node(&tcx.hir(), nodeid) { - Some(code) => { - let variants = gather_flowgraph_variants(tcx.sess); + match blocks::Code::from_node(&tcx.hir(), nodeid) { + Some(code) => { + let variants = gather_flowgraph_variants(tcx.sess); - let out: &mut dyn Write = &mut out; + let out: &mut dyn Write = &mut out; - print_flowgraph(variants, tcx, code, mode, out) - } - None => { - let message = format!("--pretty=flowgraph needs block, fn, or method; \ - got {:?}", - node); + print_flowgraph(variants, tcx, code, mode, out) + } + None => { + let message = format!("--pretty=flowgraph needs block, fn, or method; \ + got {:?}", + node); - tcx.sess.span_fatal(tcx.hir().span(nodeid), &message) - } + tcx.sess.span_fatal(tcx.hir().span(nodeid), &message) } } - _ => unreachable!(), } - }).unwrap(); + _ => unreachable!(), + }; + + print().unwrap(); write_output(out, ofile); + + Ok(()) } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 3d52f1d44ba29..f98939eb40a8e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -1,34 +1,23 @@ //! Standalone tests for the inference module. -use driver; -use errors; use errors::emitter::Emitter; use errors::{DiagnosticBuilder, Level}; use rustc::hir; -use rustc::hir::map as hir_map; use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::infer::{self, InferOk, InferResult, SuppressRegionErrors}; use rustc::middle::region; -use rustc::session::config::{OutputFilenames, OutputTypes}; -use rustc::session::{self, config}; +use rustc::session::{DiagnosticOutput, config}; use rustc::traits::ObligationCause; -use rustc::ty::query::OnDiskCache; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::sync::{self, Lrc}; -use rustc_interface::util; -use rustc_lint; -use rustc_metadata::cstore::CStore; +use rustc_data_structures::sync; use rustc_target::spec::abi::Abi; -use syntax; +use rustc_interface::interface; use syntax::ast; use syntax::feature_gate::UnstableFeatures; -use syntax::source_map::{FileName, FilePathMapping, SourceMap}; +use syntax::source_map::FileName; use syntax::symbol::Symbol; -use std::path::PathBuf; -use std::sync::mpsc; - struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>, region_scope_tree: &'a mut region::ScopeTree, @@ -75,102 +64,57 @@ impl Emitter for ExpectErrorEmitter { } } -fn errors(msgs: &[&str]) -> (Box, usize) { - let v = msgs.iter().map(|m| m.to_string()).collect(); +fn errors(msgs: &[&str]) -> (Box, usize) { + let mut v: Vec<_> = msgs.iter().map(|m| m.to_string()).collect(); + if !v.is_empty() { + v.push("aborting due to previous error".to_owned()); + } ( - box ExpectErrorEmitter { messages: v } as Box, + box ExpectErrorEmitter { messages: v } as Box, msgs.len(), ) } -fn test_env(source_string: &str, args: (Box, usize), body: F) -where - F: FnOnce(Env) + sync::Send, -{ - syntax::with_globals(|| { - let mut options = config::Options::default(); - options.debugging_opts.verbose = true; - options.unstable_features = UnstableFeatures::Allow; - - // When we're compiling this library with `--test` it'll run as a binary but - // not actually exercise much functionality. - // As a result most of the logic loading the codegen backend is defunkt - // (it assumes we're a dynamic library in a sysroot) - // so let's just use the metadata only backend which doesn't need to load any libraries. - options.debugging_opts.codegen_backend = Some("metadata_only".to_owned()); - - driver::spawn_thread_pool(options, |options| { - test_env_with_pool(options, source_string, args, body) - }) - }); -} - -fn test_env_with_pool( - options: config::Options, +fn test_env( source_string: &str, - (emitter, expected_err_count): (Box, usize), + (emitter, expected_err_count): (Box, usize), body: F, -) where - F: FnOnce(Env), +) +where + F: FnOnce(Env) + Send, { - let diagnostic_handler = errors::Handler::with_emitter(true, None, emitter); - let sess = session::build_session_( - options, - None, - diagnostic_handler, - Lrc::new(SourceMap::new(FilePathMapping::empty())), - Default::default(), - ); - let cstore = CStore::new(util::get_codegen_backend(&sess).metadata_loader()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + let mut opts = config::Options::default(); + opts.debugging_opts.verbose = true; + opts.unstable_features = UnstableFeatures::Allow; + + // When we're compiling this library with `--test` it'll run as a binary but + // not actually exercise much functionality. + // As a result most of the logic loading the codegen backend is defunkt + // (it assumes we're a dynamic library in a sysroot) + // so let's just use the metadata only backend which doesn't need to load any libraries. + opts.debugging_opts.codegen_backend = Some("metadata_only".to_owned()); + let input = config::Input::Str { name: FileName::anon_source_code(&source_string), input: source_string.to_string(), }; - let krate = - driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input).unwrap(); - let driver::ExpansionResult { - defs, - resolutions, - mut hir_forest, - .. - } = { - driver::phase_2_configure_and_expand( - &sess, - &cstore, - krate, - None, - "test", - None, - |_| Ok(()), - ).expect("phase 2 aborted") - }; - let mut arenas = ty::AllArenas::new(); - let hir_map = hir_map::map_crate(&sess, &cstore, &mut hir_forest, &defs); - - // Run just enough stuff to build a tcx. - let (tx, _rx) = mpsc::channel(); - let outputs = OutputFilenames { - out_directory: PathBuf::new(), - out_filestem: String::new(), - single_output_file: None, - extra: String::new(), - outputs: OutputTypes::new(&[]), + let config = interface::Config { + opts, + crate_cfg: Default::default(), + input, + input_path: None, + output_file: None, + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Emitter(emitter), + stderr: None, + crate_name: Some("test".to_owned()), + lint_caps: Default::default(), }; - TyCtxt::create_and_enter( - &sess, - &cstore, - ty::query::Providers::default(), - ty::query::Providers::default(), - &mut arenas, - resolutions, - hir_map, - OnDiskCache::new_empty(sess.source_map()), - "test_crate", - tx, - &outputs, - |tcx| { + + interface::run_compiler(config, |compiler| { + compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { tcx.infer_ctxt().enter(|infcx| { let mut region_scope_tree = region::ScopeTree::default(); let param_env = ty::ParamEnv::empty(); @@ -189,8 +133,8 @@ fn test_env_with_pool( ); assert_eq!(tcx.sess.err_count(), expected_err_count); }); - }, - ); + }) + }); } fn d1() -> ty::DebruijnIndex { diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 346ddaa485804..fe75bbc36c3b1 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -21,7 +21,7 @@ mod persist; pub use assert_dep_graph::assert_dep_graph; pub use persist::dep_graph_tcx_init; -pub use persist::load_dep_graph; +pub use persist::{DepGraphFuture, load_dep_graph}; pub use persist::load_query_result_cache; pub use persist::LoadResult; pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir; diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index ecf8bc4a88084..4295034692958 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -94,10 +94,10 @@ impl MaybeAsync { } } +pub type DepGraphFuture = MaybeAsync>; + /// Launch a thread and load the dependency graph in the background. -pub fn load_dep_graph(sess: &Session) -> - MaybeAsync> -{ +pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { // Since `sess` isn't `Sync`, we perform all accesses to `sess` // before we fire the background thread. diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 3aad4f5abb884..bf404140f18d5 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -16,7 +16,7 @@ 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::load_dep_graph; +pub use load::{DepGraphFuture, load_dep_graph}; pub use load::load_query_result_cache; pub use load::LoadResult; pub use save::save_dep_graph; diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs new file mode 100644 index 0000000000000..ec6b26afb8c50 --- /dev/null +++ b/src/librustc_interface/interface.rs @@ -0,0 +1,155 @@ +use queries::Queries; +use rustc::lint; +use rustc::session::config::{self, Input}; +use rustc::session::{DiagnosticOutput, Session}; +use rustc::util::common::ErrorReported; +use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_data_structures::OnDrop; +use rustc_data_structures::sync::Lrc; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_metadata::cstore::CStore; +use std::collections::HashSet; +use std::io::Write; +use std::path::PathBuf; +use std::result; +use std::sync::{Arc, Mutex}; +use syntax; +use syntax::source_map::{FileLoader, SourceMap}; +use util; +use profile; + +pub use passes::BoxedResolver; + +pub type Result = result::Result; + +/// Represents a compiler session. +/// Can be used run `rustc_interface` queries. +/// Created by passing `Config` to `run_compiler`. +pub struct Compiler { + pub(crate) sess: Lrc, + codegen_backend: Lrc>, + source_map: Lrc, + pub(crate) input: Input, + pub(crate) input_path: Option, + pub(crate) output_dir: Option, + pub(crate) output_file: Option, + pub(crate) queries: Queries, + pub(crate) cstore: Lrc, + pub(crate) crate_name: Option, +} + +impl Compiler { + pub fn session(&self) -> &Lrc { + &self.sess + } + pub fn codegen_backend(&self) -> &Lrc> { + &self.codegen_backend + } + pub fn cstore(&self) -> &Lrc { + &self.cstore + } + pub fn source_map(&self) -> &Lrc { + &self.source_map + } + pub fn input(&self) -> &Input { + &self.input + } + pub fn output_dir(&self) -> &Option { + &self.output_dir + } + pub fn output_file(&self) -> &Option { + &self.output_file + } +} + +/// The compiler configuration +pub struct Config { + /// Command line options + pub opts: config::Options, + + /// cfg! configuration in addition to the default ones + pub crate_cfg: FxHashSet<(String, Option)>, + + pub input: Input, + pub input_path: Option, + pub output_dir: Option, + pub output_file: Option, + pub file_loader: Option>, + pub diagnostic_output: DiagnosticOutput, + + /// Set to capture stderr output during compiler execution + pub stderr: Option>>>, + + pub crate_name: Option, + pub lint_caps: FxHashMap, +} + +pub fn run_compiler_in_existing_thread_pool(config: Config, f: F) -> R +where + F: FnOnce(&Compiler) -> R, +{ + let (sess, codegen_backend, source_map) = util::create_session( + config.opts, + config.crate_cfg, + config.diagnostic_output, + config.file_loader, + config.input_path.clone(), + config.lint_caps, + ); + + let cstore = Lrc::new(CStore::new(codegen_backend.metadata_loader())); + + let compiler = Compiler { + sess, + codegen_backend, + source_map, + cstore, + input: config.input, + input_path: config.input_path, + output_dir: config.output_dir, + output_file: config.output_file, + queries: Default::default(), + crate_name: config.crate_name, + }; + + let _sess_abort_error = OnDrop(|| compiler.sess.diagnostic().print_error_count()); + + if compiler.sess.profile_queries() { + profile::begin(&compiler.sess); + } + + let r = f(&compiler); + + if compiler.sess.profile_queries() { + profile::dump(&compiler.sess, "profile_queries".to_string()) + } + + if compiler.sess.opts.debugging_opts.self_profile { + compiler.sess.profiler(|p| p.dump_raw_events(&compiler.sess.opts)); + } + + r +} + +pub fn run_compiler(mut config: Config, f: F) -> R +where + F: FnOnce(&Compiler) -> R + Send, + R: Send, +{ + syntax::with_globals(move || { + let stderr = config.stderr.take(); + util::spawn_thread_pool( + config.opts.debugging_opts.threads, + &stderr, + || run_compiler_in_existing_thread_pool(config, f), + ) + }) +} + +pub fn default_thread_pool(f: F) -> R +where + F: FnOnce() -> R + Send, + R: Send, +{ + util::spawn_thread_pool(None, &None, f) +} diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index e5c7c35a36d75..6a931c249b5bf 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -3,6 +3,7 @@ #![feature(nll)] #![feature(arbitrary_self_types)] #![feature(generator_trait)] +#![feature(generators)] #![cfg_attr(unix, feature(libc))] #![allow(unused_imports)] @@ -37,7 +38,11 @@ extern crate syntax; extern crate syntax_pos; extern crate syntax_ext; -pub mod passes; -pub mod profile; +pub mod interface; +mod passes; +mod queries; pub mod util; -pub mod proc_macro_decls; +mod proc_macro_decls; +mod profile; + +pub use interface::{run_compiler, Config}; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 8277615b46502..d61ccd5605b60 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -1,3 +1,4 @@ +use interface::{Compiler, Result}; use util; use proc_macro_decls; @@ -8,7 +9,7 @@ use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::lint; use rustc::middle::{self, reachable, resolve_lifetime, stability}; use rustc::middle::privacy::AccessLevels; -use rustc::ty::{self, AllArenas, Resolutions, TyCtxt}; +use rustc::ty::{self, AllArenas, Resolutions, TyCtxt, GlobalCtxt}; use rustc::ty::steal::Steal; use rustc::traits; use rustc::util::common::{time, ErrorReported}; @@ -23,6 +24,7 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter}; use rustc_incremental; +use rustc_incremental::DepGraphFuture; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::{self, CStore}; use rustc_mir as mir; @@ -35,12 +37,13 @@ use rustc_traits; use rustc_typeck as typeck; use syntax::{self, ast, attr, diagnostics, visit}; use syntax::early_buffered_lints::BufferedEarlyLint; -use syntax::ext::base::ExtCtxt; +use syntax::ext::base::{NamedSyntaxExtension, ExtCtxt}; use syntax::mut_visit::MutVisitor; use syntax::parse::{self, PResult}; use syntax::util::node_count::NodeCounter; use syntax::util::lev_distance::find_best_match_for_name; use syntax::symbol::Symbol; +use syntax::feature_gate::AttributeType; use syntax_pos::{FileName, hygiene}; use syntax_ext; @@ -59,8 +62,524 @@ use std::rc::Rc; use std::mem; use std::ops::Generator; -/// Returns all the paths that correspond to generated files. -pub fn generated_output_paths( +pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { + sess.diagnostic() + .set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error); + hygiene::set_default_edition(sess.edition()); + + sess.profiler(|p| p.start_activity(ProfileCategory::Parsing)); + let krate = time(sess, "parsing", || match *input { + Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), + Input::Str { + ref input, + ref name, + } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), + })?; + sess.profiler(|p| p.end_activity(ProfileCategory::Parsing)); + + sess.diagnostic().set_continue_after_error(true); + + if sess.opts.debugging_opts.ast_json_noexpand { + println!("{}", json::as_json(&krate)); + } + + if sess.opts.debugging_opts.input_stats { + println!( + "Lines of code: {}", + sess.source_map().count_lines() + ); + println!("Pre-expansion node count: {}", count_nodes(&krate)); + } + + if let Some(ref s) = sess.opts.debugging_opts.show_span { + syntax::show_span::run(sess.diagnostic(), s, &krate); + } + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); + } + + Ok(krate) +} + +fn count_nodes(krate: &ast::Crate) -> usize { + let mut counter = NodeCounter::new(); + visit::walk_crate(&mut counter, krate); + counter.count +} + +declare_box_region_type!( + pub BoxedResolver, + for(), + (&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)> { + // 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 (result, resolver) = BoxedResolver::new(static move || { + let sess = &*sess; + let mut crate_loader = CrateLoader::new(sess, &*cstore, &crate_name); + let resolver_arenas = Resolver::arenas(); + let res = configure_and_expand_inner( + sess, + &*cstore, + krate, + &crate_name, + &resolver_arenas, + &mut crate_loader, + plugin_info, + ); + let mut resolver = match res { + Err(v) => { + yield BoxedResolver::initial_yield(Err(v)); + panic!() + } + Ok((krate, resolver)) => { + yield BoxedResolver::initial_yield(Ok(krate)); + resolver + } + }; + box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver)); + ExpansionResult::from_owned_resolver(resolver) + }); + result.map(|k| (k, resolver)) +} + +pub struct ExpansionResult { + pub defs: Steal, + pub resolutions: Steal, +} + +impl ExpansionResult { + fn from_owned_resolver( + resolver: Resolver<'_>, + ) -> Self { + ExpansionResult { + defs: Steal::new(resolver.definitions), + resolutions: Steal::new(Resolutions { + freevars: resolver.freevars, + export_map: resolver.export_map, + trait_map: resolver.trait_map, + glob_map: resolver.glob_map, + maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, + maybe_unused_extern_crates: resolver.maybe_unused_extern_crates, + extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { + (ident.name, entry.introduced_by_item) + }).collect(), + }), + } + } + + pub fn from_resolver_ref( + resolver: &Resolver<'_>, + ) -> Self { + ExpansionResult { + defs: Steal::new(resolver.definitions.clone()), + resolutions: Steal::new(Resolutions { + freevars: resolver.freevars.clone(), + export_map: resolver.export_map.clone(), + trait_map: resolver.trait_map.clone(), + glob_map: resolver.glob_map.clone(), + maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(), + maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(), + extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { + (ident.name, entry.introduced_by_item) + }).collect(), + }), + } + } +} + +impl BoxedResolver { + pub fn to_expansion_result( + mut resolver: Rc>>, + ) -> ExpansionResult { + if let Some(resolver) = Rc::get_mut(&mut resolver) { + mem::replace(resolver, None).unwrap().into_inner().complete() + } else { + let resolver = &*resolver; + resolver.as_ref().unwrap().borrow_mut().access(|resolver| { + ExpansionResult::from_resolver_ref(resolver) + }) + } + } +} + +pub struct PluginInfo { + syntax_exts: Vec, + attributes: Vec<(String, 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)> { + krate = time(sess, "attributes injection", || { + syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) + }); + + let (mut krate, features) = syntax::config::features( + krate, + &sess.parse_sess, + sess.edition(), + ); + // these need to be set "early" so that expansion sees `quote` if enabled. + sess.init_features(features); + + let crate_types = util::collect_crate_types(sess, &krate.attrs); + sess.crate_types.set(crate_types); + + let disambiguator = util::compute_crate_disambiguator(sess); + sess.crate_disambiguator.set(disambiguator); + rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); + + if sess.opts.incremental.is_some() { + time(sess, "garbage collect incremental cache directory", || { + if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { + warn!( + "Error while trying to garbage collect incremental \ + compilation cache directory: {}", + e + ); + } + }); + } + + // If necessary, compute the dependency graph (in the background). + compiler.dep_graph_future().ok(); + + time(sess, "recursion limit", || { + middle::recursion_limit::update_limits(sess, &krate); + }); + + krate = time(sess, "crate injection", || { + let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s); + syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition()) + }); + + let registrars = time(sess, "plugin loading", || { + plugin::load::load_plugins( + sess, + &cstore, + &krate, + crate_name, + Some(sess.opts.debugging_opts.extra_plugins.clone()), + ) + }); + + let mut registry = Registry::new(sess, krate.span); + + time(sess, "plugin registration", || { + if sess.features_untracked().rustc_diagnostic_macros { + registry.register_macro( + "__diagnostic_used", + diagnostics::plugin::expand_diagnostic_used, + ); + registry.register_macro( + "__register_diagnostic", + diagnostics::plugin::expand_register_diagnostic, + ); + registry.register_macro( + "__build_diagnostic_array", + diagnostics::plugin::expand_build_diagnostic_array, + ); + } + + for registrar in registrars { + registry.args_hidden = Some(registrar.args); + (registrar.fun)(&mut registry); + } + }); + + let Registry { + syntax_exts, + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; + + sess.track_errors(|| { + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, false, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } + + for (name, (to, deprecated_name)) in lint_groups { + ls.register_group(Some(sess), true, name, deprecated_name, to); + } + + *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; + *sess.plugin_attributes.borrow_mut() = attributes.clone(); + })?; + + Ok((krate, PluginInfo { + syntax_exts, + attributes, + })) +} + +fn configure_and_expand_inner<'a>( + sess: &'a Session, + cstore: &'a CStore, + mut krate: ast::Crate, + crate_name: &str, + resolver_arenas: &'a ResolverArenas<'a>, + crate_loader: &'a mut CrateLoader<'a>, + plugin_info: PluginInfo, +) -> Result<(ast::Crate, Resolver<'a>)> { + let attributes = plugin_info.attributes; + time(sess, "pre ast expansion lint checks", || { + lint::check_ast_crate( + sess, + &krate, + true, + rustc_lint::BuiltinCombinedPreExpansionLintPass::new()); + }); + + let mut resolver = Resolver::new( + sess, + cstore, + &krate, + crate_name, + crate_loader, + &resolver_arenas, + ); + syntax_ext::register_builtins(&mut resolver, plugin_info.syntax_exts); + + // Expand all macros + sess.profiler(|p| p.start_activity(ProfileCategory::Expansion)); + krate = time(sess, "expansion", || { + // Windows dlls do not have rpaths, so they don't know how to find their + // dependencies. It's up to us to tell the system where to find all the + // dependent dlls. Note that this uses cfg!(windows) as opposed to + // targ_cfg because syntax extensions are always loaded for the host + // compiler, not for the target. + // + // This is somewhat of an inherently racy operation, however, as + // multiple threads calling this function could possibly continue + // extending PATH far beyond what it should. To solve this for now we + // just don't add any new elements to PATH which are already there + // within PATH. This is basically a targeted fix at #17360 for rustdoc + // which runs rustc in parallel but has been seen (#33844) to cause + // problems with PATH becoming too long. + let mut old_path = OsString::new(); + if cfg!(windows) { + old_path = env::var_os("PATH").unwrap_or(old_path); + let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs(); + for path in env::split_paths(&old_path) { + if !new_path.contains(&path) { + new_path.push(path); + } + } + env::set_var( + "PATH", + &env::join_paths( + new_path + .iter() + .filter(|p| env::join_paths(iter::once(p)).is_ok()), + ).unwrap(), + ); + } + + // Create the config for macro expansion + let features = sess.features_untracked(); + let cfg = syntax::ext::expand::ExpansionConfig { + features: Some(&features), + recursion_limit: *sess.recursion_limit.get(), + trace_mac: sess.opts.debugging_opts.trace_macros, + should_test: sess.opts.test, + ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) + }; + + let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); + + // Expand macros now! + let krate = time(sess, "expand crate", || { + ecx.monotonic_expander().expand_crate(krate) + }); + + // The rest is error reporting + + time(sess, "check unused macros", || { + ecx.check_unused_macros(); + }); + + let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess + .missing_fragment_specifiers + .borrow() + .iter() + .cloned() + .collect(); + missing_fragment_specifiers.sort(); + + for span in missing_fragment_specifiers { + let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; + let msg = "missing fragment specifier"; + sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg); + } + if cfg!(windows) { + env::set_var("PATH", &old_path); + } + krate + }); + sess.profiler(|p| p.end_activity(ProfileCategory::Expansion)); + + time(sess, "maybe building test harness", || { + syntax::test::modify_for_testing( + &sess.parse_sess, + &mut resolver, + sess.opts.test, + &mut krate, + sess.diagnostic(), + &sess.features_untracked(), + ) + }); + + // If we're actually rustdoc then there's no need to actually compile + // anything, so switch everything to just looping + if sess.opts.actually_rustdoc { + util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate); + } + + let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || { + ast_validation::check_crate(sess, &krate) + }); + + // If we're in rustdoc we're always compiling as an rlib, but that'll trip a + // bunch of checks in the `modify` function below. For now just skip this + // step entirely if we're rustdoc as it's not too useful anyway. + if !sess.opts.actually_rustdoc { + krate = time(sess, "maybe creating a macro crate", || { + let crate_types = sess.crate_types.borrow(); + let num_crate_types = crate_types.len(); + let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro); + let is_test_crate = sess.opts.test; + syntax_ext::proc_macro_decls::modify( + &sess.parse_sess, + &mut resolver, + krate, + is_proc_macro_crate, + has_proc_macro_decls, + is_test_crate, + num_crate_types, + sess.diagnostic(), + ) + }); + } + + if has_global_allocator { + // Expand global allocators, which are treated as an in-tree proc macro + time(sess, "creating allocators", || { + allocator::expand::modify( + &sess.parse_sess, + &mut resolver, + &mut krate, + crate_name.to_string(), + sess.diagnostic(), + ) + }); + } + + // Done with macro expansion! + + if sess.opts.debugging_opts.input_stats { + println!("Post-expansion node count: {}", count_nodes(&krate)); + } + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); + } + + if sess.opts.debugging_opts.ast_json { + println!("{}", json::as_json(&krate)); + } + + time(sess, "name resolution", || { + resolver.resolve_crate(&krate); + }); + + // Needs to go *after* expansion to be able to check the results of macro expansion. + time(sess, "complete gated feature checking", || { + syntax::feature_gate::check_crate( + &krate, + &sess.parse_sess, + &sess.features_untracked(), + &attributes, + sess.opts.unstable_features, + ); + }); + + // Add all buffered lints from the `ParseSess` to the `Session`. + sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { + info!("{} parse sess buffered_lints", buffered_lints.len()); + for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) { + let lint = lint::Lint::from_parser_lint_id(lint_id); + sess.buffer_lint(lint, id, span, &msg); + } + }); + + Ok((krate, resolver)) +} + +pub fn lower_to_hir( + sess: &Session, + cstore: &CStore, + resolver: &mut Resolver<'_>, + dep_graph: &DepGraph, + krate: &ast::Crate, +) -> Result { + // Lower ast -> hir + let hir_forest = time(sess, "lowering ast -> hir", || { + let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver); + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_hir_stats(&hir_crate); + } + + hir::map::Forest::new(hir_crate, &dep_graph) + }); + + time(sess, "early lint checks", || { + lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new()) + }); + + // Discard hygiene data, which isn't required after lowering to HIR. + if !sess.opts.debugging_opts.keep_hygiene_data { + syntax::ext::hygiene::clear_markings(); + } + + Ok(hir_forest) +} + +// Returns all the paths that correspond to generated files. +fn generated_output_paths( sess: &Session, outputs: &OutputFilenames, exact_name: bool, @@ -106,7 +625,7 @@ where None } -pub fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool { +fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool { let input_path = input_path.canonicalize().ok(); if input_path.is_none() { return false; @@ -121,7 +640,7 @@ pub fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> b check_output(output_paths, check).is_some() } -pub fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option { +fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option { let check = |output_path: &PathBuf| { if output_path.is_dir() { Some(output_path.clone()) @@ -138,7 +657,7 @@ fn escape_dep_filename(filename: &FileName) -> String { filename.to_string().replace(" ", "\\ ") } -pub fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[PathBuf]) { +fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[PathBuf]) { // Write out dependency rules to the dep-info file if requested if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { return; @@ -178,15 +697,192 @@ pub fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn prepare_outputs( + sess: &Session, + compiler: &Compiler, + krate: &ast::Crate, + crate_name: &str +) -> Result { + // FIXME: rustdoc passes &[] instead of &krate.attrs here + let outputs = util::build_output_filenames( + &compiler.input, + &compiler.output_dir, + &compiler.output_file, + &krate.attrs, + sess + ); + + let output_paths = generated_output_paths( + sess, + &outputs, + compiler.output_file.is_some(), + &crate_name, + ); + + // Ensure the source file isn't accidentally overwritten during compilation. + if let Some(ref input_path) = compiler.input_path { + if sess.opts.will_create_output_file() { + if output_contains_path(&output_paths, input_path) { + sess.err(&format!( + "the input file \"{}\" would be overwritten by the generated \ + executable", + input_path.display() + )); + return Err(ErrorReported); + } + if let Some(dir_path) = output_conflicts_with_dir(&output_paths) { + sess.err(&format!( + "the generated executable for the input file \"{}\" conflicts with the \ + existing directory \"{}\"", + input_path.display(), + dir_path.display() + )); + return Err(ErrorReported); + } + } + } + + write_out_deps(sess, &outputs, &output_paths); + + let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1; + + if !only_dep_info { + if let Some(ref dir) = compiler.output_dir { + if fs::create_dir_all(dir).is_err() { + sess.err("failed to find or create the directory specified by --out-dir"); + return Err(ErrorReported); + } + } + } + + Ok(outputs) +} + +pub fn default_provide(providers: &mut ty::query::Providers) { providers.analysis = analysis; proc_macro_decls::provide(providers); + plugin::build::provide(providers); + hir::provide(providers); + borrowck::provide(providers); + mir::provide(providers); + reachable::provide(providers); + resolve_lifetime::provide(providers); + rustc_privacy::provide(providers); + typeck::provide(providers); + ty::provide(providers); + traits::provide(providers); + stability::provide(providers); + middle::intrinsicck::provide(providers); + middle::liveness::provide(providers); + reachable::provide(providers); + rustc_passes::provide(providers); + rustc_traits::provide(providers); + middle::region::provide(providers); + middle::entry::provide(providers); + cstore::provide(providers); + lint::provide(providers); +} + +pub fn default_provide_extern(providers: &mut ty::query::Providers) { + cstore::provide_extern(providers); +} + +declare_box_region_type!( + pub BoxedGlobalCtxt, + for('gcx), + (&'gcx GlobalCtxt<'gcx>) -> ((), ()) +); + +impl BoxedGlobalCtxt { + pub fn enter(&mut self, f: F) -> R + where + F: for<'tcx> FnOnce(TyCtxt<'tcx, 'tcx, 'tcx>) -> R + { + self.access(|gcx| ty::tls::enter_global(gcx, |tcx| f(tcx))) + } } +pub fn create_global_ctxt( + compiler: &Compiler, + mut hir_forest: hir::map::Forest, + defs: hir::map::Definitions, + resolutions: Resolutions, + outputs: OutputFilenames, + tx: mpsc::Sender>, + crate_name: &str +) -> BoxedGlobalCtxt { + let sess = compiler.session().clone(); + let cstore = compiler.cstore.clone(); + let codegen_backend = compiler.codegen_backend().clone(); + let crate_name = crate_name.to_string(); + + let ((), result) = BoxedGlobalCtxt::new(static move || { + let sess = &*sess; + let cstore = &*cstore; + + let global_ctxt: Option>; + let arenas = AllArenas::new(); + + // Construct the HIR map + let hir_map = time(sess, "indexing hir", || { + hir::map::map_crate(sess, cstore, &mut hir_forest, &defs) + }); + + let query_result_on_disk_cache = time(sess, "load query result cache", || { + rustc_incremental::load_query_result_cache(sess) + }); + + let mut local_providers = ty::query::Providers::default(); + default_provide(&mut local_providers); + codegen_backend.provide(&mut local_providers); + + let mut extern_providers = local_providers; + default_provide_extern(&mut extern_providers); + codegen_backend.provide_extern(&mut extern_providers); + + let gcx = TyCtxt::create_global_ctxt( + sess, + cstore, + local_providers, + extern_providers, + &arenas, + resolutions, + hir_map, + query_result_on_disk_cache, + &crate_name, + tx, + &outputs + ); + + 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('gcx), (&'gcx GlobalCtxt<'gcx>), (gcx)); + + gcx.queries.record_computed_queries(sess); + + if sess.opts.debugging_opts.query_stats { + gcx.queries.print_stats(); + } + }); + + result +} + +/// Runs the resolution, type-checking, region checking and other +/// miscellaneous analysis passes on the crate. fn analysis<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, cnum: CrateNum, -) -> Result<(), ErrorReported> { +) -> Result<()> { assert_eq!(cnum, LOCAL_CRATE); let sess = tcx.sess; @@ -249,9 +945,9 @@ fn analysis<'tcx>( } }); - time(sess, - "MIR borrow checking", - || tcx.par_body_owners(|def_id| { tcx.ensure().mir_borrowck(def_id); })); + time(sess, "MIR borrow checking", || { + tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); + }); time(sess, "dumping chalk-like clauses", || { rustc_traits::lowering::dump_program_clauses(tcx); @@ -304,3 +1000,39 @@ fn analysis<'tcx>( Ok(()) } + +/// Runs the codegen backend, after which the AST and analysis can +/// be discarded. +pub fn start_codegen<'tcx>( + codegen_backend: &dyn CodegenBackend, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + rx: mpsc::Receiver>, + outputs: &OutputFilenames, +) -> Box { + if log_enabled!(::log::Level::Info) { + println!("Pre-codegen"); + tcx.print_debug_stats(); + } + + time(tcx.sess, "resolving dependency formats", || { + ::rustc::middle::dependency_format::calculate(tcx) + }); + + tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen)); + let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx)); + tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen)); + + if log_enabled!(::log::Level::Info) { + println!("Post-codegen"); + tcx.print_debug_stats(); + } + + if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { + if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) { + tcx.sess.err(&format!("could not emit MIR: {}", e)); + tcx.sess.abort_if_errors(); + } + } + + codegen +} diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs new file mode 100644 index 0000000000000..57ced0464d9fa --- /dev/null +++ b/src/librustc_interface/queries.rs @@ -0,0 +1,302 @@ +use interface::{Compiler, Result}; +use passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo}; +use rustc_incremental::DepGraphFuture; +use rustc_data_structures::sync::Lrc; +use rustc::session::config::{Input, OutputFilenames, OutputType}; +use rustc::session::Session; +use rustc::util::common::{time, ErrorReported}; +use rustc::util::profiling::ProfileCategory; +use rustc::lint; +use rustc::hir; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::ty; +use rustc::ty::steal::Steal; +use rustc::dep_graph::DepGraph; +use rustc_passes::hir_stats; +use rustc_plugin::registry::Registry; +use serialize::json; +use std::cell::{Ref, RefMut, RefCell}; +use std::ops::Deref; +use std::rc::Rc; +use std::sync::mpsc; +use std::any::Any; +use std::mem; +use syntax::parse::{self, PResult}; +use syntax::util::node_count::NodeCounter; +use syntax::{self, ast, attr, diagnostics, visit}; +use syntax_pos::hygiene; + +/// Represent the result of a query. +/// This result can be stolen with the `take` method and returned with the `give` method. +pub struct Query { + result: RefCell>>, +} + +impl Query { + fn compute Result>(&self, f: F) -> Result<&Query> { + let mut result = self.result.borrow_mut(); + if result.is_none() { + *result = Some(f()); + } + result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err) + } + + /// Takes ownership of the query result. Further attempts to take or peek the query + /// result will panic unless it is returned by calling the `give` method. + pub fn take(&self) -> T { + self.result + .borrow_mut() + .take() + .expect("missing query result") + .unwrap() + } + + /// Returns a stolen query result. Panics if there's already a result. + pub fn give(&self, value: T) { + let mut result = self.result.borrow_mut(); + assert!(result.is_none(), "a result already exists"); + *result = Some(Ok(value)); + } + + /// Borrows the query result using the RefCell. Panics if the result is stolen. + pub fn peek(&self) -> Ref<'_, T> { + Ref::map(self.result.borrow(), |r| { + r.as_ref().unwrap().as_ref().expect("missing query result") + }) + } + + /// Mutably borrows the query result using the RefCell. Panics if the result is stolen. + pub fn peek_mut(&self) -> RefMut<'_, T> { + RefMut::map(self.result.borrow_mut(), |r| { + r.as_mut().unwrap().as_mut().expect("missing query result") + }) + } +} + +impl Default for Query { + fn default() -> Self { + Query { + result: RefCell::new(None), + } + } +} + +#[derive(Default)] +pub(crate) struct Queries { + dep_graph_future: Query>, + parse: Query, + crate_name: Query, + register_plugins: Query<(ast::Crate, PluginInfo)>, + expansion: Query<(ast::Crate, Rc>>)>, + dep_graph: Query, + lower_to_hir: Query<(Steal, ExpansionResult)>, + prepare_outputs: Query, + codegen_channel: Query<(Steal>>, + Steal>>)>, + global_ctxt: Query, + ongoing_codegen: Query>, + link: Query<()>, +} + +impl Compiler { + pub fn dep_graph_future(&self) -> Result<&Query>> { + self.queries.dep_graph_future.compute(|| { + Ok(if self.session().opts.build_dep_graph() { + Some(rustc_incremental::load_dep_graph(self.session())) + } else { + None + }) + }) + } + + pub fn parse(&self) -> Result<&Query> { + self.queries.parse.compute(|| { + passes::parse(self.session(), &self.input).map_err( + |mut parse_error| { + parse_error.emit(); + ErrorReported + }, + ) + }) + } + + pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> { + self.queries.register_plugins.compute(|| { + let crate_name = self.crate_name()?.peek().clone(); + let krate = self.parse()?.take(); + + passes::register_plugins( + self, + self.session(), + self.cstore(), + krate, + &crate_name, + ) + }) + } + + pub fn crate_name(&self) -> Result<&Query> { + self.queries.crate_name.compute(|| { + let parse_result = self.parse()?; + let krate = parse_result.peek(); + let result = match self.crate_name { + Some(ref crate_name) => crate_name.clone(), + None => rustc_codegen_utils::link::find_crate_name( + Some(self.session()), + &krate.attrs, + &self.input + ), + }; + Ok(result) + }) + } + + pub fn expansion( + &self + ) -> Result<&Query<(ast::Crate, Rc>>)>> { + 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, Rc::new(Some(RefCell::new(resolver))))) + }) + } + + pub fn dep_graph(&self) -> Result<&Query> { + self.queries.dep_graph.compute(|| { + Ok(match self.dep_graph_future()?.take() { + None => DepGraph::new_disabled(), + Some(future) => { + let (prev_graph, prev_work_products) = + time(self.session(), "blocked while dep-graph loading finishes", || { + future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error { + message: format!("could not decode incremental cache: {:?}", e), + }).open(self.session()) + }); + DepGraph::new(prev_graph, prev_work_products) + } + }) + }) + } + + pub fn lower_to_hir(&self) -> Result<&Query<(Steal, ExpansionResult)>> { + self.queries.lower_to_hir.compute(|| { + let expansion_result = self.expansion()?; + let (krate, resolver) = expansion_result.take(); + let resolver_ref = &*resolver; + let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| { + passes::lower_to_hir( + self.session(), + self.cstore(), + resolver, + &*self.dep_graph()?.peek(), + &krate + ) + })?); + expansion_result.give((krate, Rc::new(None))); + Ok((hir, BoxedResolver::to_expansion_result(resolver))) + }) + } + + pub fn prepare_outputs(&self) -> Result<&Query> { + self.queries.prepare_outputs.compute(|| { + self.lower_to_hir()?; + let krate = self.expansion()?; + let krate = krate.peek(); + let crate_name = self.crate_name()?; + let crate_name = crate_name.peek(); + passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name) + }) + } + + pub fn codegen_channel(&self) -> Result<&Query<(Steal>>, + Steal>>)>> { + self.queries.codegen_channel.compute(|| { + let (tx, rx) = mpsc::channel(); + Ok((Steal::new(tx), Steal::new(rx))) + }) + } + + pub fn global_ctxt(&self) -> Result<&Query> { + self.queries.global_ctxt.compute(|| { + let crate_name = self.crate_name()?.peek().clone(); + let outputs = self.prepare_outputs()?.peek().clone(); + let hir = self.lower_to_hir()?; + let hir = hir.peek(); + let (ref hir_forest, ref expansion) = *hir; + let tx = self.codegen_channel()?.peek().0.steal(); + Ok(passes::create_global_ctxt( + self, + hir_forest.steal(), + expansion.defs.steal(), + expansion.resolutions.steal(), + outputs, + tx, + &crate_name)) + }) + } + + pub fn ongoing_codegen(&self) -> Result<&Query>> { + self.queries.ongoing_codegen.compute(|| { + let rx = self.codegen_channel()?.peek().1.steal(); + let outputs = self.prepare_outputs()?; + self.global_ctxt()?.peek_mut().enter(|tcx| { + tcx.analysis(LOCAL_CRATE).ok(); + + // Don't do code generation if there were any errors + self.session().compile_status()?; + + Ok(passes::start_codegen( + &***self.codegen_backend(), + tcx, + rx, + &*outputs.peek() + )) + }) + }) + } + + pub fn link(&self) -> Result<&Query<()>> { + self.queries.link.compute(|| { + let sess = self.session(); + + let ongoing_codegen = self.ongoing_codegen()?.take(); + + self.codegen_backend().join_codegen_and_link( + ongoing_codegen, + sess, + &*self.dep_graph()?.peek(), + &*self.prepare_outputs()?.peek(), + ).map_err(|_| ErrorReported)?; + + Ok(()) + }) + } + + pub fn compile(&self) -> Result<()> { + self.prepare_outputs()?; + + if self.session().opts.output_types.contains_key(&OutputType::DepInfo) + && self.session().opts.output_types.len() == 1 + { + return Ok(()) + } + + self.global_ctxt()?; + + // Drop AST after creating GlobalCtxt to free memory + mem::drop(self.expansion()?.take()); + + self.ongoing_codegen()?; + + // Drop GlobalCtxt after starting codegen to free memory + mem::drop(self.global_ctxt()?.take()); + + self.link().map(|_| ()) + } +} diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 6f92c30446215..0f858d632060e 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -4,6 +4,8 @@ use rustc::session::CrateDisambiguator; use rustc::ty; use rustc::lint; use rustc_codegen_utils::codegen_backend::CodegenBackend; +#[cfg(parallel_compiler)] +use rustc_data_structures::jobserver; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::fingerprint::Fingerprint; @@ -79,6 +81,161 @@ pub fn add_configuration( } } +pub fn create_session( + sopts: config::Options, + cfg: FxHashSet<(String, Option)>, + diagnostic_output: DiagnosticOutput, + file_loader: Option>, + input_path: Option, + lint_caps: FxHashMap, +) -> (Lrc, Lrc>, Lrc) { + let descriptions = diagnostics_registry(); + + let loader = file_loader.unwrap_or(box RealFileLoader); + let source_map = Lrc::new(SourceMap::with_file_loader( + loader, + sopts.file_path_mapping(), + )); + let mut sess = session::build_session_with_source_map( + sopts, + input_path, + descriptions, + source_map.clone(), + diagnostic_output, + lint_caps, + ); + + let codegen_backend = get_codegen_backend(&sess); + + rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + + let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); + add_configuration(&mut cfg, &sess, &*codegen_backend); + sess.parse_sess.config = cfg; + + (Lrc::new(sess), Lrc::new(codegen_backend), source_map) +} + +// Temporarily have stack size set to 32MB to deal with various crates with long method +// chains or deep syntax trees. +// FIXME(oli-obk): get https://github.com/rust-lang/rust/pull/55617 the finish line +const STACK_SIZE: usize = 32 * 1024 * 1024; // 32MB + +fn get_stack_size() -> Option { + // FIXME: Hacks on hacks. If the env is trying to override the stack size + // then *don't* set it explicitly. + if env::var_os("RUST_MIN_STACK").is_none() { + Some(STACK_SIZE) + } else { + None + } +} + +struct Sink(Arc>>); +impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[cfg(not(parallel_compiler))] +pub fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { + struct Ptr(*mut ()); + unsafe impl Send for Ptr {} + unsafe impl Sync for Ptr {} + + let mut f = Some(f); + let run = Ptr(&mut f as *mut _ as *mut ()); + let mut result = None; + let result_ptr = Ptr(&mut result as *mut _ as *mut ()); + + let thread = cfg.spawn(move || { + let run = unsafe { (*(run.0 as *mut Option)).take().unwrap() }; + let result = unsafe { &mut *(result_ptr.0 as *mut Option) }; + *result = Some(run()); + }); + + match thread.unwrap().join() { + Ok(()) => result.unwrap(), + Err(p) => panic::resume_unwind(p), + } +} + +#[cfg(not(parallel_compiler))] +pub fn spawn_thread_pool R + Send, R: Send>( + _threads: Option, + stderr: &Option>>>, + f: F, +) -> R { + let mut cfg = thread::Builder::new().name("rustc".to_string()); + + if let Some(size) = get_stack_size() { + cfg = cfg.stack_size(size); + } + + scoped_thread(cfg, || { + syntax::with_globals( || { + ty::tls::GCX_PTR.set(&Lock::new(0), || { + if let Some(stderr) = stderr { + io::set_panic(Some(box Sink(stderr.clone()))); + } + ty::tls::with_thread_locals(|| f()) + }) + }) + }) +} + +#[cfg(parallel_compiler)] +pub fn spawn_thread_pool R + Send, R: Send>( + threads: Option, + stderr: &Option>>>, + f: F, +) -> R { + use rayon::{ThreadPool, ThreadPoolBuilder}; + use syntax; + use syntax_pos; + + let gcx_ptr = &Lock::new(0); + + let mut config = ThreadPoolBuilder::new() + .acquire_thread_handler(jobserver::acquire_thread) + .release_thread_handler(jobserver::release_thread) + .num_threads(Session::threads_from_count(threads)) + .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }); + + if let Some(size) = get_stack_size() { + config = config.stack_size(size); + } + + let with_pool = move |pool: &ThreadPool| pool.install(move || f()); + + syntax::with_globals(|| { + syntax::GLOBALS.with(|syntax_globals| { + syntax_pos::GLOBALS.with(|syntax_pos_globals| { + // The main handler runs for each Rayon worker thread and sets up + // the thread local rustc uses. syntax_globals and syntax_pos_globals are + // captured and set on the new threads. ty::tls::with_thread_locals sets up + // thread local callbacks from libsyntax + let main_handler = move |worker: &mut dyn FnMut()| { + syntax::GLOBALS.set(syntax_globals, || { + syntax_pos::GLOBALS.set(syntax_pos_globals, || { + if let Some(stderr) = stderr { + io::set_panic(Some(box Sink(stderr.clone()))); + } + ty::tls::with_thread_locals(|| { + ty::tls::GCX_PTR.set(gcx_ptr, || worker()) + }) + }) + }) + }; + + ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap() + }) + }) + }) +} + fn load_backend_from_dylib(path: &Path) -> fn() -> Box { let lib = DynamicLibrary::open(Some(path)).unwrap_or_else(|err| { let err = format!("couldn't load codegen backend {:?}: {:?}", path, err); @@ -297,7 +454,7 @@ pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box CrateDisambiguator { +pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator { use std::hash::Hasher; // The crate_disambiguator is a 128 bit hash. The disambiguator is fed diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 0b656ed44cc63..20fa6009b310b 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -7,13 +7,13 @@ use self::def_ctor::{get_def_from_def_id, get_def_from_hir_id}; use super::*; -pub struct AutoTraitFinder<'a, 'tcx: 'a, 'rcx: 'a> { - pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, +pub struct AutoTraitFinder<'a, 'tcx> { + pub cx: &'a core::DocContext<'tcx>, pub f: auto::AutoTraitFinder<'a, 'tcx>, } -impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { - pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { + pub fn new(cx: &'a core::DocContext<'tcx>) -> Self { let f = auto::AutoTraitFinder::new(&cx.tcx); AutoTraitFinder { cx, f } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 86914f66c3d29..aaae0bafd9e01 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -11,12 +11,12 @@ use super::*; use self::def_ctor::{get_def_from_def_id, get_def_from_hir_id}; -pub struct BlanketImplFinder<'a, 'tcx: 'a, 'rcx: 'a> { - pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, +pub struct BlanketImplFinder<'a, 'tcx> { + pub cx: &'a core::DocContext<'tcx>, } -impl<'a, 'tcx, 'rcx> BlanketImplFinder <'a, 'tcx, 'rcx> { - pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { + pub fn new(cx: &'a core::DocContext<'tcx>) -> Self { BlanketImplFinder { cx } } diff --git a/src/librustdoc/clean/def_ctor.rs b/src/librustdoc/clean/def_ctor.rs index 17d53479a67ae..405a2e66d6e5c 100644 --- a/src/librustdoc/clean/def_ctor.rs +++ b/src/librustdoc/clean/def_ctor.rs @@ -2,7 +2,7 @@ use crate::core::DocContext; use super::*; -pub fn get_def_from_def_id(cx: &DocContext<'_, '_, '_>, +pub fn get_def_from_def_id(cx: &DocContext<'_>, def_id: DefId, callback: &F, ) -> Vec @@ -38,7 +38,7 @@ where F: Fn(& dyn Fn(DefId) -> Def) -> Vec { } } -pub fn get_def_from_hir_id(cx: &DocContext<'_, '_, '_>, +pub fn get_def_from_hir_id(cx: &DocContext<'_>, id: hir::HirId, name: String, callback: &F, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index abaf87f7aef0f..880f67281b967 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -36,7 +36,7 @@ use super::Clean; /// The returned value is `None` if the definition could not be inlined, /// and `Some` of a vector of items if it was successfully expanded. pub fn try_inline( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, def: Def, name: ast::Name, visited: &mut FxHashSet @@ -129,7 +129,7 @@ pub fn try_inline( Some(ret) } -pub fn try_inline_glob(cx: &DocContext<'_, '_, '_>, def: Def, visited: &mut FxHashSet) +pub fn try_inline_glob(cx: &DocContext<'_>, def: Def, visited: &mut FxHashSet) -> Option> { if def == Def::Err { return None } @@ -146,7 +146,7 @@ pub fn try_inline_glob(cx: &DocContext<'_, '_, '_>, def: Def, visited: &mut FxHa } } -pub fn load_attrs(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Attributes { +pub fn load_attrs(cx: &DocContext<'_>, did: DefId) -> clean::Attributes { cx.tcx.get_attrs(did).clean(cx) } @@ -154,7 +154,7 @@ pub fn load_attrs(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Attributes /// /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. -pub fn record_extern_fqn(cx: &DocContext<'_, '_, '_>, did: DefId, kind: clean::TypeKind) { +pub fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) { let mut crate_name = cx.tcx.crate_name(did.krate).to_string(); if did.is_local() { crate_name = cx.crate_name.clone().unwrap_or(crate_name); @@ -182,7 +182,7 @@ pub fn record_extern_fqn(cx: &DocContext<'_, '_, '_>, did: DefId, kind: clean::T } } -pub fn build_external_trait(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Trait { +pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let auto_trait = cx.tcx.trait_def(did).has_auto_impl; let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); let predicates = cx.tcx.predicates_of(did); @@ -202,7 +202,7 @@ pub fn build_external_trait(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::T } } -fn build_external_function(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Function { +fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { let sig = cx.tcx.fn_sig(did); let constness = if cx.tcx.is_min_const_fn(did) { @@ -224,7 +224,7 @@ fn build_external_function(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Fu } } -fn build_enum(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Enum { +fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum { let predicates = cx.tcx.predicates_of(did); clean::Enum { @@ -234,7 +234,7 @@ fn build_enum(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Enum { } } -fn build_struct(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Struct { +fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct { let predicates = cx.tcx.predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); @@ -250,7 +250,7 @@ fn build_struct(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Struct { } } -fn build_union(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Union { +fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union { let predicates = cx.tcx.predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); @@ -262,7 +262,7 @@ fn build_union(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Union { } } -fn build_type_alias(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Typedef { +fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef { let predicates = cx.tcx.predicates_of(did); clean::Typedef { @@ -271,7 +271,7 @@ fn build_type_alias(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Typedef { } } -pub fn build_impls(cx: &DocContext<'_, '_, '_>, did: DefId) -> Vec { +pub fn build_impls(cx: &DocContext<'_>, did: DefId) -> Vec { let tcx = cx.tcx; let mut impls = Vec::new(); @@ -282,7 +282,7 @@ pub fn build_impls(cx: &DocContext<'_, '_, '_>, did: DefId) -> Vec impls } -pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec) { +pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec) { if !cx.renderinfo.borrow_mut().inlined.insert(did) { return } @@ -393,7 +393,7 @@ pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec, + cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet ) -> clean::Module { @@ -404,7 +404,7 @@ fn build_module( is_crate: false, }; - fn fill_in(cx: &DocContext<'_, '_, '_>, did: DefId, items: &mut Vec, + fn fill_in(cx: &DocContext<'_>, did: DefId, items: &mut Vec, visited: &mut FxHashSet) { // If we're re-exporting a re-export it may actually re-export something in // two namespaces, so the target may be listed twice. Make sure we only @@ -421,7 +421,7 @@ fn build_module( } } -pub fn print_inlined_const(cx: &DocContext<'_, '_, '_>, did: DefId) -> String { +pub fn print_inlined_const(cx: &DocContext<'_>, did: DefId) -> String { if let Some(node_id) = cx.tcx.hir().as_local_hir_id(did) { cx.tcx.hir().hir_to_pretty_string(node_id) } else { @@ -429,14 +429,14 @@ pub fn print_inlined_const(cx: &DocContext<'_, '_, '_>, did: DefId) -> String { } } -fn build_const(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Constant { +fn build_const(cx: &DocContext<'_>, did: DefId) -> clean::Constant { clean::Constant { type_: cx.tcx.type_of(did).clean(cx), expr: print_inlined_const(cx, did) } } -fn build_static(cx: &DocContext<'_, '_, '_>, did: DefId, mutable: bool) -> clean::Static { +fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static { clean::Static { type_: cx.tcx.type_of(did).clean(cx), mutability: if mutable {clean::Mutable} else {clean::Immutable}, @@ -444,7 +444,7 @@ fn build_static(cx: &DocContext<'_, '_, '_>, did: DefId, mutable: bool) -> clean } } -fn build_macro(cx: &DocContext<'_, '_, '_>, did: DefId, name: ast::Name) -> clean::ItemEnum { +fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemEnum { let imported_from = cx.tcx.original_crate_name(did.krate); match cx.cstore.load_macro_untracked(did, cx.sess()) { LoadedMacro::MacroDef(def) => { @@ -546,7 +546,7 @@ fn separate_supertrait_bounds(mut g: clean::Generics) (g, ty_bounds) } -pub fn record_extern_trait(cx: &DocContext<'_, '_, '_>, did: DefId) { +pub fn record_extern_trait(cx: &DocContext<'_>, did: DefId) { if did.is_local() { return; } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5a1b4d2f8ce77..f2bf7ead5619b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -71,56 +71,56 @@ thread_local!(pub static MAX_DEF_ID: RefCell> = Defau const FN_OUTPUT_NAME: &'static str = "Output"; // extract the stability index for a node from tcx, if possible -fn get_stability(cx: &DocContext<'_, '_, '_>, def_id: DefId) -> Option { +fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option { cx.tcx.lookup_stability(def_id).clean(cx) } -fn get_deprecation(cx: &DocContext<'_, '_, '_>, def_id: DefId) -> Option { +fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option { cx.tcx.lookup_deprecation(def_id).clean(cx) } pub trait Clean { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> T; + fn clean(&self, cx: &DocContext<'_>) -> T; } impl, U> Clean> for [T] { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { + fn clean(&self, cx: &DocContext<'_>) -> Vec { self.iter().map(|x| x.clean(cx)).collect() } } impl, U, V: Idx> Clean> for IndexVec { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> IndexVec { + fn clean(&self, cx: &DocContext<'_>) -> IndexVec { self.iter().map(|x| x.clean(cx)).collect() } } impl, U> Clean for P { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U { + fn clean(&self, cx: &DocContext<'_>) -> U { (**self).clean(cx) } } impl, U> Clean for Rc { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U { + fn clean(&self, cx: &DocContext<'_>) -> U { (**self).clean(cx) } } impl, U> Clean> for Option { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { self.as_ref().map(|v| v.clean(cx)) } } impl Clean for ty::Binder where T: Clean { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U { + fn clean(&self, cx: &DocContext<'_>) -> U { self.skip_binder().clean(cx) } } impl, U> Clean> for P<[T]> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { + fn clean(&self, cx: &DocContext<'_>) -> Vec { self.iter().map(|x| x.clean(cx)).collect() } } @@ -139,8 +139,8 @@ pub struct Crate { pub masked_crates: FxHashSet, } -impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Crate { +impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { + fn clean(&self, cx: &DocContext<'_>) -> Crate { use crate::visit_lib::LibEmbargoVisitor; { @@ -234,7 +234,7 @@ pub struct ExternalCrate { } impl Clean for CrateNum { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> ExternalCrate { + fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate { let root = DefId { krate: *self, index: CRATE_DEF_INDEX }; let krate_span = cx.tcx.def_span(root); let krate_src = cx.sess().source_map().span_to_filename(krate_span); @@ -582,7 +582,7 @@ pub struct Module { } impl Clean for doctree::Module { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let name = if self.name.is_some() { self.name.expect("No name provided").clean(cx) } else { @@ -1023,7 +1023,7 @@ impl AttributesExt for Attributes { } impl Clean for [ast::Attribute] { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Attributes { + fn clean(&self, cx: &DocContext<'_>) -> Attributes { Attributes::from_ast(cx.sess().diagnostic(), self) } } @@ -1035,7 +1035,7 @@ pub enum GenericBound { } impl GenericBound { - fn maybe_sized(cx: &DocContext<'_, '_, '_>) -> GenericBound { + fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem); let empty = cx.tcx.intern_substs(&[]); let path = external_path(cx, &cx.tcx.item_name(did).as_str(), @@ -1052,7 +1052,7 @@ impl GenericBound { }, hir::TraitBoundModifier::Maybe) } - fn is_sized_bound(&self, cx: &DocContext<'_, '_, '_>) -> bool { + fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { use rustc::hir::TraitBoundModifier as TBM; if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { if trait_.def_id() == cx.tcx.lang_items().sized_trait() { @@ -1078,7 +1078,7 @@ impl GenericBound { } impl Clean for hir::GenericBound { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { match *self { hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)), hir::GenericBound::Trait(ref t, modifier) => { @@ -1088,7 +1088,7 @@ impl Clean for hir::GenericBound { } } -fn external_generic_args(cx: &DocContext<'_, '_, '_>, trait_did: Option, has_self: bool, +fn external_generic_args(cx: &DocContext<'_>, trait_did: Option, has_self: bool, bindings: Vec, substs: SubstsRef<'_>) -> GenericArgs { let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect(); let types = substs.types().skip(has_self as usize).collect::>(); @@ -1130,7 +1130,7 @@ fn external_generic_args(cx: &DocContext<'_, '_, '_>, trait_did: Option, // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar // from Fn<(A, B,), C> to Fn(A, B) -> C -fn external_path(cx: &DocContext<'_, '_, '_>, name: &str, trait_did: Option, has_self: bool, +fn external_path(cx: &DocContext<'_>, name: &str, trait_did: Option, has_self: bool, bindings: Vec, substs: SubstsRef<'_>) -> Path { Path { global: false, @@ -1143,7 +1143,7 @@ fn external_path(cx: &DocContext<'_, '_, '_>, name: &str, trait_did: Option Clean for (&'a ty::TraitRef<'tcx>, Vec) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { let (trait_ref, ref bounds) = *self; inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait); let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(), @@ -1187,13 +1187,13 @@ impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec } impl<'tcx> Clean for ty::TraitRef<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound { + fn clean(&self, cx: &DocContext<'_>) -> GenericBound { (self, vec![]).clean(cx) } } impl<'tcx> Clean>> for InternalSubsts<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option> { + fn clean(&self, cx: &DocContext<'_>) -> Option> { let mut v = Vec::new(); v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives)); v.extend(self.types().map(|t| GenericBound::TraitBound(PolyTrait { @@ -1220,7 +1220,7 @@ impl Lifetime { } impl Clean for hir::Lifetime { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Lifetime { + fn clean(&self, cx: &DocContext<'_>) -> Lifetime { if self.hir_id != hir::DUMMY_HIR_ID { let def = cx.tcx.named_region(self.hir_id); match def { @@ -1239,7 +1239,7 @@ impl Clean for hir::Lifetime { } impl Clean for hir::GenericParam { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Lifetime { + fn clean(&self, _: &DocContext<'_>) -> Lifetime { match self.kind { hir::GenericParamKind::Lifetime { .. } => { if self.bounds.len() > 0 { @@ -1263,7 +1263,7 @@ impl Clean for hir::GenericParam { } impl Clean for hir::ConstArg { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Constant { + fn clean(&self, cx: &DocContext<'_>) -> Constant { Constant { type_: cx.tcx.type_of(cx.tcx.hir().body_owner_def_id(self.value.body)).clean(cx), expr: print_const_expr(cx, self.value.body), @@ -1272,13 +1272,13 @@ impl Clean for hir::ConstArg { } impl<'tcx> Clean for ty::GenericParamDef { - fn clean(&self, _cx: &DocContext<'_, '_, '_>) -> Lifetime { + fn clean(&self, _cx: &DocContext<'_>) -> Lifetime { Lifetime(self.name.to_string()) } } impl Clean> for ty::RegionKind { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { match *self { ty::ReStatic => Some(Lifetime::statik()), ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())), @@ -1307,7 +1307,7 @@ pub enum WherePredicate { } impl Clean for hir::WherePredicate { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate { + fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { match *self { hir::WherePredicate::BoundPredicate(ref wbp) => { WherePredicate::BoundPredicate { @@ -1334,7 +1334,7 @@ impl Clean for hir::WherePredicate { } impl<'a> Clean> for ty::Predicate<'a> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { use rustc::ty::Predicate; match *self { @@ -1353,7 +1353,7 @@ impl<'a> Clean> for ty::Predicate<'a> { } impl<'a> Clean for ty::TraitPredicate<'a> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate { + fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { WherePredicate::BoundPredicate { ty: self.trait_ref.self_ty().clean(cx), bounds: vec![self.trait_ref.clean(cx)] @@ -1362,7 +1362,7 @@ impl<'a> Clean for ty::TraitPredicate<'a> { } impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { - fn clean(&self, _cx: &DocContext<'_, '_, '_>) -> WherePredicate { + fn clean(&self, _cx: &DocContext<'_>) -> WherePredicate { panic!("subtype predicates are an internal rustc artifact \ and should not be seen by rustdoc") } @@ -1371,7 +1371,7 @@ impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { impl<'tcx> Clean> for ty::OutlivesPredicate,ty::Region<'tcx>> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { let ty::OutlivesPredicate(ref a, ref b) = *self; match (a, b) { @@ -1389,7 +1389,7 @@ impl<'tcx> Clean> for } impl<'tcx> Clean> for ty::OutlivesPredicate, ty::Region<'tcx>> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { let ty::OutlivesPredicate(ref ty, ref lt) = *self; match lt { @@ -1405,7 +1405,7 @@ impl<'tcx> Clean> for ty::OutlivesPredicate, ty: } impl<'tcx> Clean for ty::ProjectionPredicate<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate { + fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { WherePredicate::EqPredicate { lhs: self.projection_ty.clean(cx), rhs: self.ty.clean(cx) @@ -1414,7 +1414,7 @@ impl<'tcx> Clean for ty::ProjectionPredicate<'tcx> { } impl<'tcx> Clean for ty::ProjectionTy<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type { + fn clean(&self, cx: &DocContext<'_>) -> Type { let trait_ = match self.trait_ref(cx.tcx).clean(cx) { GenericBound::TraitBound(t, _) => t.trait_, GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"), @@ -1462,7 +1462,7 @@ impl GenericParamDef { } impl<'tcx> Clean for ty::GenericParamDef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericParamDef { + fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { ty::GenericParamDefKind::Lifetime => { (self.name.to_string(), GenericParamDefKind::Lifetime) @@ -1495,7 +1495,7 @@ impl<'tcx> Clean for ty::GenericParamDef { } impl Clean for hir::GenericParam { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericParamDef { + fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { hir::GenericParamKind::Lifetime { .. } => { let name = if self.bounds.len() > 0 { @@ -1545,7 +1545,7 @@ pub struct Generics { } impl Clean for hir::Generics { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Generics { + fn clean(&self, cx: &DocContext<'_>) -> Generics { // Synthetic type-parameters are inserted after normal ones. // In order for normal parameters to be able to refer to synthetic ones, // scans them first. @@ -1615,7 +1615,7 @@ impl Clean for hir::Generics { impl<'a, 'tcx> Clean for (&'a ty::Generics, &'a Lrc>) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Generics { + fn clean(&self, cx: &DocContext<'_>) -> Generics { use self::WherePredicate as WP; let (gens, preds) = *self; @@ -1702,7 +1702,7 @@ pub struct Method { } impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Method { + fn clean(&self, cx: &DocContext<'_>) -> Method { let (generics, decl) = enter_impl_trait(cx, || { (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)) }); @@ -1729,7 +1729,7 @@ pub struct Function { } impl Clean for doctree::Function { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let (generics, decl) = enter_impl_trait(cx, || { (self.generics.clean(cx), (&self.decl, self.body).clean(cx)) }); @@ -1800,7 +1800,7 @@ pub struct Arguments { } impl<'a> Clean for (&'a [hir::Ty], &'a [ast::Ident]) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Arguments { + fn clean(&self, cx: &DocContext<'_>) -> Arguments { Arguments { values: self.0.iter().enumerate().map(|(i, ty)| { let mut name = self.1.get(i).map(|ident| ident.to_string()) @@ -1818,7 +1818,7 @@ impl<'a> Clean for (&'a [hir::Ty], &'a [ast::Ident]) { } impl<'a> Clean for (&'a [hir::Ty], hir::BodyId) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Arguments { + fn clean(&self, cx: &DocContext<'_>) -> Arguments { let body = cx.tcx.hir().body(self.1); Arguments { @@ -1835,7 +1835,7 @@ impl<'a> Clean for (&'a [hir::Ty], hir::BodyId) { impl<'a, A: Copy> Clean for (&'a hir::FnDecl, A) where (&'a [hir::Ty], A): Clean { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FnDecl { + fn clean(&self, cx: &DocContext<'_>) -> FnDecl { FnDecl { inputs: (&self.0.inputs[..], self.1).clean(cx), output: self.0.output.clean(cx), @@ -1845,7 +1845,7 @@ impl<'a, A: Copy> Clean for (&'a hir::FnDecl, A) } impl<'a, 'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FnDecl { + fn clean(&self, cx: &DocContext<'_>) -> FnDecl { let (did, sig) = *self; let mut names = if cx.tcx.hir().as_local_hir_id(did).is_some() { vec![].into_iter() @@ -1905,7 +1905,7 @@ pub enum FunctionRetTy { } impl Clean for hir::FunctionRetTy { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FunctionRetTy { + fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy { match *self { hir::Return(ref typ) => Return(typ.clean(cx)), hir::DefaultReturn(..) => DefaultReturn, @@ -1934,7 +1934,7 @@ pub struct Trait { } impl Clean for doctree::Trait { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); let is_spotlight = attrs.has_doc_flag("spotlight"); Item { @@ -1965,7 +1965,7 @@ pub struct TraitAlias { } impl Clean for doctree::TraitAlias { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); Item { name: Some(self.name.clean(cx)), @@ -1984,7 +1984,7 @@ impl Clean for doctree::TraitAlias { } impl Clean for hir::IsAuto { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> bool { + fn clean(&self, _: &DocContext<'_>) -> bool { match *self { hir::IsAuto::Yes => true, hir::IsAuto::No => false, @@ -1993,13 +1993,13 @@ impl Clean for hir::IsAuto { } impl Clean for hir::TraitRef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type { + fn clean(&self, cx: &DocContext<'_>) -> Type { resolve_type(cx, self.path.clean(cx), self.hir_ref_id) } } impl Clean for hir::PolyTraitRef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> PolyTrait { + fn clean(&self, cx: &DocContext<'_>) -> PolyTrait { PolyTrait { trait_: self.trait_ref.clean(cx), generic_params: self.bound_generic_params.clean(cx) @@ -2008,7 +2008,7 @@ impl Clean for hir::PolyTraitRef { } impl Clean for hir::TraitItem { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.node { hir::TraitItemKind::Const(ref ty, default) => { AssociatedConstItem(ty.clean(cx), @@ -2046,7 +2046,7 @@ impl Clean for hir::TraitItem { } impl Clean for hir::ImplItem { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.node { hir::ImplItemKind::Const(ref ty, expr) => { AssociatedConstItem(ty.clean(cx), @@ -2079,7 +2079,7 @@ impl Clean for hir::ImplItem { } impl<'tcx> Clean for ty::AssociatedItem { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.kind { ty::AssociatedKind::Const => { let ty = cx.tcx.type_of(self.def_id); @@ -2524,7 +2524,7 @@ impl From for PrimitiveType { } impl Clean for hir::Ty { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type { + fn clean(&self, cx: &DocContext<'_>) -> Type { use rustc::hir::*; match self.node { @@ -2726,7 +2726,7 @@ impl Clean for hir::Ty { } impl<'tcx> Clean for Ty<'tcx> { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type { + fn clean(&self, cx: &DocContext<'_>) -> Type { match self.sty { ty::Never => Never, ty::Bool => Primitive(PrimitiveType::Bool), @@ -2921,7 +2921,7 @@ impl<'tcx> Clean for Ty<'tcx> { } impl Clean for hir::StructField { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id); Item { @@ -2938,7 +2938,7 @@ impl Clean for hir::StructField { } impl<'tcx> Clean for ty::FieldDef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.ident.name).clean(cx), attrs: cx.tcx.get_attrs(self.did).clean(cx), @@ -2961,7 +2961,7 @@ pub enum Visibility { } impl Clean> for hir::Visibility { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, cx: &DocContext<'_>) -> Option { Some(match self.node { hir::VisibilityKind::Public => Visibility::Public, hir::VisibilityKind::Inherited => Visibility::Inherited, @@ -2976,7 +2976,7 @@ impl Clean> for hir::Visibility { } impl Clean> for ty::Visibility { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Option { + fn clean(&self, _: &DocContext<'_>) -> Option { Some(if *self == ty::Visibility::Public { Public } else { Inherited }) } } @@ -2998,7 +2998,7 @@ pub struct Union { } impl Clean for doctree::Struct { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3018,7 +3018,7 @@ impl Clean for doctree::Struct { } impl Clean for doctree::Union { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3048,7 +3048,7 @@ pub struct VariantStruct { } impl Clean for ::rustc::hir::VariantData { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> VariantStruct { + fn clean(&self, cx: &DocContext<'_>) -> VariantStruct { VariantStruct { struct_type: doctree::struct_type_from_def(self), fields: self.fields().iter().map(|x| x.clean(cx)).collect(), @@ -3065,7 +3065,7 @@ pub struct Enum { } impl Clean for doctree::Enum { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3089,7 +3089,7 @@ pub struct Variant { } impl Clean for doctree::Variant { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3106,7 +3106,7 @@ impl Clean for doctree::Variant { } impl<'tcx> Clean for ty::VariantDef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let kind = match self.ctor_kind { CtorKind::Const => VariantKind::CLike, CtorKind::Fn => { @@ -3154,7 +3154,7 @@ pub enum VariantKind { } impl Clean for hir::VariantData { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> VariantKind { + fn clean(&self, cx: &DocContext<'_>) -> VariantKind { if self.is_struct() { VariantKind::Struct(self.clean(cx)) } else if self.is_unit() { @@ -3185,7 +3185,7 @@ impl Span { } impl Clean for syntax_pos::Span { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Span { + fn clean(&self, cx: &DocContext<'_>) -> Span { if self.is_dummy() { return Span::empty(); } @@ -3218,7 +3218,7 @@ impl Path { } impl Clean for hir::Path { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Path { + fn clean(&self, cx: &DocContext<'_>) -> Path { Path { global: self.is_global(), def: self.def, @@ -3241,7 +3241,7 @@ pub enum GenericArgs { } impl Clean for hir::GenericArgs { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericArgs { + fn clean(&self, cx: &DocContext<'_>) -> GenericArgs { if self.parenthesized { let output = self.bindings[0].ty.clean(cx); GenericArgs::Parenthesized { @@ -3283,7 +3283,7 @@ pub struct PathSegment { } impl Clean for hir::PathSegment { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> PathSegment { + fn clean(&self, cx: &DocContext<'_>) -> PathSegment { PathSegment { name: self.ident.name.clean(cx), args: self.with_generic_args(|generic_args| generic_args.clean(cx)) @@ -3355,21 +3355,21 @@ fn qpath_to_string(p: &hir::QPath) -> String { impl Clean for Ident { #[inline] - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> String { + fn clean(&self, cx: &DocContext<'_>) -> String { self.name.clean(cx) } } impl Clean for ast::Name { #[inline] - fn clean(&self, _: &DocContext<'_, '_, '_>) -> String { + fn clean(&self, _: &DocContext<'_>) -> String { self.to_string() } } impl Clean for InternedString { #[inline] - fn clean(&self, _: &DocContext<'_, '_, '_>) -> String { + fn clean(&self, _: &DocContext<'_>) -> String { self.to_string() } } @@ -3381,7 +3381,7 @@ pub struct Typedef { } impl Clean for doctree::Typedef { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3405,7 +3405,7 @@ pub struct Existential { } impl Clean for doctree::Existential { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3431,7 +3431,7 @@ pub struct BareFunctionDecl { } impl Clean for hir::BareFnTy { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> BareFunctionDecl { + fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, || { (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx)) }); @@ -3455,7 +3455,7 @@ pub struct Static { } impl Clean for doctree::Static { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { debug!("cleaning static {}: {:?}", self.name.clean(cx), self); Item { name: Some(self.name.clean(cx)), @@ -3481,7 +3481,7 @@ pub struct Constant { } impl Clean for doctree::Constant { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3505,7 +3505,7 @@ pub enum Mutability { } impl Clean for hir::Mutability { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Mutability { + fn clean(&self, _: &DocContext<'_>) -> Mutability { match self { &hir::MutMutable => Mutable, &hir::MutImmutable => Immutable, @@ -3520,7 +3520,7 @@ pub enum ImplPolarity { } impl Clean for hir::ImplPolarity { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> ImplPolarity { + fn clean(&self, _: &DocContext<'_>) -> ImplPolarity { match self { &hir::ImplPolarity::Positive => ImplPolarity::Positive, &hir::ImplPolarity::Negative => ImplPolarity::Negative, @@ -3542,7 +3542,7 @@ pub struct Impl { } pub fn get_auto_traits_with_hir_id( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, id: hir::HirId, name: String ) -> Vec { @@ -3551,7 +3551,7 @@ pub fn get_auto_traits_with_hir_id( } pub fn get_auto_traits_with_def_id( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, id: DefId ) -> Vec { let finder = AutoTraitFinder::new(cx); @@ -3560,7 +3560,7 @@ pub fn get_auto_traits_with_def_id( } pub fn get_blanket_impls_with_hir_id( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, id: hir::HirId, name: String ) -> Vec { @@ -3569,7 +3569,7 @@ pub fn get_blanket_impls_with_hir_id( } pub fn get_blanket_impls_with_def_id( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, id: DefId ) -> Vec { let finder = BlanketImplFinder::new(cx); @@ -3578,7 +3578,7 @@ pub fn get_blanket_impls_with_def_id( } impl Clean> for doctree::Impl { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { + fn clean(&self, cx: &DocContext<'_>) -> Vec { let mut ret = Vec::new(); let trait_ = self.trait_.clean(cx); let items = self.items.clean(cx); @@ -3620,7 +3620,7 @@ impl Clean> for doctree::Impl { } } -fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>, +fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec) { use self::PrimitiveType::*; @@ -3679,7 +3679,7 @@ fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>, } impl Clean> for doctree::ExternCrate { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { + fn clean(&self, cx: &DocContext<'_>) -> Vec { let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| { a.name() == "doc" && match a.meta_item_list() { @@ -3715,7 +3715,7 @@ impl Clean> for doctree::ExternCrate { } impl Clean> for doctree::Import { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { + fn clean(&self, cx: &DocContext<'_>) -> Vec { // We consider inlining the documentation of `pub use` statements, but we // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. @@ -3789,7 +3789,7 @@ pub struct ImportSource { } impl Clean> for hir::ForeignMod { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { + fn clean(&self, cx: &DocContext<'_>) -> Vec { let mut items = self.items.clean(cx); for item in &mut items { if let ForeignFunctionItem(ref mut f) = item.inner { @@ -3801,7 +3801,7 @@ impl Clean> for hir::ForeignMod { } impl Clean for hir::ForeignItem { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.node { hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => { let (generics, decl) = enter_impl_trait(cx, || { @@ -3848,11 +3848,11 @@ impl Clean for hir::ForeignItem { // Utilities pub trait ToSource { - fn to_src(&self, cx: &DocContext<'_, '_, '_>) -> String; + fn to_src(&self, cx: &DocContext<'_>) -> String; } impl ToSource for syntax_pos::Span { - fn to_src(&self, cx: &DocContext<'_, '_, '_>) -> String { + fn to_src(&self, cx: &DocContext<'_>) -> String { debug!("converting span {:?} to snippet", self.clean(cx)); let sn = match cx.sess().source_map().span_to_snippet(*self) { Ok(x) => x, @@ -3899,7 +3899,7 @@ fn name_from_pat(p: &hir::Pat) -> String { } } -fn print_const(cx: &DocContext<'_, '_, '_>, n: ty::LazyConst<'_>) -> String { +fn print_const(cx: &DocContext<'_>, n: ty::LazyConst<'_>) -> String { match n { ty::LazyConst::Unevaluated(def_id, _) => { if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { @@ -3921,12 +3921,12 @@ fn print_const(cx: &DocContext<'_, '_, '_>, n: ty::LazyConst<'_>) -> String { } } -fn print_const_expr(cx: &DocContext<'_, '_, '_>, body: hir::BodyId) -> String { +fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String { cx.tcx.hir().hir_to_pretty_string(body.hir_id) } /// Given a type Path, resolve it to a Type using the TyCtxt -fn resolve_type(cx: &DocContext<'_, '_, '_>, +fn resolve_type(cx: &DocContext<'_>, path: Path, id: hir::HirId) -> Type { if id == hir::DUMMY_HIR_ID { @@ -3957,7 +3957,7 @@ fn resolve_type(cx: &DocContext<'_, '_, '_>, ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic } } -pub fn register_def(cx: &DocContext<'_, '_, '_>, def: Def) -> DefId { +pub fn register_def(cx: &DocContext<'_>, def: Def) -> DefId { debug!("register_def({:?})", def); let (did, kind) = match def { @@ -3992,7 +3992,7 @@ pub fn register_def(cx: &DocContext<'_, '_, '_>, def: Def) -> DefId { did } -fn resolve_use_source(cx: &DocContext<'_, '_, '_>, path: Path) -> ImportSource { +fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource { ImportSource { did: if path.def.opt_def_id().is_none() { None @@ -4010,7 +4010,7 @@ pub struct Macro { } impl Clean for doctree::Macro { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { let name = self.name.clean(cx); Item { name: Some(name.clone()), @@ -4039,7 +4039,7 @@ pub struct ProcMacro { } impl Clean for doctree::ProcMacro { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item { + fn clean(&self, cx: &DocContext<'_>) -> Item { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -4073,7 +4073,7 @@ pub struct Deprecation { } impl Clean for attr::Stability { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Stability { + fn clean(&self, _: &DocContext<'_>) -> Stability { Stability { level: stability::StabilityLevel::from_attr_level(&self.level), feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()), @@ -4100,13 +4100,13 @@ impl Clean for attr::Stability { } impl<'a> Clean for &'a attr::Stability { - fn clean(&self, dc: &DocContext<'_, '_, '_>) -> Stability { + fn clean(&self, dc: &DocContext<'_>) -> Stability { (**self).clean(dc) } } impl Clean for attr::Deprecation { - fn clean(&self, _: &DocContext<'_, '_, '_>) -> Deprecation { + fn clean(&self, _: &DocContext<'_>) -> Deprecation { Deprecation { since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()), note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()), @@ -4122,7 +4122,7 @@ pub struct TypeBinding { } impl Clean for hir::TypeBinding { - fn clean(&self, cx: &DocContext<'_, '_, '_>) -> TypeBinding { + fn clean(&self, cx: &DocContext<'_>) -> TypeBinding { TypeBinding { name: self.ident.name.clean(cx), ty: self.ty.clean(cx) @@ -4131,7 +4131,7 @@ impl Clean for hir::TypeBinding { } pub fn def_id_to_path( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, did: DefId, name: Option ) -> Vec { @@ -4148,7 +4148,7 @@ pub fn def_id_to_path( once(crate_name).chain(relative).collect() } -pub fn enter_impl_trait(cx: &DocContext<'_, '_, '_>, f: F) -> R +pub fn enter_impl_trait(cx: &DocContext<'_>, f: F) -> R where F: FnOnce() -> R, { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 8614b72dffba7..8ca570cb443c9 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -22,7 +22,7 @@ use crate::clean::WherePredicate as WP; use crate::clean; use crate::core::DocContext; -pub fn where_clauses(cx: &DocContext<'_, '_, '_>, clauses: Vec) -> Vec { +pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { // First, partition the where clause into its separate components let mut params: BTreeMap<_, Vec<_>> = BTreeMap::new(); let mut lifetimes = Vec::new(); @@ -141,7 +141,7 @@ fn ty_bounds(bounds: Vec) -> Vec { bounds } -fn trait_is_same_or_supertrait(cx: &DocContext<'_, '_, '_>, child: DefId, +fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) -> bool { if child == trait_ { return true diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index aeff78350d37c..f2682e00430d0 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -203,7 +203,7 @@ pub struct RenderOptions { impl Options { /// Parses the given command-line for options. If an error message or other early-return has /// been printed, returns `Err` with the exit code. - pub fn from_matches(matches: &getopts::Matches) -> Result { + pub fn from_matches(matches: &getopts::Matches) -> Result { // Check for unstable options. nightly_options::check_nightly_options(&matches, &opts()); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 373856319f1f3..47dbbc20980ba 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,19 +1,18 @@ use rustc_lint; -use rustc_driver::{driver, abort_on_err}; use rustc::session::{self, config}; use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CrateNum, LOCAL_CRATE}; use rustc::hir::def::Def; use rustc::hir::{self, HirId, HirVec}; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; -use rustc::ty::{self, TyCtxt, AllArenas}; -use rustc::hir::map as hir_map; +use rustc::ty::{self, TyCtxt}; use rustc::lint::{self, LintPass}; use rustc::session::config::ErrorOutputType; +use rustc::session::DiagnosticOutput; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_interface::util; +use rustc_interface::interface; +use rustc_driver::abort_on_err; use rustc_resolve as resolve; -use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; use rustc_target::spec::TargetTriple; @@ -24,15 +23,15 @@ use syntax::json::JsonEmitter; use syntax::ptr::P; use syntax::symbol::keywords; use syntax_pos::DUMMY_SP; -use errors::{self, FatalError}; +use errors; use errors::emitter::{Emitter, EmitterWriter}; use parking_lot::ReentrantMutex; use std::cell::RefCell; use std::mem; use rustc_data_structures::sync::{self, Lrc}; -use std::rc::Rc; use std::sync::Arc; +use std::rc::Rc; use crate::visit_ast::RustdocVisitor; use crate::config::{Options as RustdocOptions, RenderOptions}; @@ -47,12 +46,13 @@ pub use rustc::session::search_paths::SearchPath; pub type ExternalPaths = FxHashMap, clean::TypeKind)>; -pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub resolver: &'a RefCell>, +pub struct DocContext<'tcx> { + + pub tcx: TyCtxt<'tcx, 'tcx, 'tcx>, + pub resolver: Rc>>, /// The stack of module NodeIds up till this point pub crate_name: Option, - pub cstore: Rc, + pub cstore: Lrc, /// Later on moved into `html::render::CACHE_KEY` pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` @@ -79,11 +79,18 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { pub all_traits: Vec, } -impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { +impl<'tcx> DocContext<'tcx> { pub fn sess(&self) -> &session::Session { &self.tcx.sess } + pub fn enter_resolver(&self, f: F) -> R + where F: FnOnce(&mut resolve::Resolver<'_>) -> R { + let resolver = &*self.resolver; + let resolver = resolver.as_ref().unwrap(); + resolver.borrow_mut().access(f) + } + /// Call the closure with the given parameters set as /// the substitutions for a type alias' RHS. pub fn enter_alias(&self, @@ -368,19 +375,31 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); - let lints = lint::builtin::HardwiredLints.get_lints() - .into_iter() - .chain(rustc_lint::SoftLints.get_lints().into_iter()) - .filter_map(|lint| { - if lint.name == warnings_lint_name || - lint.name == intra_link_resolution_failure_name { - None - } else { - Some((lint.name_lower(), lint::Allow)) - } - }) - .chain(lint_opts.into_iter()) - .collect::>(); + let lints = || { + lint::builtin::HardwiredLints + .get_lints() + .into_iter() + .chain(rustc_lint::SoftLints.get_lints().into_iter()) + }; + + let lint_opts = lints().filter_map(|lint| { + if lint.name == warnings_lint_name || + lint.name == intra_link_resolution_failure_name { + None + } else { + Some((lint.name_lower(), lint::Allow)) + } + }).chain(lint_opts.into_iter()).collect::>(); + + let lint_caps = lints().filter_map(|lint| { + // We don't want to whitelist *all* lints so let's + // ignore those ones. + if whitelisted_lints.iter().any(|l| &lint.name == l) { + None + } else { + Some((lint::LintId::of(lint), lint::Allow)) + } + }).collect(); let host_triple = TargetTriple::from_triple(config::host_triple()); // plays with error output here! @@ -389,7 +408,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt search_paths: libs, crate_types: vec![config::CrateType::Rlib], lint_opts: if !display_warnings { - lints + lint_opts } else { vec![] }, @@ -406,116 +425,42 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt describe_lints, ..Options::default() }; - driver::spawn_thread_pool(sessopts, move |sessopts| { - let source_map = Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping())); - let diagnostic_handler = new_handler(error_format, - Some(source_map.clone()), - debugging_options.treat_err_as_bug, - debugging_options.ui_testing); - - let mut sess = session::build_session_( - sessopts, cpath, diagnostic_handler, source_map, Default::default(), - ); - lint::builtin::HardwiredLints.get_lints() - .into_iter() - .chain(rustc_lint::SoftLints.get_lints().into_iter()) - .filter_map(|lint| { - // We don't want to whitelist *all* lints so let's - // ignore those ones. - if whitelisted_lints.iter().any(|l| &lint.name == l) { - None - } else { - Some(lint) - } - }) - .for_each(|l| { - sess.driver_lint_caps.insert(lint::LintId::of(l), - lint::Allow); - }); - - let codegen_backend = util::get_codegen_backend(&sess); - let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader())); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs)); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; - - let control = &driver::CompileController::basic(); - - let krate = match driver::phase_1_parse_input(control, &sess, &input) { - Ok(krate) => krate, - Err(mut e) => { - e.emit(); - FatalError.raise(); - } - }; + let config = interface::Config { + opts: sessopts, + crate_cfg: config::parse_cfgspecs(cfgs), + input, + input_path: cpath, + output_file: None, + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Default, + stderr: None, + crate_name: crate_name.clone(), + lint_caps, + }; - let name = match crate_name { - Some(ref crate_name) => crate_name.clone(), - None => ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input), - }; + interface::run_compiler_in_existing_thread_pool(config, |compiler| { + let sess = compiler.session(); - let mut crate_loader = CrateLoader::new(&sess, &cstore, &name); - - let resolver_arenas = resolve::Resolver::arenas(); - let result = driver::phase_2_configure_and_expand_inner(&sess, - &cstore, - krate, - None, - &name, - None, - &resolver_arenas, - &mut crate_loader, - |_| Ok(())); - let driver::InnerExpansionResult { - mut hir_forest, - resolver, - .. - } = abort_on_err(result, &sess); - - // We need to hold on to the complete resolver, so we clone everything - // for the analysis passes to use. Suboptimal, but necessary in the + // 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 defs = resolver.definitions.clone(); - let resolutions = ty::Resolutions { - freevars: resolver.freevars.clone(), - export_map: resolver.export_map.clone(), - trait_map: resolver.trait_map.clone(), - glob_map: resolver.glob_map.clone(), - maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(), - maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(), - extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { - (ident.name, entry.introduced_by_item) - }).collect(), - }; + let resolver = abort_on_err(compiler.expansion(), sess).peek().1.clone(); - let mut arenas = AllArenas::new(); - let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs); - let output_filenames = util::build_output_filenames(&input, - &None, - &None, - &[], - &sess); - - let resolver = RefCell::new(resolver); - driver::phase_3_run_analysis_passes(&*codegen_backend, - control, - &sess, - &*cstore, - hir_map, - resolutions, - &mut arenas, - &name, - &output_filenames, - |tcx, _, result| { - if result.is_err() { - sess.fatal("Compilation failed, aborting rustdoc"); - } + if sess.err_count() > 0 { + sess.fatal("Compilation failed, aborting rustdoc"); + } - let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); + let mut global_ctxt = abort_on_err(compiler.global_ctxt(), sess).take(); + global_ctxt.enter(|tcx| { + tcx.analysis(LOCAL_CRATE).ok(); + + // Abort if there were any errors so far + sess.abort_if_errors(); + + let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); // Convert from a NodeId set to a DefId set since we don't always have easy access // to the map from defid -> nodeid let access_levels = AccessLevels { @@ -535,9 +480,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let ctxt = DocContext { tcx, - resolver: &resolver, + resolver, crate_name, - cstore: cstore.clone(), + cstore: compiler.cstore().clone(), external_traits: Default::default(), active_extern_traits: Default::default(), renderinfo: RefCell::new(renderinfo), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2a0ef3222ab8e..f11e268b9092c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -23,14 +23,13 @@ extern crate getopts; extern crate env_logger; extern crate rustc; extern crate rustc_data_structures; -extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_resolve; extern crate rustc_lint; +extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_target; extern crate rustc_typeck; -extern crate rustc_interface; extern crate serialize; extern crate syntax; extern crate syntax_pos; @@ -91,11 +90,11 @@ pub fn main() { rustc_driver::set_sigpipe_handler(); env_logger::init(); let res = std::thread::Builder::new().stack_size(thread_stack_size).spawn(move || { - syntax::with_globals(move || { + rustc_interface::interface::default_thread_pool(move || { get_args().map(|args| main_args(&args)).unwrap_or(1) }) }).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE); - process::exit(res as i32); + process::exit(res); } fn get_args() -> Option> { @@ -364,7 +363,7 @@ fn usage(argv0: &str) { println!("{}", options.usage(&format!("{} [options] ", argv0))); } -fn main_args(args: &[String]) -> isize { +fn main_args(args: &[String]) -> i32 { let mut options = getopts::Options::new(); for option in opts() { (option.apply)(&mut options); @@ -441,7 +440,7 @@ where R: 'static + Send, let (tx, rx) = channel(); - let result = rustc_driver::monitor(move || syntax::with_globals(move || { + let result = rustc_driver::report_ices_to_stderr_if_any(move || syntax::with_globals(move || { let crate_name = options.crate_name.clone(); let crate_version = options.crate_version.clone(); let (mut krate, renderinfo, renderopts, passes) = core::run_core(options); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 0014d9ceb5ba2..a2e2303bb27f3 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -36,7 +36,7 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { /// Render `input` (e.g., "foo.md") into an HTML file in `output` /// (e.g., output = "bar" => "bar/foo.html"). -pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> isize { +pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> i32 { let mut output = options.output; output.push(input.file_stem().unwrap()); output.set_extension("html"); @@ -126,7 +126,7 @@ pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> } /// Runs any tests/code examples in the markdown file `input`. -pub fn test(mut options: Options, diag: &errors::Handler) -> isize { +pub fn test(mut options: Options, diag: &errors::Handler) -> i32 { let input_str = match load_string(&options.input, diag) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 04f403888c1fb..fe407fa24d93e 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -15,7 +15,7 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass { description: "counts the number of items with and without documentation", }; -fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { let mut calc = CoverageCalculator::default(); let krate = calc.fold_crate(krate); diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 88d9c87c52898..0556852c54ac2 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -16,15 +16,15 @@ pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { description: "validates syntax inside Rust code blocks", }; -pub fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate { SyntaxChecker { cx }.fold_crate(krate) } -struct SyntaxChecker<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a DocContext<'a, 'tcx, 'rcx>, +struct SyntaxChecker<'a, 'tcx: 'a> { + cx: &'a DocContext<'tcx>, } -impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) { let sess = ParseSess::new(FilePathMapping::empty()); let source_file = sess.source_map().new_source_file( @@ -98,7 +98,7 @@ impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> { } } -impl<'a, 'tcx, 'rcx> DocFolder for SyntaxChecker<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { fn fold_item(&mut self, item: clean::Item) -> Option { if let Some(dox) = &item.attrs.collapsed_doc_value() { for code_block in markdown::rust_code_blocks(&dox) { diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index 088a6ea77c73f..8666ba357b832 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -29,7 +29,7 @@ impl DocFragment { } } -pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { Collapser.fold_crate(krate) } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index c346714ab485a..fefff1f3a7593 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -25,7 +25,7 @@ pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass { description: "reads a crate's documentation to resolve intra-doc-links", }; -pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { +pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { if !UnstableFeatures::from_environment().is_nightly_build() { krate } else { @@ -47,14 +47,14 @@ enum PathKind { Type, } -struct LinkCollector<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a DocContext<'a, 'tcx, 'rcx>, +struct LinkCollector<'a, 'tcx> { + cx: &'a DocContext<'tcx>, mod_ids: Vec, is_nightly_build: bool, } -impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { - fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> LinkCollector<'a, 'tcx> { + fn new(cx: &'a DocContext<'tcx>) -> Self { LinkCollector { cx, mod_ids: Vec::new(), @@ -78,12 +78,11 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { // path. if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) { // FIXME: `with_scope` requires the `NodeId` of a module. - let result = cx.resolver.borrow_mut() - .with_scope(id, + let result = cx.enter_resolver(|resolver| resolver.with_scope(id, |resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path_str, is_val) - }); + })); if let Ok(result) = result { // In case this is a trait item, skip the @@ -142,11 +141,9 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { } // FIXME: `with_scope` requires the `NodeId` of a module. - let ty = cx.resolver.borrow_mut() - .with_scope(id, - |resolver| { + let ty = cx.enter_resolver(|resolver| resolver.with_scope(id, |resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, false) - })?; + }))?; match ty.def { Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => { let item = cx.tcx.inherent_impls(did) @@ -218,7 +215,7 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> { } } -impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { fn fold_item(&mut self, mut item: Item) -> Option { let item_hir_id = if item.is_mod() { if let Some(id) = self.cx.tcx.hir().as_local_hir_id(item.def_id) { @@ -437,26 +434,27 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> { } /// Resolves a string as a macro. -fn macro_resolve(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option { +fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { use syntax::ext::base::{MacroKind, SyntaxExtension}; let segment = ast::PathSegment::from_ident(Ident::from_str(path_str)); let path = ast::Path { segments: vec![segment], span: DUMMY_SP }; - let mut resolver = cx.resolver.borrow_mut(); - let parent_scope = resolver.dummy_parent_scope(); - if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang, - &parent_scope, false, false) { - if let Def::Macro(_, MacroKind::ProcMacroStub) = def { - // skip proc-macro stubs, they'll cause `get_macro` to crash - } else { - if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) { - return Some(def); + cx.enter_resolver(|resolver| { + let parent_scope = resolver.dummy_parent_scope(); + if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang, + &parent_scope, false, false) { + if let Def::Macro(_, MacroKind::ProcMacroStub) = def { + // skip proc-macro stubs, they'll cause `get_macro` to crash + } else { + if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) { + return Some(def); + } } } - } - if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) { - return Some(*def); - } - None + if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) { + return Some(*def); + } + None + }) } /// Reports a resolution failure diagnostic. @@ -465,7 +463,7 @@ fn macro_resolve(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option { /// documentation attributes themselves. This is a little heavy-handed, so we display the markdown /// line containing the failure as a note as well. fn resolution_failure( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, attrs: &Attributes, path_str: &str, dox: &str, @@ -507,7 +505,7 @@ fn resolution_failure( diag.emit(); } -fn ambiguity_error(cx: &DocContext<'_, '_, '_>, attrs: &Attributes, +fn ambiguity_error(cx: &DocContext<'_>, attrs: &Attributes, path_str: &str, article1: &str, kind1: &str, disambig1: &str, article2: &str, kind2: &str, disambig2: &str) { @@ -563,7 +561,7 @@ fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String } /// Given an enum variant's def, return the def of its enum and the associated fragment. -fn handle_variant(cx: &DocContext<'_, '_, '_>, def: Def) -> Result<(Def, Option), ()> { +fn handle_variant(cx: &DocContext<'_>, def: Def) -> Result<(Def, Option), ()> { use rustc::ty::DefIdTree; let parent = if let Some(parent) = cx.tcx.parent(def.def_id()) { @@ -604,7 +602,7 @@ fn is_primitive(path_str: &str, is_val: bool) -> Option { } } -fn primitive_impl(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option { +fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option { let tcx = cx.tcx; match path_str { "u8" => tcx.lang_items().u8_impl(), diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 044e48f990e42..de043277c8359 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -12,7 +12,7 @@ pub const COLLECT_TRAIT_IMPLS: Pass = Pass { description: "retrieves trait impls for items in the crate", }; -pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { +pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { let mut synth = SyntheticImplCollector::new(cx); let mut krate = synth.fold_crate(krate); @@ -138,13 +138,13 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { krate } -struct SyntheticImplCollector<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a DocContext<'a, 'tcx, 'rcx>, +struct SyntheticImplCollector<'a, 'tcx> { + cx: &'a DocContext<'tcx>, impls: Vec, } -impl<'a, 'tcx, 'rcx> SyntheticImplCollector<'a, 'tcx, 'rcx> { - fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> { + fn new(cx: &'a DocContext<'tcx>) -> Self { SyntheticImplCollector { cx, impls: Vec::new(), @@ -152,7 +152,7 @@ impl<'a, 'tcx, 'rcx> SyntheticImplCollector<'a, 'tcx, 'rcx> { } } -impl<'a, 'tcx, 'rcx> DocFolder for SyntheticImplCollector<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { fn fold_item(&mut self, i: Item) -> Option { if i.is_struct() || i.is_enum() || i.is_union() { if let (Some(hir_id), Some(name)) = diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 3b0aebe53f38f..3c403d421c8fd 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -54,7 +54,7 @@ pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE; #[derive(Copy, Clone)] pub struct Pass { pub name: &'static str, - pub pass: fn(clean::Crate, &DocContext<'_, '_, '_>) -> clean::Crate, + pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate, pub description: &'static str, } @@ -308,8 +308,8 @@ impl DocFolder for ImportStripper { } } -pub fn look_for_tests<'a, 'tcx: 'a, 'rcx: 'a>( - cx: &'a DocContext<'a, 'tcx, 'rcx>, +pub fn look_for_tests<'tcx>( + cx: &DocContext<'tcx>, dox: &str, item: &Item, check_missing_code: bool, @@ -370,7 +370,7 @@ crate fn span_of_attrs(attrs: &clean::Attributes) -> Span { /// attributes are not all sugared doc comments. It's difficult to calculate the correct span in /// that case due to escaping and other source features. crate fn source_span_for_markdown_range( - cx: &DocContext<'_, '_, '_>, + cx: &DocContext<'_>, markdown: &str, md_range: &Range, attrs: &clean::Attributes, diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index 1c3977c4f85cd..5560ebed9ae69 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -9,25 +9,25 @@ pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { description: "check private items doc tests", }; -struct PrivateItemDocTestLinter<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a DocContext<'a, 'tcx, 'rcx>, +struct PrivateItemDocTestLinter<'a, 'tcx> { + cx: &'a DocContext<'tcx>, } -impl<'a, 'tcx, 'rcx> PrivateItemDocTestLinter<'a, 'tcx, 'rcx> { - fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> { + fn new(cx: &'a DocContext<'tcx>) -> Self { PrivateItemDocTestLinter { cx, } } } -pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate { +pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_>) -> Crate { let mut coll = PrivateItemDocTestLinter::new(cx); coll.fold_crate(krate) } -impl<'a, 'tcx, 'rcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { fn fold_item(&mut self, item: Item) -> Option { let cx = self.cx; let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index aed80b5ba86fd..a71a1e001fc69 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -12,7 +12,7 @@ pub const PROPAGATE_DOC_CFG: Pass = Pass { description: "propagates `#[doc(cfg(...))]` to child items", }; -pub fn propagate_doc_cfg(cr: Crate, _: &DocContext<'_, '_, '_>) -> Crate { +pub fn propagate_doc_cfg(cr: Crate, _: &DocContext<'_>) -> Crate { CfgPropagator { parent_cfg: None }.fold_crate(cr) } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 330057e53843b..240299c212abc 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -14,7 +14,7 @@ pub const STRIP_HIDDEN: Pass = Pass { }; /// Strip items marked `#[doc(hidden)]` -pub fn strip_hidden(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn strip_hidden(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { let mut retained = DefIdSet::default(); // strip all #[doc(hidden)] items diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 479f0877bd7d2..516760ade6667 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -9,6 +9,6 @@ pub const STRIP_PRIV_IMPORTS: Pass = Pass { description: "strips all private import statements (`use`, `extern crate`) from a crate", }; -pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { ImportStripper.fold_crate(krate) } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 1ac3a90f38d35..fc742bf74d006 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -14,7 +14,7 @@ pub const STRIP_PRIVATE: Pass = Pass { /// Strip private items from the point of view of a crate or externally from a /// crate, specified by the `xcrate` flag. -pub fn strip_private(mut krate: clean::Crate, cx: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn strip_private(mut krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = DefIdSet::default(); let access_levels = cx.renderinfo.borrow().access_levels.clone(); diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index b77cf68d7c63f..95e322f70b2ea 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -13,7 +13,7 @@ pub const UNINDENT_COMMENTS: Pass = Pass { description: "removes excess indentation on comments in order for markdown to like it", }; -pub fn unindent_comments(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate { +pub fn unindent_comments(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { CommentCleaner.fold_crate(krate) } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 856365847ae17..f1d4d8470b2a5 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -1,21 +1,16 @@ -use errors::{self, FatalError}; -use errors::emitter::ColorConfig; use rustc_data_structures::sync::Lrc; -use rustc_lint; -use rustc_driver::{self, driver, Compilation}; -use rustc_driver::driver::phase_2_configure_and_expand; -use rustc_metadata::cstore::CStore; -use rustc_interface::util; +use rustc_interface::interface; use rustc::hir; use rustc::hir::intravisit; -use rustc::session::{self, CompileIncomplete, config}; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::session::{self, config, DiagnosticOutput}; use rustc::session::config::{OutputType, OutputTypes, Externs, CodegenOptions}; use rustc::session::search_paths::SearchPath; +use rustc::util::common::ErrorReported; use syntax::ast; use syntax::source_map::SourceMap; use syntax::edition::Edition; use syntax::feature_gate::UnstableFeatures; -use syntax::with_globals; use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName}; use tempfile::Builder as TempFileBuilder; use testing; @@ -23,8 +18,8 @@ use testing; use std::env; use std::io::prelude::*; use std::io; -use std::path::PathBuf; use std::panic::{self, AssertUnwindSafe}; +use std::path::PathBuf; use std::process::Command; use std::str; use std::sync::{Arc, Mutex}; @@ -44,7 +39,7 @@ pub struct TestOptions { pub attrs: Vec, } -pub fn run(mut options: Options) -> isize { +pub fn run(options: Options) -> i32 { let input = config::Input::File(options.input.clone()); let sessopts = config::Options { @@ -63,52 +58,31 @@ pub fn run(mut options: Options) -> isize { edition: options.edition, ..config::Options::default() }; - driver::spawn_thread_pool(sessopts, |sessopts| { - let source_map = Lrc::new(SourceMap::new(sessopts.file_path_mapping())); - let handler = - errors::Handler::with_tty_emitter(ColorConfig::Auto, - true, None, - Some(source_map.clone())); - - let mut sess = session::build_session_( - sessopts, Some(options.input), handler, source_map.clone(), Default::default(), - ); - let codegen_backend = util::get_codegen_backend(&sess); - let cstore = CStore::new(codegen_backend.metadata_loader()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let mut cfg = config::build_configuration(&sess, - config::parse_cfgspecs(options.cfgs.clone())); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; - - let krate = - match driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input) { - Ok(krate) => krate, - Err(mut e) => { - e.emit(); - FatalError.raise(); - } - }; - let driver::ExpansionResult { defs, mut hir_forest, .. } = { - phase_2_configure_and_expand( - &sess, - &cstore, - krate, - None, - "rustdoc-test", - None, - |_| Ok(()), - ).expect("phase_2_configure_and_expand aborted in rustdoc!") - }; - let crate_name = options.crate_name.unwrap_or_else(|| { - ::rustc_codegen_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input) - }); - let mut opts = scrape_test_config(hir_forest.krate()); + let config = interface::Config { + opts: sessopts, + crate_cfg: config::parse_cfgspecs(options.cfgs.clone()), + input, + input_path: None, + output_file: None, + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Default, + stderr: None, + crate_name: options.crate_name.clone(), + lint_caps: Default::default(), + }; + + let mut test_args = options.test_args.clone(); + let display_warnings = options.display_warnings; + + let tests = interface::run_compiler(config, |compiler| -> Result<_, ErrorReported> { + let lower_to_hir = compiler.lower_to_hir()?; + + let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate()); opts.display_warnings |= options.display_warnings; let mut collector = Collector::new( - crate_name, + compiler.crate_name()?.peek().to_string(), options.cfgs, options.libs, options.codegen_options, @@ -116,34 +90,40 @@ pub fn run(mut options: Options) -> isize { false, opts, options.maybe_sysroot, - Some(source_map), + Some(compiler.source_map().clone()), None, options.linker, options.edition, options.persist_doctests, ); - { - let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs); - let krate = map.krate(); + let mut global_ctxt = compiler.global_ctxt()?.take(); + global_ctxt.enter(|tcx| { + let krate = tcx.hir().krate(); let mut hir_collector = HirCollector { - sess: &sess, + sess: compiler.session(), collector: &mut collector, - map: &map, - codes: ErrorCodes::from(sess.opts.unstable_features.is_nightly_build()), + map: tcx.hir(), + codes: ErrorCodes::from(compiler.session().opts + .unstable_features.is_nightly_build()), }; hir_collector.visit_testable("".to_string(), &krate.attrs, |this| { intravisit::walk_crate(this, krate); }); - } + }); - options.test_args.insert(0, "rustdoctest".to_string()); + Ok(collector.tests) + }).expect("compiler aborted in rustdoc!"); - testing::test_main(&options.test_args, - collector.tests.into_iter().collect(), - testing::Options::new().display_output(options.display_warnings)); - 0 - }) + test_args.insert(0, "rustdoctest".to_string()); + + testing::test_main( + &test_args, + tests, + testing::Options::new().display_output(display_warnings) + ); + + 0 } // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. @@ -239,16 +219,18 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, } fn flush(&mut self) -> io::Result<()> { Ok(()) } } - struct Bomb(Arc>>, Box); + struct Bomb(Arc>>, Option>); impl Drop for Bomb { fn drop(&mut self) { - let _ = self.1.write_all(&self.0.lock().unwrap()); + let mut old = self.1.take().unwrap(); + let _ = old.write_all(&self.0.lock().unwrap()); + io::set_panic(Some(old)); } } let data = Arc::new(Mutex::new(Vec::new())); let old = io::set_panic(Some(box Sink(data.clone()))); - let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout())); + let _bomb = Bomb(data.clone(), Some(old.unwrap_or(box io::stdout()))); enum DirState { Temp(tempfile::TempDir), @@ -264,91 +246,67 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, } } - let (outdir, compile_result) = driver::spawn_thread_pool(sessopts, |sessopts| { - let source_map = Lrc::new(SourceMap::new(sessopts.file_path_mapping())); - let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), - Some(source_map.clone()), - false, - false); - - // Compile the code - let diagnostic_handler = errors::Handler::with_emitter(true, None, box emitter); - - let mut sess = session::build_session_( - sessopts, None, diagnostic_handler, source_map, Default::default(), - ); - let codegen_backend = util::get_codegen_backend(&sess); - let cstore = CStore::new(codegen_backend.metadata_loader()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let outdir = Mutex::new( - if let Some(mut path) = persist_doctests { - path.push(format!("{}_{}", - filename - .to_string() - .rsplit('/') - .next() - .unwrap() - .replace(".", "_"), - line) - ); - std::fs::create_dir_all(&path) - .expect("Couldn't create directory for doctest executables"); - - DirState::Perm(path) - } else { - DirState::Temp(TempFileBuilder::new() - .prefix("rustdoctest") - .tempdir() - .expect("rustdoc needs a tempdir")) - } + let outdir = if let Some(mut path) = persist_doctests { + path.push(format!("{}_{}", + filename + .to_string() + .rsplit('/') + .next() + .unwrap() + .replace(".", "_"), + line) ); - let mut control = driver::CompileController::basic(); - - let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; - - let out = Some(outdir.lock().unwrap().path().join("rust_out")); - - if no_run { - control.after_analysis.stop = Compilation::Stop; - } + std::fs::create_dir_all(&path) + .expect("Couldn't create directory for doctest executables"); - let res = panic::catch_unwind(AssertUnwindSafe(|| { - driver::compile_input( - codegen_backend, - &sess, - &cstore, - &None, - &input, - &None, - &out, - None, - &control - ) - })); - - let compile_result = match res { - Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()), - Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(()) - }; + DirState::Perm(path) + } else { + DirState::Temp(TempFileBuilder::new() + .prefix("rustdoctest") + .tempdir() + .expect("rustdoc needs a tempdir")) + }; + let output_file = outdir.path().join("rust_out"); + + let config = interface::Config { + opts: sessopts, + crate_cfg: config::parse_cfgspecs(cfgs), + input, + input_path: None, + output_file: Some(output_file.clone()), + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Raw(box Sink(data.clone())), + stderr: Some(data.clone()), + crate_name: None, + lint_caps: Default::default(), + }; - (outdir, compile_result) - }); + let compile_result = panic::catch_unwind(AssertUnwindSafe(|| { + interface::run_compiler(config, |compiler| { + if no_run { + compiler.global_ctxt().and_then(|global_ctxt| global_ctxt.take().enter(|tcx| { + tcx.analysis(LOCAL_CRATE) + })).ok(); + } else { + compiler.compile().ok(); + }; + compiler.session().compile_status() + }) + })).map_err(|_| ()).and_then(|s| s.map_err(|_| ())); match (compile_result, compile_fail) { (Ok(()), true) => { panic!("test compiled while it wasn't supposed to") } (Ok(()), false) => {} - (Err(()), true) => { + (Err(_), true) => { if error_codes.len() > 0 { let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); error_codes.retain(|err| !out.contains(err)); } } - (Err(()), false) => { + (Err(_), false) => { panic!("couldn't compile the test") } } @@ -360,7 +318,8 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, if no_run { return } // Run the code! - let mut cmd = Command::new(&outdir.lock().unwrap().path().join("rust_out")); + let mut cmd = Command::new(output_file); + match cmd.output() { Err(e) => panic!("couldn't run the test: {}{}", e, if e.kind() == io::ErrorKind::PermissionDenied { @@ -735,35 +694,26 @@ impl Tester for Collector { allow_fail: config.allow_fail, }, testfn: testing::DynTestFn(box move || { - let panic = io::set_panic(None); - let print = io::set_print(None); - match { - rustc_driver::in_named_rustc_thread(name, move || with_globals(move || { - io::set_panic(panic); - io::set_print(print); - run_test(&test, - &cratename, - &filename, - line, - cfgs, - libs, - cg, - externs, - config.should_panic, - config.no_run, - config.test_harness, - config.compile_fail, - config.error_codes, - &opts, - maybe_sysroot, - linker, - edition, - persist_doctests) - })) - } { - Ok(()) => (), - Err(err) => panic::resume_unwind(err), - } + run_test( + &test, + &cratename, + &filename, + line, + cfgs, + libs, + cg, + externs, + config.should_panic, + config.no_run, + config.test_harness, + config.compile_fail, + config.error_codes, + &opts, + maybe_sysroot, + linker, + edition, + persist_doctests + ) }), }); } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c1bd1d83a5b00..0c99f6ddeddf1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -27,10 +27,10 @@ use crate::doctree::*; // Also, is there some reason that this doesn't use the 'visit' // framework from syntax?. -pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { +pub struct RustdocVisitor<'a, 'tcx> { pub module: Module, pub attrs: hir::HirVec, - pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, + pub cx: &'a core::DocContext<'tcx>, view_item_stack: FxHashSet, inlining: bool, /// Are the current module and all of its parents public? @@ -38,10 +38,10 @@ pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { exact_paths: Option>>, } -impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn new( - cx: &'a core::DocContext<'a, 'tcx, 'rcx> - ) -> RustdocVisitor<'a, 'tcx, 'rcx> { + cx: &'a core::DocContext<'tcx> + ) -> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. let mut stack = FxHashSet::default(); stack.insert(ast::CRATE_NODE_ID); @@ -269,7 +269,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { om: &mut Module, please_inline: bool) -> bool { - fn inherits_doc_hidden(cx: &core::DocContext<'_, '_, '_>, mut node: ast::NodeId) -> bool { + fn inherits_doc_hidden(cx: &core::DocContext<'_>, mut node: ast::NodeId) -> bool { while let Some(id) = cx.tcx.hir().get_enclosing_scope(node) { node = id; if cx.tcx.hir().attrs(node).lists("doc").has_word("hidden") { diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index f538c58c213ee..def6f8b557b51 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -12,8 +12,8 @@ use crate::clean::{AttributesExt, NestedAttributesExt}; /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) -pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a crate::core::DocContext<'a, 'tcx, 'rcx>, +pub struct LibEmbargoVisitor<'a, 'tcx> { + cx: &'a crate::core::DocContext<'tcx>, // Accessibility levels for reachable nodes access_levels: RefMut<'a, AccessLevels>, // Previous accessibility level, None means unreachable @@ -22,10 +22,10 @@ pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> { visited_mods: FxHashSet, } -impl<'a, 'tcx, 'rcx> LibEmbargoVisitor<'a, 'tcx, 'rcx> { +impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { pub fn new( - cx: &'a crate::core::DocContext<'a, 'tcx, 'rcx> - ) -> LibEmbargoVisitor<'a, 'tcx, 'rcx> { + cx: &'a crate::core::DocContext<'tcx> + ) -> LibEmbargoVisitor<'a, 'tcx> { LibEmbargoVisitor { cx, access_levels: RefMut::map(cx.renderinfo.borrow_mut(), |ri| &mut ri.access_levels), diff --git a/src/rustc/rustc.rs b/src/rustc/rustc.rs index fef6b830040b9..626fceb581436 100644 --- a/src/rustc/rustc.rs +++ b/src/rustc/rustc.rs @@ -1,14 +1,3 @@ -#![feature(link_args)] - -// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread -// for the rationale. -#[allow(unused_attributes)] -#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")] -// We only build for msvc and gnu now, but we use a exhaustive condition here -// so we can expect either the stack size to be set or the build fails. -#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")] -// Also, don't forget to set this for rustdoc. -extern {} fn main() { // Pull in jemalloc when enabled. diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index 51891ed538770..641ff18d37e9b 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -7,12 +7,13 @@ extern crate rustc_codegen_utils; use std::any::Any; use std::sync::mpsc; use syntax::symbol::Symbol; -use rustc::session::{Session, CompileIncomplete}; +use rustc::session::Session; use rustc::session::config::OutputFilenames; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; use rustc::middle::cstore::MetadataLoader; use rustc::dep_graph::DepGraph; +use rustc::util::common::ErrorReported; use rustc_codegen_utils::codegen_backend::{CodegenBackend, MetadataOnlyCodegenBackend}; struct TheBackend(Box); @@ -46,7 +47,7 @@ impl CodegenBackend for TheBackend { sess: &Session, _dep_graph: &DepGraph, outputs: &OutputFilenames, - ) -> Result<(), CompileIncomplete> { + ) -> Result<(), ErrorReported> { use std::io::Write; use rustc::session::config::CrateType; use rustc_codegen_utils::link::out_filename; diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index e9d825df2a46e..0cbdf40e2f908 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -1,26 +1,16 @@ #![feature(rustc_private)] extern crate rustc; -extern crate rustc_driver; -extern crate rustc_lint; -extern crate rustc_metadata; -extern crate rustc_errors; -extern crate rustc_codegen_utils; extern crate rustc_interface; extern crate syntax; -use rustc::session::{build_session, Session}; +use rustc::session::DiagnosticOutput; use rustc::session::config::{Input, Options, OutputType, OutputTypes}; -use rustc_driver::driver::{self, compile_input, CompileController}; -use rustc_metadata::cstore::CStore; -use rustc_errors::registry::Registry; -use rustc_interface::util; +use rustc_interface::interface; use syntax::source_map::FileName; -use rustc_codegen_utils::codegen_backend::CodegenBackend; use std::path::PathBuf; -use std::rc::Rc; fn main() { let src = r#" @@ -44,39 +34,33 @@ fn main() { compile(src.to_string(), tmpdir.join("out"), sysroot.clone()); } -fn basic_sess(opts: Options) -> (Session, Rc, Box) { - let descriptions = Registry::new(&rustc::DIAGNOSTICS); - let sess = build_session(opts, None, descriptions); - let codegen_backend = util::get_codegen_backend(&sess); - let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader())); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - (sess, cstore, codegen_backend) -} - fn compile(code: String, output: PathBuf, sysroot: PathBuf) { - syntax::with_globals(|| { - let mut opts = Options::default(); - opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); - opts.maybe_sysroot = Some(sysroot); - if let Ok(linker) = std::env::var("RUSTC_LINKER") { - opts.cg.linker = Some(linker.into()); - } - driver::spawn_thread_pool(opts, |opts| { - let (sess, cstore, codegen_backend) = basic_sess(opts); - let control = CompileController::basic(); - let name = FileName::anon_source_code(&code); - let input = Input::Str { name, input: code }; - let _ = compile_input( - codegen_backend, - &sess, - &cstore, - &None, - &input, - &None, - &Some(output), - None, - &control - ); - }); + let mut opts = Options::default(); + opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); + opts.maybe_sysroot = Some(sysroot); + + if let Ok(linker) = std::env::var("RUSTC_LINKER") { + opts.cg.linker = Some(linker.into()); + } + + let name = FileName::anon_source_code(&code); + let input = Input::Str { name, input: code }; + + let config = interface::Config { + opts, + crate_cfg: Default::default(), + input, + input_path: None, + output_file: Some(output), + output_dir: None, + file_loader: None, + diagnostic_output: DiagnosticOutput::Default, + stderr: None, + crate_name: None, + lint_caps: Default::default(), + }; + + interface::run_compiler(config, |compiler| { + compiler.compile().ok(); }); } diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index d3a328300ba03..b4731bbaeb5ca 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -1,91 +1,30 @@ -// Test that the CompilerCalls interface to the compiler works. +// Test that the Callbacks interface to the compiler works. // ignore-cross-compile // ignore-stage1 #![feature(rustc_private)] -extern crate getopts; -extern crate rustc; extern crate rustc_driver; -extern crate rustc_codegen_utils; -extern crate syntax; -extern crate rustc_errors as errors; -extern crate rustc_metadata; +extern crate rustc_interface; -use rustc::session::Session; -use rustc::session::config::{self, Input}; -use rustc_driver::{driver, CompilerCalls, Compilation}; -use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_metadata::cstore::CStore; -use syntax::ast; - -use std::path::PathBuf; +use rustc_interface::interface; struct TestCalls<'a> { count: &'a mut u32 } -impl<'a> CompilerCalls<'a> for TestCalls<'a> { - fn early_callback(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &errors::registry::Registry, - _: config::ErrorOutputType) - -> Compilation { +impl rustc_driver::Callbacks for TestCalls<'_> { + fn config(&mut self, _config: &mut interface::Config) { *self.count *= 2; - Compilation::Continue - } - - fn late_callback(&mut self, - _: &CodegenBackend, - _: &getopts::Matches, - _: &Session, - _: &CStore, - _: &Input, - _: &Option, - _: &Option) - -> Compilation { - *self.count *= 3; - Compilation::Stop - } - - fn some_input(&mut self, input: Input, input_path: Option) - -> (Input, Option) { - *self.count *= 5; - (input, input_path) - } - - fn no_input(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &Option, - _: &Option, - _: &errors::registry::Registry) - -> Option<(Input, Option)> { - panic!("This shouldn't happen"); - } - - fn build_controller(self: Box, - _: &Session, - _: &getopts::Matches) - -> driver::CompileController<'a> { - panic!("This shouldn't be called"); } } - fn main() { let mut count = 1; - { - let tc = TestCalls { count: &mut count }; - // we should never get use this filename, but lets make sure they are valid args. - let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; - syntax::with_globals(|| { - rustc_driver::run_compiler(&args, Box::new(tc), None, None); - }); - } - assert_eq!(count, 30); + let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; + rustc_driver::report_ices_to_stderr_if_any(|| { + rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok(); + }).ok(); + assert_eq!(count, 2); } diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index e18b9909f586e..d2c4a28ce980a 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -11,3 +11,5 @@ LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr index 1cfd6092cb3a5..4cc0f4b4128fb 100644 --- a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr +++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr @@ -18,5 +18,5 @@ error: missing documentation for a struct LL | pub struct Foo; //~ ERROR | ^^^^^^^^^^^^^^^ -error: Compilation failed, aborting rustdoc +error: aborting due to 2 previous errors diff --git a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr index b87e60d8269ea..ce9584a4bb0ce 100644 --- a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr +++ b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr @@ -10,5 +10,5 @@ note: lint level defined here LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ -error: Compilation failed, aborting rustdoc +error: aborting due to previous error diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr index c07965a6ab968..208bdedf24ddb 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.stderr +++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr @@ -24,3 +24,5 @@ error: Missing code example in this documentation LL | /// Or maybe not because she saved herself! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index 895c40e4cab26..c9f59405ce012 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -12,7 +12,10 @@ error[E0425]: cannot find value `no` in this scope 3 | no | ^^ not found in this scope -thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:352:13 +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. +thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:310:13 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. ---- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ---- @@ -21,7 +24,7 @@ thread '$DIR/failed-doctest-output.rs - SomeStruct (line 11)' panicked at 'test thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. -', src/librustdoc/test.rs:373:17 +', src/librustdoc/test.rs:332:17 failures: diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index ced56897e2a21..12a56dcc4a5ef 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -11,3 +11,5 @@ LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index 4eb1861062872..93c05a0c4dd29 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -11,3 +11,5 @@ LL | #![deny(intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 48ae7910b0f15..76a9133147eac 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -42,3 +42,5 @@ LL | #![deny(rustdoc)] | ^^^^^^^ = note: #[deny(missing_doc_code_examples)] implied by #[deny(rustdoc)] +error: aborting due to 3 previous errors + diff --git a/src/test/rustdoc-ui/private-item-doc-test.stderr b/src/test/rustdoc-ui/private-item-doc-test.stderr index 38062758e92c7..20f3eb8b12025 100644 --- a/src/test/rustdoc-ui/private-item-doc-test.stderr +++ b/src/test/rustdoc-ui/private-item-doc-test.stderr @@ -14,3 +14,5 @@ note: lint level defined here LL | #![deny(private_doc_tests)] | ^^^^^^^^^^^^^^^^^ +error: aborting due to previous error + diff --git a/src/tools/rustdoc/main.rs b/src/tools/rustdoc/main.rs index 8bdc365c4ca68..8171708e99d00 100644 --- a/src/tools/rustdoc/main.rs +++ b/src/tools/rustdoc/main.rs @@ -1,15 +1,3 @@ #![deny(rust_2018_idioms)] -#![feature(link_args)] - -#[allow(unused_attributes)] -// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread -// for the rationale. -#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")] -// We only build for msvc and gnu now, but we use a exhaustive condition here -// so we can expect either the stack size to be set or the build fails. -#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")] -// See src/rustc/rustc.rs for the corresponding rustc settings. -extern {} - fn main() { rustdoc::main() }