Skip to content

Commit

Permalink
Use backtrace via generic member access
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Aug 31, 2022
1 parent 9f40a1e commit 46d3d2c
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 38 deletions.
26 changes: 17 additions & 9 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ compile_error! {
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
const PROBE: &str = r#"
#![feature(backtrace)]
#![allow(dead_code)]
#![feature(error_generic_member_access, provide_any)]
use std::any::Demand;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error;
use std::fmt::{self, Display};
#[derive(Debug)]
struct E;
struct E {
backtrace: Backtrace,
}
impl Display for E {
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
Expand All @@ -32,14 +34,20 @@ const PROBE: &str = r#"
}
impl Error for E {
fn backtrace(&self) -> Option<&Backtrace> {
let backtrace = Backtrace::capture();
match backtrace.status() {
BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
}
unimplemented!()
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
req.provide_ref(&self.backtrace);
}
}
const _: fn() = || {
let backtrace: Backtrace = Backtrace::capture();
let status: BacktraceStatus = backtrace.status();
match status {
BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
}
};
const _: fn(&dyn Error) -> Option<&Backtrace> = |err| err.request_ref::<Backtrace>();
"#;

fn main() {
Expand Down
2 changes: 1 addition & 1 deletion src/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ macro_rules! backtrace {
#[cfg(backtrace)]
macro_rules! backtrace_if_absent {
($err:expr) => {
match $err.backtrace() {
match ($err as &dyn std::error::Error).request_ref::<std::backtrace::Backtrace>() {
Some(_) => None,
None => backtrace!(),
}
Expand Down
25 changes: 13 additions & 12 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::convert::Infallible;
use core::fmt::{self, Debug, Display, Write};

#[cfg(backtrace)]
use std::backtrace::Backtrace;
use std::any::Demand;

mod ext {
use super::*;
Expand All @@ -24,7 +24,7 @@ mod ext {
where
C: Display + Send + Sync + 'static,
{
let backtrace = backtrace_if_absent!(self);
let backtrace = backtrace_if_absent!(&self);
Error::from_context(context, self, backtrace)
}
}
Expand Down Expand Up @@ -123,28 +123,29 @@ where
C: Display,
E: StdError + 'static,
{
#[cfg(backtrace)]
fn backtrace(&self) -> Option<&Backtrace> {
self.error.backtrace()
}

fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&self.error)
}

#[cfg(backtrace)]
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
self.error.provide(req);
}
}

impl<C> StdError for ContextError<C, Error>
where
C: Display,
{
#[cfg(backtrace)]
fn backtrace(&self) -> Option<&Backtrace> {
Some(self.error.backtrace())
}

fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) })
}

#[cfg(backtrace)]
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
req.provide_ref(self.error.backtrace());
self.error.provide(req);
}
}

struct Quoted<C>(C);
Expand Down
28 changes: 19 additions & 9 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use crate::ptr::Mut;
use crate::ptr::{Own, Ref};
use crate::{Error, StdError};
use alloc::boxed::Box;
#[cfg(backtrace)]
use core::any::Demand;
use core::any::TypeId;
use core::fmt::{self, Debug, Display};
use core::mem::ManuallyDrop;
Expand All @@ -31,7 +33,7 @@ impl Error {
where
E: StdError + Send + Sync + 'static,
{
let backtrace = backtrace_if_absent!(error);
let backtrace = backtrace_if_absent!(&error);
Error::from_std(error, backtrace)
}

Expand Down Expand Up @@ -530,7 +532,7 @@ where
{
#[cold]
fn from(error: E) -> Self {
let backtrace = backtrace_if_absent!(error);
let backtrace = backtrace_if_absent!(&error);
Error::from_std(error, backtrace)
}
}
Expand Down Expand Up @@ -886,13 +888,21 @@ impl ErrorImpl {
.as_ref()
.or_else(|| {
#[cfg(backtrace)]
return Self::error(this).backtrace();
#[cfg(all(not(backtrace), feature = "backtrace"))]
return Self::error(this).request_ref::<Backtrace>();
#[cfg(not(backtrace))]
return (vtable(this.ptr).object_backtrace)(this);
})
.expect("backtrace capture failed")
}

#[cfg(backtrace)]
unsafe fn provide<'a>(this: Ref<'a, Self>, req: &mut Demand<'a>) {
if let Some(backtrace) = &this.deref().backtrace {
req.provide_ref(backtrace);
}
Self::error(this).provide(req);
}

#[cold]
pub(crate) unsafe fn chain(this: Ref<Self>) -> Chain {
Chain::new(Self::error(this))
Expand All @@ -903,14 +913,14 @@ impl<E> StdError for ErrorImpl<E>
where
E: StdError,
{
#[cfg(backtrace)]
fn backtrace(&self) -> Option<&Backtrace> {
Some(unsafe { ErrorImpl::backtrace(self.erase()) })
}

fn source(&self) -> Option<&(dyn StdError + 'static)> {
unsafe { ErrorImpl::error(self.erase()).source() }
}

#[cfg(backtrace)]
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
unsafe { ErrorImpl::provide(self.erase(), req) }
}
}

impl<E> Debug for ErrorImpl<E>
Expand Down
2 changes: 1 addition & 1 deletion src/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl BoxedKind for Box<dyn StdError + Send + Sync> {}
impl Boxed {
#[cold]
pub fn new(self, error: Box<dyn StdError + Send + Sync>) -> Error {
let backtrace = backtrace_if_absent!(error);
let backtrace = backtrace_if_absent!(&*error);
Error::from_boxed(error, backtrace)
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@
//! non-Anyhow error type inside a function that returns Anyhow's error type.
#![doc(html_root_url = "https://docs.rs/anyhow/1.0.62")]
#![cfg_attr(backtrace, feature(backtrace))]
#![cfg_attr(backtrace, feature(error_generic_member_access, provide_any))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(dead_code, unused_imports, unused_mut)]
Expand Down
13 changes: 8 additions & 5 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::StdError;
use core::fmt::{self, Debug, Display};

#[cfg(backtrace)]
use std::any::Demand;

#[repr(transparent)]
pub struct MessageError<M>(pub M);

Expand Down Expand Up @@ -67,12 +70,12 @@ impl Display for BoxedError {

#[cfg(feature = "std")]
impl StdError for BoxedError {
#[cfg(backtrace)]
fn backtrace(&self) -> Option<&crate::backtrace::Backtrace> {
self.0.backtrace()
}

fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.0.source()
}

#[cfg(backtrace)]
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
self.0.provide(req);
}
}

0 comments on commit 46d3d2c

Please sign in to comment.