From 671f700dd3decdfb56c8f8b6fdae6ced5acd5ca9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 22 Dec 2024 03:11:30 -0800 Subject: [PATCH 01/13] Add construct_ prefix to name of private construct functions --- src/context.rs | 6 +++--- src/error.rs | 20 ++++++++++++-------- src/kind.rs | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/context.rs b/src/context.rs index b52f682..326c2a4 100644 --- a/src/context.rs +++ b/src/context.rs @@ -25,7 +25,7 @@ mod ext { C: Display + Send + Sync + 'static, { let backtrace = backtrace_if_absent!(&self); - Error::from_context(context, self, backtrace) + Error::construct_from_context(context, self, backtrace) } } @@ -96,7 +96,7 @@ impl Context for Option { // backtrace. match self { Some(ok) => Ok(ok), - None => Err(Error::from_display(context, backtrace!())), + None => Err(Error::construct_from_display(context, backtrace!())), } } @@ -107,7 +107,7 @@ impl Context for Option { { match self { Some(ok) => Ok(ok), - None => Err(Error::from_display(context(), backtrace!())), + None => Err(Error::construct_from_display(context(), backtrace!())), } } } diff --git a/src/error.rs b/src/error.rs index a83eb7e..76369a9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -36,7 +36,7 @@ impl Error { E: StdError + Send + Sync + 'static, { let backtrace = backtrace_if_absent!(&error); - Error::from_std(error, backtrace) + Error::construct_from_std(error, backtrace) } /// Create a new error object from a printable error message. @@ -82,12 +82,12 @@ impl Error { where M: Display + Debug + Send + Sync + 'static, { - Error::from_adhoc(message, backtrace!()) + Error::construct_from_adhoc(message, backtrace!()) } #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] - pub(crate) fn from_std(error: E, backtrace: Option) -> Self + pub(crate) fn construct_from_std(error: E, backtrace: Option) -> Self where E: StdError + Send + Sync + 'static, { @@ -113,7 +113,7 @@ impl Error { } #[cold] - pub(crate) fn from_adhoc(message: M, backtrace: Option) -> Self + pub(crate) fn construct_from_adhoc(message: M, backtrace: Option) -> Self where M: Display + Debug + Send + Sync + 'static, { @@ -142,7 +142,7 @@ impl Error { } #[cold] - pub(crate) fn from_display(message: M, backtrace: Option) -> Self + pub(crate) fn construct_from_display(message: M, backtrace: Option) -> Self where M: Display + Send + Sync + 'static, { @@ -172,7 +172,11 @@ impl Error { #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] - pub(crate) fn from_context(context: C, error: E, backtrace: Option) -> Self + pub(crate) fn construct_from_context( + context: C, + error: E, + backtrace: Option, + ) -> Self where C: Display + Send + Sync + 'static, E: StdError + Send + Sync + 'static, @@ -202,7 +206,7 @@ impl Error { #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] - pub(crate) fn from_boxed( + pub(crate) fn construct_from_boxed( error: Box, backtrace: Option, ) -> Self { @@ -562,7 +566,7 @@ where #[cold] fn from(error: E) -> Self { let backtrace = backtrace_if_absent!(&error); - Error::from_std(error, backtrace) + Error::construct_from_std(error, backtrace) } } diff --git a/src/kind.rs b/src/kind.rs index 042af32..a9f40c3 100644 --- a/src/kind.rs +++ b/src/kind.rs @@ -70,7 +70,7 @@ impl Adhoc { where M: Display + Debug + Send + Sync + 'static, { - Error::from_adhoc(message, backtrace!()) + Error::construct_from_adhoc(message, backtrace!()) } } @@ -116,6 +116,6 @@ impl Boxed { #[cold] pub fn new(self, error: Box) -> Error { let backtrace = backtrace_if_absent!(&*error); - Error::from_boxed(error, backtrace) + Error::construct_from_boxed(error, backtrace) } } From 52e4abb1f2167c71c2f99d9a1048d9321baed963 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 22 Dec 2024 03:19:46 -0800 Subject: [PATCH 02/13] Add Error::from_boxed with documentation about bidirectional `?` --- src/error.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/error.rs b/src/error.rs index 76369a9..cd1f5f5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -85,6 +85,67 @@ impl Error { Error::construct_from_adhoc(message, backtrace!()) } + /// Construct an error object from a type-erased standard library error. + /// + /// This is mostly useful for interop with other error libraries. + /// + /// # Example + /// + /// Here is a skeleton of a library that provides its own error abstraction. + /// The pair of `From` impls provide bidirectional support for `?` + /// conversion between `Report` and `anyhow::Error`. + /// + /// ``` + /// use std::error::Error as StdError; + /// + /// pub struct Report {/* ... */} + /// + /// impl From for Report + /// where + /// E: Into, + /// Result<(), E>: anyhow::Context<(), E>, + /// { + /// fn from(error: E) -> Self { + /// let anyhow_error: anyhow::Error = error.into(); + /// let boxed_error: Box = anyhow_error.into(); + /// Report::from_boxed(boxed_error) + /// } + /// } + /// + /// impl From for anyhow::Error { + /// fn from(report: Report) -> Self { + /// let boxed_error: Box = report.into_boxed(); + /// anyhow::Error::from_boxed(boxed_error) + /// } + /// } + /// + /// impl Report { + /// fn from_boxed(boxed_error: Box) -> Self { + /// todo!() + /// } + /// fn into_boxed(self) -> Box { + /// todo!() + /// } + /// } + /// + /// // Example usage: can use `?` in both directions. + /// fn a() -> anyhow::Result<()> { + /// b()?; + /// Ok(()) + /// } + /// fn b() -> Result<(), Report> { + /// a()?; + /// Ok(()) + /// } + /// ``` + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[cold] + #[must_use] + pub fn from_boxed(boxed_error: Box) -> Self { + let backtrace = backtrace_if_absent!(&*boxed_error); + Error::construct_from_boxed(boxed_error, backtrace) + } + #[cfg(any(feature = "std", not(anyhow_no_core_error)))] #[cold] pub(crate) fn construct_from_std(error: E, backtrace: Option) -> Self From 48be1caa24fa65467aaa8071eb698542e4fa1d43 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 22 Dec 2024 03:26:36 -0800 Subject: [PATCH 03/13] Release 1.0.95 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4b2c7ca..0a4eb72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "anyhow" -version = "1.0.94" +version = "1.0.95" authors = ["David Tolnay "] categories = ["rust-patterns", "no-std"] description = "Flexible concrete Error type built on std::error::Error" diff --git a/src/lib.rs b/src/lib.rs index d3d0767..947ed20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,7 +206,7 @@ //! function that returns Anyhow's error type, as the trait that `?`-based error //! conversions are defined by is only available in std in those old versions. -#![doc(html_root_url = "https://docs.rs/anyhow/1.0.94")] +#![doc(html_root_url = "https://docs.rs/anyhow/1.0.95")] #![cfg_attr(error_generic_member_access, feature(error_generic_member_access))] #![no_std] #![deny(dead_code, unused_imports, unused_mut)] From 9c0fb8b56cd19dfed91d05072c75fa7e0ec1a947 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 26 Dec 2024 18:29:05 -0800 Subject: [PATCH 04/13] Ignore literal_string_with_formatting_args clippy lint in test warning: this looks like a formatting argument but it is not part of a formatting macro --> tests/test_ensure.rs:505:44 | 505 | "Condition failed: `\"\" == format!(\"{:#?}\", point)`", | ^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#literal_string_with_formatting_args = note: `-W clippy::literal-string-with-formatting-args` implied by `-W clippy::all` = help: to override `-W clippy::all` add `#[allow(clippy::literal_string_with_formatting_args)]` --- tests/test_ensure.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_ensure.rs b/tests/test_ensure.rs index b43490a..100b378 100644 --- a/tests/test_ensure.rs +++ b/tests/test_ensure.rs @@ -11,6 +11,7 @@ clippy::items_after_statements, clippy::let_and_return, clippy::let_underscore_untyped, + clippy::literal_string_with_formatting_args, clippy::match_bool, clippy::needless_else, clippy::never_loop, From af0937ef72fbaf9784a6c991e029738728d025e2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 1 Jan 2025 18:20:00 -0800 Subject: [PATCH 05/13] Update ui test suite to nightly-2025-01-02 --- tests/ui/ensure-nonbool.stderr | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/ui/ensure-nonbool.stderr b/tests/ui/ensure-nonbool.stderr index 3fdb8e6..1fff52d 100644 --- a/tests/ui/ensure-nonbool.stderr +++ b/tests/ui/ensure-nonbool.stderr @@ -25,15 +25,16 @@ error[E0277]: the trait bound `&mut bool: __private::not::Bool` is not satisfied | | the trait `__private::not::Bool` is not implemented for `&mut bool` | required by a bound introduced by this call | - = help: the following other types implement trait `__private::not::Bool`: - &bool - bool = note: `__private::not::Bool` is implemented for `&bool`, but not for `&mut bool` note: required by a bound in `anyhow::__private::not` --> src/lib.rs | | pub fn not(cond: impl Bool) -> bool { | ^^^^ required by this bound in `not` +help: consider dereferencing here + | +29 | Bool(cond) => ensure!(*cond), + | + error[E0277]: the trait bound `DerefBool: __private::not::Bool` is not satisfied --> tests/ui/ensure-nonbool.rs:33:13 @@ -44,14 +45,15 @@ error[E0277]: the trait bound `DerefBool: __private::not::Bool` is not satisfied | | the trait `__private::not::Bool` is not implemented for `DerefBool` | required by a bound introduced by this call | - = help: the following other types implement trait `__private::not::Bool`: - &bool - bool note: required by a bound in `anyhow::__private::not` --> src/lib.rs | | pub fn not(cond: impl Bool) -> bool { | ^^^^ required by this bound in `not` +help: consider dereferencing here + | +33 | ensure!(*db); + | + error[E0277]: the trait bound `&DerefBool: __private::not::Bool` is not satisfied --> tests/ui/ensure-nonbool.rs:34:13 From 4d71a84097b67307dff20f489621b015388cccc6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 10 Jan 2025 19:35:08 -0800 Subject: [PATCH 06/13] Ignore double_ended_iterator_last clippy lint warning: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator --> src/error.rs:482:22 | 482 | self.chain().last().unwrap() | ^^^^^^ help: try: `next_back()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last = note: `-W clippy::double-ended-iterator-last` implied by `-W clippy::all` = help: to override `-W clippy::all` add `#[allow(clippy::double_ended_iterator_last)]` --- src/error.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/error.rs b/src/error.rs index cd1f5f5..4c4504b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -478,6 +478,7 @@ impl Error { /// The root cause is the last error in the iterator produced by /// [`chain()`][Error::chain]. #[cfg(any(feature = "std", not(anyhow_no_core_error)))] + #[allow(clippy::double_ended_iterator_last)] pub fn root_cause(&self) -> &(dyn StdError + 'static) { self.chain().last().unwrap() } From 51a173ee6894f01a1cb720406b42e6bc799260bf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 15 Jan 2025 18:35:52 -0800 Subject: [PATCH 07/13] Ignore missing_abi lint in nightly-2025-01-16 warning: extern declarations without an explicit ABI are deprecated --> tests/test_ensure.rs:617:43 | 617 | let test = || Ok(ensure!(extern_fn as extern fn() as usize * 0 != 0)); | ^^^^^^ help: explicitly specify the C ABI: `extern "C"` | = note: `#[warn(missing_abi)]` on by default --- tests/test_ensure.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_ensure.rs b/tests/test_ensure.rs index 100b378..5fe5278 100644 --- a/tests/test_ensure.rs +++ b/tests/test_ensure.rs @@ -614,6 +614,7 @@ fn test_as() { extern "C" fn extern_fn() {} #[rustfmt::skip] + #[allow(missing_abi)] let test = || Ok(ensure!(extern_fn as extern fn() as usize * 0 != 0)); assert_err( test, From b880dd050e98417ad2b47472b71e47c788126faf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 22 Jan 2025 19:15:08 -0800 Subject: [PATCH 08/13] Ignore Cargo-generated tests/crate/target directory --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6936990..98e5fcf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -/target +target **/*.rs.bk Cargo.lock From 3e409755ce450b19ba42f620f0db0d102e41bb92 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 22 Jan 2025 19:29:51 -0800 Subject: [PATCH 09/13] Remove **/*.rs.bk from project-specific gitignore Cargo stopped generating this in its project template 5 years ago. It would belong in a global gitignore instead. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 98e5fcf..a9d37c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ target -**/*.rs.bk Cargo.lock From d71c806e972e27004121337813fe54beefc661ba Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 22 Jan 2025 20:18:05 -0800 Subject: [PATCH 10/13] More precise gitignore patterns --- .gitignore | 4 ++-- tests/crate/.gitignore | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 tests/crate/.gitignore diff --git a/.gitignore b/.gitignore index a9d37c5..e9e2199 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -target -Cargo.lock +/target/ +/Cargo.lock diff --git a/tests/crate/.gitignore b/tests/crate/.gitignore new file mode 100644 index 0000000..e9e2199 --- /dev/null +++ b/tests/crate/.gitignore @@ -0,0 +1,2 @@ +/target/ +/Cargo.lock From 1cff785c761491ea42f41e8981d81042945e5952 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 9 Feb 2025 17:52:30 -0800 Subject: [PATCH 11/13] Unset doc-scrape-examples for lib target False is the default value since Cargo PR 11499. --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0a4eb72..e74a81c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,9 +29,6 @@ syn = { version = "2.0", features = ["full"] } thiserror = "2" trybuild = { version = "1.0.66", features = ["diff"] } -[lib] -doc-scrape-examples = false - [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = ["--generate-link-to-definition"] From bc33c24bd29029e2e609c94f59b67dec489bb325 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Feb 2025 18:49:20 -0800 Subject: [PATCH 12/13] Convert html links to intra-doc links --- src/error.rs | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index 4c4504b..098b328 100644 --- a/src/error.rs +++ b/src/error.rs @@ -490,7 +490,7 @@ impl Error { /// context has been attached. For details about the interaction between /// context and downcasting, [see here]. /// - /// [see here]: trait.Context.html#effect-on-downcasting + /// [see here]: crate::Context#effect-on-downcasting pub fn is(&self) -> bool where E: Display + Debug + Send + Sync + 'static, diff --git a/src/lib.rs b/src/lib.rs index 947ed20..70fbf3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,7 +139,7 @@ //! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and //! `RUST_LIB_BACKTRACE=0`. //! -//! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables +//! [`std::backtrace`]: std::backtrace#environment-variables //! //! - 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)` From f0aa0d367f7545827d4034c9fe4394b9ce9069c3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Feb 2025 18:50:08 -0800 Subject: [PATCH 13/13] Release 1.0.96 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e74a81c..9a96fe4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "anyhow" -version = "1.0.95" +version = "1.0.96" authors = ["David Tolnay "] categories = ["rust-patterns", "no-std"] description = "Flexible concrete Error type built on std::error::Error" diff --git a/src/lib.rs b/src/lib.rs index 70fbf3a..8cbb25a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,7 +206,7 @@ //! function that returns Anyhow's error type, as the trait that `?`-based error //! conversions are defined by is only available in std in those old versions. -#![doc(html_root_url = "https://docs.rs/anyhow/1.0.95")] +#![doc(html_root_url = "https://docs.rs/anyhow/1.0.96")] #![cfg_attr(error_generic_member_access, feature(error_generic_member_access))] #![no_std] #![deny(dead_code, unused_imports, unused_mut)]