Make the rustc driver and interface demand driven

This commit is contained in:
John Kåre Alsaker 2018-12-08 20:30:23 +01:00
parent 26b4cb4848
commit 51938c61f6
60 changed files with 2521 additions and 2755 deletions

View file

@ -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 {

View file

@ -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());

View file

@ -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)
}
}

View file

@ -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)
})
}

View file

@ -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,

View file

@ -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::

View file

@ -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() {

View 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,
}
}
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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(())
}

View file

@ -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 {

View file

@ -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;

View file

@ -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.

View file

@ -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;

View 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)
}

View file

@ -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};

View file

@ -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
}

View 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(|_| ())
}
}

View file

@ -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

View file

@ -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 }

View file

@ -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 }
}

View file

@ -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,

View file

@ -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;
}

View file

@ -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,
{

View file

@ -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

View file

@ -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());

View file

@ -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),

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -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) {

View file

@ -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)
}

View file

@ -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(),

View file

@ -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)) =

View file

@ -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,

View file

@ -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);

View file

@ -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)
}

View file

@ -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

View file

@ -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)
}

View file

@ -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();

View file

@ -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)
}

View file

@ -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
)
}),
});
}

View file

@ -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") {

View file

@ -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),

View file

@ -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.

View file

@ -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;

View file

@ -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();
});
}

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -10,5 +10,5 @@ note: lint level defined here
LL | #![deny(missing_docs)]
| ^^^^^^^^^^^^
error: Compilation failed, aborting rustdoc
error: aborting due to previous error

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -42,3 +42,5 @@ LL | #![deny(rustdoc)]
| ^^^^^^^
= note: #[deny(missing_doc_code_examples)] implied by #[deny(rustdoc)]
error: aborting due to 3 previous errors

View file

@ -14,3 +14,5 @@ note: lint level defined here
LL | #![deny(private_doc_tests)]
| ^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -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() }