From 339af705ccffdf8a6be8f9f671309b6924ce2059 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 24 Dec 2016 19:57:50 -0800 Subject: [PATCH 1/2] Make error_chain with default-features = false work with Rust 1.10 error_chain uses attributes on statements, stablized in Rust 1.13. Factor them out of functions in the non-backtrace codepath, making it possible to build a crate that uses error_chain with Rust 1.10. The backtrace feature still requires Rust 1.13 for attributes on statements, due to the impl_extract_backtrace macro, which needs to emit a function with one block for each linked error type, some of which may have attributes on them. And any code using compile-time conditionals in attributes on variants within an error_chain! invocation (which includes many of the tests and examples) will produce an error due to https://github.com/rust-lang/rust/issues/22250 (fixed in Rust 1.11). But a crate using error_chain with default-features = false and avoiding such compile-time conditionals will now compile. --- src/lib.rs | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4aae10cff..e297e5a42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -455,42 +455,47 @@ pub struct State { } impl Default for State { + #[cfg(feature = "backtrace")] fn default() -> State { - #[cfg(feature = "backtrace")] - let state = State { + State { next_error: None, backtrace: make_backtrace(), - }; - #[cfg(not(feature = "backtrace"))] - let state = State { next_error: None }; - state + } + } + + #[cfg(not(feature = "backtrace"))] + fn default() -> State { + State { next_error: None } } } impl State { /// Creates a new State type + #[cfg(feature = "backtrace")] pub fn new(e: Box) -> State { - #[cfg(feature = "backtrace")] - let state = { - let backtrace = CE::extract_backtrace(&*e).or_else(make_backtrace); - State { - next_error: Some(e), - backtrace: backtrace, - } - }; - #[cfg(not(feature = "backtrace"))] - let state = State { next_error: Some(e) }; + let backtrace = CE::extract_backtrace(&*e).or_else(make_backtrace); + State { + next_error: Some(e), + backtrace: backtrace, + } + } + + /// Creates a new State type + #[cfg(not(feature = "backtrace"))] + pub fn new(e: Box) -> State { + State { next_error: Some(e) } + } - state + /// Returns the inner backtrace if present. + #[cfg(feature = "backtrace")] + pub fn backtrace(&self) -> Option<&Backtrace> { + self.backtrace.as_ref().map(|v| &**v) } /// Returns the inner backtrace if present. + #[cfg(not(feature = "backtrace"))] pub fn backtrace(&self) -> Option<&Backtrace> { - #[cfg(feature = "backtrace")] - let b = self.backtrace.as_ref().map(|v| &**v); - #[cfg(not(feature = "backtrace"))] - let b = None; - b + None } } From eb9ba6e3dbae4e31797202401fcc9942609f7fe1 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 24 Dec 2016 20:28:42 -0800 Subject: [PATCH 2/2] WIP: Make tests and examples compile with Rust 1.10 - Avoid using attributes on statements; use them on items instead. - Change a test to use std::env::VarError instead of std::fmt::Error, because the latter didn't impl Error until Rust 1.11. - Add an empty block after invocations of `error_chain!` inside functions, to work around https://github.com/rust-lang/rust/pull/34436 (fixed in Rust 1.11). - Replace a single instance of `?` with `try!`. This still fails to work with 1.10 due to https://github.com/rust-lang/rust/issues/22250 . Because of that issue, an invocation of `#[derive(Debug)]` inside a macro doesn't take cfg(...) attributes into account, and fails to compile due to referencing enum variants that don't exist. Posted for reference only. --- examples/quickstart.rs | 3 +-- examples/size.rs | 18 ++++++------------ tests/tests.rs | 14 +++++++++++--- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/examples/quickstart.rs b/examples/quickstart.rs index 7c53ad3eb..0b0a20749 100644 --- a/examples/quickstart.rs +++ b/examples/quickstart.rs @@ -53,8 +53,7 @@ fn run() -> Result<()> { use std::fs::File; // This operation will fail - File::open("tretrete") - .chain_err(|| "unable to open tretrete file")?; + try!(File::open("tretrete").chain_err(|| "unable to open tretrete file")); Ok(()) } diff --git a/examples/size.rs b/examples/size.rs index 01f677b49..df0010f3f 100644 --- a/examples/size.rs +++ b/examples/size.rs @@ -21,20 +21,14 @@ fn main() { println!(" ErrorKind::Msg: {}", size_of_val(&msg)); println!(" String: {}", size_of::()); println!(" State: {}", size_of::()); + let state = error_chain::State::default(); + println!(" State.next_error: {}", size_of_val(&state.next_error)); #[cfg(feature = "backtrace")] - { - let state = error_chain::State { - next_error: None, - backtrace: None, - }; - println!(" State.next_error: {}", size_of_val(&state.next_error)); + fn size_of_backtrace() { + let state = error_chain::State::default(); println!(" State.backtrace: {}", size_of_val(&state.backtrace)); } #[cfg(not(feature = "backtrace"))] - { - let state = error_chain::State { - next_error: None, - }; - println!(" State.next_error: {}", size_of_val(&state.next_error)); - } + fn size_of_backtrace() {} + size_of_backtrace(); } diff --git a/tests/tests.rs b/tests/tests.rs index 1d7544c33..cc61d1eb2 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -236,18 +236,18 @@ fn has_backtrace_depending_on_env() { #[test] fn chain_err() { - use std::fmt; + use std::env; error_chain! { foreign_links { - Fmt(fmt::Error); + Var(env::VarError); } errors { Test } } - let _: Result<()> = Err(fmt::Error).chain_err(|| ""); + let _: Result<()> = Err(env::VarError::NotPresent).chain_err(|| ""); let _: Result<()> = Err(Error::from_kind(ErrorKind::Test)).chain_err(|| ""); } @@ -262,6 +262,8 @@ fn links() { Test(test::Error, test::ErrorKind); } } + + {} } #[cfg(test)] @@ -435,6 +437,8 @@ fn documentation() { Variant } } + + {} } #[cfg(test)] @@ -469,6 +473,8 @@ fn rustup_regression() { } } } + + {} } #[test] @@ -503,6 +509,8 @@ fn error_first() { foreign_links { } } + + {} } #[test]