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

Enable backtrace support for >= 1.65 stable compilers #293

Merged
merged 1 commit into from
Dec 26, 2023
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
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,18 @@ anyhow = "1.0"
}
```

- If using the nightly channel, or stable with `features = ["backtrace"]`, a
backtrace is captured and printed with the error if the underlying error type
does not already provide its own. In order to see backtraces, they must be
enabled through the environment variables described in [`std::backtrace`]:
- If using Rust ≥ 1.65 or `features = ["backtrace"]`, a backtrace is captured
and printed with the error if the underlying error type does not already
provide its own. In order to see backtraces, they must be enabled through the
environment variables described in [`std::backtrace`]:

- If you want panics and errors to both have backtraces, set
`RUST_BACKTRACE=1`;
- If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`;
- If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
`RUST_LIB_BACKTRACE=0`.

The tracking issue for this feature is [rust-lang/rust#53487].

[`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
[rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487

- Anyhow works with any error type that has an impl of `std::error::Error`,
including ones defined in your crate. We do not bundle a `derive(Error)` macro
Expand Down
15 changes: 14 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,18 @@ const PROBE: &str = r#"
"#;

fn main() {
// If the compile probe succeeds, i.e. if a nightly compiler is used and the
// provide API exists, then `std::backtrace` is also usable. So `cfg
// (provide_api)` implies `cfg(backtrace)`. We do set `cfg(backtrace)` in
// this script explicitly anyway to make the `cfg()` attributes in the main
// code less complex.
let mut nightly_backtrace_support = false;
if cfg!(feature = "std") {
match compile_probe() {
Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
Some(status) if status.success() => {
println!("cargo:rustc-cfg=provide_api");
nightly_backtrace_support = true;
}
_ => {}
}
}
Expand All @@ -76,6 +85,10 @@ fn main() {
if rustc < 52 {
println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str");
}

if nightly_backtrace_support || (cfg!(feature = "std") && rustc >= 65) {
println!("cargo:rustc-cfg=backtrace");
}
}

fn compile_probe() -> Option<ExitStatus> {
Expand Down
4 changes: 2 additions & 2 deletions src/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ macro_rules! backtrace {
};
}

#[cfg(backtrace)]
#[cfg(provide_api)]
macro_rules! backtrace_if_absent {
($err:expr) => {
match ($err as &dyn std::error::Error).request_ref::<std::backtrace::Backtrace>() {
Expand All @@ -45,7 +45,7 @@ macro_rules! backtrace_if_absent {
};
}

#[cfg(all(feature = "std", not(backtrace), feature = "backtrace"))]
#[cfg(all(feature = "std", not(provide_api), any(backtrace, feature = "backtrace")))]
macro_rules! backtrace_if_absent {
($err:expr) => {
backtrace!()
Expand Down
6 changes: 3 additions & 3 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{Context, Error, StdError};
use core::convert::Infallible;
use core::fmt::{self, Debug, Display, Write};

#[cfg(backtrace)]
#[cfg(provide_api)]
use std::any::{Demand, Provider};

mod ext {
Expand Down Expand Up @@ -143,7 +143,7 @@ where
Some(&self.error)
}

#[cfg(backtrace)]
#[cfg(provide_api)]
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
StdError::provide(&self.error, demand);
}
Expand All @@ -157,7 +157,7 @@ where
Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) })
}

#[cfg(backtrace)]
#[cfg(provide_api)]
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
Provider::provide(&self.error, demand);
}
Expand Down
36 changes: 17 additions & 19 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::ptr::Mut;
use crate::ptr::{Own, Ref};
use crate::{Error, StdError};
use alloc::boxed::Box;
#[cfg(backtrace)]
#[cfg(provide_api)]
use core::any::Demand;
use core::any::TypeId;
use core::fmt::{self, Debug, Display};
Expand Down Expand Up @@ -99,7 +99,7 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<E>,
object_drop_rest: object_drop_front::<E>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
object_backtrace: no_backtrace,
};

Expand All @@ -124,7 +124,7 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<M>,
object_drop_rest: object_drop_front::<M>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
object_backtrace: no_backtrace,
};

Expand All @@ -150,7 +150,7 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<M>,
object_drop_rest: object_drop_front::<M>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
object_backtrace: no_backtrace,
};

Expand Down Expand Up @@ -178,7 +178,7 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: context_downcast_mut::<C, E>,
object_drop_rest: context_drop_rest::<C, E>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
object_backtrace: no_backtrace,
};

Expand All @@ -204,7 +204,7 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: object_downcast_mut::<Box<dyn StdError + Send + Sync>>,
object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
object_backtrace: no_backtrace,
};

Expand Down Expand Up @@ -317,7 +317,7 @@ impl Error {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: context_chain_downcast_mut::<C>,
object_drop_rest: context_chain_drop_rest::<C>,
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
object_backtrace: context_backtrace::<C>,
};

Expand Down Expand Up @@ -345,10 +345,8 @@ impl Error {
///
/// # Stability
///
/// Standard library backtraces are only available on the nightly channel.
/// Tracking issue: [rust-lang/rust#53487][tracking].
///
/// On stable compilers, this function is only available if the crate's
/// Standard library backtraces are only available when using Rust ≥ 1.65.
/// On older compilers, this function is only available if the crate's
/// "backtrace" feature is enabled, and will use the `backtrace` crate as
/// the underlying backtrace implementation.
///
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few lines down there is:

#[cfg_attr(doc_cfg, doc(cfg(any(nightly, feature = "backtrace"))))]

I don't know how to replace that :/
any(>=1.65, feature = "backtrace") surely won't work.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose an alternative would be bumping the MSRV? (And maybe bumping the Rust edition as well)

Expand Down Expand Up @@ -524,7 +522,7 @@ impl Error {
}
}

#[cfg(backtrace)]
#[cfg(provide_api)]
impl std::any::Provider for Error {
// Called by thiserror when you have `#[source] anyhow::Error`. This provide
// implementation includes the anyhow::Error's Backtrace if any, unlike
Expand Down Expand Up @@ -598,7 +596,7 @@ struct ErrorVTable {
#[cfg(anyhow_no_ptr_addr_of)]
object_downcast_mut: unsafe fn(Mut<ErrorImpl>, TypeId) -> Option<Mut<()>>,
object_drop_rest: unsafe fn(Own<ErrorImpl>, TypeId),
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
object_backtrace: unsafe fn(Ref<ErrorImpl>) -> Option<&Backtrace>,
}

Expand Down Expand Up @@ -700,7 +698,7 @@ where
}
}

#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
fn no_backtrace(e: Ref<ErrorImpl>) -> Option<&Backtrace> {
let _ = e;
None
Expand Down Expand Up @@ -822,7 +820,7 @@ where
}

// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
#[cfg(all(not(backtrace), feature = "backtrace"))]
#[cfg(all(not(provide_api), any(backtrace, feature = "backtrace")))]
#[allow(clippy::unnecessary_wraps)]
unsafe fn context_backtrace<C>(e: Ref<ErrorImpl>) -> Option<&Backtrace>
where
Expand Down Expand Up @@ -899,15 +897,15 @@ impl ErrorImpl {
.backtrace
.as_ref()
.or_else(|| {
#[cfg(backtrace)]
#[cfg(provide_api)]
return Self::error(this).request_ref::<Backtrace>();
#[cfg(not(backtrace))]
#[cfg(not(provide_api))]
return (vtable(this.ptr).object_backtrace)(this);
})
.expect("backtrace capture failed")
}

#[cfg(backtrace)]
#[cfg(provide_api)]
unsafe fn provide<'a>(this: Ref<'a, Self>, demand: &mut Demand<'a>) {
if let Some(backtrace) = &this.deref().backtrace {
demand.provide_ref(backtrace);
Expand All @@ -929,7 +927,7 @@ where
unsafe { ErrorImpl::error(self.erase()).source() }
}

#[cfg(backtrace)]
#[cfg(provide_api)]
fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
unsafe { ErrorImpl::provide(self.erase(), demand) }
}
Expand Down
14 changes: 5 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,22 +128,18 @@
//! # ;
//! ```
//!
//! - If using the nightly channel, or stable with `features = ["backtrace"]`, a
//! backtrace is captured and printed with the error if the underlying error
//! type does not already provide its own. In order to see backtraces, they
//! must be enabled through the environment variables described in
//! [`std::backtrace`]:
//! - If using Rust ≥ 1.65 or `features = ["backtrace"]`, a backtrace is captured
//! and printed with the error if the underlying error type does not already
//! provide its own. In order to see backtraces, they must be enabled through the
//! environment variables described in [`std::backtrace`]:
//!
//! - If you want panics and errors to both have backtraces, set
//! `RUST_BACKTRACE=1`;
//! - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`;
//! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
//! `RUST_LIB_BACKTRACE=0`.
//!
//! The tracking issue for this feature is [rust-lang/rust#53487].
//!
//! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
//! [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487
//!
//! - Anyhow works with any error type that has an impl of `std::error::Error`,
//! including ones defined in your crate. We do not bundle a `derive(Error)`
Expand Down Expand Up @@ -211,7 +207,7 @@
//! non-Anyhow error type inside a function that returns Anyhow's error type.

#![doc(html_root_url = "https://docs.rs/anyhow/1.0.68")]
#![cfg_attr(backtrace, feature(error_generic_member_access, provide_any))]
#![cfg_attr(provide_api, 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
4 changes: 2 additions & 2 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::StdError;
use core::fmt::{self, Debug, Display};

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

#[repr(transparent)]
Expand Down Expand Up @@ -74,7 +74,7 @@ impl StdError for BoxedError {
self.0.source()
}

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