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

Feature: track caller #287

Closed
wants to merge 3 commits into from
Closed
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
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -14,6 +14,7 @@ rust-version = "1.39"
[features]
default = ["std"]
std = []
track_caller = []

[dependencies]
backtrace = { version = "0.3.51", optional = true }
Expand Down
14 changes: 14 additions & 0 deletions src/backtrace.rs
Expand Up @@ -35,6 +35,20 @@ macro_rules! backtrace {
};
}

#[cfg(feature = "track_caller")]
macro_rules! caller {
() => {
Some(core::panic::Location::caller())
}
}

#[cfg(not(feature = "track_caller"))]
macro_rules! caller {
() => {
None
}
}

#[cfg(backtrace)]
macro_rules! backtrace_if_absent {
($err:expr) => {
Expand Down
11 changes: 8 additions & 3 deletions src/context.rs
Expand Up @@ -25,11 +25,12 @@ mod ext {
C: Display + Send + Sync + 'static,
{
let backtrace = backtrace_if_absent!(&self);
Error::from_context(context, self, backtrace)
Error::from_context(context, self, backtrace, caller!())
}
}

impl StdError for Error {
#[cfg_attr(feature = "track_caller", track_caller)]
fn ext_context<C>(self, context: C) -> Error
where
C: Display + Send + Sync + 'static,
Expand All @@ -43,6 +44,7 @@ impl<T, E> Context<T, E> for Result<T, E>
where
E: ext::StdError + Send + Sync + 'static,
{
#[cfg_attr(feature = "track_caller", track_caller)]
fn context<C>(self, context: C) -> Result<T, Error>
where
C: Display + Send + Sync + 'static,
Expand All @@ -55,6 +57,7 @@ where
}
}

#[cfg_attr(feature = "track_caller", track_caller)]
fn with_context<C, F>(self, context: F) -> Result<T, Error>
where
C: Display + Send + Sync + 'static,
Expand Down Expand Up @@ -88,6 +91,7 @@ where
/// }
/// ```
impl<T> Context<T, Infallible> for Option<T> {
#[cfg_attr(feature = "track_caller", track_caller)]
fn context<C>(self, context: C) -> Result<T, Error>
where
C: Display + Send + Sync + 'static,
Expand All @@ -96,18 +100,19 @@ impl<T> Context<T, Infallible> for Option<T> {
// backtrace.
match self {
Some(ok) => Ok(ok),
None => Err(Error::from_display(context, backtrace!())),
None => Err(Error::from_display(context, backtrace!(), caller!())),
}
}

#[cfg_attr(feature = "track_caller", track_caller)]
fn with_context<C, F>(self, context: F) -> Result<T, Error>
where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
match self {
Some(ok) => Ok(ok),
None => Err(Error::from_display(context(), backtrace!())),
None => Err(Error::from_display(context(), backtrace!(), caller!())),
}
}
}
Expand Down
36 changes: 23 additions & 13 deletions src/error.rs
Expand Up @@ -13,6 +13,7 @@ use core::mem::ManuallyDrop;
#[cfg(not(anyhow_no_ptr_addr_of))]
use core::ptr;
use core::ptr::NonNull;
use core::panic::Location;

#[cfg(feature = "std")]
use core::ops::{Deref, DerefMut};
Expand All @@ -34,7 +35,7 @@ impl Error {
E: StdError + Send + Sync + 'static,
{
let backtrace = backtrace_if_absent!(&error);
Error::from_std(error, backtrace)
Error::from_std(error, backtrace, caller!())
}

/// Create a new error object from a printable error message.
Expand Down Expand Up @@ -80,12 +81,12 @@ impl Error {
where
M: Display + Debug + Send + Sync + 'static,
{
Error::from_adhoc(message, backtrace!())
Error::from_adhoc(message, backtrace!(), caller!())
}

#[cfg(feature = "std")]
#[cold]
pub(crate) fn from_std<E>(error: E, backtrace: Option<Backtrace>) -> Self
pub(crate) fn from_std<E>(error: E, backtrace: Option<Backtrace>, caller: Option<&'static Location<'static>>) -> Self
where
E: StdError + Send + Sync + 'static,
{
Expand All @@ -104,11 +105,11 @@ impl Error {
};

// Safety: passing vtable that operates on the right type E.
unsafe { Error::construct(error, vtable, backtrace) }
unsafe { Error::construct(error, vtable, backtrace, caller) }
}

#[cold]
pub(crate) fn from_adhoc<M>(message: M, backtrace: Option<Backtrace>) -> Self
pub(crate) fn from_adhoc<M>(message: M, backtrace: Option<Backtrace>, caller: Option<&'static Location<'static>>) -> Self
where
M: Display + Debug + Send + Sync + 'static,
{
Expand All @@ -130,11 +131,11 @@ impl Error {

// Safety: MessageError is repr(transparent) so it is okay for the
// vtable to allow casting the MessageError<M> to M.
unsafe { Error::construct(error, vtable, backtrace) }
unsafe { Error::construct(error, vtable, backtrace, caller) }
}

#[cold]
pub(crate) fn from_display<M>(message: M, backtrace: Option<Backtrace>) -> Self
pub(crate) fn from_display<M>(message: M, backtrace: Option<Backtrace>, caller: Option<&'static Location<'static>>) -> Self
where
M: Display + Send + Sync + 'static,
{
Expand All @@ -156,12 +157,12 @@ impl Error {

// Safety: DisplayError is repr(transparent) so it is okay for the
// vtable to allow casting the DisplayError<M> to M.
unsafe { Error::construct(error, vtable, backtrace) }
unsafe { Error::construct(error, vtable, backtrace, caller) }
}

#[cfg(feature = "std")]
#[cold]
pub(crate) fn from_context<C, E>(context: C, error: E, backtrace: Option<Backtrace>) -> Self
pub(crate) fn from_context<C, E>(context: C, error: E, backtrace: Option<Backtrace>, caller: Option<&'static Location<'static>>) -> Self
where
C: Display + Send + Sync + 'static,
E: StdError + Send + Sync + 'static,
Expand All @@ -183,14 +184,15 @@ impl Error {
};

// Safety: passing vtable that operates on the right type.
unsafe { Error::construct(error, vtable, backtrace) }
unsafe { Error::construct(error, vtable, backtrace, caller) }
}

#[cfg(feature = "std")]
#[cold]
pub(crate) fn from_boxed(
error: Box<dyn StdError + Send + Sync>,
backtrace: Option<Backtrace>,
caller: Option<&'static Location<'static>>
) -> Self {
use crate::wrapper::BoxedError;
let error = BoxedError(error);
Expand All @@ -210,7 +212,7 @@ impl Error {

// Safety: BoxedError is repr(transparent) so it is okay for the vtable
// to allow casting to Box<dyn StdError + Send + Sync>.
unsafe { Error::construct(error, vtable, backtrace) }
unsafe { Error::construct(error, vtable, backtrace, caller) }
}

// Takes backtrace as argument rather than capturing it here so that the
Expand All @@ -223,13 +225,15 @@ impl Error {
error: E,
vtable: &'static ErrorVTable,
backtrace: Option<Backtrace>,
caller: Option<&'static Location<'static>>,
) -> Self
where
E: StdError + Send + Sync + 'static,
{
let inner: Box<ErrorImpl<E>> = Box::new(ErrorImpl {
vtable,
backtrace,
caller,
_object: error,
});
// Erase the concrete type of E from the compile-time type system. This
Expand Down Expand Up @@ -298,6 +302,7 @@ impl Error {
/// ```
#[cold]
#[must_use]
#[cfg_attr(feature = "track_caller", track_caller)]
pub fn context<C>(self, context: C) -> Self
where
C: Display + Send + Sync + 'static,
Expand Down Expand Up @@ -325,7 +330,7 @@ impl Error {
let backtrace = None;

// Safety: passing vtable that operates on the right type.
unsafe { Error::construct(error, vtable, backtrace) }
unsafe { Error::construct(error, vtable, backtrace, caller!()) }
}

/// Get the backtrace for this Error.
Expand Down Expand Up @@ -545,7 +550,7 @@ where
#[cold]
fn from(error: E) -> Self {
let backtrace = backtrace_if_absent!(&error);
Error::from_std(error, backtrace)
Error::from_std(error, backtrace, caller!())
}
}

Expand Down Expand Up @@ -840,6 +845,7 @@ where
pub(crate) struct ErrorImpl<E = ()> {
vtable: &'static ErrorVTable,
backtrace: Option<Backtrace>,
caller: Option<&'static Location<'static>>,
// NOTE: Don't use directly. Use only through vtable. Erased type may have
// different alignment.
_object: E,
Expand Down Expand Up @@ -876,6 +882,10 @@ impl ErrorImpl {
(vtable(this.ptr).object_ref)(this).deref()
}

pub(crate) unsafe fn caller(this: Ref<Self>) -> Option<&Location<'static>> {
this.deref().caller
}

#[cfg(feature = "std")]
pub(crate) unsafe fn error_mut(this: Mut<Self>) -> &mut (dyn StdError + Send + Sync + 'static) {
// Use vtable to attach E's native StdError vtable for the right
Expand Down
3 changes: 3 additions & 0 deletions src/fmt.rs
Expand Up @@ -24,6 +24,9 @@ impl ErrorImpl {
}

write!(f, "{}", error)?;
if let Some(location) = Self::caller(this) {
writeln!(f, "\n at {}:{}", location.file(), location.line())?;
}

if let Some(cause) = error.source() {
write!(f, "\n\nCaused by:")?;
Expand Down
4 changes: 2 additions & 2 deletions src/kind.rs
Expand Up @@ -67,7 +67,7 @@ impl Adhoc {
where
M: Display + Debug + Send + Sync + 'static,
{
Error::from_adhoc(message, backtrace!())
Error::from_adhoc(message, backtrace!(), caller!())
}
}

Expand Down Expand Up @@ -111,6 +111,6 @@ impl Boxed {
#[cold]
pub fn new(self, error: Box<dyn StdError + Send + Sync>) -> Error {
let backtrace = backtrace_if_absent!(&*error);
Error::from_boxed(error, backtrace)
Error::from_boxed(error, backtrace, caller!())
}
}