(&None, &Some(..), Closed) => "RangeToInclusive",
(&Some(..), &Some(..), Closed) => "RangeInclusive",
(_, &None, Closed) =>
- panic!(self.diagnostic().span_fatal(
- e.span, "inclusive range with no end")),
+ self.diagnostic().span_fatal(
+ e.span, "inclusive range with no end").raise(),
};
let fields =
sp.struct_fatal(&format!("Error loading target specification: {}", e))
.help("Use `--print target-list` for a list of built-in targets")
.emit();
- panic!(FatalError);
+ FatalError.raise();
}
};
"16" => (ast::IntTy::I16, ast::UintTy::U16),
"32" => (ast::IntTy::I32, ast::UintTy::U32),
"64" => (ast::IntTy::I64, ast::UintTy::U64),
- w => panic!(sp.fatal(&format!("target specification was invalid: \
- unrecognized target-pointer-width {}", w))),
+ w => sp.fatal(&format!("target specification was invalid: \
+ unrecognized target-pointer-width {}", w)).raise(),
};
Config {
}
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
- panic!(self.diagnostic().span_fatal(sp, msg))
+ self.diagnostic().span_fatal(sp, msg).raise()
}
pub fn span_fatal_with_code<S: Into<MultiSpan>>(
&self,
msg: &str,
code: DiagnosticId,
) -> ! {
- panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
+ self.diagnostic().span_fatal_with_code(sp, msg, code).raise()
}
pub fn fatal(&self, msg: &str) -> ! {
- panic!(self.diagnostic().fatal(msg))
+ self.diagnostic().fatal(msg).raise()
}
pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg: &str) {
if is_warning {
let host = match Target::search(config::host_triple()) {
Ok(t) => t,
Err(e) => {
- panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
+ span_diagnostic.fatal(&format!("Error loading host specification: {}", e)).raise();
}
};
let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
let working_dir = match env::current_dir() {
Ok(dir) => dir,
Err(e) => {
- panic!(p_s.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)))
+ p_s.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)).raise()
}
};
let working_dir = file_path_mapping.map_prefix(working_dir);
};
let handler = errors::Handler::with_emitter(true, false, emitter);
handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
- panic!(errors::FatalError);
+ errors::FatalError.raise();
}
pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
use std::ffi::OsString;
use std::io::{self, Read, Write};
use std::iter::repeat;
+use std::panic;
use std::path::PathBuf;
use std::process::{self, Command, Stdio};
use std::rc::Rc;
use std::str;
-use std::sync::{Arc, Mutex};
use std::thread;
use syntax::ast;
handler.emit(&MultiSpan::new(),
"aborting due to previous error(s)",
errors::Level::Fatal);
- exit_on_err();
+ panic::resume_unwind(Box::new(errors::FatalErrorMarker));
}
}
}
/// 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) {
- 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(())
- }
- }
-
- let data = Arc::new(Mutex::new(Vec::new()));
- let err = Sink(data.clone());
-
let result = in_rustc_thread(move || {
- io::set_panic(Some(box err));
f()
});
if let Err(value) = result {
// Thread panicked without emitting a fatal diagnostic
- if !value.is::<errors::FatalError>() {
+ if !value.is::<errors::FatalErrorMarker>() {
+ // Emit a newline
+ eprintln!("");
+
let emitter =
Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
None,
¬e,
errors::Level::Note);
}
-
- eprintln!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
}
- exit_on_err();
+ panic::resume_unwind(Box::new(errors::FatalErrorMarker));
}
}
-fn exit_on_err() -> ! {
- // Panic so the process returns a failure code, but don't pollute the
- // output with some unnecessary panic messages, we've already
- // printed everything that we needed to.
- io::set_panic(Some(box io::sink()));
- panic!();
-}
-
#[cfg(stage0)]
pub fn diagnostics_registry() -> errors::registry::Registry {
use errors::registry::Registry;
#![cfg_attr(unix, feature(libc))]
#![feature(conservative_impl_trait)]
#![feature(i128_type)]
+#![feature(optin_builtin_traits)]
extern crate term;
#[cfg(unix)]
use std::{error, fmt};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
+use std::panic;
mod diagnostic;
mod diagnostic_builder;
#[must_use]
pub struct FatalError;
+pub struct FatalErrorMarker;
+
+// Don't implement Send on FatalError. This makes it impossible to panic!(FatalError).
+// We don't want to invoke the panic handler and print a backtrace for fatal errors.
+impl !Send for FatalError {}
+
+impl FatalError {
+ pub fn raise(self) -> ! {
+ panic::resume_unwind(Box::new(FatalErrorMarker))
+ }
+}
+
impl fmt::Display for FatalError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "parser fatal error")
}
}
- panic!(self.fatal(&s));
+ self.fatal(&s).raise();
}
pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
if lvl == Warning && !self.flags.can_emit_warnings {
pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
target_machine_factory(sess)().unwrap_or_else(|err| {
- panic!(llvm_err(sess.diagnostic(), err))
+ llvm_err(sess.diagnostic(), err).raise()
})
}
lto::LTOMode::JustThisCrate
};
let lto_modules = lto::run(cgcx, modules, mode, &mut timeline)
- .unwrap_or_else(|e| panic!(e));
+ .unwrap_or_else(|e| e.raise());
lto_modules.into_iter().map(|module| {
let cost = module.cost();
/// substitute; we never hit resolve/type-checking so the dummy
/// value doesn't have to match anything)
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
- panic!(self.parse_sess.span_diagnostic.span_fatal(sp, msg));
+ self.parse_sess.span_diagnostic.span_fatal(sp, msg).raise();
}
/// Emit `msg` attached to `sp`, without immediately stopping
suggested_limit));
err.emit();
self.cx.trace_macros_diag();
- panic!(FatalError);
+ FatalError.raise();
}
Some(result)
while self.p.token != token::Eof {
match panictry!(self.p.parse_item()) {
Some(item) => ret.push(item),
- None => panic!(self.p.diagnostic().span_fatal(self.p.span,
+ None => self.p.diagnostic().span_fatal(self.p.span,
&format!("expected item, found `{}`",
- self.p.this_token_to_string())))
+ self.p.this_token_to_string()))
+ .raise()
}
}
Some(ret)
Some(i) => token::NtItem(i),
None => {
p.fatal("expected an item keyword").emit();
- panic!(FatalError);
+ FatalError.raise();
}
},
"block" => token::NtBlock(panictry!(p.parse_block())),
Some(s) => token::NtStmt(s),
None => {
p.fatal("expected a statement").emit();
- panic!(FatalError);
+ FatalError.raise();
}
},
"pat" => token::NtPat(panictry!(p.parse_pat())),
let token_str = pprust::token_to_string(&p.token);
p.fatal(&format!("expected ident, found {}",
&token_str[..])).emit();
- panic!(FatalError)
+ FatalError.raise()
}
},
"path" => token::NtPath(panictry!(p.parse_path_common(PathStyle::Type, false))),
Success(m) => m,
Failure(sp, tok) => {
let s = parse_failure_msg(tok);
- panic!(sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s));
+ sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s).raise();
}
Error(sp, s) => {
- panic!(sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s));
+ sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s).raise();
}
};
.span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
.emit();
- panic!(FatalError);
+ FatalError.raise();
}
if let (Some(span), None) = (self.copy_closures, self.clone_closures) {
.span_note(span, "`#![feature(copy_closures)]` declared here")
.emit();
- panic!(FatalError);
+ FatalError.raise();
}
}
}
Ok(e) => e,
Err(mut e) => {
e.emit();
- panic!(FatalError);
+ FatalError.raise()
}
}
})
while level > 0 {
debug!("=== block comment level {}", level);
if rdr.is_eof() {
- panic!(rdr.fatal("unterminated block comment"));
+ rdr.fatal("unterminated block comment").raise();
}
if rdr.ch_is('\n') {
trim_whitespace_prefix_and_push_line(&mut lines, curr_line, col);
Ok(tok) => tok,
Err(_) => {
self.emit_fatal_errors();
- panic!(FatalError);
+ FatalError.raise();
}
}
}
let mut sr = StringReader::new_raw(sess, filemap);
if sr.advance_token().is_err() {
sr.emit_fatal_errors();
- panic!(FatalError);
+ FatalError.raise();
}
sr
}
if sr.advance_token().is_err() {
sr.emit_fatal_errors();
- panic!(FatalError);
+ FatalError.raise();
}
sr
}
"unterminated block comment"
};
let last_bpos = self.pos;
- panic!(self.fatal_span_(start_bpos, last_bpos, msg));
+ self.fatal_span_(start_bpos, last_bpos, msg).raise();
}
let n = self.ch.unwrap();
match n {
for _ in 0..n_digits {
if self.is_eof() {
let last_bpos = self.pos;
- panic!(self.fatal_span_(start_bpos,
- last_bpos,
- "unterminated numeric character escape"));
+ self.fatal_span_(start_bpos,
+ last_bpos,
+ "unterminated numeric character escape").raise();
}
if self.ch_is(delim) {
let last_bpos = self.pos;
}
},
None => {
- panic!(self.fatal_span_(start_bpos,
- self.pos,
- "unterminated unicode escape (found EOF)"));
+ self.fatal_span_(start_bpos,
+ self.pos,
+ "unterminated unicode escape (found EOF)").raise();
}
}
self.bump();
// lifetimes shouldn't end with a single quote
// if we find one, then this is an invalid character literal
if self.ch_is('\'') {
- panic!(self.fatal_span_verbose(
- start_with_quote, self.next_pos,
- String::from("character literal may only contain one codepoint")));
+ self.fatal_span_verbose(start_with_quote, self.next_pos,
+ String::from("character literal may only contain one codepoint"))
+ .raise();
}
break;
}
}
- panic!(self.fatal_span_verbose(
- start_with_quote, pos,
- String::from("character literal may only contain one codepoint")));
+ self.fatal_span_verbose(start_with_quote, pos,
+ String::from("character literal may only contain one codepoint")).raise();
}
let id = if valid {
while !self.ch_is('"') {
if self.is_eof() {
let last_bpos = self.pos;
- panic!(self.fatal_span_(start_bpos,
- last_bpos,
- "unterminated double quote string"));
+ self.fatal_span_(start_bpos,
+ last_bpos,
+ "unterminated double quote string").raise();
}
let ch_start = self.pos;
if self.is_eof() {
let last_bpos = self.pos;
- panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
+ self.fatal_span_(start_bpos, last_bpos, "unterminated raw string").raise();
} else if !self.ch_is('"') {
let last_bpos = self.pos;
let curr_char = self.ch.unwrap();
- panic!(self.fatal_span_char(start_bpos,
- last_bpos,
- "found invalid character; only `#` is allowed \
- in raw string delimitation",
- curr_char));
+ self.fatal_span_char(start_bpos,
+ last_bpos,
+ "found invalid character; only `#` is allowed \
+ in raw string delimitation",
+ curr_char).raise();
}
self.bump();
let content_start_bpos = self.pos;
'outer: loop {
if self.is_eof() {
let last_bpos = self.pos;
- panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
+ self.fatal_span_(start_bpos, last_bpos, "unterminated raw string").raise();
}
// if self.ch_is('"') {
// content_end_bpos = self.pos;
// character before position `start` are an
// ascii single quote and ascii 'b'.
let pos = self.pos;
- panic!(self.fatal_span_verbose(start - BytePos(2),
- pos,
- "unterminated byte constant".to_string()));
+ self.fatal_span_verbose(start - BytePos(2),
+ pos,
+ "unterminated byte constant".to_string()).raise();
}
let id = if valid {
while !self.ch_is('"') {
if self.is_eof() {
let pos = self.pos;
- panic!(self.fatal_span_(start, pos, "unterminated double quote byte string"));
+ self.fatal_span_(start, pos, "unterminated double quote byte string").raise();
}
let ch_start = self.pos;
if self.is_eof() {
let pos = self.pos;
- panic!(self.fatal_span_(start_bpos, pos, "unterminated raw string"));
+ self.fatal_span_(start_bpos, pos, "unterminated raw string").raise();
} else if !self.ch_is('"') {
let pos = self.pos;
let ch = self.ch.unwrap();
- panic!(self.fatal_span_char(start_bpos,
+ self.fatal_span_char(start_bpos,
pos,
"found invalid character; only `#` is allowed in raw \
string delimitation",
- ch));
+ ch).raise();
}
self.bump();
let content_start_bpos = self.pos;
match self.ch {
None => {
let pos = self.pos;
- panic!(self.fatal_span_(start_bpos, pos, "unterminated raw string"))
+ self.fatal_span_(start_bpos, pos, "unterminated raw string").raise()
}
Some('"') => {
content_end_bpos = self.pos;
Err(e) => {
let msg = format!("couldn't read {:?}: {}", path.display(), e);
match spanopt {
- Some(sp) => panic!(sess.span_diagnostic.span_fatal(sp, &msg)),
- None => panic!(sess.span_diagnostic.fatal(&msg))
+ Some(sp) => sess.span_diagnostic.span_fatal(sp, &msg).raise(),
+ None => sess.span_diagnostic.fatal(&msg).raise()
}
}
}
match i.node {
ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
let diag = self.cx.span_diagnostic;
- panic!(diag.span_fatal(i.span, "unsafe functions cannot be used for tests"));
+ diag.span_fatal(i.span, "unsafe functions cannot be used for tests").raise();
}
_ => {
debug!("this is a test function");
}
err.emit();
- panic!(FatalError);
+ FatalError.raise();
}
};
// fail if there have been errors emitted
Ok(_) if ecx.parse_sess.span_diagnostic.err_count() > error_count_before => {
ecx.struct_span_fatal(span, msg).emit();
- panic!(FatalError);
+ FatalError.raise();
}
Ok(new_items) => new_items.into_iter().map(Annotatable::Item).collect(),
Err(_) => {
// FIXME: handle this better
ecx.struct_span_fatal(span, msg).emit();
- panic!(FatalError);
+ FatalError.raise();
}
}
})
}
err.emit();
- panic!(FatalError);
+ FatalError.raise();
}
}
}
}
err.emit();
- panic!(FatalError);
+ FatalError.raise();
}
}
}