//!
//! This API is completely unstable and subject to change.
+#![deny(bare_trait_objects)]
+
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
use std::default::Default;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::env;
+use std::error::Error;
use std::ffi::OsString;
+use std::fmt::{self, Display};
use std::io::{self, Read, Write};
-use std::iter::repeat;
use std::mem;
use std::panic;
use std::path::{PathBuf, Path};
/// features is available on the target machine, by querying LLVM.
pub fn add_configuration(cfg: &mut ast::CrateConfig,
sess: &Session,
- codegen_backend: &CodegenBackend) {
+ codegen_backend: &dyn CodegenBackend) {
let tf = Symbol::intern("target_feature");
for feat in codegen_backend.target_features(sess) {
}
}
+/// Exit status code used for successful compilation and help output.
+pub const EXIT_SUCCESS: isize = 0;
+
+/// Exit status code used for compilation failures and invalid flags.
+pub const EXIT_FAILURE: isize = 1;
+
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
md#bug-reports";
pub fn run<F>(run_compiler: F) -> isize
where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
{
- monitor(move || {
+ let result = monitor(move || {
let (result, session) = run_compiler();
if let Err(CompileIncomplete::Errored(_)) = result {
match session {
}
}
});
- 0
+
+ match result {
+ Ok(()) => EXIT_SUCCESS,
+ Err(_) => EXIT_FAILURE,
+ }
}
-fn load_backend_from_dylib(path: &Path) -> fn() -> Box<CodegenBackend> {
+fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
// Note that we're specifically using `open_global_now` here rather than
// `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW,
// where NOW means "bind everything right now" because we don't want
}
}
-pub fn get_codegen_backend(sess: &Session) -> Box<CodegenBackend> {
+pub fn get_codegen_backend(sess: &Session) -> Box<dyn CodegenBackend> {
static INIT: Once = ONCE_INIT;
#[allow(deprecated)]
#[no_debug]
- static mut LOAD: fn() -> Box<CodegenBackend> = || unreachable!();
+ static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
INIT.call_once(|| {
let codegen_name = sess.opts.debugging_opts.codegen_backend.as_ref()
backend
}
-fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<CodegenBackend> {
+fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
// For now we only allow this function to be called once as it'll dlopen a
// few things, which seems to work best if we only do that once. In
// general this assertion never trips due to the once guard in `get_codegen_backend`,
// 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<CompilerCalls<'a> + sync::Send + 'a>,
- file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
- emitter_dest: Option<Box<Write + Send>>)
+ 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>)
{
syntax::with_globals(|| {
matches: getopts::Matches,
sopts: config::Options,
cfg: ast::CrateConfig,
- mut callbacks: Box<CompilerCalls<'a> + sync::Send + 'a>,
- file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
- emitter_dest: Option<Box<Write + Send>>
+ 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 {
/// 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,
- _: &CodegenBackend,
+ _: &dyn CodegenBackend,
_: &getopts::Matches,
_: &Session,
- _: &CrateStore,
+ _: &dyn CrateStore,
_: &Input,
_: &Option<PathBuf>,
_: &Option<PathBuf>)
}
fn late_callback(&mut self,
- codegen_backend: &CodegenBackend,
+ codegen_backend: &dyn CodegenBackend,
matches: &getopts::Matches,
sess: &Session,
- cstore: &CrateStore,
+ cstore: &dyn CrateStore,
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>)
impl RustcDefaultCalls {
pub fn list_metadata(sess: &Session,
- cstore: &CrateStore,
+ cstore: &dyn CrateStore,
matches: &getopts::Matches,
input: &Input)
-> Compilation {
}
- fn print_crate_info(codegen_backend: &CodegenBackend,
+ fn print_crate_info(codegen_backend: &dyn CodegenBackend,
sess: &Session,
input: Option<&Input>,
odir: &Option<PathBuf>,
fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>)
-> Vec<(&'static str, Vec<lint::LintId>)> {
let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
- lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>),
- &(y, _): &(&'static str, Vec<lint::LintId>)| {
- x.cmp(y)
- });
+ lints.sort_by_key(|l| l.0);
lints
}
.max()
.unwrap_or(0);
let padded = |x: &str| {
- let mut s = repeat(" ")
- .take(max_name_len - x.chars().count())
- .collect::<String>();
+ let mut s = " ".repeat(max_name_len - x.chars().count());
s.push_str(x);
s
};
.unwrap_or(0));
let padded = |x: &str| {
- let mut s = repeat(" ")
- .take(max_name_len - x.chars().count())
- .collect::<String>();
+ let mut s = " ".repeat(max_name_len - x.chars().count());
s.push_str(x);
s
};
}
}
-/// 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<Any + Send>>
+/// 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,
{
// The or condition is added from backward compatibility.
if spawn_thread || env::var_os("RUST_MIN_STACK").is_some() {
- let mut cfg = thread::Builder::new().name("rustc".to_string());
+ let mut cfg = thread::Builder::new().name(name);
// FIXME: Hacks on hacks. If the env is trying to override the stack size
// then *don't* set it explicitly.
}
}
+/// 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)
+}
+
/// Get 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
}
}
+#[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")
+ }
+}
+
/// Run 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) {
- let result = in_rustc_thread(move || {
+pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFailure> {
+ in_rustc_thread(move || {
f()
- });
-
- if let Err(value) = result {
- // Thread panicked without emitting a fatal diagnostic
- if !value.is::<errors::FatalErrorMarker>() {
- // Emit a newline
+ }).map_err(|value| {
+ if value.is::<errors::FatalErrorMarker>() {
+ CompilationFailure
+ } else {
+ // Thread panicked without emitting a fatal diagnostic
eprintln!("");
let emitter =
¬e,
errors::Level::Note);
}
- }
- panic::resume_unwind(Box::new(errors::FatalErrorMarker));
- }
+ panic::resume_unwind(Box::new(errors::FatalErrorMarker));
+ }
+ })
}
pub fn diagnostics_registry() -> errors::registry::Registry {