Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use backtrace via generic member access #266

Merged
merged 1 commit into from Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 17 additions & 9 deletions build.rs
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
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
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
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
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
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
@@ -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);
}
}