aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-04-02 10:04:42 -0700
committerJoel Galenson <jgalenson@google.com>2021-04-02 10:06:44 -0700
commit2153686a12e98717c7a520ac6fbf6f3814a889a6 (patch)
treedd8360869e62ac9b22ce2a19ce05434856048830
parent1d824608daa25736aea27fb7667f805023cfe4ca (diff)
downloadanyhow-2153686a12e98717c7a520ac6fbf6f3814a889a6.tar.gz
Upgrade rust/crates/anyhow to 1.0.40
Test: make Change-Id: I43fcb2f4fcc9ddb5b6dccb21efc8aac90026e76b
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/ci.yml19
-rw-r--r--Android.bp38
-rw-r--r--Cargo.toml5
-rw-r--r--Cargo.toml.orig5
-rw-r--r--METADATA8
-rw-r--r--README.md4
-rw-r--r--TEST_MAPPING32
-rw-r--r--build.rs9
-rw-r--r--patches/Android.bp.diff21
-rw-r--r--src/backtrace.rs377
-rw-r--r--src/error.rs157
-rw-r--r--src/fmt.rs4
-rw-r--r--src/kind.rs3
-rw-r--r--src/lib.rs8
-rw-r--r--src/ptr.rs107
-rw-r--r--tests/ui/no-impl.stderr6
17 files changed, 701 insertions, 104 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index f2d0a8f..694bf81 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "6a16413b656f20480dc8edfa2efe01bad2b0e710"
+ "sha1": "704622f25d098b9e9925b93fbe2540745ff73f92"
}
}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4882f77..7e685ee 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- rust: [nightly, beta, stable]
+ rust: [nightly, beta, stable, 1.51.0, 1.50.0]
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@master
@@ -20,6 +20,15 @@ jobs:
toolchain: ${{matrix.rust}}
- run: cargo test
- run: cargo check --no-default-features
+ - run: cargo check --features backtrace
+
+ backtrace:
+ name: Rust 1.42.0
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: dtolnay/rust-toolchain@1.42.0
+ - run: cargo check --features backtrace
nostd:
name: Rust 1.36.0
@@ -37,6 +46,14 @@ jobs:
- uses: dtolnay/rust-toolchain@1.34.0
- run: cargo check
+ windows:
+ name: Windows
+ runs-on: windows-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: dtolnay/rust-toolchain@stable
+ - run: cargo check --features backtrace
+
clippy:
name: Clippy
runs-on: ubuntu-latest
diff --git a/Android.bp b/Android.bp
index d47df68..2b17953 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,5 @@
// This file is generated by cargo2android.py --run --device --dependencies --tests --patch=patches/Android.bp.diff.
+// Do not modify this file as changes will be overridden on upgrade.
package {
default_applicable_licenses: ["external_rust_crates_anyhow_license"],
@@ -48,6 +49,7 @@ rust_defaults {
"std",
],
flags: [
+ "--cfg anyhow_no_ptr_addr_of",
"--cfg backtrace",
],
rustlibs: [
@@ -80,6 +82,7 @@ rust_defaults {
"std",
],
flags: [
+ "--cfg anyhow_no_ptr_addr_of",
"--cfg backtrace",
],
rustlibs: [
@@ -265,6 +268,7 @@ rust_library {
"std",
],
flags: [
+ "--cfg anyhow_no_ptr_addr_of",
"--cfg backtrace",
],
apex_available: [
@@ -275,29 +279,29 @@ rust_library {
// dependent_library ["feature_list"]
// dissimilar-1.0.2
-// futures-0.3.12
-// futures-channel-0.3.12 "futures-sink,sink"
-// futures-core-0.3.12
-// futures-io-0.3.12
-// futures-sink-0.3.12
-// futures-task-0.3.12
-// futures-util-0.3.12 "futures-sink,sink"
+// futures-0.3.13
+// futures-channel-0.3.13 "futures-sink,sink"
+// futures-core-0.3.13
+// futures-io-0.3.13
+// futures-sink-0.3.13
+// futures-task-0.3.13
+// futures-util-0.3.13 "futures-sink,sink"
// glob-0.3.0
// itoa-0.4.7
// lazy_static-1.4.0
-// pin-project-lite-0.2.4
+// pin-project-lite-0.2.6
// pin-utils-0.1.0
-// proc-macro2-1.0.24 "default,proc-macro"
-// quote-1.0.8 "default,proc-macro"
+// proc-macro2-1.0.26 "default,proc-macro"
+// quote-1.0.9 "default,proc-macro"
// rustversion-1.0.4
// ryu-1.0.5
-// serde-1.0.123 "default,derive,serde_derive,std"
-// serde_derive-1.0.123 "default"
-// serde_json-1.0.62 "default,std"
-// syn-1.0.60 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote"
+// serde-1.0.125 "default,derive,serde_derive,std"
+// serde_derive-1.0.125 "default"
+// serde_json-1.0.64 "default,std"
+// syn-1.0.68 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote"
// termcolor-1.1.2
-// thiserror-1.0.23
-// thiserror-impl-1.0.23
+// thiserror-1.0.24
+// thiserror-impl-1.0.24
// toml-0.5.8 "default"
-// trybuild-1.0.40 "diff,dissimilar"
+// trybuild-1.0.41 "diff,dissimilar"
// unicode-xid-0.2.1 "default"
diff --git a/Cargo.toml b/Cargo.toml
index c36e376..09c3dbf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "anyhow"
-version = "1.0.38"
+version = "1.0.40"
authors = ["David Tolnay <dtolnay@gmail.com>"]
description = "Flexible concrete Error type built on std::error::Error"
documentation = "https://docs.rs/anyhow"
@@ -24,6 +24,9 @@ repository = "https://github.com/dtolnay/anyhow"
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "doc_cfg"]
targets = ["x86_64-unknown-linux-gnu"]
+[dependencies.backtrace]
+version = "0.3"
+optional = true
[dev-dependencies.futures]
version = "0.3"
default-features = false
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index e3f92ee..dca266a 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "anyhow"
-version = "1.0.38" # remember to update html_root_url
+version = "1.0.40" # remember to update html_root_url
authors = ["David Tolnay <dtolnay@gmail.com>"]
edition = "2018"
license = "MIT OR Apache-2.0"
@@ -14,6 +14,9 @@ categories = ["rust-patterns"]
default = ["std"]
std = []
+[dependencies]
+backtrace = { version = "0.3", optional = true }
+
[dev-dependencies]
futures = { version = "0.3", default-features = false }
rustversion = "1.0"
diff --git a/METADATA b/METADATA
index dbd4845..5c77561 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/anyhow/anyhow-1.0.38.crate"
+ value: "https://static.crates.io/crates/anyhow/anyhow-1.0.40.crate"
}
- version: "1.0.38"
+ version: "1.0.40"
license_type: NOTICE
last_upgrade_date {
year: 2021
- month: 1
- day: 11
+ month: 4
+ day: 2
}
}
diff --git a/README.md b/README.md
index 336f879..c6eb0f1 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-Anyhow&ensp;¯\\\_(ツ)\_/¯
-=========================
+Anyhow&ensp;¯\\\_(°ペ)\_/¯
+==========================
[<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)
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 835d573..2ef5af6 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,43 +2,49 @@
{
"presubmit": [
{
- "name": "anyhow_device_test_src_lib"
+ "name": "anyhow_device_test_tests_test_autotrait"
},
{
- "name": "anyhow_device_test_tests_test_source"
+ "name": "anyhow_device_test_tests_test_context"
},
{
- "name": "anyhow_device_test_tests_test_context"
+ "name": "anyhow_device_test_tests_test_repr"
},
{
- "name": "anyhow_device_test_tests_test_downcast"
+ "name": "keystore2_test"
},
{
- "name": "anyhow_device_test_tests_test_autotrait"
+ "name": "anyhow_device_test_tests_test_chain"
},
{
- "name": "anyhow_device_test_tests_test_macros"
+ "name": "anyhow_device_test_tests_test_fmt"
},
{
- "name": "anyhow_device_test_tests_test_repr"
+ "name": "anyhow_device_test_tests_test_convert"
},
{
- "name": "anyhow_device_test_tests_test_chain"
+ "name": "anyhow_device_test_tests_test_downcast"
},
{
- "name": "anyhow_device_test_tests_test_convert"
+ "name": "anyhow_device_test_tests_test_macros"
},
{
- "name": "anyhow_device_test_tests_test_ffi"
+ "name": "anyhow_device_test_tests_test_boxed"
},
{
- "name": "anyhow_device_test_tests_test_fmt"
+ "name": "keystore2_selinux_test"
},
{
- "name": "anyhow_device_test_tests_test_boxed"
+ "name": "anyhow_device_test_tests_test_source"
+ },
+ {
+ "name": "anyhow_device_test_src_lib"
+ },
+ {
+ "name": "anyhow_device_test_tests_test_ffi"
},
{
- "name": "authfs_device_test_src_lib"
+ "name": "vpnprofilestore_test"
}
]
}
diff --git a/build.rs b/build.rs
index a7dc8f2..df2e73b 100644
--- a/build.rs
+++ b/build.rs
@@ -4,6 +4,11 @@ use std::path::Path;
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
// type. If the current toolchain is able to compile it, we go ahead and use
// backtrace in anyhow.
@@ -51,6 +56,10 @@ fn main() {
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> {
diff --git a/patches/Android.bp.diff b/patches/Android.bp.diff
index a9d53ce..2959c82 100644
--- a/patches/Android.bp.diff
+++ b/patches/Android.bp.diff
@@ -1,8 +1,8 @@
diff --git a/Android.bp b/Android.bp
-index b941928..3cfbf28 100644
+index 1099708..a2e3476 100644
--- a/Android.bp
+++ b/Android.bp
-@@ -16,11 +16,8 @@ rust_defaults {
+@@ -54,11 +54,8 @@ rust_defaults {
],
rustlibs: [
"libfutures",
@@ -14,7 +14,7 @@ index b941928..3cfbf28 100644
}
rust_test_host {
-@@ -52,11 +49,8 @@ rust_defaults {
+@@ -91,11 +88,8 @@ rust_defaults {
rustlibs: [
"libanyhow",
"libfutures",
@@ -26,3 +26,18 @@ index b941928..3cfbf28 100644
}
rust_test_host {
+diff --git a/Android.bp b/Android.bp
+index ca491cf..2b17953 100644
+--- a/Android.bp
++++ b/Android.bp
+@@ -271,6 +271,10 @@ rust_library {
+ "--cfg anyhow_no_ptr_addr_of",
+ "--cfg backtrace",
+ ],
++ apex_available: [
++ "//apex_available:platform",
++ "com.android.virt",
++ ],
+ }
+
+ // dependent_library ["feature_list"]
diff --git a/src/backtrace.rs b/src/backtrace.rs
index 01e33cb..1fa20a6 100644
--- a/src/backtrace.rs
+++ b/src/backtrace.rs
@@ -1,17 +1,34 @@
#[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 {}
#[cfg(backtrace)]
+macro_rules! impl_backtrace {
+ () => {
+ std::backtrace::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(Backtrace::capture())
+ Some(crate::backtrace::Backtrace::capture())
};
}
-#[cfg(not(backtrace))]
+#[cfg(not(any(backtrace, feature = "backtrace")))]
macro_rules! backtrace {
() => {
None
@@ -23,14 +40,362 @@ macro_rules! backtrace_if_absent {
($err:expr) => {
match $err.backtrace() {
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 {
($err:expr) => {
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>();
+}
diff --git a/src/error.rs b/src/error.rs
index e7c086f..f4f5bc2 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,11 +1,15 @@
use crate::alloc::Box;
use crate::backtrace::Backtrace;
use crate::chain::Chain;
-use crate::ptr::{Mut, Own, Ref};
+#[cfg(any(feature = "std", anyhow_no_ptr_addr_of))]
+use crate::ptr::Mut;
+use crate::ptr::{Own, Ref};
use crate::{Error, StdError};
use core::any::TypeId;
use core::fmt::{self, Debug, Display};
use core::mem::ManuallyDrop;
+#[cfg(not(anyhow_no_ptr_addr_of))]
+use core::ptr;
use core::ptr::NonNull;
#[cfg(feature = "std")]
@@ -81,11 +85,15 @@ impl Error {
let vtable = &ErrorVTable {
object_drop: object_drop::<E>,
object_ref: object_ref::<E>,
+ #[cfg(anyhow_no_ptr_addr_of)]
object_mut: object_mut::<E>,
object_boxed: object_boxed::<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>,
+ #[cfg(all(not(backtrace), feature = "backtrace"))]
+ object_backtrace: no_backtrace,
};
// Safety: passing vtable that operates on the right type E.
@@ -101,12 +109,15 @@ impl Error {
let vtable = &ErrorVTable {
object_drop: object_drop::<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_boxed: object_boxed::<MessageError<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>,
+ #[cfg(all(not(backtrace), feature = "backtrace"))]
+ object_backtrace: no_backtrace,
};
// Safety: MessageError is repr(transparent) so it is okay for the
@@ -123,12 +134,15 @@ impl Error {
let vtable = &ErrorVTable {
object_drop: object_drop::<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_boxed: object_boxed::<DisplayError<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>,
+ #[cfg(all(not(backtrace), feature = "backtrace"))]
+ object_backtrace: no_backtrace,
};
// Safety: DisplayError is repr(transparent) so it is okay for the
@@ -147,11 +161,15 @@ impl Error {
let vtable = &ErrorVTable {
object_drop: object_drop::<ContextError<C, E>>,
object_ref: object_ref::<ContextError<C, E>>,
+ #[cfg(anyhow_no_ptr_addr_of)]
object_mut: object_mut::<ContextError<C, E>>,
object_boxed: object_boxed::<ContextError<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>,
+ #[cfg(all(not(backtrace), feature = "backtrace"))]
+ object_backtrace: no_backtrace,
};
// Safety: passing vtable that operates on the right type.
@@ -168,11 +186,15 @@ impl Error {
let vtable = &ErrorVTable {
object_drop: object_drop::<BoxedError>,
object_ref: object_ref::<BoxedError>,
+ #[cfg(anyhow_no_ptr_addr_of)]
object_mut: object_mut::<BoxedError>,
object_boxed: object_boxed::<BoxedError>,
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>>,
+ #[cfg(all(not(backtrace), feature = "backtrace"))]
+ object_backtrace: no_backtrace,
};
// Safety: BoxedError is repr(transparent) so it is okay for the vtable
@@ -274,12 +296,15 @@ impl Error {
let vtable = &ErrorVTable {
object_drop: object_drop::<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_boxed: object_boxed::<ContextError<C, Error>>,
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>,
+ #[cfg(all(not(backtrace), feature = "backtrace"))]
+ object_backtrace: context_backtrace::<C>,
};
// As the cause is anyhow::Error, we already have a backtrace for it.
@@ -291,9 +316,6 @@ impl 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
/// variables `RUST_LIB_BACKTRACE=1` or `RUST_BACKTRACE=1` must be defined
/// and `RUST_LIB_BACKTRACE` must not be `0`. Backtraces are somewhat
@@ -307,9 +329,24 @@ impl Error {
/// - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
/// `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
- #[cfg(backtrace)]
- pub fn backtrace(&self) -> &Backtrace {
+ #[cfg(any(backtrace, feature = "backtrace"))]
+ #[cfg_attr(doc_cfg, doc(cfg(any(nightly, feature = "backtrace"))))]
+ pub fn backtrace(&self) -> &impl_backtrace!() {
unsafe { ErrorImpl::backtrace(self.inner.by_ref()) }
}
@@ -372,14 +409,20 @@ impl Error {
E: Display + Debug + Send + Sync + 'static,
{
let target = TypeId::of::<E>();
+ let inner = self.inner.by_mut();
unsafe {
// Use vtable to find NonNull<()> which points to a value of type E
// somewhere inside the data structure.
- let addr =
- match (vtable(self.inner.ptr).object_downcast_mut)(self.inner.by_mut(), target) {
- Some(addr) => addr.extend(),
- None => return Err(self),
- };
+ #[cfg(not(anyhow_no_ptr_addr_of))]
+ 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),
+ };
// Prepare to read E out of the data structure. We'll drop the rest
// of the data structure separately so that E is not dropped.
@@ -453,7 +496,14 @@ impl Error {
unsafe {
// Use vtable to find NonNull<()> which points to a value of type E
// somewhere inside the data structure.
+
+ #[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())
}
}
@@ -512,13 +562,16 @@ impl Drop for Error {
struct ErrorVTable {
object_drop: unsafe fn(Own<ErrorImpl>),
- object_ref: unsafe fn(Ref<ErrorImpl>) -> &(dyn StdError + Send + Sync + 'static),
- #[cfg(feature = "std")]
+ object_ref: unsafe fn(Ref<ErrorImpl>) -> Ref<dyn StdError + Send + Sync + 'static>,
+ #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
object_mut: unsafe fn(Mut<ErrorImpl>) -> &mut (dyn StdError + Send + Sync + 'static),
object_boxed: unsafe fn(Own<ErrorImpl>) -> Box<dyn StdError + Send + Sync + 'static>,
object_downcast: unsafe fn(Ref<ErrorImpl>, TypeId) -> Option<Ref<()>>,
+ #[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>.
@@ -540,17 +593,26 @@ unsafe fn object_drop_front<E>(e: Own<ErrorImpl>, target: TypeId) {
}
// Safety: requires layout of *e to match ErrorImpl<E>.
-unsafe fn object_ref<E>(e: Ref<ErrorImpl>) -> &(dyn StdError + Send + Sync + 'static)
+unsafe fn object_ref<E>(e: Ref<ErrorImpl>) -> Ref<dyn StdError + Send + Sync + 'static>
where
E: StdError + Send + Sync + 'static,
{
// Attach E's native StdError vtable onto a pointer to self._object.
- &e.cast::<ErrorImpl<E>>().deref()._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>, and for `e` to be derived
// from a `&mut`
-#[cfg(feature = "std")]
+#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))]
unsafe fn object_mut<E>(e: Mut<ErrorImpl>) -> &mut (dyn StdError + Send + Sync + 'static)
where
E: StdError + Send + Sync + 'static,
@@ -576,14 +638,26 @@ where
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();
- Some(Ref::new(&unerased._object).cast::<()>())
+
+ let unerased = e.cast::<ErrorImpl<E>>();
+
+ #[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 {
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,
@@ -598,6 +672,12 @@ where
}
}
+#[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>>.
#[cfg(feature = "std")]
unsafe fn context_downcast<C, E>(e: Ref<ErrorImpl>, target: TypeId) -> Option<Ref<()>>
@@ -617,7 +697,7 @@ where
}
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, E>>.
-#[cfg(feature = "std")]
+#[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,
@@ -673,6 +753,7 @@ where
}
// Safety: requires layout of *e to match ErrorImpl<ContextError<C, Error>>.
+#[cfg(anyhow_no_ptr_addr_of)]
unsafe fn context_chain_downcast_mut<C>(e: Mut<ErrorImpl>, target: TypeId) -> Option<Mut<()>>
where
C: 'static,
@@ -714,6 +795,18 @@ where
}
}
+// 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.
@@ -754,17 +847,24 @@ impl ErrorImpl {
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
// original type E.
- (vtable(this.ptr).object_ref)(this)
+ (vtable(this.ptr).object_ref)(this).deref()
}
#[cfg(feature = "std")]
pub(crate) unsafe fn error_mut(this: Mut<Self>) -> &mut (dyn StdError + Send + Sync + 'static) {
// Use vtable to attach E's native StdError vtable for the right
// original type E.
- (vtable(this.ptr).object_mut)(this)
+
+ #[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) unsafe fn backtrace(this: Ref<Self>) -> &Backtrace {
// This unwrap can only panic if the underlying error's backtrace method
// is nondeterministic, which would only happen in maliciously
@@ -772,7 +872,12 @@ impl ErrorImpl {
this.deref()
.backtrace
.as_ref()
- .or_else(|| Self::error(this).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")
}
diff --git a/src/fmt.rs b/src/fmt.rs
index 68f6755..03d8fd3 100644
--- a/src/fmt.rs
+++ b/src/fmt.rs
@@ -39,9 +39,9 @@ impl ErrorImpl {
}
}
- #[cfg(backtrace)]
+ #[cfg(any(backtrace, feature = "backtrace"))]
{
- use std::backtrace::BacktraceStatus;
+ use crate::backtrace::BacktraceStatus;
let backtrace = Self::backtrace(this);
if let BacktraceStatus::Captured = backtrace.status() {
diff --git a/src/kind.rs b/src/kind.rs
index fdeb060..eb8d604 100644
--- a/src/kind.rs
+++ b/src/kind.rs
@@ -50,9 +50,6 @@ use core::fmt::{Debug, Display};
#[cfg(feature = "std")]
use crate::StdError;
-#[cfg(backtrace)]
-use std::backtrace::Backtrace;
-
pub struct Adhoc;
pub trait AdhocKind: Sized {
diff --git a/src/lib.rs b/src/lib.rs
index c8bc599..d6d70cf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -209,18 +209,21 @@
//! 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.
-#![doc(html_root_url = "https://docs.rs/anyhow/1.0.38")]
+#![doc(html_root_url = "https://docs.rs/anyhow/1.0.40")]
#![cfg_attr(backtrace, feature(backtrace))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
+#![deny(dead_code, unused_imports, unused_mut)]
#![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::new_ret_no_self,
+ clippy::redundant_else,
clippy::unused_self,
clippy::used_underscore_binding,
clippy::wildcard_imports,
@@ -612,9 +615,6 @@ pub mod private {
use crate::Error;
use core::fmt::{Debug, Display};
- #[cfg(backtrace)]
- use std::backtrace::Backtrace;
-
pub use core::result::Result::Err;
#[doc(hidden)]
diff --git a/src/ptr.rs b/src/ptr.rs
index bcfdc6d..6840833 100644
--- a/src/ptr.rs
+++ b/src/ptr.rs
@@ -3,27 +3,39 @@ use core::marker::PhantomData;
use core::ptr::NonNull;
#[repr(transparent)]
-pub struct Own<T> {
+pub struct Own<T>
+where
+ T: ?Sized,
+{
pub ptr: NonNull<T>,
}
-unsafe impl<T> Send for Own<T> {}
-unsafe impl<T> Sync for Own<T> {}
-impl<T> Copy for Own<T> {}
-impl<T> Clone for Own<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> {
+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>(self) -> Own<U> {
+ pub fn cast<U: CastTo>(self) -> Own<U::Target> {
Own {
ptr: self.ptr.cast(),
}
@@ -49,19 +61,29 @@ impl<T> Own<T> {
}
#[repr(transparent)]
-pub struct Ref<'a, T> {
+pub struct Ref<'a, T>
+where
+ T: ?Sized,
+{
pub ptr: NonNull<T>,
lifetime: PhantomData<&'a T>,
}
-impl<'a, T> Copy for Ref<'a, T> {}
-impl<'a, T> Clone for Ref<'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> {
+impl<'a, T> Ref<'a, T>
+where
+ T: ?Sized,
+{
pub fn new(ptr: &'a T) -> Self {
Ref {
ptr: NonNull::from(ptr),
@@ -69,32 +91,64 @@ impl<'a, T> Ref<'a, T> {
}
}
- pub fn cast<U>(self) -> Ref<'a, U> {
+ #[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> {
+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> {}
-impl<'a, T> Clone for Mut<'a, 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> {
+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),
@@ -102,13 +156,21 @@ impl<'a, T> Mut<'a, T> {
}
}
- pub fn cast<U>(self) -> Mut<'a, U> {
+ 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,
@@ -119,8 +181,19 @@ impl<'a, T> Mut<'a, T> {
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;
+}
diff --git a/tests/ui/no-impl.stderr b/tests/ui/no-impl.stderr
index 0af29af..a4a829b 100644
--- a/tests/ui/no-impl.stderr
+++ b/tests/ui/no-impl.stderr
@@ -1,4 +1,4 @@
-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
|
4 | struct Error;
@@ -9,9 +9,9 @@ error[E0599]: no method named `anyhow_kind` found for reference `&Error` in the
| doesn't satisfy `Error: std::fmt::Display`
...
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: Into<anyhow::Error>`
which is required by `Error: anyhow::private::kind::TraitKind`
`Error: std::fmt::Display`