зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1716518 - Upgrade anyhow to v1.0.41. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D117755
This commit is contained in:
Родитель
9b25e1d86e
Коммит
2c1e53b8e4
|
@ -35,9 +35,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.30"
|
version = "1.0.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2494382e9ba43995f3c56359e518641f450f5c36feeb4632a75cde2ec297c867"
|
checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "app_services_logger"
|
name = "app_services_logger"
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"files":{"Cargo.toml":"76e6e0a729a4038b0d8bcdd36a054e96f3e93dc1922813f512d28cdf8d21e516","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"0d9c5facc3db17123752af8c3dbcdb9bb3785c8ed046b27de26669e4e87f131c","build.rs":"d8b58acc2cd88d627763135b3b25b46f276e2672ef740efb7fb5b1404fb230d8","src/backtrace.rs":"a82a8ffae2c68ee385dc78d8ec8cb6f3351234f0ad6af7e87df2371593e0f6aa","src/chain.rs":"1627608ce95c3484d26e1742a1b8b533b74c6159916b717bacffae3ae53731f9","src/context.rs":"f2be36af9588c924ed087bcb7bd681d330889e54b8f98cdc2aba93512a28762e","src/error.rs":"2c6a51880c7379265f7f7b6557e7bed808ff0f3267337a0c77dbbc1d2c4662e7","src/fmt.rs":"079d7b4faaa23f42423e0bb6b4e8a80d7d6d45c38c0d46bebd7d647c8679469f","src/kind.rs":"8481a8b7835eebb3859a8c32c217bf9c73543cfc62e3916b98d39af8b063125c","src/lib.rs":"119a39d1062a4b99a9f888a9f595a48fabacba6c8f2c3c59361ce2065d938ef6","src/macros.rs":"77722190b58a6106b21aefd3b5d4f136a076afcdbc0fae21562d99e2c22912e1","src/wrapper.rs":"1229beca67dbd95ca77c9ecce282272acc55276c267c58cb73a75388b4693dda","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"0a52a44786aea1c299c695bf948b2ed2081e4cc344e5c2cadceab4eb03d0010d","tests/drop/mod.rs":"464bc1ddeae307eac906928286ec3edb77057c5c1302e02150d3649e2b861f1a","tests/test_autotrait.rs":"981e792db353be2f14c7a1cabe43b5f1329c168cb7679077cc2be786a0920d48","tests/test_backtrace.rs":"0e50edbb33b6bd07ba89ff3db72fb7c688ba2a4371fccdbbb20309ab02948b6a","tests/test_boxed.rs":"98a45325b1e86d4c5d3094ab99cd1ada1f771c505d2d7322f0afcbe7bdb71cfa","tests/test_chain.rs":"f28efeae7395d1c395e6f1a647b4199c25a00410ade45248c145c6fcf2fb448a","tests/test_context.rs":"f82c915b182df1a604a4cd558a03b1a821414983d6f6af6822398104cea70676","tests/test_convert.rs":"62840be1ee8022ba5e8c0d3fc1752a1526b2c47d4cceecff2b86790524c3b3ea","tests/test_downcast.rs":"253d6f54e554965023b378b037827ec6289c4779a7a7c12706e19c2731d219fe","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"c7d3d5e0b756f59d4858035025fb341d031369c88486fd9f961ee16bae6c78bf","tests/test_repr.rs":"dbb9b04ddbe1ab31eb5331ea69f05bb3a147299da2275a3d4dcc92947b5591b9","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"7c2c3f46c266a437300591f10be330f937ac6a0a2213ed5030a9fbc895e2d100"},"package":"2494382e9ba43995f3c56359e518641f450f5c36feeb4632a75cde2ec297c867"}
|
{"files":{"Cargo.toml":"05c1bbd8a9f36fba15398f0dc3634198aca3c3f6887b085b9812d21f4f33c450","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"4a58a26808c92aae6265a60e21745bb2891a60cf1d69985fc05d26b77c2b9a79","build.rs":"afa03584629443ec723ca4e99bd087d5f07602d8640772f6f57c8e3847f75ae6","src/backtrace.rs":"a1a52f9874f0aa1382fb404f029c6fa88e53afe38fb2417877d5711f1f2b90c9","src/chain.rs":"1627608ce95c3484d26e1742a1b8b533b74c6159916b717bacffae3ae53731f9","src/context.rs":"559478ae785ce913523aa21358cc1561ef4b0b95c5c87675a77890364c0162fe","src/error.rs":"2aa93ec95f16980037c244e94fa8ac75f8b20ac22530fe45a24550d1878eb0b5","src/fmt.rs":"c2d4aad6ce20625a70a7c091e3087b6a2c19a4a87c7a12edb4c98978307245ea","src/kind.rs":"ccf5d8075d44b03cc69c0478ee5e5b3a02d4f2e7cecb37588b30043d3fcdf65f","src/lib.rs":"c0a0f94d85f5cc4aed37048ca12d8652da85b50f0999d998903ccd3ebf043eec","src/macros.rs":"88daf58370b2fcc93c43ebd5b9c1659bf5460c972681b63d89d51132126e5560","src/ptr.rs":"f1ece995b5be064773ee3d516710b4948b0bee3c237786d9988c7d2acc52c95c","src/wrapper.rs":"1229beca67dbd95ca77c9ecce282272acc55276c267c58cb73a75388b4693dda","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"382956f4bd3dcd1f6036efb8f11193595a7c60e0a5dbf5f2da149f1f25183abf","tests/test_autotrait.rs":"981e792db353be2f14c7a1cabe43b5f1329c168cb7679077cc2be786a0920d48","tests/test_backtrace.rs":"0e50edbb33b6bd07ba89ff3db72fb7c688ba2a4371fccdbbb20309ab02948b6a","tests/test_boxed.rs":"98a45325b1e86d4c5d3094ab99cd1ada1f771c505d2d7322f0afcbe7bdb71cfa","tests/test_chain.rs":"f28efeae7395d1c395e6f1a647b4199c25a00410ade45248c145c6fcf2fb448a","tests/test_context.rs":"f82c915b182df1a604a4cd558a03b1a821414983d6f6af6822398104cea70676","tests/test_convert.rs":"cae1c941727f2371b2439ff95b2628f810cfb2f77431a0807de32db84c5844e1","tests/test_downcast.rs":"e9dc236dad1cbb8b7ad74a0d87d328f23a585fbb55670b8fe55a9a2644041c5c","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"17572596f257aac9aa2ec4620e292ca6a954128b94772bb948399fab53832e70","tests/test_macros.rs":"0288c879c4735a8d317560baa3d4a6efbf1435d8ec350c5cb12cc1ba7c484080","tests/test_repr.rs":"dbb9b04ddbe1ab31eb5331ea69f05bb3a147299da2275a3d4dcc92947b5591b9","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"7dd1b84a267c83121d9f85a9c1aadc072a863ec324e170af4d7d19516f0f526c","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"4b0cceae9e9b27fe2594e6c02bb3e3fd9965ed04498738e5877934dab807b50f"},"package":"15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"}
|
|
@ -13,7 +13,7 @@
|
||||||
[package]
|
[package]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.30"
|
version = "1.0.41"
|
||||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||||
description = "Flexible concrete Error type built on std::error::Error"
|
description = "Flexible concrete Error type built on std::error::Error"
|
||||||
documentation = "https://docs.rs/anyhow"
|
documentation = "https://docs.rs/anyhow"
|
||||||
|
@ -24,6 +24,9 @@ repository = "https://github.com/dtolnay/anyhow"
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
rustdoc-args = ["--cfg", "doc_cfg"]
|
rustdoc-args = ["--cfg", "doc_cfg"]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
[dependencies.backtrace]
|
||||||
|
version = "0.3.51"
|
||||||
|
optional = true
|
||||||
[dev-dependencies.futures]
|
[dev-dependencies.futures]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
@ -31,6 +34,10 @@ default-features = false
|
||||||
[dev-dependencies.rustversion]
|
[dev-dependencies.rustversion]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|
||||||
|
[dev-dependencies.syn]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["full"]
|
||||||
|
|
||||||
[dev-dependencies.thiserror]
|
[dev-dependencies.thiserror]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Anyhow ¯\\\_(ツ)\_/¯
|
Anyhow ¯\\\_(°ペ)\_/¯
|
||||||
=========================
|
==========================
|
||||||
|
|
||||||
[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/anyhow-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/anyhow)
|
[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/anyhow-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/anyhow)
|
||||||
[<img alt="crates.io" src="https://img.shields.io/crates/v/anyhow.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/anyhow)
|
[<img alt="crates.io" src="https://img.shields.io/crates/v/anyhow.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/anyhow)
|
||||||
|
@ -118,6 +118,12 @@ anyhow = "1.0"
|
||||||
return Err(anyhow!("Missing attribute: {}", missing));
|
return Err(anyhow!("Missing attribute: {}", missing));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A `bail!` macro is provided as a shorthand for the same early return.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
bail!("Missing attribute: {}", missing);
|
||||||
|
```
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## No-std support
|
## No-std support
|
||||||
|
|
|
@ -2,6 +2,12 @@ use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, ExitStatus, Stdio};
|
use std::process::{Command, ExitStatus, Stdio};
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "backtrace", not(feature = "std")))]
|
||||||
|
compile_error! {
|
||||||
|
"`backtrace` feature without `std` feature is not supported"
|
||||||
|
}
|
||||||
|
|
||||||
// This code exercises the surface area that we expect of the std Backtrace
|
// This code exercises the surface area that we expect of the std Backtrace
|
||||||
// type. If the current toolchain is able to compile it, we go ahead and use
|
// type. If the current toolchain is able to compile it, we go ahead and use
|
||||||
|
@ -35,13 +41,25 @@ const PROBE: &str = r#"
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if !cfg!(feature = "std") {
|
if cfg!(feature = "std") {
|
||||||
return;
|
|
||||||
}
|
|
||||||
match compile_probe() {
|
match compile_probe() {
|
||||||
Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
|
Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rustc = match rustc_minor_version() {
|
||||||
|
Some(rustc) => rustc,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
if rustc < 38 {
|
||||||
|
println!("cargo:rustc-cfg=anyhow_no_macro_reexport");
|
||||||
|
}
|
||||||
|
|
||||||
|
if rustc < 51 {
|
||||||
|
println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_probe() -> Option<ExitStatus> {
|
fn compile_probe() -> Option<ExitStatus> {
|
||||||
|
@ -61,3 +79,14 @@ fn compile_probe() -> Option<ExitStatus> {
|
||||||
.status()
|
.status()
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rustc_minor_version() -> Option<u32> {
|
||||||
|
let rustc = env::var_os("RUSTC")?;
|
||||||
|
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||||
|
let version = str::from_utf8(&output.stdout).ok()?;
|
||||||
|
let mut pieces = version.split('.');
|
||||||
|
if pieces.next() != Some("rustc 1") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
pieces.next()?.parse().ok()
|
||||||
|
}
|
||||||
|
|
|
@ -1,17 +1,34 @@
|
||||||
#[cfg(backtrace)]
|
#[cfg(backtrace)]
|
||||||
pub(crate) use std::backtrace::Backtrace;
|
pub(crate) use std::backtrace::{Backtrace, BacktraceStatus};
|
||||||
|
|
||||||
#[cfg(not(backtrace))]
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
pub(crate) use self::capture::{Backtrace, BacktraceStatus};
|
||||||
|
|
||||||
|
#[cfg(not(any(backtrace, feature = "backtrace")))]
|
||||||
pub(crate) enum Backtrace {}
|
pub(crate) enum Backtrace {}
|
||||||
|
|
||||||
#[cfg(backtrace)]
|
#[cfg(backtrace)]
|
||||||
macro_rules! backtrace {
|
macro_rules! impl_backtrace {
|
||||||
() => {
|
() => {
|
||||||
Some(Backtrace::capture())
|
std::backtrace::Backtrace
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(backtrace))]
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
macro_rules! impl_backtrace {
|
||||||
|
() => {
|
||||||
|
impl core::fmt::Debug + core::fmt::Display
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(backtrace, feature = "backtrace"))]
|
||||||
|
macro_rules! backtrace {
|
||||||
|
() => {
|
||||||
|
Some(crate::backtrace::Backtrace::capture())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(backtrace, feature = "backtrace")))]
|
||||||
macro_rules! backtrace {
|
macro_rules! backtrace {
|
||||||
() => {
|
() => {
|
||||||
None
|
None
|
||||||
|
@ -23,14 +40,362 @@ macro_rules! backtrace_if_absent {
|
||||||
($err:expr) => {
|
($err:expr) => {
|
||||||
match $err.backtrace() {
|
match $err.backtrace() {
|
||||||
Some(_) => None,
|
Some(_) => None,
|
||||||
None => Some(Backtrace::capture()),
|
None => backtrace!(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "std", not(backtrace)))]
|
#[cfg(all(feature = "std", not(backtrace), feature = "backtrace"))]
|
||||||
|
macro_rules! backtrace_if_absent {
|
||||||
|
($err:expr) => {
|
||||||
|
backtrace!()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", not(backtrace), not(feature = "backtrace")))]
|
||||||
macro_rules! backtrace_if_absent {
|
macro_rules! backtrace_if_absent {
|
||||||
($err:expr) => {
|
($err:expr) => {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
mod capture {
|
||||||
|
use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName};
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
|
use core::fmt::{self, Debug, Display};
|
||||||
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::env;
|
||||||
|
use std::path::{self, Path, PathBuf};
|
||||||
|
use std::sync::Once;
|
||||||
|
|
||||||
|
pub(crate) struct Backtrace {
|
||||||
|
inner: Inner,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum BacktraceStatus {
|
||||||
|
Unsupported,
|
||||||
|
Disabled,
|
||||||
|
Captured,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Inner {
|
||||||
|
Unsupported,
|
||||||
|
Disabled,
|
||||||
|
Captured(LazilyResolvedCapture),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Capture {
|
||||||
|
actual_start: usize,
|
||||||
|
resolved: bool,
|
||||||
|
frames: Vec<BacktraceFrame>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BacktraceFrame {
|
||||||
|
frame: Frame,
|
||||||
|
symbols: Vec<BacktraceSymbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BacktraceSymbol {
|
||||||
|
name: Option<Vec<u8>>,
|
||||||
|
filename: Option<BytesOrWide>,
|
||||||
|
lineno: Option<u32>,
|
||||||
|
colno: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BytesOrWide {
|
||||||
|
Bytes(Vec<u8>),
|
||||||
|
Wide(Vec<u16>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Backtrace {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let capture = match &self.inner {
|
||||||
|
Inner::Unsupported => return fmt.write_str("<unsupported>"),
|
||||||
|
Inner::Disabled => return fmt.write_str("<disabled>"),
|
||||||
|
Inner::Captured(c) => c.force(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let frames = &capture.frames[capture.actual_start..];
|
||||||
|
|
||||||
|
write!(fmt, "Backtrace ")?;
|
||||||
|
|
||||||
|
let mut dbg = fmt.debug_list();
|
||||||
|
|
||||||
|
for frame in frames {
|
||||||
|
if frame.frame.ip().is_null() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg.entries(&frame.symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for BacktraceFrame {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut dbg = fmt.debug_list();
|
||||||
|
dbg.entries(&self.symbols);
|
||||||
|
dbg.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for BacktraceSymbol {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(fmt, "{{ ")?;
|
||||||
|
|
||||||
|
if let Some(fn_name) = self.name.as_ref().map(|b| SymbolName::new(b)) {
|
||||||
|
write!(fmt, "fn: \"{:#}\"", fn_name)?;
|
||||||
|
} else {
|
||||||
|
write!(fmt, "fn: <unknown>")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(fname) = self.filename.as_ref() {
|
||||||
|
write!(fmt, ", file: \"{:?}\"", fname)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(line) = self.lineno {
|
||||||
|
write!(fmt, ", line: {:?}", line)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(fmt, " }}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for BytesOrWide {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
output_filename(
|
||||||
|
fmt,
|
||||||
|
match self {
|
||||||
|
BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
|
||||||
|
BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
|
||||||
|
},
|
||||||
|
PrintFmt::Short,
|
||||||
|
env::current_dir().as_ref().ok(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Backtrace {
|
||||||
|
fn enabled() -> bool {
|
||||||
|
static ENABLED: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
match ENABLED.load(Ordering::SeqCst) {
|
||||||
|
0 => {}
|
||||||
|
1 => return false,
|
||||||
|
_ => return true,
|
||||||
|
}
|
||||||
|
let enabled = match env::var_os("RUST_LIB_BACKTRACE") {
|
||||||
|
Some(s) => s != "0",
|
||||||
|
None => match env::var_os("RUST_BACKTRACE") {
|
||||||
|
Some(s) => s != "0",
|
||||||
|
None => false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ENABLED.store(enabled as usize + 1, Ordering::SeqCst);
|
||||||
|
enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)] // want to make sure there's a frame here to remove
|
||||||
|
pub(crate) fn capture() -> Backtrace {
|
||||||
|
if Backtrace::enabled() {
|
||||||
|
Backtrace::create(Backtrace::capture as usize)
|
||||||
|
} else {
|
||||||
|
let inner = Inner::Disabled;
|
||||||
|
Backtrace { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture a backtrace which starts just before the function addressed
|
||||||
|
// by `ip`
|
||||||
|
fn create(ip: usize) -> Backtrace {
|
||||||
|
let mut frames = Vec::new();
|
||||||
|
let mut actual_start = None;
|
||||||
|
backtrace::trace(|frame| {
|
||||||
|
frames.push(BacktraceFrame {
|
||||||
|
frame: frame.clone(),
|
||||||
|
symbols: Vec::new(),
|
||||||
|
});
|
||||||
|
if frame.symbol_address() as usize == ip && actual_start.is_none() {
|
||||||
|
actual_start = Some(frames.len() + 1);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
});
|
||||||
|
|
||||||
|
// If no frames came out assume that this is an unsupported platform
|
||||||
|
// since `backtrace` doesn't provide a way of learning this right
|
||||||
|
// now, and this should be a good enough approximation.
|
||||||
|
let inner = if frames.is_empty() {
|
||||||
|
Inner::Unsupported
|
||||||
|
} else {
|
||||||
|
Inner::Captured(LazilyResolvedCapture::new(Capture {
|
||||||
|
actual_start: actual_start.unwrap_or(0),
|
||||||
|
frames,
|
||||||
|
resolved: false,
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
Backtrace { inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn status(&self) -> BacktraceStatus {
|
||||||
|
match self.inner {
|
||||||
|
Inner::Unsupported => BacktraceStatus::Unsupported,
|
||||||
|
Inner::Disabled => BacktraceStatus::Disabled,
|
||||||
|
Inner::Captured(_) => BacktraceStatus::Captured,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Backtrace {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let capture = match &self.inner {
|
||||||
|
Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
|
||||||
|
Inner::Disabled => return fmt.write_str("disabled backtrace"),
|
||||||
|
Inner::Captured(c) => c.force(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let full = fmt.alternate();
|
||||||
|
let (frames, style) = if full {
|
||||||
|
(&capture.frames[..], PrintFmt::Full)
|
||||||
|
} else {
|
||||||
|
(&capture.frames[capture.actual_start..], PrintFmt::Short)
|
||||||
|
};
|
||||||
|
|
||||||
|
// When printing paths we try to strip the cwd if it exists,
|
||||||
|
// otherwise we just print the path as-is. Note that we also only do
|
||||||
|
// this for the short format, because if it's full we presumably
|
||||||
|
// want to print everything.
|
||||||
|
let cwd = env::current_dir();
|
||||||
|
let mut print_path = move |fmt: &mut fmt::Formatter, path: BytesOrWideString| {
|
||||||
|
output_filename(fmt, path, style, cwd.as_ref().ok())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
|
||||||
|
f.add_context()?;
|
||||||
|
for frame in frames {
|
||||||
|
let mut f = f.frame();
|
||||||
|
if frame.symbols.is_empty() {
|
||||||
|
f.print_raw(frame.frame.ip(), None, None, None)?;
|
||||||
|
} else {
|
||||||
|
for symbol in frame.symbols.iter() {
|
||||||
|
f.print_raw_with_column(
|
||||||
|
frame.frame.ip(),
|
||||||
|
symbol.name.as_ref().map(|b| SymbolName::new(b)),
|
||||||
|
symbol.filename.as_ref().map(|b| match b {
|
||||||
|
BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
|
||||||
|
BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
|
||||||
|
}),
|
||||||
|
symbol.lineno,
|
||||||
|
symbol.colno,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.finish()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LazilyResolvedCapture {
|
||||||
|
sync: Once,
|
||||||
|
capture: UnsafeCell<Capture>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LazilyResolvedCapture {
|
||||||
|
fn new(capture: Capture) -> Self {
|
||||||
|
LazilyResolvedCapture {
|
||||||
|
sync: Once::new(),
|
||||||
|
capture: UnsafeCell::new(capture),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn force(&self) -> &Capture {
|
||||||
|
self.sync.call_once(|| {
|
||||||
|
// Safety: This exclusive reference can't overlap with any
|
||||||
|
// others. `Once` guarantees callers will block until this
|
||||||
|
// closure returns. `Once` also guarantees only a single caller
|
||||||
|
// will enter this closure.
|
||||||
|
unsafe { &mut *self.capture.get() }.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Safety: This shared reference can't overlap with the exclusive
|
||||||
|
// reference above.
|
||||||
|
unsafe { &*self.capture.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety: Access to the inner value is synchronized using a thread-safe
|
||||||
|
// `Once`. So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too
|
||||||
|
unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {}
|
||||||
|
|
||||||
|
impl Capture {
|
||||||
|
fn resolve(&mut self) {
|
||||||
|
// If we're already resolved, nothing to do!
|
||||||
|
if self.resolved {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.resolved = true;
|
||||||
|
|
||||||
|
for frame in self.frames.iter_mut() {
|
||||||
|
let symbols = &mut frame.symbols;
|
||||||
|
let frame = &frame.frame;
|
||||||
|
backtrace::resolve_frame(frame, |symbol| {
|
||||||
|
symbols.push(BacktraceSymbol {
|
||||||
|
name: symbol.name().map(|m| m.as_bytes().to_vec()),
|
||||||
|
filename: symbol.filename_raw().map(|b| match b {
|
||||||
|
BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
|
||||||
|
BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
|
||||||
|
}),
|
||||||
|
lineno: symbol.lineno(),
|
||||||
|
colno: symbol.colno(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the filename of the backtrace frame.
|
||||||
|
fn output_filename(
|
||||||
|
fmt: &mut fmt::Formatter,
|
||||||
|
bows: BytesOrWideString,
|
||||||
|
print_fmt: PrintFmt,
|
||||||
|
cwd: Option<&PathBuf>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
let file: Cow<Path> = match bows {
|
||||||
|
#[cfg(unix)]
|
||||||
|
BytesOrWideString::Bytes(bytes) => {
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
Path::new(std::ffi::OsStr::from_bytes(bytes)).into()
|
||||||
|
}
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
BytesOrWideString::Bytes(bytes) => {
|
||||||
|
Path::new(std::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
BytesOrWideString::Wide(wide) => {
|
||||||
|
use std::os::windows::ffi::OsStringExt;
|
||||||
|
Cow::Owned(std::ffi::OsString::from_wide(wide).into())
|
||||||
|
}
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
|
||||||
|
};
|
||||||
|
if print_fmt == PrintFmt::Short && file.is_absolute() {
|
||||||
|
if let Some(cwd) = cwd {
|
||||||
|
if let Ok(stripped) = file.strip_prefix(&cwd) {
|
||||||
|
if let Some(s) = stripped.to_str() {
|
||||||
|
return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Display::fmt(&file.display(), fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _assert_send_sync() {
|
||||||
|
fn _assert<T: Send + Sync>() {}
|
||||||
|
_assert::<Backtrace>();
|
||||||
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
Some(self.error.inner.error())
|
Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
use crate::alloc::Box;
|
use crate::alloc::Box;
|
||||||
use crate::backtrace::Backtrace;
|
use crate::backtrace::Backtrace;
|
||||||
use crate::chain::Chain;
|
use crate::chain::Chain;
|
||||||
|
#[cfg(any(feature = "std", anyhow_no_ptr_addr_of))]
|
||||||
|
use crate::ptr::Mut;
|
||||||
|
use crate::ptr::{Own, Ref};
|
||||||
use crate::{Error, StdError};
|
use crate::{Error, StdError};
|
||||||
use core::any::TypeId;
|
use core::any::TypeId;
|
||||||
use core::fmt::{self, Debug, Display};
|
use core::fmt::{self, Debug, Display};
|
||||||
use core::mem::{self, ManuallyDrop};
|
use core::mem::ManuallyDrop;
|
||||||
use core::ptr::{self, NonNull};
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
use core::ptr;
|
||||||
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
@ -80,11 +85,15 @@ impl Error {
|
||||||
let vtable = &ErrorVTable {
|
let vtable = &ErrorVTable {
|
||||||
object_drop: object_drop::<E>,
|
object_drop: object_drop::<E>,
|
||||||
object_ref: object_ref::<E>,
|
object_ref: object_ref::<E>,
|
||||||
#[cfg(feature = "std")]
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
object_mut: object_mut::<E>,
|
object_mut: object_mut::<E>,
|
||||||
object_boxed: object_boxed::<E>,
|
object_boxed: object_boxed::<E>,
|
||||||
object_downcast: object_downcast::<E>,
|
object_downcast: object_downcast::<E>,
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
object_downcast_mut: object_downcast_mut::<E>,
|
||||||
object_drop_rest: object_drop_front::<E>,
|
object_drop_rest: object_drop_front::<E>,
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
object_backtrace: no_backtrace,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Safety: passing vtable that operates on the right type E.
|
// Safety: passing vtable that operates on the right type E.
|
||||||
|
@ -100,11 +109,15 @@ impl Error {
|
||||||
let vtable = &ErrorVTable {
|
let vtable = &ErrorVTable {
|
||||||
object_drop: object_drop::<MessageError<M>>,
|
object_drop: object_drop::<MessageError<M>>,
|
||||||
object_ref: object_ref::<MessageError<M>>,
|
object_ref: object_ref::<MessageError<M>>,
|
||||||
#[cfg(feature = "std")]
|
#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
|
||||||
object_mut: object_mut::<MessageError<M>>,
|
object_mut: object_mut::<MessageError<M>>,
|
||||||
object_boxed: object_boxed::<MessageError<M>>,
|
object_boxed: object_boxed::<MessageError<M>>,
|
||||||
object_downcast: object_downcast::<M>,
|
object_downcast: object_downcast::<M>,
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
object_downcast_mut: object_downcast_mut::<M>,
|
||||||
object_drop_rest: object_drop_front::<M>,
|
object_drop_rest: object_drop_front::<M>,
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
object_backtrace: no_backtrace,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Safety: MessageError is repr(transparent) so it is okay for the
|
// Safety: MessageError is repr(transparent) so it is okay for the
|
||||||
|
@ -121,11 +134,15 @@ impl Error {
|
||||||
let vtable = &ErrorVTable {
|
let vtable = &ErrorVTable {
|
||||||
object_drop: object_drop::<DisplayError<M>>,
|
object_drop: object_drop::<DisplayError<M>>,
|
||||||
object_ref: object_ref::<DisplayError<M>>,
|
object_ref: object_ref::<DisplayError<M>>,
|
||||||
#[cfg(feature = "std")]
|
#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
|
||||||
object_mut: object_mut::<DisplayError<M>>,
|
object_mut: object_mut::<DisplayError<M>>,
|
||||||
object_boxed: object_boxed::<DisplayError<M>>,
|
object_boxed: object_boxed::<DisplayError<M>>,
|
||||||
object_downcast: object_downcast::<M>,
|
object_downcast: object_downcast::<M>,
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
object_downcast_mut: object_downcast_mut::<M>,
|
||||||
object_drop_rest: object_drop_front::<M>,
|
object_drop_rest: object_drop_front::<M>,
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
object_backtrace: no_backtrace,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Safety: DisplayError is repr(transparent) so it is okay for the
|
// Safety: DisplayError is repr(transparent) so it is okay for the
|
||||||
|
@ -144,11 +161,15 @@ impl Error {
|
||||||
let vtable = &ErrorVTable {
|
let vtable = &ErrorVTable {
|
||||||
object_drop: object_drop::<ContextError<C, E>>,
|
object_drop: object_drop::<ContextError<C, E>>,
|
||||||
object_ref: object_ref::<ContextError<C, E>>,
|
object_ref: object_ref::<ContextError<C, E>>,
|
||||||
#[cfg(feature = "std")]
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
object_mut: object_mut::<ContextError<C, E>>,
|
object_mut: object_mut::<ContextError<C, E>>,
|
||||||
object_boxed: object_boxed::<ContextError<C, E>>,
|
object_boxed: object_boxed::<ContextError<C, E>>,
|
||||||
object_downcast: context_downcast::<C, E>,
|
object_downcast: context_downcast::<C, E>,
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
object_downcast_mut: context_downcast_mut::<C, E>,
|
||||||
object_drop_rest: context_drop_rest::<C, E>,
|
object_drop_rest: context_drop_rest::<C, E>,
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
object_backtrace: no_backtrace,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Safety: passing vtable that operates on the right type.
|
// Safety: passing vtable that operates on the right type.
|
||||||
|
@ -165,11 +186,15 @@ impl Error {
|
||||||
let vtable = &ErrorVTable {
|
let vtable = &ErrorVTable {
|
||||||
object_drop: object_drop::<BoxedError>,
|
object_drop: object_drop::<BoxedError>,
|
||||||
object_ref: object_ref::<BoxedError>,
|
object_ref: object_ref::<BoxedError>,
|
||||||
#[cfg(feature = "std")]
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
object_mut: object_mut::<BoxedError>,
|
object_mut: object_mut::<BoxedError>,
|
||||||
object_boxed: object_boxed::<BoxedError>,
|
object_boxed: object_boxed::<BoxedError>,
|
||||||
object_downcast: object_downcast::<Box<dyn StdError + Send + Sync>>,
|
object_downcast: object_downcast::<Box<dyn StdError + Send + Sync>>,
|
||||||
|
#[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>>,
|
object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
object_backtrace: no_backtrace,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Safety: BoxedError is repr(transparent) so it is okay for the vtable
|
// Safety: BoxedError is repr(transparent) so it is okay for the vtable
|
||||||
|
@ -190,19 +215,18 @@ impl Error {
|
||||||
where
|
where
|
||||||
E: StdError + Send + Sync + 'static,
|
E: StdError + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let inner = Box::new(ErrorImpl {
|
let inner: Box<ErrorImpl<E>> = Box::new(ErrorImpl {
|
||||||
vtable,
|
vtable,
|
||||||
backtrace,
|
backtrace,
|
||||||
_object: error,
|
_object: error,
|
||||||
});
|
});
|
||||||
// Erase the concrete type of E from the compile-time type system. This
|
// Erase the concrete type of E from the compile-time type system. This
|
||||||
// is equivalent to the safe unsize coersion from Box<ErrorImpl<E>> to
|
// is equivalent to the safe unsize coercion from Box<ErrorImpl<E>> to
|
||||||
// Box<ErrorImpl<dyn StdError + Send + Sync + 'static>> except that the
|
// Box<ErrorImpl<dyn StdError + Send + Sync + 'static>> except that the
|
||||||
// result is a thin pointer. The necessary behavior for manipulating the
|
// result is a thin pointer. The necessary behavior for manipulating the
|
||||||
// underlying ErrorImpl<E> is preserved in the vtable provided by the
|
// underlying ErrorImpl<E> is preserved in the vtable provided by the
|
||||||
// caller rather than a builtin fat pointer vtable.
|
// caller rather than a builtin fat pointer vtable.
|
||||||
let erased = mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner);
|
let inner = Own::new(inner).cast::<ErrorImpl>();
|
||||||
let inner = ManuallyDrop::new(erased);
|
|
||||||
Error { inner }
|
Error { inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,11 +296,15 @@ impl Error {
|
||||||
let vtable = &ErrorVTable {
|
let vtable = &ErrorVTable {
|
||||||
object_drop: object_drop::<ContextError<C, Error>>,
|
object_drop: object_drop::<ContextError<C, Error>>,
|
||||||
object_ref: object_ref::<ContextError<C, Error>>,
|
object_ref: object_ref::<ContextError<C, Error>>,
|
||||||
#[cfg(feature = "std")]
|
#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
|
||||||
object_mut: object_mut::<ContextError<C, Error>>,
|
object_mut: object_mut::<ContextError<C, Error>>,
|
||||||
object_boxed: object_boxed::<ContextError<C, Error>>,
|
object_boxed: object_boxed::<ContextError<C, Error>>,
|
||||||
object_downcast: context_chain_downcast::<C>,
|
object_downcast: context_chain_downcast::<C>,
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
object_downcast_mut: context_chain_downcast_mut::<C>,
|
||||||
object_drop_rest: context_chain_drop_rest::<C>,
|
object_drop_rest: context_chain_drop_rest::<C>,
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
object_backtrace: context_backtrace::<C>,
|
||||||
};
|
};
|
||||||
|
|
||||||
// As the cause is anyhow::Error, we already have a backtrace for it.
|
// As the cause is anyhow::Error, we already have a backtrace for it.
|
||||||
|
@ -288,9 +316,6 @@ impl Error {
|
||||||
|
|
||||||
/// Get the backtrace for this Error.
|
/// Get the backtrace for this Error.
|
||||||
///
|
///
|
||||||
/// Backtraces are only available on the nightly channel. Tracking issue:
|
|
||||||
/// [rust-lang/rust#53487][tracking].
|
|
||||||
///
|
|
||||||
/// In order for the backtrace to be meaningful, one of the two environment
|
/// In order for the backtrace to be meaningful, one of the two environment
|
||||||
/// variables `RUST_LIB_BACKTRACE=1` or `RUST_BACKTRACE=1` must be defined
|
/// variables `RUST_LIB_BACKTRACE=1` or `RUST_BACKTRACE=1` must be defined
|
||||||
/// and `RUST_LIB_BACKTRACE` must not be `0`. Backtraces are somewhat
|
/// and `RUST_LIB_BACKTRACE` must not be `0`. Backtraces are somewhat
|
||||||
|
@ -304,10 +329,25 @@ impl Error {
|
||||||
/// - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
|
/// - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
|
||||||
/// `RUST_LIB_BACKTRACE=0`.
|
/// `RUST_LIB_BACKTRACE=0`.
|
||||||
///
|
///
|
||||||
|
/// # 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
|
||||||
|
/// "backtrace" feature is enabled, and will use the `backtrace` crate as
|
||||||
|
/// the underlying backtrace implementation.
|
||||||
|
///
|
||||||
|
/// ```toml
|
||||||
|
/// [dependencies]
|
||||||
|
/// anyhow = { version = "1.0", features = ["backtrace"] }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// [tracking]: https://github.com/rust-lang/rust/issues/53487
|
/// [tracking]: https://github.com/rust-lang/rust/issues/53487
|
||||||
#[cfg(backtrace)]
|
#[cfg(any(backtrace, feature = "backtrace"))]
|
||||||
pub fn backtrace(&self) -> &Backtrace {
|
#[cfg_attr(doc_cfg, doc(cfg(any(nightly, feature = "backtrace"))))]
|
||||||
self.inner.backtrace()
|
pub fn backtrace(&self) -> &impl_backtrace!() {
|
||||||
|
unsafe { ErrorImpl::backtrace(self.inner.by_ref()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator of the chain of source errors contained by this Error.
|
/// An iterator of the chain of source errors contained by this Error.
|
||||||
|
@ -332,8 +372,9 @@ impl Error {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||||
pub fn chain(&self) -> Chain {
|
pub fn chain(&self) -> Chain {
|
||||||
self.inner.chain()
|
unsafe { ErrorImpl::chain(self.inner.by_ref()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The lowest level cause of this error — this error's cause's
|
/// The lowest level cause of this error — this error's cause's
|
||||||
|
@ -342,13 +383,9 @@ impl Error {
|
||||||
/// The root cause is the last error in the iterator produced by
|
/// The root cause is the last error in the iterator produced by
|
||||||
/// [`chain()`][Error::chain].
|
/// [`chain()`][Error::chain].
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||||
pub fn root_cause(&self) -> &(dyn StdError + 'static) {
|
pub fn root_cause(&self) -> &(dyn StdError + 'static) {
|
||||||
let mut chain = self.chain();
|
self.chain().last().unwrap()
|
||||||
let mut root_cause = chain.next().unwrap();
|
|
||||||
for cause in chain {
|
|
||||||
root_cause = cause;
|
|
||||||
}
|
|
||||||
root_cause
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if `E` is the type held by this error object.
|
/// Returns true if `E` is the type held by this error object.
|
||||||
|
@ -367,16 +404,23 @@ impl Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to downcast the error object to a concrete type.
|
/// Attempt to downcast the error object to a concrete type.
|
||||||
pub fn downcast<E>(self) -> Result<E, Self>
|
pub fn downcast<E>(mut self) -> Result<E, Self>
|
||||||
where
|
where
|
||||||
E: Display + Debug + Send + Sync + 'static,
|
E: Display + Debug + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let target = TypeId::of::<E>();
|
let target = TypeId::of::<E>();
|
||||||
|
let inner = self.inner.by_mut();
|
||||||
unsafe {
|
unsafe {
|
||||||
// Use vtable to find NonNull<()> which points to a value of type E
|
// Use vtable to find NonNull<()> which points to a value of type E
|
||||||
// somewhere inside the data structure.
|
// somewhere inside the data structure.
|
||||||
let addr = match (self.inner.vtable.object_downcast)(&self.inner, target) {
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
Some(addr) => addr,
|
let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) {
|
||||||
|
Some(addr) => addr.by_mut().extend(),
|
||||||
|
None => return Err(self),
|
||||||
|
};
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
let addr = match (vtable(inner.ptr).object_downcast_mut)(inner, target) {
|
||||||
|
Some(addr) => addr.extend(),
|
||||||
None => return Err(self),
|
None => return Err(self),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -385,15 +429,10 @@ impl Error {
|
||||||
let outer = ManuallyDrop::new(self);
|
let outer = ManuallyDrop::new(self);
|
||||||
|
|
||||||
// Read E from where the vtable found it.
|
// Read E from where the vtable found it.
|
||||||
let error = ptr::read(addr.cast::<E>().as_ptr());
|
let error = addr.cast::<E>().read();
|
||||||
|
|
||||||
// Read Box<ErrorImpl<()>> from self. Can't move it out because
|
|
||||||
// Error has a Drop impl which we want to not run.
|
|
||||||
let inner = ptr::read(&outer.inner);
|
|
||||||
let erased = ManuallyDrop::into_inner(inner);
|
|
||||||
|
|
||||||
// Drop rest of the data structure outside of E.
|
// Drop rest of the data structure outside of E.
|
||||||
(erased.vtable.object_drop_rest)(erased, target);
|
(vtable(outer.inner.ptr).object_drop_rest)(outer.inner, target);
|
||||||
|
|
||||||
Ok(error)
|
Ok(error)
|
||||||
}
|
}
|
||||||
|
@ -443,8 +482,8 @@ impl Error {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Use vtable to find NonNull<()> which points to a value of type E
|
// Use vtable to find NonNull<()> which points to a value of type E
|
||||||
// somewhere inside the data structure.
|
// somewhere inside the data structure.
|
||||||
let addr = (self.inner.vtable.object_downcast)(&self.inner, target)?;
|
let addr = (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?;
|
||||||
Some(&*addr.cast::<E>().as_ptr())
|
Some(addr.cast::<E>().deref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,13 +496,21 @@ impl Error {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Use vtable to find NonNull<()> which points to a value of type E
|
// Use vtable to find NonNull<()> which points to a value of type E
|
||||||
// somewhere inside the data structure.
|
// somewhere inside the data structure.
|
||||||
let addr = (self.inner.vtable.object_downcast)(&self.inner, target)?;
|
|
||||||
Some(&mut *addr.cast::<E>().as_ptr())
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
let addr =
|
||||||
|
(vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut();
|
||||||
|
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
let addr = (vtable(self.inner.ptr).object_downcast_mut)(self.inner.by_mut(), target)?;
|
||||||
|
|
||||||
|
Some(addr.cast::<E>().deref_mut())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||||
impl<E> From<E> for Error
|
impl<E> From<E> for Error
|
||||||
where
|
where
|
||||||
E: StdError + Send + Sync + 'static,
|
E: StdError + Send + Sync + 'static,
|
||||||
|
@ -475,133 +522,193 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||||
impl Deref for Error {
|
impl Deref for Error {
|
||||||
type Target = dyn StdError + Send + Sync + 'static;
|
type Target = dyn StdError + Send + Sync + 'static;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.inner.error()
|
unsafe { ErrorImpl::error(self.inner.by_ref()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||||
impl DerefMut for Error {
|
impl DerefMut for Error {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.inner.error_mut()
|
unsafe { ErrorImpl::error_mut(self.inner.by_mut()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.inner.display(formatter)
|
unsafe { ErrorImpl::display(self.inner.by_ref(), formatter) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Error {
|
impl Debug for Error {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.inner.debug(formatter)
|
unsafe { ErrorImpl::debug(self.inner.by_ref(), formatter) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Error {
|
impl Drop for Error {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Read Box<ErrorImpl<()>> from self.
|
|
||||||
let inner = ptr::read(&self.inner);
|
|
||||||
let erased = ManuallyDrop::into_inner(inner);
|
|
||||||
|
|
||||||
// Invoke the vtable's drop behavior.
|
// Invoke the vtable's drop behavior.
|
||||||
(erased.vtable.object_drop)(erased);
|
(vtable(self.inner.ptr).object_drop)(self.inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ErrorVTable {
|
struct ErrorVTable {
|
||||||
object_drop: unsafe fn(Box<ErrorImpl<()>>),
|
object_drop: unsafe fn(Own<ErrorImpl>),
|
||||||
object_ref: unsafe fn(&ErrorImpl<()>) -> &(dyn StdError + Send + Sync + 'static),
|
object_ref: unsafe fn(Ref<ErrorImpl>) -> Ref<dyn StdError + Send + Sync + 'static>,
|
||||||
#[cfg(feature = "std")]
|
#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
|
||||||
object_mut: unsafe fn(&mut ErrorImpl<()>) -> &mut (dyn StdError + Send + Sync + 'static),
|
object_mut: unsafe fn(Mut<ErrorImpl>) -> &mut (dyn StdError + Send + Sync + 'static),
|
||||||
object_boxed: unsafe fn(Box<ErrorImpl<()>>) -> Box<dyn StdError + Send + Sync + 'static>,
|
object_boxed: unsafe fn(Own<ErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>,
|
||||||
object_downcast: unsafe fn(&ErrorImpl<()>, TypeId) -> Option<NonNull<()>>,
|
object_downcast: unsafe fn(Ref<ErrorImpl>, TypeId) -> Option<Ref<()>>,
|
||||||
object_drop_rest: unsafe fn(Box<ErrorImpl<()>>, TypeId),
|
#[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"))]
|
||||||
|
object_backtrace: unsafe fn(Ref<ErrorImpl>) -> Option<&Backtrace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<E>.
|
// Safety: requires layout of *e to match ErrorImpl<E>.
|
||||||
unsafe fn object_drop<E>(e: Box<ErrorImpl<()>>) {
|
unsafe fn object_drop<E>(e: Own<ErrorImpl>) {
|
||||||
// Cast back to ErrorImpl<E> so that the allocator receives the correct
|
// Cast back to ErrorImpl<E> so that the allocator receives the correct
|
||||||
// Layout to deallocate the Box's memory.
|
// Layout to deallocate the Box's memory.
|
||||||
let unerased = mem::transmute::<Box<ErrorImpl<()>>, Box<ErrorImpl<E>>>(e);
|
let unerased = e.cast::<ErrorImpl<E>>().boxed();
|
||||||
drop(unerased);
|
drop(unerased);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<E>.
|
// Safety: requires layout of *e to match ErrorImpl<E>.
|
||||||
unsafe fn object_drop_front<E>(e: Box<ErrorImpl<()>>, target: TypeId) {
|
unsafe fn object_drop_front<E>(e: Own<ErrorImpl>, target: TypeId) {
|
||||||
// Drop the fields of ErrorImpl other than E as well as the Box allocation,
|
// Drop the fields of ErrorImpl other than E as well as the Box allocation,
|
||||||
// without dropping E itself. This is used by downcast after doing a
|
// without dropping E itself. This is used by downcast after doing a
|
||||||
// ptr::read to take ownership of the E.
|
// ptr::read to take ownership of the E.
|
||||||
let _ = target;
|
let _ = target;
|
||||||
let unerased = mem::transmute::<Box<ErrorImpl<()>>, Box<ErrorImpl<ManuallyDrop<E>>>>(e);
|
let unerased = e.cast::<ErrorImpl<ManuallyDrop<E>>>().boxed();
|
||||||
drop(unerased);
|
drop(unerased);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<E>.
|
// Safety: requires layout of *e to match ErrorImpl<E>.
|
||||||
unsafe fn object_ref<E>(e: &ErrorImpl<()>) -> &(dyn StdError + Send + Sync + 'static)
|
unsafe fn object_ref<E>(e: Ref<ErrorImpl>) -> Ref<dyn StdError + Send + Sync + 'static>
|
||||||
where
|
where
|
||||||
E: StdError + Send + Sync + 'static,
|
E: StdError + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
// Attach E's native StdError vtable onto a pointer to self._object.
|
// Attach E's native StdError vtable onto a pointer to self._object.
|
||||||
&(*(e as *const ErrorImpl<()> as *const ErrorImpl<E>))._object
|
|
||||||
|
let unerased = e.cast::<ErrorImpl<E>>();
|
||||||
|
|
||||||
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
return Ref::from_raw(NonNull::new_unchecked(
|
||||||
|
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
|
||||||
|
));
|
||||||
|
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
return Ref::new(&unerased.deref()._object);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<E>.
|
// Safety: requires layout of *e to match ErrorImpl<E>, and for `e` to be derived
|
||||||
#[cfg(feature = "std")]
|
// from a `&mut`
|
||||||
unsafe fn object_mut<E>(e: &mut ErrorImpl<()>) -> &mut (dyn StdError + Send + Sync + 'static)
|
#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
|
||||||
|
unsafe fn object_mut<E>(e: Mut<ErrorImpl>) -> &mut (dyn StdError + Send + Sync + 'static)
|
||||||
where
|
where
|
||||||
E: StdError + Send + Sync + 'static,
|
E: StdError + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
// Attach E's native StdError vtable onto a pointer to self._object.
|
// Attach E's native StdError vtable onto a pointer to self._object.
|
||||||
&mut (*(e as *mut ErrorImpl<()> as *mut ErrorImpl<E>))._object
|
&mut e.cast::<ErrorImpl<E>>().deref_mut()._object
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<E>.
|
// Safety: requires layout of *e to match ErrorImpl<E>.
|
||||||
unsafe fn object_boxed<E>(e: Box<ErrorImpl<()>>) -> Box<dyn StdError + Send + Sync + 'static>
|
unsafe fn object_boxed<E>(e: Own<ErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>
|
||||||
where
|
where
|
||||||
E: StdError + Send + Sync + 'static,
|
E: StdError + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
// Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
|
// Attach ErrorImpl<E>'s native StdError vtable. The StdError impl is below.
|
||||||
mem::transmute::<Box<ErrorImpl<()>>, Box<ErrorImpl<E>>>(e)
|
e.cast::<ErrorImpl<E>>().boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<E>.
|
// Safety: requires layout of *e to match ErrorImpl<E>.
|
||||||
unsafe fn object_downcast<E>(e: &ErrorImpl<()>, target: TypeId) -> Option<NonNull<()>>
|
unsafe fn object_downcast<E>(e: Ref<ErrorImpl>, target: TypeId) -> Option<Ref<()>>
|
||||||
where
|
where
|
||||||
E: 'static,
|
E: 'static,
|
||||||
{
|
{
|
||||||
if TypeId::of::<E>() == target {
|
if TypeId::of::<E>() == target {
|
||||||
// Caller is looking for an E pointer and e is ErrorImpl<E>, take a
|
// Caller is looking for an E pointer and e is ErrorImpl<E>, take a
|
||||||
// pointer to its E field.
|
// pointer to its E field.
|
||||||
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<E>;
|
|
||||||
let addr = &(*unerased)._object as *const E as *mut ();
|
let unerased = e.cast::<ErrorImpl<E>>();
|
||||||
Some(NonNull::new_unchecked(addr))
|
|
||||||
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
return Some(
|
||||||
|
Ref::from_raw(NonNull::new_unchecked(
|
||||||
|
ptr::addr_of!((*unerased.as_ptr())._object) as *mut E,
|
||||||
|
))
|
||||||
|
.cast::<()>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
return Some(Ref::new(&unerased.deref()._object).cast::<()>());
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: requires layout of *e to match ErrorImpl<E>.
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
unsafe fn object_downcast_mut<E>(e: Mut<ErrorImpl>, target: TypeId) -> Option<Mut<()>>
|
||||||
|
where
|
||||||
|
E: 'static,
|
||||||
|
{
|
||||||
|
if TypeId::of::<E>() == target {
|
||||||
|
// Caller is looking for an E pointer and e is ErrorImpl<E>, take a
|
||||||
|
// pointer to its E field.
|
||||||
|
let unerased = e.cast::<ErrorImpl<E>>().deref_mut();
|
||||||
|
Some(Mut::new(&mut unerased._object).cast::<()>())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
fn no_backtrace(e: Ref<ErrorImpl>) -> Option<&Backtrace> {
|
||||||
|
let _ = e;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, E>>.
|
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, E>>.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
unsafe fn context_downcast<C, E>(e: &ErrorImpl<()>, target: TypeId) -> Option<NonNull<()>>
|
unsafe fn context_downcast<C, E>(e: Ref<ErrorImpl>, target: TypeId) -> Option<Ref<()>>
|
||||||
where
|
where
|
||||||
C: 'static,
|
C: 'static,
|
||||||
E: 'static,
|
E: 'static,
|
||||||
{
|
{
|
||||||
if TypeId::of::<C>() == target {
|
if TypeId::of::<C>() == target {
|
||||||
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<ContextError<C, E>>;
|
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref();
|
||||||
let addr = &(*unerased)._object.context as *const C as *mut ();
|
Some(Ref::new(&unerased._object.context).cast::<()>())
|
||||||
Some(NonNull::new_unchecked(addr))
|
|
||||||
} else if TypeId::of::<E>() == target {
|
} else if TypeId::of::<E>() == target {
|
||||||
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<ContextError<C, E>>;
|
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref();
|
||||||
let addr = &(*unerased)._object.error as *const E as *mut ();
|
Some(Ref::new(&unerased._object.error).cast::<()>())
|
||||||
Some(NonNull::new_unchecked(addr))
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, E>>.
|
||||||
|
#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
|
||||||
|
unsafe fn context_downcast_mut<C, E>(e: Mut<ErrorImpl>, target: TypeId) -> Option<Mut<()>>
|
||||||
|
where
|
||||||
|
C: 'static,
|
||||||
|
E: 'static,
|
||||||
|
{
|
||||||
|
if TypeId::of::<C>() == target {
|
||||||
|
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref_mut();
|
||||||
|
Some(Mut::new(&mut unerased._object.context).cast::<()>())
|
||||||
|
} else if TypeId::of::<E>() == target {
|
||||||
|
let unerased = e.cast::<ErrorImpl<ContextError<C, E>>>().deref_mut();
|
||||||
|
Some(Mut::new(&mut unerased._object.error).cast::<()>())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -609,7 +716,7 @@ where
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, E>>.
|
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, E>>.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
unsafe fn context_drop_rest<C, E>(e: Box<ErrorImpl<()>>, target: TypeId)
|
unsafe fn context_drop_rest<C, E>(e: Own<ErrorImpl>, target: TypeId)
|
||||||
where
|
where
|
||||||
C: 'static,
|
C: 'static,
|
||||||
E: 'static,
|
E: 'static,
|
||||||
|
@ -617,68 +724,92 @@ where
|
||||||
// Called after downcasting by value to either the C or the E and doing a
|
// Called after downcasting by value to either the C or the E and doing a
|
||||||
// ptr::read to take ownership of that value.
|
// ptr::read to take ownership of that value.
|
||||||
if TypeId::of::<C>() == target {
|
if TypeId::of::<C>() == target {
|
||||||
let unerased = mem::transmute::<
|
let unerased = e
|
||||||
Box<ErrorImpl<()>>,
|
.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, E>>>()
|
||||||
Box<ErrorImpl<ContextError<ManuallyDrop<C>, E>>>,
|
.boxed();
|
||||||
>(e);
|
|
||||||
drop(unerased);
|
drop(unerased);
|
||||||
} else {
|
} else {
|
||||||
let unerased = mem::transmute::<
|
let unerased = e
|
||||||
Box<ErrorImpl<()>>,
|
.cast::<ErrorImpl<ContextError<C, ManuallyDrop<E>>>>()
|
||||||
Box<ErrorImpl<ContextError<C, ManuallyDrop<E>>>>,
|
.boxed();
|
||||||
>(e);
|
|
||||||
drop(unerased);
|
drop(unerased);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
|
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
|
||||||
unsafe fn context_chain_downcast<C>(e: &ErrorImpl<()>, target: TypeId) -> Option<NonNull<()>>
|
unsafe fn context_chain_downcast<C>(e: Ref<ErrorImpl>, target: TypeId) -> Option<Ref<()>>
|
||||||
where
|
where
|
||||||
C: 'static,
|
C: 'static,
|
||||||
{
|
{
|
||||||
|
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref();
|
||||||
if TypeId::of::<C>() == target {
|
if TypeId::of::<C>() == target {
|
||||||
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<ContextError<C, Error>>;
|
Some(Ref::new(&unerased._object.context).cast::<()>())
|
||||||
let addr = &(*unerased)._object.context as *const C as *mut ();
|
|
||||||
Some(NonNull::new_unchecked(addr))
|
|
||||||
} else {
|
} else {
|
||||||
// Recurse down the context chain per the inner error's vtable.
|
// Recurse down the context chain per the inner error's vtable.
|
||||||
let unerased = e as *const ErrorImpl<()> as *const ErrorImpl<ContextError<C, Error>>;
|
let source = &unerased._object.error;
|
||||||
let source = &(*unerased)._object.error;
|
(vtable(source.inner.ptr).object_downcast)(source.inner.by_ref(), target)
|
||||||
(source.inner.vtable.object_downcast)(&source.inner, target)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
|
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
|
||||||
unsafe fn context_chain_drop_rest<C>(e: Box<ErrorImpl<()>>, target: TypeId)
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
unsafe fn context_chain_downcast_mut<C>(e: Mut<ErrorImpl>, target: TypeId) -> Option<Mut<()>>
|
||||||
|
where
|
||||||
|
C: 'static,
|
||||||
|
{
|
||||||
|
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref_mut();
|
||||||
|
if TypeId::of::<C>() == target {
|
||||||
|
Some(Mut::new(&mut unerased._object.context).cast::<()>())
|
||||||
|
} else {
|
||||||
|
// Recurse down the context chain per the inner error's vtable.
|
||||||
|
let source = &mut unerased._object.error;
|
||||||
|
(vtable(source.inner.ptr).object_downcast_mut)(source.inner.by_mut(), target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
|
||||||
|
unsafe fn context_chain_drop_rest<C>(e: Own<ErrorImpl>, target: TypeId)
|
||||||
where
|
where
|
||||||
C: 'static,
|
C: 'static,
|
||||||
{
|
{
|
||||||
// Called after downcasting by value to either the C or one of the causes
|
// Called after downcasting by value to either the C or one of the causes
|
||||||
// and doing a ptr::read to take ownership of that value.
|
// and doing a ptr::read to take ownership of that value.
|
||||||
if TypeId::of::<C>() == target {
|
if TypeId::of::<C>() == target {
|
||||||
let unerased = mem::transmute::<
|
let unerased = e
|
||||||
Box<ErrorImpl<()>>,
|
.cast::<ErrorImpl<ContextError<ManuallyDrop<C>, Error>>>()
|
||||||
Box<ErrorImpl<ContextError<ManuallyDrop<C>, Error>>>,
|
.boxed();
|
||||||
>(e);
|
|
||||||
// Drop the entire rest of the data structure rooted in the next Error.
|
// Drop the entire rest of the data structure rooted in the next Error.
|
||||||
drop(unerased);
|
drop(unerased);
|
||||||
} else {
|
} else {
|
||||||
let unerased = mem::transmute::<
|
let unerased = e
|
||||||
Box<ErrorImpl<()>>,
|
.cast::<ErrorImpl<ContextError<C, ManuallyDrop<Error>>>>()
|
||||||
Box<ErrorImpl<ContextError<C, ManuallyDrop<Error>>>>,
|
.boxed();
|
||||||
>(e);
|
// Read the Own<ErrorImpl> from the next error.
|
||||||
// Read out a ManuallyDrop<Box<ErrorImpl<()>>> from the next error.
|
let inner = unerased._object.error.inner;
|
||||||
let inner = ptr::read(&unerased._object.error.inner);
|
|
||||||
drop(unerased);
|
drop(unerased);
|
||||||
let erased = ManuallyDrop::into_inner(inner);
|
let vtable = vtable(inner.ptr);
|
||||||
// Recursively drop the next error using the same target typeid.
|
// Recursively drop the next error using the same target typeid.
|
||||||
(erased.vtable.object_drop_rest)(erased, target);
|
(vtable.object_drop_rest)(inner, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
|
unsafe fn context_backtrace<C>(e: Ref<ErrorImpl>) -> Option<&Backtrace>
|
||||||
|
where
|
||||||
|
C: 'static,
|
||||||
|
{
|
||||||
|
let unerased = e.cast::<ErrorImpl<ContextError<C, Error>>>().deref();
|
||||||
|
let backtrace = ErrorImpl::backtrace(unerased._object.error.inner.by_ref());
|
||||||
|
Some(backtrace)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: If working with `ErrorImpl<()>`, references should be avoided in favor
|
||||||
|
// of raw pointers and `NonNull`.
|
||||||
// repr C to ensure that E remains in the final position.
|
// repr C to ensure that E remains in the final position.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(crate) struct ErrorImpl<E> {
|
pub(crate) struct ErrorImpl<E = ()> {
|
||||||
vtable: &'static ErrorVTable,
|
vtable: &'static ErrorVTable,
|
||||||
backtrace: Option<Backtrace>,
|
backtrace: Option<Backtrace>,
|
||||||
// NOTE: Don't use directly. Use only through vtable. Erased type may have
|
// NOTE: Don't use directly. Use only through vtable. Erased type may have
|
||||||
|
@ -686,6 +817,13 @@ pub(crate) struct ErrorImpl<E> {
|
||||||
_object: E,
|
_object: E,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reads the vtable out of `p`. This is the same as `p.as_ref().vtable`, but
|
||||||
|
// avoids converting `p` into a reference.
|
||||||
|
unsafe fn vtable(p: NonNull<ErrorImpl>) -> &'static ErrorVTable {
|
||||||
|
// NOTE: This assumes that `ErrorVTable` is the first field of ErrorImpl.
|
||||||
|
*(p.as_ptr() as *const &'static ErrorVTable)
|
||||||
|
}
|
||||||
|
|
||||||
// repr C to ensure that ContextError<C, E> has the same layout as
|
// repr C to ensure that ContextError<C, E> has the same layout as
|
||||||
// ContextError<ManuallyDrop<C>, E> and ContextError<C, ManuallyDrop<E>>.
|
// ContextError<ManuallyDrop<C>, E> and ContextError<C, ManuallyDrop<E>>.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -695,41 +833,54 @@ pub(crate) struct ContextError<C, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> ErrorImpl<E> {
|
impl<E> ErrorImpl<E> {
|
||||||
fn erase(&self) -> &ErrorImpl<()> {
|
fn erase(&self) -> Ref<ErrorImpl> {
|
||||||
// Erase the concrete type of E but preserve the vtable in self.vtable
|
// Erase the concrete type of E but preserve the vtable in self.vtable
|
||||||
// for manipulating the resulting thin pointer. This is analogous to an
|
// for manipulating the resulting thin pointer. This is analogous to an
|
||||||
// unsize coersion.
|
// unsize coercion.
|
||||||
unsafe { &*(self as *const ErrorImpl<E> as *const ErrorImpl<()>) }
|
Ref::new(self).cast::<ErrorImpl>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorImpl<()> {
|
impl ErrorImpl {
|
||||||
pub(crate) fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
|
pub(crate) unsafe fn error(this: Ref<Self>) -> &(dyn StdError + Send + Sync + 'static) {
|
||||||
// Use vtable to attach E's native StdError vtable for the right
|
// Use vtable to attach E's native StdError vtable for the right
|
||||||
// original type E.
|
// original type E.
|
||||||
unsafe { &*(self.vtable.object_ref)(self) }
|
(vtable(this.ptr).object_ref)(this).deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub(crate) fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
|
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
|
// Use vtable to attach E's native StdError vtable for the right
|
||||||
// original type E.
|
// original type E.
|
||||||
unsafe { &mut *(self.vtable.object_mut)(self) }
|
|
||||||
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
return (vtable(this.ptr).object_ref)(this.by_ref())
|
||||||
|
.by_mut()
|
||||||
|
.deref_mut();
|
||||||
|
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
return (vtable(this.ptr).object_mut)(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(backtrace)]
|
#[cfg(any(backtrace, feature = "backtrace"))]
|
||||||
pub(crate) fn backtrace(&self) -> &Backtrace {
|
pub(crate) unsafe fn backtrace(this: Ref<Self>) -> &Backtrace {
|
||||||
// This unwrap can only panic if the underlying error's backtrace method
|
// This unwrap can only panic if the underlying error's backtrace method
|
||||||
// is nondeterministic, which would only happen in maliciously
|
// is nondeterministic, which would only happen in maliciously
|
||||||
// constructed code.
|
// constructed code.
|
||||||
self.backtrace
|
this.deref()
|
||||||
|
.backtrace
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.or_else(|| self.error().backtrace())
|
.or_else(|| {
|
||||||
|
#[cfg(backtrace)]
|
||||||
|
return Self::error(this).backtrace();
|
||||||
|
#[cfg(all(not(backtrace), feature = "backtrace"))]
|
||||||
|
return (vtable(this.ptr).object_backtrace)(this);
|
||||||
|
})
|
||||||
.expect("backtrace capture failed")
|
.expect("backtrace capture failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn chain(&self) -> Chain {
|
pub(crate) unsafe fn chain(this: Ref<Self>) -> Chain {
|
||||||
Chain::new(self.error())
|
Chain::new(Self::error(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,11 +890,11 @@ where
|
||||||
{
|
{
|
||||||
#[cfg(backtrace)]
|
#[cfg(backtrace)]
|
||||||
fn backtrace(&self) -> Option<&Backtrace> {
|
fn backtrace(&self) -> Option<&Backtrace> {
|
||||||
Some(self.erase().backtrace())
|
Some(unsafe { ErrorImpl::backtrace(self.erase()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
self.erase().error().source()
|
unsafe { ErrorImpl::error(self.erase()).source() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,7 +903,7 @@ where
|
||||||
E: Debug,
|
E: Debug,
|
||||||
{
|
{
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.erase().debug(formatter)
|
unsafe { ErrorImpl::debug(self.erase(), formatter) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,7 +912,7 @@ where
|
||||||
E: Display,
|
E: Display,
|
||||||
{
|
{
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
Display::fmt(&self.erase().error(), formatter)
|
unsafe { Display::fmt(ErrorImpl::error(self.erase()), formatter) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,18 +920,19 @@ impl From<Error> for Box<dyn StdError + Send + Sync + 'static> {
|
||||||
fn from(error: Error) -> Self {
|
fn from(error: Error) -> Self {
|
||||||
let outer = ManuallyDrop::new(error);
|
let outer = ManuallyDrop::new(error);
|
||||||
unsafe {
|
unsafe {
|
||||||
// Read Box<ErrorImpl<()>> from error. Can't move it out because
|
|
||||||
// Error has a Drop impl which we want to not run.
|
|
||||||
let inner = ptr::read(&outer.inner);
|
|
||||||
let erased = ManuallyDrop::into_inner(inner);
|
|
||||||
|
|
||||||
// Use vtable to attach ErrorImpl<E>'s native StdError vtable for
|
// Use vtable to attach ErrorImpl<E>'s native StdError vtable for
|
||||||
// the right original type E.
|
// the right original type E.
|
||||||
(erased.vtable.object_boxed)(erased)
|
(vtable(outer.inner.ptr).object_boxed)(outer.inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Error> for Box<dyn StdError + Send + 'static> {
|
||||||
|
fn from(error: Error) -> Self {
|
||||||
|
Box::<dyn StdError + Send + Sync>::from(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Error> for Box<dyn StdError + 'static> {
|
impl From<Error> for Box<dyn StdError + 'static> {
|
||||||
fn from(error: Error) -> Self {
|
fn from(error: Error) -> Self {
|
||||||
Box::<dyn StdError + Send + Sync>::from(error)
|
Box::<dyn StdError + Send + Sync>::from(error)
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use crate::chain::Chain;
|
use crate::chain::Chain;
|
||||||
use crate::error::ErrorImpl;
|
use crate::error::ErrorImpl;
|
||||||
|
use crate::ptr::Ref;
|
||||||
use core::fmt::{self, Debug, Write};
|
use core::fmt::{self, Debug, Write};
|
||||||
|
|
||||||
impl ErrorImpl<()> {
|
impl ErrorImpl {
|
||||||
pub(crate) fn display(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
pub(crate) unsafe fn display(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.error())?;
|
write!(f, "{}", Self::error(this))?;
|
||||||
|
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
for cause in self.chain().skip(1) {
|
for cause in Self::chain(this).skip(1) {
|
||||||
write!(f, ": {}", cause)?;
|
write!(f, ": {}", cause)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +16,8 @@ impl ErrorImpl<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
pub(crate) unsafe fn debug(this: Ref<Self>, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let error = self.error();
|
let error = Self::error(this);
|
||||||
|
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
return Debug::fmt(error, f);
|
return Debug::fmt(error, f);
|
||||||
|
@ -38,19 +39,24 @@ impl ErrorImpl<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(backtrace)]
|
#[cfg(any(backtrace, feature = "backtrace"))]
|
||||||
{
|
{
|
||||||
use std::backtrace::BacktraceStatus;
|
use crate::backtrace::BacktraceStatus;
|
||||||
|
|
||||||
let backtrace = self.backtrace();
|
let backtrace = Self::backtrace(this);
|
||||||
if let BacktraceStatus::Captured = backtrace.status() {
|
if let BacktraceStatus::Captured = backtrace.status() {
|
||||||
let mut backtrace = backtrace.to_string();
|
let mut backtrace = backtrace.to_string();
|
||||||
|
write!(f, "\n\n")?;
|
||||||
if backtrace.starts_with("stack backtrace:") {
|
if backtrace.starts_with("stack backtrace:") {
|
||||||
// Capitalize to match "Caused by:"
|
// Capitalize to match "Caused by:"
|
||||||
backtrace.replace_range(0..1, "S");
|
backtrace.replace_range(0..1, "S");
|
||||||
|
} else {
|
||||||
|
// "stack backtrace:" prefix was removed in
|
||||||
|
// https://github.com/rust-lang/backtrace-rs/pull/286
|
||||||
|
writeln!(f, "Stack backtrace:")?;
|
||||||
}
|
}
|
||||||
backtrace.truncate(backtrace.trim_end().len());
|
backtrace.truncate(backtrace.trim_end().len());
|
||||||
write!(f, "\n\n{}", backtrace)?;
|
write!(f, "{}", backtrace)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,6 @@ use core::fmt::{Debug, Display};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use crate::StdError;
|
use crate::StdError;
|
||||||
|
|
||||||
#[cfg(backtrace)]
|
|
||||||
use std::backtrace::Backtrace;
|
|
||||||
|
|
||||||
pub struct Adhoc;
|
pub struct Adhoc;
|
||||||
|
|
||||||
pub trait AdhocKind: Sized {
|
pub trait AdhocKind: Sized {
|
||||||
|
|
|
@ -179,6 +179,18 @@
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! A `bail!` macro is provided as a shorthand for the same early return.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # use anyhow::{bail, Result};
|
||||||
|
//! #
|
||||||
|
//! # fn demo() -> Result<()> {
|
||||||
|
//! # let missing = "...";
|
||||||
|
//! bail!("Missing attribute: {}", missing);
|
||||||
|
//! # Ok(())
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
//! <br>
|
//! <br>
|
||||||
//!
|
//!
|
||||||
//! # No-std support
|
//! # No-std support
|
||||||
|
@ -197,13 +209,24 @@
|
||||||
//! will require an explicit `.map_err(Error::msg)` when working with a
|
//! will require an explicit `.map_err(Error::msg)` when working with a
|
||||||
//! non-Anyhow error type inside a function that returns Anyhow's error type.
|
//! non-Anyhow error type inside a function that returns Anyhow's error type.
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/anyhow/1.0.30")]
|
#![doc(html_root_url = "https://docs.rs/anyhow/1.0.41")]
|
||||||
#![cfg_attr(backtrace, feature(backtrace))]
|
#![cfg_attr(backtrace, feature(backtrace))]
|
||||||
#![cfg_attr(doc_cfg, feature(doc_cfg))]
|
#![cfg_attr(doc_cfg, feature(doc_cfg))]
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
#![deny(dead_code, unused_imports, unused_mut)]
|
||||||
#![allow(
|
#![allow(
|
||||||
|
clippy::doc_markdown,
|
||||||
|
clippy::enum_glob_use,
|
||||||
|
clippy::missing_errors_doc,
|
||||||
|
clippy::missing_panics_doc,
|
||||||
|
clippy::module_name_repetitions,
|
||||||
|
clippy::must_use_candidate,
|
||||||
clippy::needless_doctest_main,
|
clippy::needless_doctest_main,
|
||||||
clippy::new_ret_no_self,
|
clippy::new_ret_no_self,
|
||||||
|
clippy::redundant_else,
|
||||||
|
clippy::unused_self,
|
||||||
|
clippy::used_underscore_binding,
|
||||||
|
clippy::wildcard_imports,
|
||||||
clippy::wrong_self_convention
|
clippy::wrong_self_convention
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
@ -226,12 +249,12 @@ mod error;
|
||||||
mod fmt;
|
mod fmt;
|
||||||
mod kind;
|
mod kind;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
mod ptr;
|
||||||
mod wrapper;
|
mod wrapper;
|
||||||
|
|
||||||
use crate::alloc::Box;
|
|
||||||
use crate::error::ErrorImpl;
|
use crate::error::ErrorImpl;
|
||||||
|
use crate::ptr::Own;
|
||||||
use core::fmt::Display;
|
use core::fmt::Display;
|
||||||
use core::mem::ManuallyDrop;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
@ -288,6 +311,15 @@ pub use anyhow as format_err;
|
||||||
///
|
///
|
||||||
/// Caused by:
|
/// Caused by:
|
||||||
/// No such file or directory (os error 2)
|
/// No such file or directory (os error 2)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// and if there is a backtrace available:
|
||||||
|
///
|
||||||
|
/// ```console
|
||||||
|
/// Error: Failed to read instrs from ./path/to/instrs.json
|
||||||
|
///
|
||||||
|
/// Caused by:
|
||||||
|
/// No such file or directory (os error 2)
|
||||||
///
|
///
|
||||||
/// Stack backtrace:
|
/// Stack backtrace:
|
||||||
/// 0: <E as anyhow::context::ext::StdError>::ext_context
|
/// 0: <E as anyhow::context::ext::StdError>::ext_context
|
||||||
|
@ -340,8 +372,9 @@ pub use anyhow as format_err;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
inner: ManuallyDrop<Box<ErrorImpl<()>>>,
|
inner: Own<ErrorImpl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator of a chain of source errors.
|
/// Iterator of a chain of source errors.
|
||||||
|
@ -364,6 +397,7 @@ pub struct Error {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Chain<'a> {
|
pub struct Chain<'a> {
|
||||||
state: crate::chain::ChainState<'a>,
|
state: crate::chain::ChainState<'a>,
|
||||||
|
@ -581,9 +615,6 @@ pub mod private {
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use core::fmt::{Debug, Display};
|
use core::fmt::{Debug, Display};
|
||||||
|
|
||||||
#[cfg(backtrace)]
|
|
||||||
use std::backtrace::Backtrace;
|
|
||||||
|
|
||||||
pub use core::result::Result::Err;
|
pub use core::result::Result::Err;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -600,4 +631,27 @@ pub mod private {
|
||||||
{
|
{
|
||||||
Error::from_adhoc(message, backtrace!())
|
Error::from_adhoc(message, backtrace!())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(anyhow_no_macro_reexport)]
|
||||||
|
pub use crate::{__anyhow_concat as concat, __anyhow_stringify as stringify};
|
||||||
|
#[cfg(not(anyhow_no_macro_reexport))]
|
||||||
|
pub use core::{concat, stringify};
|
||||||
|
|
||||||
|
#[cfg(anyhow_no_macro_reexport)]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __anyhow_concat {
|
||||||
|
($($tt:tt)*) => {
|
||||||
|
concat!($($tt)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(anyhow_no_macro_reexport)]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! __anyhow_stringify {
|
||||||
|
($($tt:tt)*) => {
|
||||||
|
stringify!($($tt)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/// Return early with an error.
|
/// Return early with an error.
|
||||||
///
|
///
|
||||||
/// This macro is equivalent to `return Err(From::from($err))`.
|
/// This macro is equivalent to `return Err(`[`anyhow!($args...)`][anyhow!]`)`.
|
||||||
|
///
|
||||||
|
/// The surrounding function's or closure's return value is required to be
|
||||||
|
/// `Result<_,`[`anyhow::Error`][crate::Error]`>`.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -50,19 +53,23 @@
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! bail {
|
macro_rules! bail {
|
||||||
($msg:literal $(,)?) => {
|
($msg:literal $(,)?) => {
|
||||||
return $crate::private::Err($crate::anyhow!($msg));
|
return $crate::private::Err($crate::anyhow!($msg))
|
||||||
};
|
};
|
||||||
($err:expr $(,)?) => {
|
($err:expr $(,)?) => {
|
||||||
return $crate::private::Err($crate::anyhow!($err));
|
return $crate::private::Err($crate::anyhow!($err))
|
||||||
};
|
};
|
||||||
($fmt:expr, $($arg:tt)*) => {
|
($fmt:expr, $($arg:tt)*) => {
|
||||||
return $crate::private::Err($crate::anyhow!($fmt, $($arg)*));
|
return $crate::private::Err($crate::anyhow!($fmt, $($arg)*))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return early with an error if a condition is not satisfied.
|
/// Return early with an error if a condition is not satisfied.
|
||||||
///
|
///
|
||||||
/// This macro is equivalent to `if !$cond { return Err(From::from($err)); }`.
|
/// This macro is equivalent to `if !$cond { return
|
||||||
|
/// Err(`[`anyhow!($args...)`][anyhow!]`); }`.
|
||||||
|
///
|
||||||
|
/// The surrounding function's or closure's return value is required to be
|
||||||
|
/// `Result<_,`[`anyhow::Error`][crate::Error]`>`.
|
||||||
///
|
///
|
||||||
/// Analogously to `assert!`, `ensure!` takes a condition and exits the function
|
/// Analogously to `assert!`, `ensure!` takes a condition and exits the function
|
||||||
/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`
|
/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`
|
||||||
|
@ -106,6 +113,12 @@ macro_rules! bail {
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! ensure {
|
macro_rules! ensure {
|
||||||
|
($cond:expr $(,)?) => {
|
||||||
|
$crate::ensure!(
|
||||||
|
$cond,
|
||||||
|
$crate::private::concat!("Condition failed: `", $crate::private::stringify!($cond), "`"),
|
||||||
|
)
|
||||||
|
};
|
||||||
($cond:expr, $msg:literal $(,)?) => {
|
($cond:expr, $msg:literal $(,)?) => {
|
||||||
if !$cond {
|
if !$cond {
|
||||||
return $crate::private::Err($crate::anyhow!($msg));
|
return $crate::private::Err($crate::anyhow!($msg));
|
||||||
|
@ -123,11 +136,17 @@ macro_rules! ensure {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct an ad-hoc error from a string.
|
/// Construct an ad-hoc error from a string or existing non-`anyhow` error
|
||||||
|
/// value.
|
||||||
///
|
///
|
||||||
/// This evaluates to an `Error`. It can take either just a string, or a format
|
/// This evaluates to an [`Error`][crate::Error]. It can take either just a
|
||||||
/// string with arguments. It also can take any custom type which implements
|
/// string, or a format string with arguments. It also can take any custom type
|
||||||
/// `Debug` and `Display`.
|
/// which implements `Debug` and `Display`.
|
||||||
|
///
|
||||||
|
/// If called with a single argument whose type implements `std::error::Error`
|
||||||
|
/// (in addition to `Debug` and `Display`, which are always required), then that
|
||||||
|
/// Error impl's `source` is preserved as the `source` of the resulting
|
||||||
|
/// `anyhow::Error`.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -154,8 +173,9 @@ macro_rules! anyhow {
|
||||||
};
|
};
|
||||||
($err:expr $(,)?) => ({
|
($err:expr $(,)?) => ({
|
||||||
use $crate::private::kind::*;
|
use $crate::private::kind::*;
|
||||||
let error = $err;
|
match $err {
|
||||||
(&error).anyhow_kind().new(error)
|
error => (&error).anyhow_kind().new(error),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
($fmt:expr, $($arg:tt)*) => {
|
($fmt:expr, $($arg:tt)*) => {
|
||||||
$crate::private::new_adhoc(format!($fmt, $($arg)*))
|
$crate::private::new_adhoc(format!($fmt, $($arg)*))
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
use crate::alloc::Box;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Own<T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
pub ptr: NonNull<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> Send for Own<T> where T: ?Sized {}
|
||||||
|
|
||||||
|
unsafe impl<T> Sync for Own<T> where T: ?Sized {}
|
||||||
|
|
||||||
|
impl<T> Copy for Own<T> where T: ?Sized {}
|
||||||
|
|
||||||
|
impl<T> Clone for Own<T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Own<T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
pub fn new(ptr: Box<T>) -> Self {
|
||||||
|
Own {
|
||||||
|
ptr: unsafe { NonNull::new_unchecked(Box::into_raw(ptr)) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast<U: CastTo>(self) -> Own<U::Target> {
|
||||||
|
Own {
|
||||||
|
ptr: self.ptr.cast(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn boxed(self) -> Box<T> {
|
||||||
|
Box::from_raw(self.ptr.as_ptr())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn by_ref(&self) -> Ref<T> {
|
||||||
|
Ref {
|
||||||
|
ptr: self.ptr,
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn by_mut(&mut self) -> Mut<T> {
|
||||||
|
Mut {
|
||||||
|
ptr: self.ptr,
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Ref<'a, T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
pub ptr: NonNull<T>,
|
||||||
|
lifetime: PhantomData<&'a T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Copy for Ref<'a, T> where T: ?Sized {}
|
||||||
|
|
||||||
|
impl<'a, T> Clone for Ref<'a, T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Ref<'a, T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
pub fn new(ptr: &'a T) -> Self {
|
||||||
|
Ref {
|
||||||
|
ptr: NonNull::from(ptr),
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
pub fn from_raw(ptr: NonNull<T>) -> Self {
|
||||||
|
Ref {
|
||||||
|
ptr,
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast<U: CastTo>(self) -> Ref<'a, U::Target> {
|
||||||
|
Ref {
|
||||||
|
ptr: self.ptr.cast(),
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
pub fn by_mut(self) -> Mut<'a, T> {
|
||||||
|
Mut {
|
||||||
|
ptr: self.ptr,
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
pub fn as_ptr(self) -> *const T {
|
||||||
|
self.ptr.as_ptr() as *const T
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn deref(self) -> &'a T {
|
||||||
|
&*self.ptr.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Mut<'a, T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
pub ptr: NonNull<T>,
|
||||||
|
lifetime: PhantomData<&'a mut T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Copy for Mut<'a, T> where T: ?Sized {}
|
||||||
|
|
||||||
|
impl<'a, T> Clone for Mut<'a, T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Mut<'a, T>
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
{
|
||||||
|
#[cfg(anyhow_no_ptr_addr_of)]
|
||||||
|
pub fn new(ptr: &'a mut T) -> Self {
|
||||||
|
Mut {
|
||||||
|
ptr: NonNull::from(ptr),
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast<U: CastTo>(self) -> Mut<'a, U::Target> {
|
||||||
|
Mut {
|
||||||
|
ptr: self.ptr.cast(),
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(anyhow_no_ptr_addr_of))]
|
||||||
|
pub fn by_ref(self) -> Ref<'a, T> {
|
||||||
|
Ref {
|
||||||
|
ptr: self.ptr,
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend<'b>(self) -> Mut<'b, T> {
|
||||||
|
Mut {
|
||||||
|
ptr: self.ptr,
|
||||||
|
lifetime: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn deref_mut(self) -> &'a mut T {
|
||||||
|
&mut *self.ptr.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Mut<'a, T> {
|
||||||
|
pub unsafe fn read(self) -> T {
|
||||||
|
self.ptr.as_ptr().read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force turbofish on all calls of `.cast::<U>()`.
|
||||||
|
pub trait CastTo {
|
||||||
|
type Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> CastTo for T {
|
||||||
|
type Target = T;
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
#[rustversion::attr(not(nightly), ignore)]
|
#[rustversion::attr(not(nightly), ignore)]
|
||||||
|
#[cfg_attr(miri, ignore)]
|
||||||
#[test]
|
#[test]
|
||||||
fn ui() {
|
fn ui() {
|
||||||
let t = trybuild::TestCases::new();
|
let t = trybuild::TestCases::new();
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::module_name_repetitions)]
|
||||||
|
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::unnecessary_wraps)]
|
||||||
|
|
||||||
mod drop;
|
mod drop;
|
||||||
|
|
||||||
use self::drop::{DetectDrop, Flag};
|
use self::drop::{DetectDrop, Flag};
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::wildcard_imports)]
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
mod drop;
|
mod drop;
|
||||||
|
|
||||||
|
@ -66,6 +68,12 @@ fn test_downcast_mut() {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut bailed = bail_fmt().unwrap_err();
|
||||||
|
*bailed.downcast_mut::<String>().unwrap() = "clobber".to_string();
|
||||||
|
assert_eq!(bailed.downcast_ref::<String>().unwrap(), "clobber");
|
||||||
|
assert_eq!(bailed.downcast_mut::<String>().unwrap(), "clobber");
|
||||||
|
assert_eq!(bailed.downcast::<String>().unwrap(), "clobber");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#![deny(improper_ctypes, improper_ctypes_definitions)]
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn anyhow1(err: anyhow::Error) {
|
||||||
|
println!("{:?}", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn anyhow2(err: &mut Option<anyhow::Error>) {
|
||||||
|
*err = Some(anyhow!("ffi error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn anyhow3() -> Option<anyhow::Error> {
|
||||||
|
Some(anyhow!("ffi error"))
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(clippy::eq_op, clippy::shadow_unrelated, clippy::wildcard_imports)]
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
use self::common::*;
|
use self::common::*;
|
||||||
|
@ -30,4 +32,13 @@ fn test_ensure() {
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
assert!(f().is_err());
|
assert!(f().is_err());
|
||||||
|
|
||||||
|
let f = || {
|
||||||
|
ensure!(v + v == 1);
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
f().unwrap_err().to_string(),
|
||||||
|
"Condition failed: `v + v == 1`",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
error[E0599]: no method named `anyhow_kind` found for reference `&Error` in the current scope
|
error[E0599]: the method `anyhow_kind` exists for reference `&Error`, but its trait bounds were not satisfied
|
||||||
--> $DIR/no-impl.rs:7:13
|
--> $DIR/no-impl.rs:7:13
|
||||||
|
|
|
|
||||||
4 | struct Error;
|
4 | struct Error;
|
||||||
| -------------
|
| -------------
|
||||||
| |
|
| |
|
||||||
| doesn't satisfy `Error: anyhow::kind::TraitKind`
|
| doesn't satisfy `Error: Into<anyhow::Error>`
|
||||||
| doesn't satisfy `Error: std::convert::Into<anyhow::Error>`
|
| doesn't satisfy `Error: anyhow::private::kind::TraitKind`
|
||||||
| doesn't satisfy `Error: std::fmt::Display`
|
| doesn't satisfy `Error: std::fmt::Display`
|
||||||
...
|
...
|
||||||
7 | let _ = anyhow!(Error);
|
7 | let _ = anyhow!(Error);
|
||||||
| ^^^^^^^^^^^^^^ method not found in `&Error`
|
| ^^^^^^^^^^^^^^ method cannot be called on `&Error` due to unsatisfied trait bounds
|
||||||
|
|
|
|
||||||
= note: the method `anyhow_kind` exists but the following trait bounds were not satisfied:
|
= note: the following trait bounds were not satisfied:
|
||||||
`Error: std::convert::Into<anyhow::Error>`
|
`Error: Into<anyhow::Error>`
|
||||||
which is required by `Error: anyhow::kind::TraitKind`
|
which is required by `Error: anyhow::private::kind::TraitKind`
|
||||||
`Error: std::fmt::Display`
|
`Error: std::fmt::Display`
|
||||||
which is required by `&Error: anyhow::kind::AdhocKind`
|
which is required by `&Error: anyhow::private::kind::AdhocKind`
|
||||||
`&Error: std::convert::Into<anyhow::Error>`
|
`&Error: Into<anyhow::Error>`
|
||||||
which is required by `&Error: anyhow::kind::TraitKind`
|
which is required by `&Error: anyhow::private::kind::TraitKind`
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
use anyhow::anyhow;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = anyhow!(&String::new());
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
error[E0716]: temporary value dropped while borrowed
|
||||||
|
--> $DIR/temporary-value.rs:4:22
|
||||||
|
|
|
||||||
|
4 | let _ = anyhow!(&String::new());
|
||||||
|
| ---------^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
|
||||||
|
| | |
|
||||||
|
| | creates a temporary which is freed while still in use
|
||||||
|
| argument requires that borrow lasts for `'static`
|
Загрузка…
Ссылка в новой задаче