diff --git a/eyre/build.rs b/eyre/build.rs index e0b2d29..162f1cc 100644 --- a/eyre/build.rs +++ b/eyre/build.rs @@ -5,35 +5,38 @@ use std::path::Path; use std::process::{Command, ExitStatus}; use std::str; -// This code exercises the surface area that we expect of the std Backtrace -// type. If the current toolchain is able to compile it, we go ahead and use -// backtrace in eyre. +// This code exercises the surface area that we expect of the Error generic +// member access API. If the current toolchain is able to compile it, then +// anyhow is able to provide backtrace support. const BACKTRACE_PROBE: &str = r#" - #![feature(backtrace)] - #![allow(dead_code)] + #![feature(error_generic_member_access)] - use std::backtrace::{Backtrace, BacktraceStatus}; - use std::error::Error; - use std::fmt::{self, Display}; + use std::backtrace::Backtrace; + use std::error::{self, Error, Request}; + use std::fmt::{self, Debug, Display}; - #[derive(Debug)] - struct E; + struct MyError(Thing); + struct Thing; - impl Display for E { + impl Debug for MyError { fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } } - impl Error for E { - fn backtrace(&self) -> Option<&Backtrace> { - let backtrace = Backtrace::capture(); - match backtrace.status() { - BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {} - } + impl Display for MyError { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } } + + impl Error for MyError { + fn provide<'a>(&'a self, request: &mut Request<'a>) { + request.provide_ref(&self.0); + } + } + + const _: fn(&dyn Error) -> Option<&Backtrace> = |err| error::request_ref::(err); "#; const TRACK_CALLER_PROBE: &str = r#" diff --git a/eyre/src/backtrace.rs b/eyre/src/backtrace.rs index 6c00d7f..c6787a9 100644 --- a/eyre/src/backtrace.rs +++ b/eyre/src/backtrace.rs @@ -7,7 +7,7 @@ pub(crate) enum Backtrace {} #[cfg(backtrace)] macro_rules! backtrace_if_absent { ($err:expr) => { - match $err.backtrace() { + match std::error::request_ref::($err as &dyn std::error::Error) { Some(_) => None, None => Some(Backtrace::capture()), } diff --git a/eyre/src/context.rs b/eyre/src/context.rs index a15b41b..5fdde59 100644 --- a/eyre/src/context.rs +++ b/eyre/src/context.rs @@ -3,7 +3,7 @@ use crate::{ContextCompat, Report, StdError, WrapErr}; use core::fmt::{self, Debug, Display, Write}; #[cfg(backtrace)] -use std::backtrace::Backtrace; +use std::error::Request; mod ext { use super::*; @@ -144,8 +144,8 @@ where E: StdError + 'static, { #[cfg(backtrace)] - fn backtrace(&self) -> Option<&Backtrace> { - self.error.backtrace() + fn provide<'a>(&'a self, request: &mut Request<'a>) { + StdError::provide(&self.error, request); } fn source(&self) -> Option<&(dyn StdError + 'static)> { diff --git a/eyre/src/lib.rs b/eyre/src/lib.rs index 3d887ab..7aabafa 100644 --- a/eyre/src/lib.rs +++ b/eyre/src/lib.rs @@ -341,7 +341,7 @@ unused_parens, while_true )] -#![cfg_attr(backtrace, feature(backtrace))] +#![cfg_attr(backtrace, feature(error_generic_member_access))] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![allow( clippy::needless_doctest_main, @@ -789,6 +789,8 @@ impl EyreHandler for DefaultHandler { f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { use core::fmt::Write as _; + #[cfg(backtrace)] + use std::error::request_ref; if f.alternate() { return core::fmt::Debug::fmt(error, f); @@ -824,7 +826,7 @@ impl EyreHandler for DefaultHandler { let backtrace = self .backtrace .as_ref() - .or_else(|| error.backtrace()) + .or_else(|| request_ref::(error)) .expect("backtrace capture failed"); if let BacktraceStatus::Captured = backtrace.status() { write!(f, "\n\nStack backtrace:\n{}", backtrace)?; diff --git a/eyre/src/wrapper.rs b/eyre/src/wrapper.rs index b4da68a..58eb378 100644 --- a/eyre/src/wrapper.rs +++ b/eyre/src/wrapper.rs @@ -1,6 +1,9 @@ use crate::StdError; use core::fmt::{self, Debug, Display}; +#[cfg(backtrace)] +use std::error::Request; + #[repr(transparent)] pub(crate) struct DisplayError(pub(crate) M); @@ -83,8 +86,8 @@ impl Display for BoxedError { impl StdError for BoxedError { #[cfg(backtrace)] - fn backtrace(&self) -> Option<&crate::backtrace::Backtrace> { - self.0.backtrace() + fn provide<'a>(&'a self, request: &mut Request<'a>) { + self.0.provide(request); } fn source(&self) -> Option<&(dyn StdError + 'static)> {