diff options
author | Joel Galenson <jgalenson@google.com> | 2021-04-02 10:04:42 -0700 |
---|---|---|
committer | Joel Galenson <jgalenson@google.com> | 2021-04-02 10:06:44 -0700 |
commit | 2153686a12e98717c7a520ac6fbf6f3814a889a6 (patch) | |
tree | dd8360869e62ac9b22ce2a19ce05434856048830 | |
parent | 1d824608daa25736aea27fb7667f805023cfe4ca (diff) | |
download | anyhow-2153686a12e98717c7a520ac6fbf6f3814a889a6.tar.gz |
Upgrade rust/crates/anyhow to 1.0.40
Test: make
Change-Id: I43fcb2f4fcc9ddb5b6dccb21efc8aac90026e76b
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 19 | ||||
-rw-r--r-- | Android.bp | 38 | ||||
-rw-r--r-- | Cargo.toml | 5 | ||||
-rw-r--r-- | Cargo.toml.orig | 5 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | TEST_MAPPING | 32 | ||||
-rw-r--r-- | build.rs | 9 | ||||
-rw-r--r-- | patches/Android.bp.diff | 21 | ||||
-rw-r--r-- | src/backtrace.rs | 377 | ||||
-rw-r--r-- | src/error.rs | 157 | ||||
-rw-r--r-- | src/fmt.rs | 4 | ||||
-rw-r--r-- | src/kind.rs | 3 | ||||
-rw-r--r-- | src/lib.rs | 8 | ||||
-rw-r--r-- | src/ptr.rs | 107 | ||||
-rw-r--r-- | tests/ui/no-impl.stderr | 6 |
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 @@ -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" @@ -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" @@ -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 } } @@ -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="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" } ] } @@ -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") } @@ -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 { @@ -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)] @@ -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` |