aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 01:04:44 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 01:04:44 +0000
commit8ace054e8beded7d221a271c81995729c7055914 (patch)
treefbd871b491dbc21eaaf6404fa69d2bb888876cb5
parent1bbcb10399b16c086bff6e8f054cc2e3f6ea202c (diff)
parentf9551be63242edf33268776fd81b1c30ec8dbe80 (diff)
downloadthiserror-aml_cbr_341610000.tar.gz
Change-Id: Ib5af5c8aed0fc370a95c07a199f42ce16b547f80
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/ci.yml42
-rw-r--r--Android.bp6
-rw-r--r--Cargo.toml16
-rw-r--r--Cargo.toml.orig18
-rw-r--r--METADATA12
-rw-r--r--README.md34
-rw-r--r--TEST_MAPPING118
-rw-r--r--build.rs66
-rw-r--r--cargo2android.json5
-rw-r--r--src/aserror.rs9
-rw-r--r--src/lib.rs44
-rw-r--r--src/provide.rs15
-rw-r--r--tests/compiletest.rs3
-rw-r--r--tests/test_backtrace.rs85
-rw-r--r--tests/test_deprecated.rs10
-rw-r--r--tests/test_display.rs33
-rw-r--r--tests/test_error.rs1
-rw-r--r--tests/test_expr.rs3
-rw-r--r--tests/test_from.rs2
-rw-r--r--tests/test_generics.rs2
-rw-r--r--tests/test_option.rs6
-rw-r--r--tests/test_path.rs2
-rw-r--r--tests/test_source.rs2
-rw-r--r--tests/test_transparent.rs2
-rw-r--r--tests/ui/concat-display.stderr2
-rw-r--r--tests/ui/from-backtrace-backtrace.rs10
-rw-r--r--tests/ui/from-backtrace-backtrace.stderr5
-rw-r--r--tests/ui/no-display.stderr36
-rw-r--r--tests/ui/source-enum-not-error.stderr46
-rw-r--r--tests/ui/source-struct-not-error.stderr44
31 files changed, 429 insertions, 252 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index cafa20e..302d141 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "672e9525bbc2e5682c380d36974f34716b963591"
+ "sha1": "74bfe75eb25ba9d39b0ae5b570d611855cbc5086"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 61714b6..e1db2ed 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,6 +5,12 @@ on:
pull_request:
schedule: [cron: "40 1 * * *"]
+permissions:
+ contents: read
+
+env:
+ RUSTFLAGS: -Dwarnings
+
jobs:
test:
name: Rust ${{matrix.rust}}
@@ -12,41 +18,61 @@ jobs:
strategy:
fail-fast: false
matrix:
- rust: [beta, stable, 1.36.0]
+ rust: [beta, stable, 1.56.0]
include:
- rust: nightly
rustflags: --cfg thiserror_nightly_testing
+ timeout-minutes: 45
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
components: rust-src
- run: cargo test --all
env:
- RUSTFLAGS: ${{matrix.rustflags}}
+ RUSTFLAGS: ${{matrix.rustflags}} ${{env.RUSTFLAGS}}
msrv:
name: Rust 1.31.0
runs-on: ubuntu-latest
+ timeout-minutes: 45
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@1.31.0
+ with:
+ components: rust-src
- run: cargo check
clippy:
name: Clippy
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
+ timeout-minutes: 45
steps:
- - uses: actions/checkout@v2
- - uses: dtolnay/rust-toolchain@clippy
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@nightly
+ with:
+ components: clippy, rust-src
- run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic
+ miri:
+ name: Miri
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v3
+ - uses: dtolnay/rust-toolchain@miri
+ - run: cargo miri test
+ env:
+ MIRIFLAGS: -Zmiri-strict-provenance
+
outdated:
name: Outdated
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
+ timeout-minutes: 45
steps:
- - uses: actions/checkout@v2
- - run: cargo outdated --exit-code 1
+ - uses: actions/checkout@v3
+ - uses: dtolnay/install@cargo-outdated
+ - run: cargo outdated --workspace --exit-code 1
diff --git a/Android.bp b/Android.bp
index b1dc159..8081558 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,18 +42,20 @@ rust_library {
host_supported: true,
crate_name: "thiserror",
cargo_env_compat: true,
- cargo_pkg_version: "1.0.30",
+ cargo_pkg_version: "1.0.38",
srcs: ["src/lib.rs"],
edition: "2018",
+ cfgs: ["provide_any"],
proc_macros: ["libthiserror_impl"],
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.compos",
"com.android.resolv",
"com.android.uwb",
"com.android.virt",
],
+ product_available: true,
vendor_available: true,
min_sdk_version: "29",
}
diff --git a/Cargo.toml b/Cargo.toml
index 78c99d6..e235408 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,20 +13,28 @@
edition = "2018"
rust-version = "1.31"
name = "thiserror"
-version = "1.0.30"
+version = "1.0.38"
authors = ["David Tolnay <dtolnay@gmail.com>"]
description = "derive(Error)"
documentation = "https://docs.rs/thiserror"
readme = "README.md"
+keywords = [
+ "error",
+ "error-handling",
+ "derive",
+]
categories = ["rust-patterns"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/dtolnay/thiserror"
+
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
+
[dependencies.thiserror-impl]
-version = "=1.0.30"
+version = "=1.0.38"
+
[dev-dependencies.anyhow]
-version = "1.0"
+version = "1.0.65"
[dev-dependencies.ref-cast]
version = "1.0"
@@ -35,5 +43,5 @@ version = "1.0"
version = "1.0"
[dev-dependencies.trybuild]
-version = "1.0.49"
+version = "1.0.66"
features = ["diff"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index efa9af1..82ef03d 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,24 +1,24 @@
[package]
name = "thiserror"
-version = "1.0.30"
+version = "1.0.38"
authors = ["David Tolnay <dtolnay@gmail.com>"]
+categories = ["rust-patterns"]
+description = "derive(Error)"
+documentation = "https://docs.rs/thiserror"
edition = "2018"
-rust-version = "1.31"
+keywords = ["error", "error-handling", "derive"]
license = "MIT OR Apache-2.0"
-description = "derive(Error)"
repository = "https://github.com/dtolnay/thiserror"
-documentation = "https://docs.rs/thiserror"
-categories = ["rust-patterns"]
-readme = "README.md"
+rust-version = "1.31"
[dependencies]
-thiserror-impl = { version = "=1.0.30", path = "impl" }
+thiserror-impl = { version = "=1.0.38", path = "impl" }
[dev-dependencies]
-anyhow = "1.0"
+anyhow = "1.0.65"
ref-cast = "1.0"
rustversion = "1.0"
-trybuild = { version = "1.0.49", features = ["diff"] }
+trybuild = { version = "1.0.66", features = ["diff"] }
[workspace]
members = ["impl"]
diff --git a/METADATA b/METADATA
index e961418..db2395f 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/thiserror
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "thiserror"
description: "derive(Error)"
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/thiserror/thiserror-1.0.30.crate"
+ value: "https://static.crates.io/crates/thiserror/thiserror-1.0.38.crate"
}
- version: "1.0.30"
+ version: "1.0.38"
license_type: NOTICE
last_upgrade_date {
year: 2022
- month: 3
- day: 1
+ month: 12
+ day: 19
}
}
diff --git a/README.md b/README.md
index e12b693..3ba375f 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@ derive(Error)
[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/thiserror-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/thiserror)
[<img alt="crates.io" src="https://img.shields.io/crates/v/thiserror.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/thiserror)
-[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-thiserror-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/thiserror)
-[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/thiserror/CI/master?style=for-the-badge" height="20">](https://github.com/dtolnay/thiserror/actions?query=branch%3Amaster)
+[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-thiserror-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/thiserror)
+[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/thiserror/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/thiserror/actions?query=branch%3Amaster)
This library provides a convenient derive macro for the standard library's
[`std::error::Error`] trait.
@@ -124,8 +124,8 @@ pub enum DataStoreError {
}
```
-- The Error trait's `backtrace()` method is implemented to return whichever
- field has a type named `Backtrace`, if any.
+- The Error trait's `provide()` method is implemented to provide whichever field
+ has a type named `Backtrace`, if any, as a `std::backtrace::Backtrace`.
```rust
use std::backtrace::Backtrace;
@@ -138,8 +138,9 @@ pub enum DataStoreError {
```
- If a field is both a source (named `source`, or has `#[source]` or `#[from]`
- attribute) *and* is marked `#[backtrace]`, then the Error trait's
- `backtrace()` method is forwarded to the source's backtrace.
+ attribute) *and* is marked `#[backtrace]`, then the Error trait's `provide()`
+ method is forwarded to the source's `provide` so that both layers of the error
+ share the same backtrace.
```rust
#[derive(Error, Debug)]
@@ -165,6 +166,27 @@ pub enum DataStoreError {
}
```
+ Another use case is hiding implementation details of an error representation
+ behind an opaque error type, so that the representation is able to evolve
+ without breaking the crate's public API.
+
+ ```rust
+ // PublicError is public, but opaque and easy to keep compatible.
+ #[derive(Error, Debug)]
+ #[error(transparent)]
+ pub struct PublicError(#[from] ErrorRepr);
+
+ impl PublicError {
+ // Accessors for anything we do want to expose publicly.
+ }
+
+ // Private and free to change across minor version of the crate.
+ #[derive(Error, Debug)]
+ enum ErrorRepr {
+ ...
+ }
+ ```
+
- See also the [`anyhow`] library for a convenient single error type to use in
application code.
diff --git a/TEST_MAPPING b/TEST_MAPPING
index eea7991..6b4c996 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -9,142 +9,60 @@
},
{
"path": "external/rust/crates/serde-xml-rs"
- }
- ],
- "presubmit": [
- {
- "name": "ZipFuseTest"
- },
- {
- "name": "apkdmverity.test"
- },
- {
- "name": "authfs_device_test_src_lib"
- },
- {
- "name": "diced_open_dice_cbor_test"
- },
- {
- "name": "diced_sample_inputs_test"
- },
- {
- "name": "diced_test"
- },
- {
- "name": "diced_utils_test"
- },
- {
- "name": "diced_vendor_test"
- },
- {
- "name": "doh_unit_test"
- },
- {
- "name": "keystore2_crypto_test_rust"
- },
- {
- "name": "keystore2_selinux_concurrency_test"
- },
- {
- "name": "keystore2_selinux_test"
- },
- {
- "name": "keystore2_test"
- },
- {
- "name": "keystore2_test_utils_test"
- },
- {
- "name": "keystore2_vintf_test"
- },
- {
- "name": "legacykeystore_test"
- },
- {
- "name": "libapkverify.integration_test"
- },
- {
- "name": "libapkverify.test"
- },
- {
- "name": "libcert_request_validator_tests"
- },
- {
- "name": "librustutils_test"
- },
- {
- "name": "microdroid_manager_test"
- },
- {
- "name": "virtualizationservice_device_test"
- }
- ],
- "presubmit-rust": [
- {
- "name": "ZipFuseTest"
- },
- {
- "name": "apkdmverity.test"
- },
- {
- "name": "authfs_device_test_src_lib"
- },
- {
- "name": "diced_open_dice_cbor_test"
},
{
- "name": "diced_sample_inputs_test"
+ "path": "external/uwb/src"
},
{
- "name": "diced_test"
+ "path": "packages/modules/DnsResolver"
},
{
- "name": "diced_utils_test"
+ "path": "packages/modules/Virtualization/apkdmverity"
},
{
- "name": "diced_vendor_test"
+ "path": "packages/modules/Virtualization/authfs"
},
{
- "name": "doh_unit_test"
+ "path": "packages/modules/Virtualization/avmd"
},
{
- "name": "keystore2_crypto_test_rust"
+ "path": "packages/modules/Virtualization/encryptedstore"
},
{
- "name": "keystore2_selinux_concurrency_test"
+ "path": "packages/modules/Virtualization/libs/apexutil"
},
{
- "name": "keystore2_selinux_test"
+ "path": "packages/modules/Virtualization/libs/devicemapper"
},
{
- "name": "keystore2_test"
+ "path": "packages/modules/Virtualization/microdroid_manager"
},
{
- "name": "keystore2_test_utils_test"
+ "path": "packages/modules/Virtualization/virtualizationmanager"
},
{
- "name": "keystore2_vintf_test"
+ "path": "packages/modules/Virtualization/vm"
},
{
- "name": "legacykeystore_test"
+ "path": "packages/modules/Virtualization/zipfuse"
},
{
- "name": "libapkverify.integration_test"
+ "path": "system/keymint/hal"
},
{
- "name": "libapkverify.test"
+ "path": "system/security/diced"
},
{
- "name": "libcert_request_validator_tests"
+ "path": "system/security/keystore2"
},
{
- "name": "librustutils_test"
+ "path": "system/security/keystore2/legacykeystore"
},
{
- "name": "microdroid_manager_test"
+ "path": "system/security/keystore2/selinux"
},
{
- "name": "virtualizationservice_device_test"
+ "path": "system/security/keystore2/src/crypto"
}
]
}
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..004dfb0
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,66 @@
+use std::env;
+use std::fs;
+use std::path::Path;
+use std::process::{Command, ExitStatus, Stdio};
+use std::str;
+
+// This code exercises the surface area that we expect of the Provider API. If
+// the current toolchain is able to compile it, then thiserror is able to use
+// providers for backtrace support.
+const PROBE: &str = r#"
+ #![feature(provide_any)]
+
+ use std::any::{Demand, Provider};
+
+ fn _f<'a, P: Provider>(p: &'a P, demand: &mut Demand<'a>) {
+ p.provide(demand);
+ }
+"#;
+
+fn main() {
+ match compile_probe() {
+ Some(status) if status.success() => println!("cargo:rustc-cfg=provide_any"),
+ _ => {}
+ }
+}
+
+fn compile_probe() -> Option<ExitStatus> {
+ let rustc = env::var_os("RUSTC")?;
+ let out_dir = env::var_os("OUT_DIR")?;
+ let probefile = Path::new(&out_dir).join("probe.rs");
+ fs::write(&probefile, PROBE).ok()?;
+
+ // Make sure to pick up Cargo rustc configuration.
+ let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
+ let mut cmd = Command::new(wrapper);
+ // The wrapper's first argument is supposed to be the path to rustc.
+ cmd.arg(rustc);
+ cmd
+ } else {
+ Command::new(rustc)
+ };
+
+ cmd.stderr(Stdio::null())
+ .arg("--edition=2018")
+ .arg("--crate-name=thiserror_build")
+ .arg("--crate-type=lib")
+ .arg("--emit=metadata")
+ .arg("--out-dir")
+ .arg(out_dir)
+ .arg(probefile);
+
+ if let Some(target) = env::var_os("TARGET") {
+ cmd.arg("--target").arg(target);
+ }
+
+ // If Cargo wants to set RUSTFLAGS, use that.
+ if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
+ if !rustflags.is_empty() {
+ for arg in rustflags.split('\x1f') {
+ cmd.arg(arg);
+ }
+ }
+ }
+
+ cmd.status().ok()
+}
diff --git a/cargo2android.json b/cargo2android.json
index 9a52406..7d5c2b4 100644
--- a/cargo2android.json
+++ b/cargo2android.json
@@ -1,7 +1,7 @@
{
"apex-available": [
"//apex_available:platform",
- "com.android.bluetooth",
+ "com.android.btservices",
"com.android.compos",
"com.android.resolv",
"com.android.uwb",
@@ -11,5 +11,6 @@
"device": true,
"min-sdk-version": "29",
"run": true,
- "vendor-available": true
+ "vendor-available": true,
+ "product-available": true
}
diff --git a/src/aserror.rs b/src/aserror.rs
index c036b7b..5fea84e 100644
--- a/src/aserror.rs
+++ b/src/aserror.rs
@@ -1,7 +1,7 @@
use std::error::Error;
use std::panic::UnwindSafe;
-pub trait AsDynError<'a> {
+pub trait AsDynError<'a>: Sealed {
fn as_dyn_error(&self) -> &(dyn Error + 'a);
}
@@ -39,3 +39,10 @@ impl<'a> AsDynError<'a> for dyn Error + Send + Sync + UnwindSafe + 'a {
self
}
}
+
+pub trait Sealed {}
+impl<'a, T: Error + 'a> Sealed for T {}
+impl<'a> Sealed for dyn Error + 'a {}
+impl<'a> Sealed for dyn Error + Send + 'a {}
+impl<'a> Sealed for dyn Error + Send + Sync + 'a {}
+impl<'a> Sealed for dyn Error + Send + Sync + UnwindSafe + 'a {}
diff --git a/src/lib.rs b/src/lib.rs
index 2fae25c..aae6552 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,7 +2,7 @@
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
-//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
+//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
//!
//! <br>
//!
@@ -146,8 +146,9 @@
//! # }
//! ```
//!
-//! - The Error trait's `backtrace()` method is implemented to return whichever
-//! field has a type named `Backtrace`, if any.
+//! - The Error trait's `provide()` method is implemented to provide whichever
+//! field has a type named `Backtrace`, if any, as a
+//! `std::backtrace::Backtrace`.
//!
//! ```rust
//! # const IGNORE: &str = stringify! {
@@ -163,7 +164,8 @@
//!
//! - If a field is both a source (named `source`, or has `#[source]` or
//! `#[from]` attribute) *and* is marked `#[backtrace]`, then the Error
-//! trait's `backtrace()` method is forwarded to the source's backtrace.
+//! trait's `provide()` method is forwarded to the source's `provide` so that
+//! both layers of the error share the same backtrace.
//!
//! ```rust
//! # const IGNORE: &str = stringify! {
@@ -196,6 +198,31 @@
//! }
//! ```
//!
+//! Another use case is hiding implementation details of an error
+//! representation behind an opaque error type, so that the representation is
+//! able to evolve without breaking the crate's public API.
+//!
+//! ```
+//! # use thiserror::Error;
+//! #
+//! // PublicError is public, but opaque and easy to keep compatible.
+//! #[derive(Error, Debug)]
+//! #[error(transparent)]
+//! pub struct PublicError(#[from] ErrorRepr);
+//!
+//! impl PublicError {
+//! // Accessors for anything we do want to expose publicly.
+//! }
+//!
+//! // Private and free to change across minor version of the crate.
+//! #[derive(Error, Debug)]
+//! enum ErrorRepr {
+//! # /*
+//! ...
+//! # */
+//! }
+//! ```
+//!
//! - See also the [`anyhow`] library for a convenient single error type to use
//! in application code.
//!
@@ -205,16 +232,23 @@
// Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7421
clippy::doc_markdown,
clippy::module_name_repetitions,
+ clippy::return_self_not_must_use,
+ clippy::wildcard_imports,
)]
+#![cfg_attr(provide_any, feature(provide_any))]
mod aserror;
mod display;
+#[cfg(provide_any)]
+mod provide;
pub use thiserror_impl::*;
// Not public API.
#[doc(hidden)]
-pub mod private {
+pub mod __private {
pub use crate::aserror::AsDynError;
pub use crate::display::{DisplayAsDisplay, PathAsDisplay};
+ #[cfg(provide_any)]
+ pub use crate::provide::ThiserrorProvide;
}
diff --git a/src/provide.rs b/src/provide.rs
new file mode 100644
index 0000000..524e743
--- /dev/null
+++ b/src/provide.rs
@@ -0,0 +1,15 @@
+use std::any::{Demand, Provider};
+
+pub trait ThiserrorProvide: Sealed {
+ fn thiserror_provide<'a>(&'a self, demand: &mut Demand<'a>);
+}
+
+impl<T: Provider + ?Sized> ThiserrorProvide for T {
+ #[inline]
+ fn thiserror_provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ self.provide(demand);
+ }
+}
+
+pub trait Sealed {}
+impl<T: Provider + ?Sized> Sealed for T {}
diff --git a/tests/compiletest.rs b/tests/compiletest.rs
index 641d03c..7974a62 100644
--- a/tests/compiletest.rs
+++ b/tests/compiletest.rs
@@ -1,6 +1,5 @@
-#![deny(clippy::all, clippy::pedantic)]
-
#[rustversion::attr(not(nightly), ignore)]
+#[cfg_attr(miri, ignore)]
#[test]
fn ui() {
let t = trybuild::TestCases::new();
diff --git a/tests/test_backtrace.rs b/tests/test_backtrace.rs
index 42e37ca..43f68b8 100644
--- a/tests/test_backtrace.rs
+++ b/tests/test_backtrace.rs
@@ -1,4 +1,7 @@
-#![cfg_attr(thiserror_nightly_testing, feature(backtrace))]
+#![cfg_attr(
+ thiserror_nightly_testing,
+ feature(error_generic_member_access, provide_any)
+)]
use thiserror::Error;
@@ -16,6 +19,7 @@ pub struct InnerBacktrace {
#[cfg(thiserror_nightly_testing)]
pub mod structs {
use super::{Inner, InnerBacktrace};
+ use std::any;
use std::backtrace::Backtrace;
use std::error::Error;
use std::sync::Arc;
@@ -83,49 +87,94 @@ pub mod structs {
backtrace: Arc<Backtrace>,
}
+ #[derive(Error, Debug)]
+ #[error("...")]
+ pub struct AnyhowBacktrace {
+ #[backtrace]
+ source: anyhow::Error,
+ }
+
+ #[derive(Error, Debug)]
+ #[error("...")]
+ pub struct BoxDynErrorBacktrace {
+ #[backtrace]
+ source: Box<dyn Error>,
+ }
+
#[test]
fn test_backtrace() {
let error = PlainBacktrace {
backtrace: Backtrace::capture(),
};
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = ExplicitBacktrace {
backtrace: Backtrace::capture(),
};
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = OptBacktrace {
backtrace: Some(Backtrace::capture()),
};
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = ArcBacktrace {
backtrace: Arc::new(Backtrace::capture()),
};
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = BacktraceFrom::from(Inner);
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = CombinedBacktraceFrom::from(InnerBacktrace {
backtrace: Backtrace::capture(),
});
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = OptBacktraceFrom::from(Inner);
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = ArcBacktraceFrom::from(Inner);
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
+
+ let error = AnyhowBacktrace {
+ source: anyhow::Error::msg("..."),
+ };
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
+
+ let error = BoxDynErrorBacktrace {
+ source: Box::new(PlainBacktrace {
+ backtrace: Backtrace::capture(),
+ }),
+ };
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
+ }
+
+ // https://github.com/dtolnay/thiserror/issues/185 -- std::error::Error and
+ // std::any::Provide both have a method called 'provide', so directly
+ // calling it from generated code could be ambiguous.
+ #[test]
+ fn test_provide_name_collision() {
+ use std::any::Provider;
+
+ #[derive(Error, Debug)]
+ #[error("...")]
+ struct MyError {
+ #[source]
+ #[backtrace]
+ x: std::io::Error,
+ }
+
+ let _: dyn Error;
+ let _: dyn Provider;
}
}
#[cfg(thiserror_nightly_testing)]
pub mod enums {
use super::{Inner, InnerBacktrace};
+ use std::any;
use std::backtrace::Backtrace;
- use std::error::Error;
use std::sync::Arc;
use thiserror::Error;
@@ -210,36 +259,36 @@ pub mod enums {
let error = PlainBacktrace::Test {
backtrace: Backtrace::capture(),
};
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = ExplicitBacktrace::Test {
backtrace: Backtrace::capture(),
};
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = OptBacktrace::Test {
backtrace: Some(Backtrace::capture()),
};
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = ArcBacktrace::Test {
backtrace: Arc::new(Backtrace::capture()),
};
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = BacktraceFrom::from(Inner);
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = CombinedBacktraceFrom::from(InnerBacktrace {
backtrace: Backtrace::capture(),
});
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = OptBacktraceFrom::from(Inner);
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
let error = ArcBacktraceFrom::from(Inner);
- assert!(error.backtrace().is_some());
+ assert!(any::request_ref::<Backtrace>(&error).is_some());
}
}
diff --git a/tests/test_deprecated.rs b/tests/test_deprecated.rs
new file mode 100644
index 0000000..5524666
--- /dev/null
+++ b/tests/test_deprecated.rs
@@ -0,0 +1,10 @@
+#![deny(deprecated, clippy::all, clippy::pedantic)]
+
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+ #[deprecated]
+ #[error("...")]
+ Deprecated,
+}
diff --git a/tests/test_display.rs b/tests/test_display.rs
index 949d9ed..99ce2fd 100644
--- a/tests/test_display.rs
+++ b/tests/test_display.rs
@@ -1,6 +1,4 @@
-#![deny(clippy::all, clippy::pedantic)]
-
-use std::fmt::Display;
+use std::fmt::{self, Display};
use thiserror::Error;
fn assert<T: Display>(expected: &str, value: T) {
@@ -144,6 +142,35 @@ fn test_match() {
}
#[test]
+fn test_nested_display() {
+ // Same behavior as the one in `test_match`, but without String allocations.
+ #[derive(Error, Debug)]
+ #[error("{}", {
+ struct Msg<'a>(&'a String, &'a Option<usize>);
+ impl<'a> Display for Msg<'a> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match self.1 {
+ Some(n) => write!(formatter, "error occurred with {}", n),
+ None => write!(formatter, "there was an empty error"),
+ }?;
+ write!(formatter, ": {}", self.0)
+ }
+ }
+ Msg(.0, .1)
+ })]
+ struct Error(String, Option<usize>);
+
+ assert(
+ "error occurred with 1: ...",
+ Error("...".to_owned(), Some(1)),
+ );
+ assert(
+ "there was an empty error: ...",
+ Error("...".to_owned(), None),
+ );
+}
+
+#[test]
fn test_void() {
#[allow(clippy::empty_enum)]
#[derive(Error, Debug)]
diff --git a/tests/test_error.rs b/tests/test_error.rs
index ece7f91..fab934d 100644
--- a/tests/test_error.rs
+++ b/tests/test_error.rs
@@ -1,4 +1,3 @@
-#![deny(clippy::all, clippy::pedantic)]
#![allow(dead_code)]
use std::fmt::{self, Display};
diff --git a/tests/test_expr.rs b/tests/test_expr.rs
index 87a56cf..34de560 100644
--- a/tests/test_expr.rs
+++ b/tests/test_expr.rs
@@ -1,5 +1,4 @@
-#![deny(clippy::all, clippy::pedantic)]
-#![allow(clippy::option_if_let_else)]
+#![allow(clippy::iter_cloned_collect, clippy::option_if_let_else)]
use std::fmt::Display;
use thiserror::Error;
diff --git a/tests/test_from.rs b/tests/test_from.rs
index a25ce35..1f38705 100644
--- a/tests/test_from.rs
+++ b/tests/test_from.rs
@@ -1,5 +1,3 @@
-#![deny(clippy::all, clippy::pedantic)]
-
use std::io;
use thiserror::Error;
diff --git a/tests/test_generics.rs b/tests/test_generics.rs
index f5e1de2..4ab9f37 100644
--- a/tests/test_generics.rs
+++ b/tests/test_generics.rs
@@ -1,4 +1,4 @@
-#![deny(clippy::all, clippy::pedantic)]
+#![allow(clippy::needless_late_init)]
use std::fmt::{self, Debug, Display};
use thiserror::Error;
diff --git a/tests/test_option.rs b/tests/test_option.rs
index ca21713..ed5287d 100644
--- a/tests/test_option.rs
+++ b/tests/test_option.rs
@@ -1,5 +1,7 @@
-#![cfg_attr(thiserror_nightly_testing, feature(backtrace))]
-#![deny(clippy::all, clippy::pedantic)]
+#![cfg_attr(
+ thiserror_nightly_testing,
+ feature(error_generic_member_access, provide_any)
+)]
#[cfg(thiserror_nightly_testing)]
pub mod structs {
diff --git a/tests/test_path.rs b/tests/test_path.rs
index a10b1f3..a34a3d7 100644
--- a/tests/test_path.rs
+++ b/tests/test_path.rs
@@ -1,5 +1,3 @@
-#![deny(clippy::all, clippy::pedantic)]
-
use ref_cast::RefCast;
use std::fmt::Display;
use std::path::{Path, PathBuf};
diff --git a/tests/test_source.rs b/tests/test_source.rs
index ab16097..637f4ac 100644
--- a/tests/test_source.rs
+++ b/tests/test_source.rs
@@ -1,5 +1,3 @@
-#![deny(clippy::all, clippy::pedantic)]
-
use std::error::Error as StdError;
use std::io;
use thiserror::Error;
diff --git a/tests/test_transparent.rs b/tests/test_transparent.rs
index 84d7c91..6f3c03e 100644
--- a/tests/test_transparent.rs
+++ b/tests/test_transparent.rs
@@ -1,5 +1,3 @@
-#![deny(clippy::all, clippy::pedantic)]
-
use anyhow::anyhow;
use std::error::Error as _;
use std::io;
diff --git a/tests/ui/concat-display.stderr b/tests/ui/concat-display.stderr
index 6ab4048..dbecd69 100644
--- a/tests/ui/concat-display.stderr
+++ b/tests/ui/concat-display.stderr
@@ -5,6 +5,6 @@ error: expected string literal
| ^^^^^^
...
13 | error_type!(Error, "foo");
- | -------------------------- in this macro invocation
+ | ------------------------- in this macro invocation
|
= note: this error originates in the macro `error_type` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/from-backtrace-backtrace.rs b/tests/ui/from-backtrace-backtrace.rs
new file mode 100644
index 0000000..8f411bf
--- /dev/null
+++ b/tests/ui/from-backtrace-backtrace.rs
@@ -0,0 +1,10 @@
+// https://github.com/dtolnay/thiserror/issues/163
+
+use std::backtrace::Backtrace;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct Error(#[from] #[backtrace] std::io::Error, Backtrace);
+
+fn main() {}
diff --git a/tests/ui/from-backtrace-backtrace.stderr b/tests/ui/from-backtrace-backtrace.stderr
new file mode 100644
index 0000000..55d647b
--- /dev/null
+++ b/tests/ui/from-backtrace-backtrace.stderr
@@ -0,0 +1,5 @@
+error: deriving From requires no fields other than source and backtrace
+ --> tests/ui/from-backtrace-backtrace.rs:8:18
+ |
+8 | pub struct Error(#[from] #[backtrace] std::io::Error, Backtrace);
+ | ^^^^^^^
diff --git a/tests/ui/no-display.stderr b/tests/ui/no-display.stderr
index e6a52f5..76818e1 100644
--- a/tests/ui/no-display.stderr
+++ b/tests/ui/no-display.stderr
@@ -1,23 +1,17 @@
error[E0599]: the method `as_display` exists for reference `&NoDisplay`, but its trait bounds were not satisfied
- --> tests/ui/no-display.rs:7:9
- |
-4 | struct NoDisplay;
- | ----------------- doesn't satisfy `NoDisplay: std::fmt::Display`
+ --> tests/ui/no-display.rs:7:9
+ |
+4 | struct NoDisplay;
+ | ---------------- doesn't satisfy `NoDisplay: std::fmt::Display`
...
-7 | #[error("thread: {thread}")]
- | ^^^^^^^^^^^^^^^^^^ method cannot be called on `&NoDisplay` due to unsatisfied trait bounds
- |
- = note: the following trait bounds were not satisfied:
- `NoDisplay: std::fmt::Display`
- which is required by `&NoDisplay: DisplayAsDisplay`
-note: the following trait must be implemented
- --> $RUST/core/src/fmt/mod.rs
- |
- | / pub trait Display {
- | | /// Formats the value using the given formatter.
- | | ///
- | | /// # Examples
-... |
- | | fn fmt(&self, f: &mut Formatter<'_>) -> Result;
- | | }
- | |_^
+7 | #[error("thread: {thread}")]
+ | ^^^^^^^^^^^^^^^^^^ method cannot be called on `&NoDisplay` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `NoDisplay: std::fmt::Display`
+ which is required by `&NoDisplay: DisplayAsDisplay`
+note: the trait `std::fmt::Display` must be implemented
+ --> $RUST/core/src/fmt/mod.rs
+ |
+ | pub trait Display {
+ | ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/source-enum-not-error.stderr b/tests/ui/source-enum-not-error.stderr
index d01cba5..750c69e 100644
--- a/tests/ui/source-enum-not-error.stderr
+++ b/tests/ui/source-enum-not-error.stderr
@@ -1,28 +1,22 @@
error[E0599]: the method `as_dyn_error` exists for reference `&NotError`, but its trait bounds were not satisfied
- --> tests/ui/source-enum-not-error.rs:10:9
- |
-4 | pub struct NotError;
- | --------------------
- | |
- | doesn't satisfy `NotError: AsDynError`
- | doesn't satisfy `NotError: std::error::Error`
+ --> tests/ui/source-enum-not-error.rs:10:9
+ |
+4 | pub struct NotError;
+ | -------------------
+ | |
+ | doesn't satisfy `NotError: AsDynError<'_>`
+ | doesn't satisfy `NotError: std::error::Error`
...
-10 | source: NotError,
- | ^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds
- |
- = note: the following trait bounds were not satisfied:
- `NotError: std::error::Error`
- which is required by `NotError: AsDynError`
- `&NotError: std::error::Error`
- which is required by `&NotError: AsDynError`
-note: the following trait must be implemented
- --> $RUST/std/src/error.rs
- |
- | / pub trait Error: Debug + Display {
- | | /// The lower-level source of this error, if any.
- | | ///
- | | /// # Examples
-... |
- | | }
- | | }
- | |_^
+10 | source: NotError,
+ | ^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `NotError: std::error::Error`
+ which is required by `NotError: AsDynError<'_>`
+ `&NotError: std::error::Error`
+ which is required by `&NotError: AsDynError<'_>`
+note: the trait `std::error::Error` must be implemented
+ --> $RUST/core/src/error.rs
+ |
+ | pub trait Error: Debug + Display {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/source-struct-not-error.stderr b/tests/ui/source-struct-not-error.stderr
index be1331a..b98460f 100644
--- a/tests/ui/source-struct-not-error.stderr
+++ b/tests/ui/source-struct-not-error.stderr
@@ -1,27 +1,21 @@
error[E0599]: the method `as_dyn_error` exists for struct `NotError`, but its trait bounds were not satisfied
- --> tests/ui/source-struct-not-error.rs:9:5
- |
-4 | struct NotError;
- | ----------------
- | |
- | method `as_dyn_error` not found for this
- | doesn't satisfy `NotError: AsDynError`
- | doesn't satisfy `NotError: std::error::Error`
+ --> tests/ui/source-struct-not-error.rs:9:5
+ |
+4 | struct NotError;
+ | ---------------
+ | |
+ | method `as_dyn_error` not found for this struct
+ | doesn't satisfy `NotError: AsDynError<'_>`
+ | doesn't satisfy `NotError: std::error::Error`
...
-9 | source: NotError,
- | ^^^^^^ method cannot be called on `NotError` due to unsatisfied trait bounds
- |
- = note: the following trait bounds were not satisfied:
- `NotError: std::error::Error`
- which is required by `NotError: AsDynError`
-note: the following trait must be implemented
- --> $RUST/std/src/error.rs
- |
- | / pub trait Error: Debug + Display {
- | | /// The lower-level source of this error, if any.
- | | ///
- | | /// # Examples
-... |
- | | }
- | | }
- | |_^
+9 | source: NotError,
+ | ^^^^^^ method cannot be called on `NotError` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `NotError: std::error::Error`
+ which is required by `NotError: AsDynError<'_>`
+note: the trait `std::error::Error` must be implemented
+ --> $RUST/core/src/error.rs
+ |
+ | pub trait Error: Debug + Display {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^