Detect nightly and only expose backtrace if available

This commit is contained in:
David Tolnay 2019-10-05 23:20:51 -04:00
parent 3cd72734d5
commit 270ea5e7d5
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
4 changed files with 71 additions and 15 deletions

39
build.rs Normal file
View File

@ -0,0 +1,39 @@
use std::env;
use std::process::Command;
use std::str;
fn main() {
let compiler = match rustc_version() {
Some(compiler) => compiler,
None => return,
};
if compiler.nightly {
println!("cargo:rustc-cfg=backtrace");
}
}
struct Compiler {
nightly: bool,
}
fn rustc_version() -> Option<Compiler> {
let rustc = match env::var_os("RUSTC") {
Some(rustc) => rustc,
None => return None,
};
let output = match Command::new(rustc).arg("--version").output() {
Ok(output) => output,
Err(_) => return None,
};
let version = match str::from_utf8(&output.stdout) {
Ok(version) => version,
Err(_) => return None,
};
Some(Compiler {
nightly: version.contains("nightly") || version.contains("dev"),
})
}

View File

@ -1,8 +1,9 @@
use std::backtrace::Backtrace;
use crate::Error;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use crate::Error;
#[cfg(backtrace)]
use std::backtrace::Backtrace;
/// Provides the `context` method for `Result`.
pub trait Context<T, E> {
@ -89,6 +90,7 @@ where
E: StdError + 'static,
C: Display,
{
#[cfg(backtrace)]
fn backtrace(&self) -> Option<&Backtrace> {
self.error.backtrace()
}
@ -102,6 +104,7 @@ impl<C> StdError for ContextError<Error, C>
where
C: Display,
{
#[cfg(backtrace)]
fn backtrace(&self) -> Option<&Backtrace> {
Some(self.error.backtrace())
}

View File

@ -1,12 +1,14 @@
use crate::context::ContextError;
use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;
#[cfg(backtrace)]
use std::backtrace::{Backtrace, BacktraceStatus};
/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
@ -48,6 +50,7 @@ impl Error {
where
E: StdError + Send + Sync + 'static,
{
#[cfg(backtrace)]
let backtrace = match error.backtrace() {
Some(_) => None,
None => Some(Backtrace::capture()),
@ -59,6 +62,7 @@ impl Error {
let inner = Box::new(ErrorImpl {
vtable,
type_id,
#[cfg(backtrace)]
backtrace,
error,
});
@ -90,6 +94,12 @@ impl Error {
}
/// Get the backtrace for this Error.
///
/// Backtraces are only available on the nightly channel. Tracking issue:
/// [rust-lang/rust#53487][tracking].
///
/// [tracking]: https://github.com/rust-lang/rust/issues/53487
#[cfg(backtrace)]
pub fn backtrace(&self) -> &Backtrace {
// NB: this unwrap can only fail if the underlying error's backtrace
// method is nondeterministic, which would only happen in maliciously
@ -197,6 +207,8 @@ impl Debug for Error {
}
}
#[cfg(backtrace)]
{
let backtrace = self.backtrace();
match backtrace.status() {
BacktraceStatus::Captured => {
@ -210,6 +222,7 @@ impl Debug for Error {
}
_ => {}
}
}
Ok(())
}
@ -235,6 +248,7 @@ impl Drop for Error {
struct ErrorImpl<E> {
vtable: *const (),
type_id: TypeId,
#[cfg(backtrace)]
backtrace: Option<Backtrace>,
error: E,
}

View File

@ -1,4 +1,4 @@
#![feature(backtrace)]
#![cfg_attr(backtrace, feature(backtrace))]
mod context;
mod error;