From bee814ab1bb09332bb97cfeb943e229df5d0c35b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 6 Sep 2024 11:54:23 -0700 Subject: [PATCH] Support error sources in no-std on Rust 1.81+ --- .github/workflows/ci.yml | 2 +- build.rs | 7 ++++++ src/backtrace.rs | 8 +++++-- src/chain.rs | 16 ++++++------- src/context.rs | 4 ++-- src/error.rs | 51 +++++++++++++++++----------------------- src/kind.rs | 12 +++++----- src/lib.rs | 12 ++++++---- src/wrapper.rs | 10 ++++---- 9 files changed, 64 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a84d20..9e8a9ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [nightly, beta, stable, 1.70.0] + rust: [nightly, beta, stable, 1.80.0, 1.70.0] timeout-minutes: 45 steps: - uses: actions/checkout@v4 diff --git a/build.rs b/build.rs index 1c083cf..a065e04 100644 --- a/build.rs +++ b/build.rs @@ -67,6 +67,7 @@ fn main() { if rustc >= 80 { println!("cargo:rustc-check-cfg=cfg(anyhow_nightly_testing)"); + println!("cargo:rustc-check-cfg=cfg(anyhow_no_core_error)"); println!("cargo:rustc-check-cfg=cfg(anyhow_no_fmt_arguments_as_str)"); println!("cargo:rustc-check-cfg=cfg(anyhow_no_ptr_addr_of)"); println!("cargo:rustc-check-cfg=cfg(anyhow_no_unsafe_op_in_unsafe_fn_lint)"); @@ -95,6 +96,12 @@ fn main() { // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#stabilized-apis println!("cargo:rustc-cfg=std_backtrace"); } + + if rustc < 81 { + // core::error::Error + // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror + println!("cargo:rustc-cfg=anyhow_no_core_error"); + } } fn compile_probe(rustc_bootstrap: bool) -> bool { diff --git a/src/backtrace.rs b/src/backtrace.rs index fc5c072..c9ca1a8 100644 --- a/src/backtrace.rs +++ b/src/backtrace.rs @@ -47,7 +47,7 @@ macro_rules! backtrace_if_absent { } #[cfg(all( - feature = "std", + any(feature = "std", not(anyhow_no_core_error)), not(error_generic_member_access), any(std_backtrace, feature = "backtrace") ))] @@ -57,7 +57,11 @@ macro_rules! backtrace_if_absent { }; } -#[cfg(all(feature = "std", not(std_backtrace), not(feature = "backtrace")))] +#[cfg(all( + any(feature = "std", not(anyhow_no_core_error)), + not(std_backtrace), + not(feature = "backtrace"), +))] macro_rules! backtrace_if_absent { ($err:expr) => { None diff --git a/src/chain.rs b/src/chain.rs index b75885d..e56bc66 100644 --- a/src/chain.rs +++ b/src/chain.rs @@ -1,13 +1,13 @@ use self::ChainState::*; use crate::StdError; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] use alloc::vec::{self, Vec}; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] pub(crate) use crate::Chain; -#[cfg(not(feature = "std"))] +#[cfg(all(not(feature = "std"), anyhow_no_core_error))] pub(crate) struct Chain<'a> { state: ChainState<'a>, } @@ -17,7 +17,7 @@ pub(crate) enum ChainState<'a> { Linked { next: Option<&'a (dyn StdError + 'static)>, }, - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] Buffered { rest: vec::IntoIter<&'a (dyn StdError + 'static)>, }, @@ -42,7 +42,7 @@ impl<'a> Iterator for Chain<'a> { *next = error.source(); Some(error) } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] Buffered { rest } => rest.next(), } } @@ -53,7 +53,7 @@ impl<'a> Iterator for Chain<'a> { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl DoubleEndedIterator for Chain<'_> { fn next_back(&mut self) -> Option { match &mut self.state { @@ -84,13 +84,13 @@ impl ExactSizeIterator for Chain<'_> { } len } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] Buffered { rest } => rest.len(), } } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl Default for Chain<'_> { fn default() -> Self { Chain { diff --git a/src/context.rs b/src/context.rs index d8c6273..b52f682 100644 --- a/src/context.rs +++ b/src/context.rs @@ -15,10 +15,10 @@ mod ext { C: Display + Send + Sync + 'static; } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl StdError for E where - E: std::error::Error + Send + Sync + 'static, + E: crate::StdError + Send + Sync + 'static, { fn ext_context(self, context: C) -> Error where diff --git a/src/error.rs b/src/error.rs index 16ad92d..6d8b54d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ use crate::backtrace::Backtrace; use crate::chain::Chain; -#[cfg(any(feature = "std", anyhow_no_ptr_addr_of))] +#[cfg(any(feature = "std", not(anyhow_no_core_error), anyhow_no_ptr_addr_of))] use crate::ptr::Mut; use crate::ptr::{Own, Ref}; use crate::{Error, StdError}; @@ -10,13 +10,12 @@ use core::any::TypeId; use core::error::{self, Request}; use core::fmt::{self, Debug, Display}; use core::mem::ManuallyDrop; +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] +use core::ops::{Deref, DerefMut}; #[cfg(not(anyhow_no_ptr_addr_of))] use core::ptr; use core::ptr::NonNull; -#[cfg(feature = "std")] -use core::ops::{Deref, DerefMut}; - impl Error { /// Create a new error object from any error type. /// @@ -25,8 +24,7 @@ impl Error { /// /// If the error type does not provide a backtrace, a backtrace will be /// created here to ensure that a backtrace exists. - #[cfg(feature = "std")] - #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] #[must_use] pub fn new(error: E) -> Self @@ -83,7 +81,7 @@ impl Error { Error::from_adhoc(message, backtrace!()) } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] pub(crate) fn from_std(error: E, backtrace: Option) -> Self where @@ -120,7 +118,7 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, - #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] + #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: object_downcast::, @@ -149,7 +147,7 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, - #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] + #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: object_downcast::, @@ -168,7 +166,7 @@ impl Error { unsafe { Error::construct(error, vtable, backtrace) } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] pub(crate) fn from_context(context: C, error: E, backtrace: Option) -> Self where @@ -198,7 +196,7 @@ impl Error { unsafe { Error::construct(error, vtable, backtrace) } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] pub(crate) fn from_boxed( error: Box, @@ -325,7 +323,7 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, - #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] + #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: context_chain_downcast::, @@ -399,8 +397,7 @@ impl Error { /// None /// } /// ``` - #[cfg(feature = "std")] - #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] pub fn chain(&self) -> Chain { unsafe { ErrorImpl::chain(self.inner.by_ref()) } @@ -411,8 +408,7 @@ impl Error { /// /// The root cause is the last error in the iterator produced by /// [`chain()`][Error::chain]. - #[cfg(feature = "std")] - #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] pub fn root_cause(&self) -> &(dyn StdError + 'static) { self.chain().last().unwrap() } @@ -554,8 +550,7 @@ impl Error { } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl From for Error where E: StdError + Send + Sync + 'static, @@ -567,8 +562,7 @@ where } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl Deref for Error { type Target = dyn StdError + Send + Sync + 'static; @@ -577,8 +571,7 @@ impl Deref for Error { } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl DerefMut for Error { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { ErrorImpl::error_mut(self.inner.by_mut()) } @@ -609,7 +602,7 @@ impl Drop for Error { struct ErrorVTable { object_drop: unsafe fn(Own), object_ref: unsafe fn(Ref) -> Ref, - #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] + #[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] object_mut: unsafe fn(Mut) -> &mut (dyn StdError + Send + Sync + 'static), object_boxed: unsafe fn(Own) -> Box, object_downcast: unsafe fn(Ref, TypeId) -> Option>, @@ -661,7 +654,7 @@ where // Safety: requires layout of *e to match ErrorImpl, and for `e` to be derived // from a `&mut` -#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] +#[cfg(all(any(feature = "std", not(anyhow_no_core_error)), anyhow_no_ptr_addr_of))] unsafe fn object_mut(e: Mut) -> &mut (dyn StdError + Send + Sync + 'static) where E: StdError + Send + Sync + 'static, @@ -734,7 +727,7 @@ fn no_backtrace(e: Ref) -> Option<&Backtrace> { } // Safety: requires layout of *e to match ErrorImpl>. -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] unsafe fn context_downcast(e: Ref, target: TypeId) -> Option> where C: 'static, @@ -774,7 +767,7 @@ where } // Safety: requires layout of *e to match ErrorImpl>. -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] unsafe fn context_drop_rest(e: Own, target: TypeId) where C: 'static, @@ -906,7 +899,7 @@ impl ErrorImpl { unsafe { (vtable(this.ptr).object_ref)(this).deref() } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] pub(crate) unsafe fn error_mut(this: Mut) -> &mut (dyn StdError + Send + Sync + 'static) { // Use vtable to attach E's native StdError vtable for the right // original type E. @@ -1009,14 +1002,14 @@ impl From for Box { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl AsRef for Error { fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) { &**self } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl AsRef for Error { fn as_ref(&self) -> &(dyn StdError + 'static) { &**self diff --git a/src/kind.rs b/src/kind.rs index 15d9f9b..042af32 100644 --- a/src/kind.rs +++ b/src/kind.rs @@ -47,9 +47,9 @@ use crate::Error; use core::fmt::{Debug, Display}; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] use crate::StdError; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] use alloc::boxed::Box; pub struct Adhoc; @@ -96,10 +96,10 @@ impl Trait { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] pub struct Boxed; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[doc(hidden)] pub trait BoxedKind: Sized { #[inline] @@ -108,10 +108,10 @@ pub trait BoxedKind: Sized { } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl BoxedKind for Box {} -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl Boxed { #[cold] pub fn new(self, error: Box) -> Error { diff --git a/src/lib.rs b/src/lib.rs index a471e22..d10430e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -266,13 +266,16 @@ use crate::error::ErrorImpl; use crate::ptr::Own; use core::fmt::Display; -#[cfg(not(feature = "std"))] +#[cfg(all(not(feature = "std"), anyhow_no_core_error))] use core::fmt::Debug; #[cfg(feature = "std")] use std::error::Error as StdError; -#[cfg(not(feature = "std"))] +#[cfg(not(any(feature = "std", anyhow_no_core_error)))] +use core::error::Error as StdError; + +#[cfg(all(not(feature = "std"), anyhow_no_core_error))] trait StdError: Debug + Display { fn source(&self) -> Option<&(dyn StdError + 'static)> { None @@ -407,8 +410,7 @@ pub struct Error { /// None /// } /// ``` -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[derive(Clone)] pub struct Chain<'a> { state: crate::chain::ChainState<'a>, @@ -670,7 +672,7 @@ pub mod __private { #[doc(hidden)] pub use crate::kind::{AdhocKind, TraitKind}; - #[cfg(feature = "std")] + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[doc(hidden)] pub use crate::kind::BoxedKind; } diff --git a/src/wrapper.rs b/src/wrapper.rs index 6639c50..6f46779 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -1,7 +1,7 @@ use crate::StdError; use core::fmt::{self, Debug, Display}; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] use alloc::boxed::Box; #[cfg(error_generic_member_access)] @@ -53,25 +53,25 @@ where impl StdError for DisplayError where M: Display + 'static {} -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[repr(transparent)] pub struct BoxedError(pub Box); -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl Debug for BoxedError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Debug::fmt(&self.0, f) } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl Display for BoxedError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Display::fmt(&self.0, f) } } -#[cfg(feature = "std")] +#[cfg(any(feature = "std", not(anyhow_no_core_error)))] impl StdError for BoxedError { fn source(&self) -> Option<&(dyn StdError + 'static)> { self.0.source()