use session::config::DebugInfoLevel;
use ty::tls;
use util::nodemap::{FxHashMap, FxHashSet};
-use util::common::duration_to_secs_str;
+use util::common::{duration_to_secs_str, ErrorReported};
use syntax::ast::NodeId;
use errors::{self, DiagnosticBuilder};
use rustc_back::{LinkerFlavor, PanicStrategy};
use rustc_back::target::Target;
use rustc_data_structures::flock;
+use jobserver::Client;
-use std::path::{Path, PathBuf};
use std::cell::{self, Cell, RefCell};
use std::collections::HashMap;
use std::env;
+use std::fmt;
use std::io::Write;
+use std::path::{Path, PathBuf};
use std::rc::Rc;
-use std::fmt;
+use std::sync::{Once, ONCE_INIT};
use std::time::Duration;
mod code_stats;
pub working_dir: (String, bool),
pub lint_store: RefCell<lint::LintStore>,
pub lints: RefCell<lint::LintTable>,
- /// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics
- /// that have been set once, but should not be set again, in order to avoid
- /// redundantly verbose output (Issue #24690).
- pub one_time_diagnostics: RefCell<FxHashSet<(lint::LintId, Span, String)>>,
+ /// Set of (LintId, Option<Span>, message) tuples tracking lint
+ /// (sub)diagnostics that have been set once, but should not be set again,
+ /// in order to avoid redundantly verbose output (Issue #24690).
+ pub one_time_diagnostics: RefCell<FxHashSet<(lint::LintId, Option<Span>, String)>>,
pub plugin_llvm_passes: RefCell<Vec<String>>,
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub print_fuel_crate: Option<String>,
/// Always set to zero and incremented so that we can print fuel expended by a crate.
pub print_fuel: Cell<u64>,
+
+ /// Loaded up early on in the initialization of this `Session` to avoid
+ /// false positives about a job server in our environment.
+ pub jobserver_from_env: Option<Client>,
}
pub struct PerfStats {
pub decode_def_path_tables_time: Cell<Duration>,
}
+/// Enum to support dispatch of one-time diagnostics (in Session.diag_once)
+enum DiagnosticBuilderMethod {
+ Note,
+ SpanNote,
+ // add more variants as needed to support one-time diagnostics
+}
+
impl Session {
pub fn local_crate_disambiguator(&self) -> Symbol {
*self.crate_disambiguator.borrow()
pub fn abort_if_errors(&self) {
self.diagnostic().abort_if_errors();
}
- pub fn track_errors<F, T>(&self, f: F) -> Result<T, usize>
+ pub fn compile_status(&self) -> Result<(), CompileIncomplete> {
+ compile_result_from_err_count(self.err_count())
+ }
+ pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorReported>
where F: FnOnce() -> T
{
let old_count = self.err_count();
if errors == 0 {
Ok(result)
} else {
- Err(errors)
+ Err(ErrorReported)
}
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
&self.parse_sess.span_diagnostic
}
- /// Analogous to calling `.span_note` on the given DiagnosticBuilder, but
- /// deduplicates on lint ID, span, and message for this `Session` if we're
- /// not outputting in JSON mode.
- //
- // FIXME: if the need arises for one-time diagnostics other than
- // `span_note`, we almost certainly want to generalize this
- // "check/insert-into the one-time diagnostics map, then set message if
- // it's not already there" code to accomodate all of them
- pub fn diag_span_note_once<'a, 'b>(&'a self,
- diag_builder: &'b mut DiagnosticBuilder<'a>,
- lint: &'static lint::Lint, span: Span, message: &str) {
+ /// Analogous to calling methods on the given `DiagnosticBuilder`, but
+ /// deduplicates on lint ID, span (if any), and message for this `Session`
+ /// if we're not outputting in JSON mode.
+ fn diag_once<'a, 'b>(&'a self,
+ diag_builder: &'b mut DiagnosticBuilder<'a>,
+ method: DiagnosticBuilderMethod,
+ lint: &'static lint::Lint, message: &str, span: Option<Span>) {
+ let mut do_method = || {
+ match method {
+ DiagnosticBuilderMethod::Note => {
+ diag_builder.note(message);
+ },
+ DiagnosticBuilderMethod::SpanNote => {
+ diag_builder.span_note(span.expect("span_note expects a span"), message);
+ }
+ }
+ };
+
match self.opts.error_format {
// when outputting JSON for tool consumption, the tool might want
// the duplicates
config::ErrorOutputType::Json => {
- diag_builder.span_note(span, &message);
+ do_method()
},
_ => {
let lint_id = lint::LintId::of(lint);
let id_span_message = (lint_id, span, message.to_owned());
let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message);
if fresh {
- diag_builder.span_note(span, &message);
+ do_method()
}
}
}
}
+ pub fn diag_span_note_once<'a, 'b>(&'a self,
+ diag_builder: &'b mut DiagnosticBuilder<'a>,
+ lint: &'static lint::Lint, span: Span, message: &str) {
+ self.diag_once(diag_builder, DiagnosticBuilderMethod::SpanNote, lint, message, Some(span));
+ }
+
+ pub fn diag_note_once<'a, 'b>(&'a self,
+ diag_builder: &'b mut DiagnosticBuilder<'a>,
+ lint: &'static lint::Lint, message: &str) {
+ self.diag_once(diag_builder, DiagnosticBuilderMethod::Note, lint, message, None);
+ }
+
pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap {
self.parse_sess.codemap()
}
print_fuel_crate: print_fuel_crate,
print_fuel: print_fuel,
out_of_fuel: Cell::new(false),
+
+ // Note that this is unsafe because it may misinterpret file descriptors
+ // on Unix as jobserver file descriptors. We hopefully execute this near
+ // the beginning of the process though to ensure we don't get false
+ // positives, or in other words we try to execute this before we open
+ // any file descriptors ourselves.
+ //
+ // Also note that we stick this in a global because there could be
+ // multiple `Session` instances in this process, and the jobserver is
+ // per-process.
+ jobserver_from_env: unsafe {
+ static mut GLOBAL_JOBSERVER: *mut Option<Client> = 0 as *mut _;
+ static INIT: Once = ONCE_INIT;
+ INIT.call_once(|| {
+ GLOBAL_JOBSERVER = Box::into_raw(Box::new(Client::from_env()));
+ });
+ (*GLOBAL_JOBSERVER).clone()
+ },
};
sess
handler.emit(&MultiSpan::new(), msg, errors::Level::Warning);
}
-// Err(0) means compilation was stopped, but no errors were found.
-// This would be better as a dedicated enum, but using try! is so convenient.
-pub type CompileResult = Result<(), usize>;
+#[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 fn compile_result_from_err_count(err_count: usize) -> CompileResult {
if err_count == 0 {
Ok(())
} else {
- Err(err_count)
+ Err(CompileIncomplete::Errored(ErrorReported))
}
}