Make the rustc driver and interface demand driven
This commit is contained in:
parent
26b4cb4848
commit
51938c61f6
60 changed files with 2521 additions and 2755 deletions
|
@ -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 {
|
||||
|
|
|
@ -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<String>)>) -> 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<RustcOptGroup> {
|
|||
}
|
||||
|
||||
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
|
||||
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> ast::CrateConfig {
|
||||
cfgspecs
|
||||
.into_iter()
|
||||
.map(|s| {
|
||||
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
|
||||
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<String>) -> ast::CrateConfig {
|
|||
}
|
||||
|
||||
error!(r#"expected `key` or `key="value"`"#);
|
||||
})
|
||||
.collect::<ast::CrateConfig>()
|
||||
}).collect::<ast::CrateConfig>();
|
||||
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<String>)>) {
|
||||
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());
|
||||
|
|
|
@ -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<F, T>(&self, f: F) -> Result<T, ErrorReported>
|
||||
|
@ -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<PathBuf>,
|
||||
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<ErrorReported> 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,6 @@ use crate::hir;
|
|||
pub struct AllArenas<'tcx> {
|
||||
pub global: WorkerLocal<GlobalArenas<'tcx>>,
|
||||
pub interner: SyncDroplessArena,
|
||||
global_ctxt: Option<GlobalCtxt<'tcx>>,
|
||||
}
|
||||
|
||||
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<F, R>(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<Box<dyn Any + Send>>,
|
||||
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<Box<dyn Any + Send>>,
|
||||
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<T: Fn() -> 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)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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::
|
||||
|
|
|
@ -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::<OngoingCodegen>()
|
||||
.expect("Expected MetadataOnlyCodegenBackend's OngoingCodegen, found Box<dyn Any>");
|
||||
for &crate_type in sess.opts.crate_types.iter() {
|
||||
|
|
172
src/librustc_data_structures/box_region.rs
Normal file
172
src/librustc_data_structures/box_region.rs
Normal file
|
@ -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<Action> = Cell::new(Action::Complete));
|
||||
|
||||
pub struct PinnedGenerator<I, A, R> {
|
||||
generator: Pin<Box<dyn Generator<Yield = YieldType<I, A>, Return = R>>>
|
||||
}
|
||||
|
||||
impl<I, A, R> PinnedGenerator<I, A, R> {
|
||||
pub fn new<
|
||||
T: Generator<Yield = YieldType<I, A>, 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<T>(PhantomData<T>);
|
||||
|
||||
impl<T> Marker<T> {
|
||||
pub unsafe fn new() -> Self {
|
||||
Marker(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum YieldType<I, A> {
|
||||
Initial(I),
|
||||
Accessor(Marker<A>),
|
||||
}
|
||||
|
||||
#[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<T: ::std::ops::Generator<Yield = $yield_type, Return = $retc> + 'static>(
|
||||
generator: T
|
||||
) -> ($reti, Self) {
|
||||
let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator);
|
||||
(initial, $name(pinned))
|
||||
}
|
||||
|
||||
$v fn access<F: for<$($lifetimes)*> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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<T>(result: Result<T, CompileIncomplete>, 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<T>(result: Result<T, ErrorReported>, 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<F>(run_compiler: F) -> isize
|
||||
where F: FnOnce() -> (CompileResult, Option<Session>) + 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<dyn CompilerCalls<'a> + sync::Send + 'a>,
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
|
||||
emitter_dest: Option<Box<dyn Write + Send>>)
|
||||
-> (CompileResult, Option<Session>)
|
||||
{
|
||||
pub fn run_compiler(
|
||||
args: &[String],
|
||||
callbacks: &mut (dyn Callbacks + Send),
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||
emitter: Option<Box<dyn Write + Send>>
|
||||
) -> 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(()),
|
||||
};
|
||||
|
||||
install_panic_hook();
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
fn run_compiler_with_pool<'a>(
|
||||
matches: getopts::Matches,
|
||||
sopts: config::Options,
|
||||
cfg: ast::CrateConfig,
|
||||
mut callbacks: Box<dyn CompilerCalls<'a> + sync::Send + 'a>,
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
|
||||
emitter_dest: Option<Box<dyn Write + Send>>
|
||||
) -> (CompileResult, Option<Session>) {
|
||||
macro_rules! do_or_return {($expr: expr, $sess: expr) => {
|
||||
match $expr {
|
||||
Compilation::Stop => return (Ok(()), $sess),
|
||||
Compilation::Continue => {}
|
||||
}
|
||||
}}
|
||||
|
||||
let descriptions = diagnostics_registry();
|
||||
|
||||
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);
|
||||
|
||||
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
|
||||
|
||||
let mut cfg = config::build_configuration(&sess, cfg);
|
||||
util::add_configuration(&mut cfg, &sess, &*codegen_backend);
|
||||
sess.parse_sess.config = cfg;
|
||||
|
||||
let result = {
|
||||
let plugins = sess.opts.debugging_opts.extra_plugins.clone();
|
||||
|
||||
let cstore = CStore::new(codegen_backend.metadata_loader());
|
||||
|
||||
do_or_return!(callbacks.late_callback(&*codegen_backend,
|
||||
&matches,
|
||||
&sess,
|
||||
&cstore,
|
||||
&input,
|
||||
&odir,
|
||||
&ofile), Some(sess));
|
||||
|
||||
let _sess_abort_error = OnDrop(|| sess.diagnostic().print_error_count());
|
||||
|
||||
let control = callbacks.build_controller(&sess, &matches);
|
||||
|
||||
driver::compile_input(codegen_backend,
|
||||
&sess,
|
||||
&cstore,
|
||||
&input_file_path,
|
||||
&input,
|
||||
&odir,
|
||||
&ofile,
|
||||
Some(plugins),
|
||||
&control)
|
||||
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(),
|
||||
};
|
||||
|
||||
if sess.opts.debugging_opts.self_profile {
|
||||
sess.profiler(|p| p.dump_raw_events(&sess.opts));
|
||||
}
|
||||
callbacks.config(&mut config);
|
||||
|
||||
(result, Some(sess))
|
||||
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()?;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if !callbacks.after_parsing(compiler) {
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
compiler.register_plugins()?;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
compiler.prepare_outputs()?;
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
&& sess.opts.output_types.len() == 1
|
||||
{
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
compiler.global_ctxt()?;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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<PathBuf>,
|
||||
_: &Option<PathBuf>)
|
||||
-> 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<PathBuf>)
|
||||
-> (Input, Option<PathBuf>) {
|
||||
(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<PathBuf>,
|
||||
_: &Option<PathBuf>,
|
||||
_: &errors::registry::Registry)
|
||||
-> Option<(Input, Option<PathBuf>)> {
|
||||
None
|
||||
}
|
||||
|
||||
// Create a CompilController struct for controlling the behaviour of
|
||||
// compilation.
|
||||
fn build_controller(
|
||||
self: Box<Self>,
|
||||
_: &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<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
descriptions: &errors::registry::Registry)
|
||||
-> Option<(Input, Option<PathBuf>)> {
|
||||
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<PathBuf>,
|
||||
ofile: &Option<PathBuf>)
|
||||
-> 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<Self>,
|
||||
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<as
|
|||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// This version applies the given name to the thread. This is used by rustdoc to ensure consistent
|
||||
/// doctest output across platforms and executions.
|
||||
pub fn in_named_rustc_thread<F, R>(name: String, f: F) -> Result<R, Box<dyn Any + Send>>
|
||||
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, R>(f: F) -> Result<R, Box<dyn Any + Send>>
|
||||
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<String>, 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: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFailure> {
|
||||
in_rustc_thread(move || {
|
||||
f()
|
||||
}).map_err(|value| {
|
||||
pub fn report_ices_to_stderr_if_any<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
|
||||
catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
|
||||
if value.is::<errors::FatalErrorMarker>() {
|
||||
CompilationFailure
|
||||
ErrorReported
|
||||
} else {
|
||||
// Thread panicked without emitting a fatal diagnostic
|
||||
eprintln!("");
|
||||
|
@ -1364,25 +1184,6 @@ pub fn monitor<F: FnOnce() + Send + 'static>(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::<Vec<_>>();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<TyCtxt<'tcx, 'tcx, 'tcx>>,
|
||||
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<hir_map::Map<'hir>>,
|
||||
tcx: Option<TyCtxt<'hir, 'hir, 'hir>>,
|
||||
}
|
||||
|
||||
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<hir_map::Map<'hir>>,
|
||||
tcx: Option<TyCtxt<'hir, 'hir, 'hir>>,
|
||||
}
|
||||
|
||||
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<borrowck_dot::Variant>,
|
|||
|
||||
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<u8>, 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<UserIdentifiedItem>,
|
||||
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<UserIdentifiedItem>,
|
||||
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<UserIdentifiedItem>,
|
||||
ofile: Option<&Path>) {
|
||||
fn print_with_analysis<'tcx>(
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
ppm: PpMode,
|
||||
uii: Option<UserIdentifiedItem>,
|
||||
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))
|
||||
});
|
||||
|
||||
match blocks::Code::from_node(&tcx.hir(), nodeid) {
|
||||
Some(code) => {
|
||||
let variants = gather_flowgraph_variants(tcx.sess);
|
||||
|
||||
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);
|
||||
|
||||
tcx.sess.span_fatal(tcx.hir().span(nodeid), &message)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
Ok(())
|
||||
}
|
||||
}).unwrap();
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
tcx.sess.span_fatal(tcx.hir().span(nodeid), &message)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
print().unwrap();
|
||||
|
||||
write_output(out, ofile);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -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<dyn Emitter + sync::Send>, usize) {
|
||||
let v = msgs.iter().map(|m| m.to_string()).collect();
|
||||
fn errors(msgs: &[&str]) -> (Box<dyn Emitter + Send + sync::Send>, 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<dyn Emitter + sync::Send>,
|
||||
box ExpectErrorEmitter { messages: v } as Box<dyn Emitter + Send + sync::Send>,
|
||||
msgs.len(),
|
||||
)
|
||||
}
|
||||
|
||||
fn test_env<F>(source_string: &str, args: (Box<dyn Emitter + sync::Send>, 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<F>(
|
||||
options: config::Options,
|
||||
fn test_env<F>(
|
||||
source_string: &str,
|
||||
(emitter, expected_err_count): (Box<dyn Emitter + sync::Send>, usize),
|
||||
(emitter, expected_err_count): (Box<dyn Emitter + Send + sync::Send>, 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 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(),
|
||||
};
|
||||
|
||||
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(&[]),
|
||||
};
|
||||
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<F>(
|
|||
);
|
||||
assert_eq!(tcx.sess.err_count(), expected_err_count);
|
||||
});
|
||||
},
|
||||
);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn d1() -> ty::DebruijnIndex {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -94,10 +94,10 @@ impl<T> MaybeAsync<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type DepGraphFuture = MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>;
|
||||
|
||||
/// Launch a thread and load the dependency graph in the background.
|
||||
pub fn load_dep_graph(sess: &Session) ->
|
||||
MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>
|
||||
{
|
||||
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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
155
src/librustc_interface/interface.rs
Normal file
155
src/librustc_interface/interface.rs
Normal file
|
@ -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<T> = result::Result<T, ErrorReported>;
|
||||
|
||||
/// 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<Session>,
|
||||
codegen_backend: Lrc<Box<dyn CodegenBackend>>,
|
||||
source_map: Lrc<SourceMap>,
|
||||
pub(crate) input: Input,
|
||||
pub(crate) input_path: Option<PathBuf>,
|
||||
pub(crate) output_dir: Option<PathBuf>,
|
||||
pub(crate) output_file: Option<PathBuf>,
|
||||
pub(crate) queries: Queries,
|
||||
pub(crate) cstore: Lrc<CStore>,
|
||||
pub(crate) crate_name: Option<String>,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
pub fn session(&self) -> &Lrc<Session> {
|
||||
&self.sess
|
||||
}
|
||||
pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
|
||||
&self.codegen_backend
|
||||
}
|
||||
pub fn cstore(&self) -> &Lrc<CStore> {
|
||||
&self.cstore
|
||||
}
|
||||
pub fn source_map(&self) -> &Lrc<SourceMap> {
|
||||
&self.source_map
|
||||
}
|
||||
pub fn input(&self) -> &Input {
|
||||
&self.input
|
||||
}
|
||||
pub fn output_dir(&self) -> &Option<PathBuf> {
|
||||
&self.output_dir
|
||||
}
|
||||
pub fn output_file(&self) -> &Option<PathBuf> {
|
||||
&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<String>)>,
|
||||
|
||||
pub input: Input,
|
||||
pub input_path: Option<PathBuf>,
|
||||
pub output_dir: Option<PathBuf>,
|
||||
pub output_file: Option<PathBuf>,
|
||||
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||
pub diagnostic_output: DiagnosticOutput,
|
||||
|
||||
/// Set to capture stderr output during compiler execution
|
||||
pub stderr: Option<Arc<Mutex<Vec<u8>>>>,
|
||||
|
||||
pub crate_name: Option<String>,
|
||||
pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
||||
}
|
||||
|
||||
pub fn run_compiler_in_existing_thread_pool<F, R>(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<F, R>(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, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R + Send,
|
||||
R: Send,
|
||||
{
|
||||
util::spawn_thread_pool(None, &None, f)
|
||||
}
|
|
@ -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};
|
||||
|
|
|
@ -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<ast::Crate>, 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<Session>,
|
||||
cstore: Lrc<CStore>,
|
||||
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<hir::map::Definitions>,
|
||||
pub resolutions: Steal<Resolutions>,
|
||||
}
|
||||
|
||||
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<Option<RefCell<BoxedResolver>>>,
|
||||
) -> 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<NamedSyntaxExtension>,
|
||||
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<hir::map::Forest> {
|
||||
// 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<PathBuf> {
|
||||
fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
|
||||
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) {
|
||||
providers.analysis = analysis;
|
||||
proc_macro_decls::provide(providers);
|
||||
pub fn prepare_outputs(
|
||||
sess: &Session,
|
||||
compiler: &Compiler,
|
||||
krate: &ast::Crate,
|
||||
crate_name: &str
|
||||
) -> Result<OutputFilenames> {
|
||||
// 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<F, R>(&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<Box<dyn Any + Send>>,
|
||||
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<GlobalCtxt<'_>>;
|
||||
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<Box<dyn Any + Send>>,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Box<dyn Any> {
|
||||
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
|
||||
}
|
||||
|
|
302
src/librustc_interface/queries.rs
Normal file
302
src/librustc_interface/queries.rs
Normal file
|
@ -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<T> {
|
||||
result: RefCell<Option<Result<T>>>,
|
||||
}
|
||||
|
||||
impl<T> Query<T> {
|
||||
fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
|
||||
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<T> Default for Query<T> {
|
||||
fn default() -> Self {
|
||||
Query {
|
||||
result: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Queries {
|
||||
dep_graph_future: Query<Option<DepGraphFuture>>,
|
||||
parse: Query<ast::Crate>,
|
||||
crate_name: Query<String>,
|
||||
register_plugins: Query<(ast::Crate, PluginInfo)>,
|
||||
expansion: Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>,
|
||||
dep_graph: Query<DepGraph>,
|
||||
lower_to_hir: Query<(Steal<hir::map::Forest>, ExpansionResult)>,
|
||||
prepare_outputs: Query<OutputFilenames>,
|
||||
codegen_channel: Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
|
||||
Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>,
|
||||
global_ctxt: Query<BoxedGlobalCtxt>,
|
||||
ongoing_codegen: Query<Box<dyn Any>>,
|
||||
link: Query<()>,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
|
||||
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<ast::Crate>> {
|
||||
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<String>> {
|
||||
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<Option<RefCell<BoxedResolver>>>)>> {
|
||||
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<DepGraph>> {
|
||||
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<hir::map::Forest>, 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<OutputFilenames>> {
|
||||
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<mpsc::Sender<Box<dyn Any + Send>>>,
|
||||
Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>> {
|
||||
self.queries.codegen_channel.compute(|| {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
Ok((Steal::new(tx), Steal::new(rx)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn global_ctxt(&self) -> Result<&Query<BoxedGlobalCtxt>> {
|
||||
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<Box<dyn Any>>> {
|
||||
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(|_| ())
|
||||
}
|
||||
}
|
|
@ -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<String>)>,
|
||||
diagnostic_output: DiagnosticOutput,
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
|
||||
input_path: Option<PathBuf>,
|
||||
lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
||||
) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>, Lrc<SourceMap>) {
|
||||
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<usize> {
|
||||
// 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<Mutex<Vec<u8>>>);
|
||||
impl Write for Sink {
|
||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
Write::write(&mut *self.0.lock().unwrap(), data)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
#[cfg(not(parallel_compiler))]
|
||||
pub fn scoped_thread<F: FnOnce() -> 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<F>)).take().unwrap() };
|
||||
let result = unsafe { &mut *(result_ptr.0 as *mut Option<R>) };
|
||||
*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<F: FnOnce() -> R + Send, R: Send>(
|
||||
_threads: Option<usize>,
|
||||
stderr: &Option<Arc<Mutex<Vec<u8>>>>,
|
||||
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<F: FnOnce() -> R + Send, R: Send>(
|
||||
threads: Option<usize>,
|
||||
stderr: &Option<Arc<Mutex<Vec<u8>>>>,
|
||||
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<dyn CodegenBackend> {
|
||||
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<dyn CodegenBackend
|
|||
}
|
||||
}
|
||||
|
||||
pub fn compute_crate_disambiguator(session: &Session) -> 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
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::core::DocContext;
|
|||
|
||||
use super::*;
|
||||
|
||||
pub fn get_def_from_def_id<F>(cx: &DocContext<'_, '_, '_>,
|
||||
pub fn get_def_from_def_id<F>(cx: &DocContext<'_>,
|
||||
def_id: DefId,
|
||||
callback: &F,
|
||||
) -> Vec<Item>
|
||||
|
@ -38,7 +38,7 @@ where F: Fn(& dyn Fn(DefId) -> Def) -> Vec<Item> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_def_from_hir_id<F>(cx: &DocContext<'_, '_, '_>,
|
||||
pub fn get_def_from_hir_id<F>(cx: &DocContext<'_>,
|
||||
id: hir::HirId,
|
||||
name: String,
|
||||
callback: &F,
|
||||
|
|
|
@ -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<DefId>
|
||||
|
@ -129,7 +129,7 @@ pub fn try_inline(
|
|||
Some(ret)
|
||||
}
|
||||
|
||||
pub fn try_inline_glob(cx: &DocContext<'_, '_, '_>, def: Def, visited: &mut FxHashSet<DefId>)
|
||||
pub fn try_inline_glob(cx: &DocContext<'_>, def: Def, visited: &mut FxHashSet<DefId>)
|
||||
-> Option<Vec<clean::Item>>
|
||||
{
|
||||
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<clean::Item> {
|
||||
pub fn build_impls(cx: &DocContext<'_>, did: DefId) -> Vec<clean::Item> {
|
||||
let tcx = cx.tcx;
|
||||
let mut impls = Vec::new();
|
||||
|
||||
|
@ -282,7 +282,7 @@ pub fn build_impls(cx: &DocContext<'_, '_, '_>, did: DefId) -> Vec<clean::Item>
|
|||
impls
|
||||
}
|
||||
|
||||
pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec<clean::Item>) {
|
||||
pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec<clean::Item>) {
|
||||
if !cx.renderinfo.borrow_mut().inlined.insert(did) {
|
||||
return
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec<clean::
|
|||
}
|
||||
|
||||
fn build_module(
|
||||
cx: &DocContext<'_, '_, '_>,
|
||||
cx: &DocContext<'_>,
|
||||
did: DefId,
|
||||
visited: &mut FxHashSet<DefId>
|
||||
) -> clean::Module {
|
||||
|
@ -404,7 +404,7 @@ fn build_module(
|
|||
is_crate: false,
|
||||
};
|
||||
|
||||
fn fill_in(cx: &DocContext<'_, '_, '_>, did: DefId, items: &mut Vec<clean::Item>,
|
||||
fn fill_in(cx: &DocContext<'_>, did: DefId, items: &mut Vec<clean::Item>,
|
||||
visited: &mut FxHashSet<DefId>) {
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -71,56 +71,56 @@ thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = 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<Stability> {
|
||||
fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
|
||||
cx.tcx.lookup_stability(def_id).clean(cx)
|
||||
}
|
||||
|
||||
fn get_deprecation(cx: &DocContext<'_, '_, '_>, def_id: DefId) -> Option<Deprecation> {
|
||||
fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
|
||||
cx.tcx.lookup_deprecation(def_id).clean(cx)
|
||||
}
|
||||
|
||||
pub trait Clean<T> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> T;
|
||||
fn clean(&self, cx: &DocContext<'_>) -> T;
|
||||
}
|
||||
|
||||
impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<U> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
|
||||
self.iter().map(|x| x.clean(cx)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clean<U>, U, V: Idx> Clean<IndexVec<V, U>> for IndexVec<V, T> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> IndexVec<V, U> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> IndexVec<V, U> {
|
||||
self.iter().map(|x| x.clean(cx)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clean<U>, U> Clean<U> for P<T> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> U {
|
||||
(**self).clean(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clean<U>, U> Clean<U> for Rc<T> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> U {
|
||||
(**self).clean(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<U> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<U> {
|
||||
self.as_ref().map(|v| v.clean(cx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> U {
|
||||
self.skip_binder().clean(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clean<U>, U> Clean<Vec<U>> for P<[T]> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<U> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
|
||||
self.iter().map(|x| x.clean(cx)).collect()
|
||||
}
|
||||
}
|
||||
|
@ -139,8 +139,8 @@ pub struct Crate {
|
|||
pub masked_crates: FxHashSet<CrateNum>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'rcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Crate {
|
||||
impl<'a, 'tcx> Clean<Crate> 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<ExternalCrate> 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<Item> 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<Attributes> 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<GenericBound> 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<GenericBound> for hir::GenericBound {
|
|||
}
|
||||
}
|
||||
|
||||
fn external_generic_args(cx: &DocContext<'_, '_, '_>, trait_did: Option<DefId>, has_self: bool,
|
||||
fn external_generic_args(cx: &DocContext<'_>, trait_did: Option<DefId>, has_self: bool,
|
||||
bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> GenericArgs {
|
||||
let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
|
||||
let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
|
||||
|
@ -1130,7 +1130,7 @@ fn external_generic_args(cx: &DocContext<'_, '_, '_>, trait_did: Option<DefId>,
|
|||
|
||||
// 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<DefId>, has_self: bool,
|
||||
fn external_path(cx: &DocContext<'_>, name: &str, trait_did: Option<DefId>, has_self: bool,
|
||||
bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> Path {
|
||||
Path {
|
||||
global: false,
|
||||
|
@ -1143,7 +1143,7 @@ fn external_path(cx: &DocContext<'_, '_, '_>, name: &str, trait_did: Option<DefI
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
|
||||
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<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
|
||||
(self, vec![]).clean(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<Option<Vec<GenericBound>>> for InternalSubsts<'tcx> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<Vec<GenericBound>> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<Vec<GenericBound>> {
|
||||
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<Lifetime> 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<Lifetime> for hir::Lifetime {
|
|||
}
|
||||
|
||||
impl Clean<Lifetime> 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<Lifetime> for hir::GenericParam {
|
|||
}
|
||||
|
||||
impl Clean<Constant> 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<Constant> for hir::ConstArg {
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<Lifetime> for ty::GenericParamDef {
|
||||
fn clean(&self, _cx: &DocContext<'_, '_, '_>) -> Lifetime {
|
||||
fn clean(&self, _cx: &DocContext<'_>) -> Lifetime {
|
||||
Lifetime(self.name.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Option<Lifetime>> for ty::RegionKind {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<Lifetime> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<Lifetime> {
|
||||
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<WherePredicate> 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<WherePredicate> for hir::WherePredicate {
|
|||
}
|
||||
|
||||
impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<WherePredicate> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
|
||||
use rustc::ty::Predicate;
|
||||
|
||||
match *self {
|
||||
|
@ -1353,7 +1353,7 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Clean<WherePredicate> 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<WherePredicate> for ty::TraitPredicate<'a> {
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<WherePredicate> 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<WherePredicate> for ty::SubtypePredicate<'tcx> {
|
|||
impl<'tcx> Clean<Option<WherePredicate>> for
|
||||
ty::OutlivesPredicate<ty::Region<'tcx>,ty::Region<'tcx>> {
|
||||
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<WherePredicate> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
|
||||
let ty::OutlivesPredicate(ref a, ref b) = *self;
|
||||
|
||||
match (a, b) {
|
||||
|
@ -1389,7 +1389,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<WherePredicate> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
|
||||
let ty::OutlivesPredicate(ref ty, ref lt) = *self;
|
||||
|
||||
match lt {
|
||||
|
@ -1405,7 +1405,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<WherePredicate> 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<WherePredicate> for ty::ProjectionPredicate<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<Type> 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<GenericParamDef> 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<GenericParamDef> for ty::GenericParamDef {
|
|||
}
|
||||
|
||||
impl Clean<GenericParamDef> 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<Generics> 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<Generics> for hir::Generics {
|
|||
|
||||
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
|
||||
&'a Lrc<ty::GenericPredicates<'tcx>>) {
|
||||
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<Method> 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<Item> 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<Arguments> 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<Arguments> for (&'a [hir::Ty], &'a [ast::Ident]) {
|
|||
}
|
||||
|
||||
impl<'a> Clean<Arguments> 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<Arguments> for (&'a [hir::Ty], hir::BodyId) {
|
|||
impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
|
||||
where (&'a [hir::Ty], A): Clean<Arguments>
|
||||
{
|
||||
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<FnDecl> for (&'a hir::FnDecl, A)
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> Clean<FnDecl> 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<FunctionRetTy> 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<Item> 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<Item> 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<Item> for doctree::TraitAlias {
|
|||
}
|
||||
|
||||
impl Clean<bool> 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<bool> for hir::IsAuto {
|
|||
}
|
||||
|
||||
impl Clean<Type> 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<PolyTrait> 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<PolyTrait> for hir::PolyTraitRef {
|
|||
}
|
||||
|
||||
impl Clean<Item> 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<Item> for hir::TraitItem {
|
|||
}
|
||||
|
||||
impl Clean<Item> 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<Item> for hir::ImplItem {
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<Item> 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<ast::FloatTy> for PrimitiveType {
|
|||
}
|
||||
|
||||
impl Clean<Type> 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<Type> for hir::Ty {
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<Type> 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<Type> for Ty<'tcx> {
|
|||
}
|
||||
|
||||
impl Clean<Item> 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<Item> for hir::StructField {
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<Item> 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<Option<Visibility>> for hir::Visibility {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<Visibility> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Option<Visibility> {
|
||||
Some(match self.node {
|
||||
hir::VisibilityKind::Public => Visibility::Public,
|
||||
hir::VisibilityKind::Inherited => Visibility::Inherited,
|
||||
|
@ -2976,7 +2976,7 @@ impl Clean<Option<Visibility>> for hir::Visibility {
|
|||
}
|
||||
|
||||
impl Clean<Option<Visibility>> for ty::Visibility {
|
||||
fn clean(&self, _: &DocContext<'_, '_, '_>) -> Option<Visibility> {
|
||||
fn clean(&self, _: &DocContext<'_>) -> Option<Visibility> {
|
||||
Some(if *self == ty::Visibility::Public { Public } else { Inherited })
|
||||
}
|
||||
}
|
||||
|
@ -2998,7 +2998,7 @@ pub struct Union {
|
|||
}
|
||||
|
||||
impl Clean<Item> 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<Item> for doctree::Struct {
|
|||
}
|
||||
|
||||
impl Clean<Item> 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<VariantStruct> 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<Item> 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<Item> 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<Item> for doctree::Variant {
|
|||
}
|
||||
|
||||
impl<'tcx> Clean<Item> 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<VariantKind> 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<Span> 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<Path> 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<GenericArgs> 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<PathSegment> 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<String> for Ident {
|
||||
#[inline]
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> String {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> String {
|
||||
self.name.clean(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<String> for ast::Name {
|
||||
#[inline]
|
||||
fn clean(&self, _: &DocContext<'_, '_, '_>) -> String {
|
||||
fn clean(&self, _: &DocContext<'_>) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<String> 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<Item> 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<Item> 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<BareFunctionDecl> 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<Item> 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<Item> 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<Mutability> 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<ImplPolarity> 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<Item> {
|
||||
|
@ -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<Item> {
|
||||
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<Item> {
|
||||
|
@ -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<Item> {
|
||||
let finder = BlanketImplFinder::new(cx);
|
||||
|
@ -3578,7 +3578,7 @@ pub fn get_blanket_impls_with_def_id(
|
|||
}
|
||||
|
||||
impl Clean<Vec<Item>> for doctree::Impl {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<Item> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
let mut ret = Vec::new();
|
||||
let trait_ = self.trait_.clean(cx);
|
||||
let items = self.items.clean(cx);
|
||||
|
@ -3620,7 +3620,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>,
|
||||
fn build_deref_target_impls(cx: &DocContext<'_>,
|
||||
items: &[Item],
|
||||
ret: &mut Vec<Item>) {
|
||||
use self::PrimitiveType::*;
|
||||
|
@ -3679,7 +3679,7 @@ fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>,
|
|||
}
|
||||
|
||||
impl Clean<Vec<Item>> for doctree::ExternCrate {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<Item> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
|
||||
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<Vec<Item>> for doctree::ExternCrate {
|
|||
}
|
||||
|
||||
impl Clean<Vec<Item>> for doctree::Import {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<Item> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
// 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<Vec<Item>> for hir::ForeignMod {
|
||||
fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<Item> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
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<Vec<Item>> for hir::ForeignMod {
|
|||
}
|
||||
|
||||
impl Clean<Item> 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<Item> 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<Item> 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<Item> 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<Stability> 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<Stability> for attr::Stability {
|
|||
}
|
||||
|
||||
impl<'a> Clean<Stability> for &'a attr::Stability {
|
||||
fn clean(&self, dc: &DocContext<'_, '_, '_>) -> Stability {
|
||||
fn clean(&self, dc: &DocContext<'_>) -> Stability {
|
||||
(**self).clean(dc)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Deprecation> 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<TypeBinding> 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<TypeBinding> for hir::TypeBinding {
|
|||
}
|
||||
|
||||
pub fn def_id_to_path(
|
||||
cx: &DocContext<'_, '_, '_>,
|
||||
cx: &DocContext<'_>,
|
||||
did: DefId,
|
||||
name: Option<String>
|
||||
) -> Vec<String> {
|
||||
|
@ -4148,7 +4148,7 @@ pub fn def_id_to_path(
|
|||
once(crate_name).chain(relative).collect()
|
||||
}
|
||||
|
||||
pub fn enter_impl_trait<F, R>(cx: &DocContext<'_, '_, '_>, f: F) -> R
|
||||
pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
|
|
|
@ -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<WP>) -> Vec<WP> {
|
||||
pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
|
||||
// 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<clean::GenericBound>) -> Vec<clean::GenericBound> {
|
|||
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
|
||||
|
|
|
@ -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<Options, isize> {
|
||||
pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
|
||||
// Check for unstable options.
|
||||
nightly_options::check_nightly_options(&matches, &opts());
|
||||
|
||||
|
|
|
@ -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<DefId, (Vec<String>, clean::TypeKind)>;
|
||||
|
||||
pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
|
||||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
pub resolver: &'a RefCell<resolve::Resolver<'rcx>>,
|
||||
pub struct DocContext<'tcx> {
|
||||
|
||||
pub tcx: TyCtxt<'tcx, 'tcx, 'tcx>,
|
||||
pub resolver: Rc<Option<RefCell<interface::BoxedResolver>>>,
|
||||
/// The stack of module NodeIds up till this point
|
||||
pub crate_name: Option<String>,
|
||||
pub cstore: Rc<CStore>,
|
||||
pub cstore: Lrc<CStore>,
|
||||
/// Later on moved into `html::render::CACHE_KEY`
|
||||
pub renderinfo: RefCell<RenderInfo>,
|
||||
/// 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<DefId>,
|
||||
}
|
||||
|
||||
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<F, R>(&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<F, R>(&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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
|
||||
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(),
|
||||
);
|
||||
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,
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
interface::run_compiler_in_existing_thread_pool(config, |compiler| {
|
||||
let sess = compiler.session();
|
||||
|
||||
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 name = match crate_name {
|
||||
Some(ref crate_name) => crate_name.clone(),
|
||||
None => ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input),
|
||||
};
|
||||
|
||||
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);
|
||||
if sess.err_count() > 0 {
|
||||
sess.fatal("Compilation failed, aborting rustdoc");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
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),
|
||||
|
|
|
@ -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<Vec<String>> {
|
||||
|
@ -364,7 +363,7 @@ fn usage(argv0: &str) {
|
|||
println!("{}", options.usage(&format!("{} [options] <input>", 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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<clean::Item> {
|
||||
if let Some(dox) = &item.attrs.collapsed_doc_value() {
|
||||
for code_block in markdown::rust_code_blocks(&dox) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ast::NodeId>,
|
||||
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<Item> {
|
||||
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<Def> {
|
||||
fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Def> {
|
||||
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<Def> {
|
|||
/// 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<String>), ()> {
|
||||
fn handle_variant(cx: &DocContext<'_>, def: Def) -> Result<(Def, Option<String>), ()> {
|
||||
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<Def> {
|
|||
}
|
||||
}
|
||||
|
||||
fn primitive_impl(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option<DefId> {
|
||||
fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<DefId> {
|
||||
let tcx = cx.tcx;
|
||||
match path_str {
|
||||
"u8" => tcx.lang_items().u8_impl(),
|
||||
|
|
|
@ -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<Item>,
|
||||
}
|
||||
|
||||
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<Item> {
|
||||
if i.is_struct() || i.is_enum() || i.is_union() {
|
||||
if let (Some(hir_id), Some(name)) =
|
||||
|
|
|
@ -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<usize>,
|
||||
attrs: &clean::Attributes,
|
||||
|
|
|
@ -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<Item> {
|
||||
let cx = self.cx;
|
||||
let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String>,
|
||||
}
|
||||
|
||||
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 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 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 mut test_args = options.test_args.clone();
|
||||
let display_warnings = options.display_warnings;
|
||||
|
||||
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 tests = interface::run_compiler(config, |compiler| -> Result<_, ErrorReported> {
|
||||
let lower_to_hir = compiler.lower_to_hir()?;
|
||||
|
||||
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 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<Mutex<Vec<u8>>>, Box<dyn Write+Send>);
|
||||
struct Bomb(Arc<Mutex<Vec<u8>>>, Option<Box<dyn Write+Send>>);
|
||||
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 outdir = if let Some(mut path) = persist_doctests {
|
||||
path.push(format!("{}_{}",
|
||||
filename
|
||||
.to_string()
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.unwrap()
|
||||
.replace(".", "_"),
|
||||
line)
|
||||
);
|
||||
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));
|
||||
std::fs::create_dir_all(&path)
|
||||
.expect("Couldn't create directory for doctest executables");
|
||||
|
||||
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 output_file = outdir.path().join("rust_out");
|
||||
|
||||
DirState::Perm(path)
|
||||
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(),
|
||||
};
|
||||
|
||||
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 {
|
||||
DirState::Temp(TempFileBuilder::new()
|
||||
.prefix("rustdoctest")
|
||||
.tempdir()
|
||||
.expect("rustdoc needs a tempdir"))
|
||||
}
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
||||
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(())
|
||||
};
|
||||
|
||||
(outdir, compile_result)
|
||||
});
|
||||
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
|
||||
)
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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<ast::Attribute>,
|
||||
pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>,
|
||||
pub cx: &'a core::DocContext<'tcx>,
|
||||
view_item_stack: FxHashSet<ast::NodeId>,
|
||||
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<FxHashMap<DefId, Vec<String>>>,
|
||||
}
|
||||
|
||||
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") {
|
||||
|
|
|
@ -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<DefId>>,
|
||||
// Previous accessibility level, None means unreachable
|
||||
|
@ -22,10 +22,10 @@ pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> {
|
|||
visited_mods: FxHashSet<DefId>,
|
||||
}
|
||||
|
||||
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),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<CodegenBackend>);
|
||||
|
@ -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;
|
||||
|
|
|
@ -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<CStore>, Box<CodegenBackend>) {
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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<PathBuf>,
|
||||
_: &Option<PathBuf>)
|
||||
-> Compilation {
|
||||
*self.count *= 3;
|
||||
Compilation::Stop
|
||||
}
|
||||
|
||||
fn some_input(&mut self, input: Input, input_path: Option<PathBuf>)
|
||||
-> (Input, Option<PathBuf>) {
|
||||
*self.count *= 5;
|
||||
(input, input_path)
|
||||
}
|
||||
|
||||
fn no_input(&mut self,
|
||||
_: &getopts::Matches,
|
||||
_: &config::Options,
|
||||
_: &ast::CrateConfig,
|
||||
_: &Option<PathBuf>,
|
||||
_: &Option<PathBuf>,
|
||||
_: &errors::registry::Registry)
|
||||
-> Option<(Input, Option<PathBuf>)> {
|
||||
panic!("This shouldn't happen");
|
||||
}
|
||||
|
||||
fn build_controller(self: Box<Self>,
|
||||
_: &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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -10,5 +10,5 @@ note: lint level defined here
|
|||
LL | #![deny(missing_docs)]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: Compilation failed, aborting rustdoc
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -42,3 +42,5 @@ LL | #![deny(rustdoc)]
|
|||
| ^^^^^^^
|
||||
= note: #[deny(missing_doc_code_examples)] implied by #[deny(rustdoc)]
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -14,3 +14,5 @@ note: lint level defined here
|
|||
LL | #![deny(private_doc_tests)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -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() }
|
||||
|
|
Loading…
Add table
Reference in a new issue