From 436e1f9abf4cdfac21fb9cb2061b96b0b8d5ea6e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Jun 2022 20:26:25 -0500 Subject: [PATCH] WIP: fix: Ensure 'ArgMatches' is unwind safe Fixes #3876 --- src/builder/command.rs | 8 +++++- src/builder/value_parser.rs | 21 +++++++++++--- src/parser/matches/any_value.rs | 37 ++++++++++++++++++++++--- src/parser/matches/arg_matches.rs | 46 +++++++++++++++++++++++++------ 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/src/builder/command.rs b/src/builder/command.rs index bbd14dc6caf..cc046890fa8 100644 --- a/src/builder/command.rs +++ b/src/builder/command.rs @@ -5110,5 +5110,11 @@ where #[test] fn check_auto_traits() { - static_assertions::assert_impl_all!(Command: Send, Sync, Unpin); + static_assertions::assert_impl_all!( + Command: Send, + Sync, + std::panic::RefUnwindSafe, + std::panic::UnwindSafe, + Unpin + ); } diff --git a/src/builder/value_parser.rs b/src/builder/value_parser.rs index 397537c9f52..60729da5764 100644 --- a/src/builder/value_parser.rs +++ b/src/builder/value_parser.rs @@ -108,7 +108,7 @@ impl ValueParser { pub fn new

(other: P) -> Self where P: TypedValueParser, - P::Value: Send + Sync + Clone, + P::Value: Send + Sync + Clone + std::panic::UnwindSafe + std::panic::RefUnwindSafe, { Self(ValueParserInner::Other(Box::new(other))) } @@ -284,7 +284,7 @@ impl ValueParser { impl

From

for ValueParser where P: TypedValueParser + Send + Sync + 'static, - P::Value: Send + Sync + Clone, + P::Value: Send + Sync + Clone + std::panic::UnwindSafe + std::panic::RefUnwindSafe, { fn from(p: P) -> Self { Self::new(p) @@ -563,7 +563,13 @@ trait AnyValueParser: Send + Sync + 'static { impl AnyValueParser for P where - T: std::any::Any + Clone + Send + Sync + 'static, + T: std::any::Any + + Clone + + Send + + Sync + + std::panic::UnwindSafe + + std::panic::RefUnwindSafe + + 'static, P: TypedValueParser, { fn parse_ref( @@ -1963,7 +1969,14 @@ pub mod via_prelude { } impl _ValueParserViaFromStr for _AutoValueParser where - FromStr: std::str::FromStr + std::any::Any + Clone + Send + Sync + 'static, + FromStr: std::str::FromStr + + std::any::Any + + Clone + + Send + + Sync + + std::panic::UnwindSafe + + std::panic::RefUnwindSafe + + 'static, ::Err: Into>, { diff --git a/src/parser/matches/any_value.rs b/src/parser/matches/any_value.rs index a9277e75fa8..39bbc180754 100644 --- a/src/parser/matches/any_value.rs +++ b/src/parser/matches/any_value.rs @@ -1,25 +1,54 @@ #[derive(Clone)] pub(crate) struct AnyValue { - inner: std::sync::Arc, + inner: std::sync::Arc< + dyn std::any::Any + + Send + + Sync + + std::panic::UnwindSafe + + std::panic::RefUnwindSafe + + 'static, + >, // While we can extract `TypeId` from `inner`, the debug repr is of a number, so let's track // the type_name in debug builds. id: AnyValueId, } impl AnyValue { - pub(crate) fn new(inner: V) -> Self { + pub(crate) fn new< + V: std::any::Any + + Clone + + Send + + Sync + + std::panic::UnwindSafe + + std::panic::RefUnwindSafe + + 'static, + >( + inner: V, + ) -> Self { let id = AnyValueId::of::(); let inner = std::sync::Arc::new(inner); Self { inner, id } } - pub(crate) fn downcast_ref( + pub(crate) fn downcast_ref< + T: std::any::Any + + Clone + + Send + + Sync + + std::panic::UnwindSafe + + std::panic::RefUnwindSafe + + 'static, + >( &self, ) -> Option<&T> { self.inner.downcast_ref::() } - pub(crate) fn downcast_into(self) -> Result { + pub(crate) fn downcast_into< + T: std::any::Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe, + >( + self, + ) -> Result { let id = self.id; let value = std::sync::Arc::downcast::(self.inner).map_err(|inner| Self { inner, id })?; diff --git a/src/parser/matches/arg_matches.rs b/src/parser/matches/arg_matches.rs index d0df68441ff..fc344170d65 100644 --- a/src/parser/matches/arg_matches.rs +++ b/src/parser/matches/arg_matches.rs @@ -114,7 +114,12 @@ impl ArgMatches { /// [positional]: crate::Arg::index() /// [`default_value`]: crate::Arg::default_value() #[track_caller] - pub fn get_one(&self, id: &str) -> Option<&T> { + pub fn get_one< + T: Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static, + >( + &self, + id: &str, + ) -> Option<&T> { let internal_id = Id::from(id); MatchesError::unwrap(&internal_id, self.try_get_one(id)) } @@ -153,7 +158,9 @@ impl ArgMatches { /// assert_eq!(vals, [22, 80, 2020]); /// ``` #[track_caller] - pub fn get_many( + pub fn get_many< + T: Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static, + >( &self, id: &str, ) -> Option> { @@ -243,7 +250,12 @@ impl ArgMatches { /// [positional]: crate::Arg::index() /// [`default_value`]: crate::Arg::default_value() #[track_caller] - pub fn remove_one(&mut self, id: &str) -> Option { + pub fn remove_one< + T: Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static, + >( + &mut self, + id: &str, + ) -> Option { let internal_id = Id::from(id); MatchesError::unwrap(&internal_id, self.try_remove_one(id)) } @@ -280,7 +292,9 @@ impl ArgMatches { /// assert_eq!(vals, ["file1.txt", "file2.txt", "file3.txt", "file4.txt"]); /// ``` #[track_caller] - pub fn remove_many( + pub fn remove_many< + T: Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static, + >( &mut self, id: &str, ) -> Option> { @@ -1074,7 +1088,9 @@ impl ArgMatches { /// # Advanced impl ArgMatches { /// Non-panicking version of [`ArgMatches::get_one`] - pub fn try_get_one( + pub fn try_get_one< + T: Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static, + >( &self, id: &str, ) -> Result, MatchesError> { @@ -1093,7 +1109,9 @@ impl ArgMatches { } /// Non-panicking version of [`ArgMatches::get_many`] - pub fn try_get_many( + pub fn try_get_many< + T: Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static, + >( &self, id: &str, ) -> Result>, MatchesError> { @@ -1129,7 +1147,9 @@ impl ArgMatches { } /// Non-panicking version of [`ArgMatches::remove_one`] - pub fn try_remove_one( + pub fn try_remove_one< + T: Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static, + >( &mut self, id: &str, ) -> Result, MatchesError> { @@ -1145,7 +1165,9 @@ impl ArgMatches { } /// Non-panicking version of [`ArgMatches::remove_many`] - pub fn try_remove_many( + pub fn try_remove_many< + T: Any + Clone + Send + Sync + std::panic::UnwindSafe + std::panic::RefUnwindSafe + 'static, + >( &mut self, id: &str, ) -> Result>, MatchesError> { @@ -1743,7 +1765,13 @@ mod tests { #[test] fn check_auto_traits() { - static_assertions::assert_impl_all!(ArgMatches: Send, Sync, Unpin); + static_assertions::assert_impl_all!( + ArgMatches: Send, + Sync, + std::panic::RefUnwindSafe, + std::panic::UnwindSafe, + Unpin + ); } #[test]