@@ -159,6 +159,8 @@ impl Error {
159159 object_mut : object_mut :: < E > ,
160160 #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
161161 object_boxed : object_boxed :: < E > ,
162+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
163+ object_reallocate_boxed : object_reallocate_boxed :: < E > ,
162164 object_downcast : object_downcast :: < E > ,
163165 #[ cfg( anyhow_no_ptr_addr_of) ]
164166 object_downcast_mut : object_downcast_mut :: < E > ,
@@ -188,6 +190,8 @@ impl Error {
188190 object_mut : object_mut :: < MessageError < M > > ,
189191 #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
190192 object_boxed : object_boxed :: < MessageError < M > > ,
193+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
194+ object_reallocate_boxed : object_reallocate_boxed :: < MessageError < M > > ,
191195 object_downcast : object_downcast :: < M > ,
192196 #[ cfg( anyhow_no_ptr_addr_of) ]
193197 object_downcast_mut : object_downcast_mut :: < M > ,
@@ -218,6 +222,8 @@ impl Error {
218222 object_mut : object_mut :: < DisplayError < M > > ,
219223 #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
220224 object_boxed : object_boxed :: < DisplayError < M > > ,
225+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
226+ object_reallocate_boxed : object_reallocate_boxed :: < DisplayError < M > > ,
221227 object_downcast : object_downcast :: < M > ,
222228 #[ cfg( anyhow_no_ptr_addr_of) ]
223229 object_downcast_mut : object_downcast_mut :: < M > ,
@@ -254,6 +260,8 @@ impl Error {
254260 object_mut : object_mut :: < ContextError < C , E > > ,
255261 #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
256262 object_boxed : object_boxed :: < ContextError < C , E > > ,
263+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
264+ object_reallocate_boxed : object_reallocate_boxed :: < ContextError < C , E > > ,
257265 object_downcast : context_downcast :: < C , E > ,
258266 #[ cfg( anyhow_no_ptr_addr_of) ]
259267 object_downcast_mut : context_downcast_mut :: < C , E > ,
@@ -284,6 +292,8 @@ impl Error {
284292 object_mut : object_mut :: < BoxedError > ,
285293 #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
286294 object_boxed : object_boxed :: < BoxedError > ,
295+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
296+ object_reallocate_boxed : object_reallocate_boxed :: < BoxedError > ,
287297 object_downcast : object_downcast :: < Box < dyn StdError + Send + Sync > > ,
288298 #[ cfg( anyhow_no_ptr_addr_of) ]
289299 object_downcast_mut : object_downcast_mut :: < Box < dyn StdError + Send + Sync > > ,
@@ -401,6 +411,8 @@ impl Error {
401411 object_mut : object_mut :: < ContextError < C , Error > > ,
402412 #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
403413 object_boxed : object_boxed :: < ContextError < C , Error > > ,
414+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
415+ object_reallocate_boxed : object_reallocate_boxed :: < ContextError < C , Error > > ,
404416 object_downcast : context_chain_downcast :: < C > ,
405417 #[ cfg( anyhow_no_ptr_addr_of) ]
406418 object_downcast_mut : context_chain_downcast_mut :: < C > ,
@@ -609,6 +621,98 @@ impl Error {
609621 }
610622 }
611623
624+ /// Convert to a standard library error trait object.
625+ ///
626+ /// This is implemented as a cheap pointer cast that does not allocate or
627+ /// deallocate memory. Like [`anyhow::Error::from_boxed`], it's useful for
628+ /// interop with other error libraries.
629+ ///
630+ /// The same conversion is also available as
631+ /// <code style="display:inline;white-space:normal;">impl From<anyhow::Error>
632+ /// for Box<dyn Error + Send + Sync + 'static></code>.
633+ ///
634+ /// If a backtrace was collected during construction of the `anyhow::Error`,
635+ /// that backtrace remains accessible using the standard library `Error`
636+ /// trait's provider API, but as a consequence, the resulting boxed error
637+ /// can no longer be downcast to its original underlying type.
638+ ///
639+ /// ```
640+ #[ cfg_attr( not( error_generic_member_access) , doc = "# _ = stringify! {" ) ]
641+ /// #![feature(error_generic_member_access)]
642+ ///
643+ /// use anyhow::anyhow;
644+ /// use std::backtrace::Backtrace;
645+ /// use thiserror::Error;
646+ ///
647+ /// #[derive(Error, Debug)]
648+ /// #[error("...")]
649+ /// struct MyError;
650+ ///
651+ /// let anyhow_error = anyhow!(MyError);
652+ /// println!("{}", anyhow_error.backtrace()); // has Backtrace
653+ /// assert!(anyhow_error.downcast_ref::<MyError>().is_some()); // can downcast
654+ ///
655+ /// let boxed_dyn_error = anyhow_error.into_boxed_dyn_error();
656+ /// assert!(std::error::request_ref::<Backtrace>(&*boxed_dyn_error).is_some()); // has Backtrace
657+ /// assert!(boxed_dyn_error.downcast_ref::<MyError>().is_none()); // can no longer downcast
658+ #[ cfg_attr( not( error_generic_member_access) , doc = "# };" ) ]
659+ /// ```
660+ ///
661+ /// [`anyhow::Error::from_boxed`]: Self::from_boxed
662+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
663+ #[ must_use]
664+ pub fn into_boxed_dyn_error ( self ) -> Box < dyn StdError + Send + Sync + ' static > {
665+ let outer = ManuallyDrop :: new ( self ) ;
666+ unsafe {
667+ // Use vtable to attach ErrorImpl<E>'s native StdError vtable for
668+ // the right original type E.
669+ ( vtable ( outer. inner . ptr ) . object_boxed ) ( outer. inner )
670+ }
671+ }
672+
673+ /// Convert to a standard library error trait object.
674+ ///
675+ /// Unlike `self.into_boxed_dyn_error()`, this method relocates the
676+ /// underlying error into a new allocation in order to make it downcastable
677+ /// to `&E` or `Box<E>` for its original underlying error type. Any
678+ /// backtrace collected during construction of the `anyhow::Error` is
679+ /// discarded.
680+ ///
681+ /// ```
682+ #[ cfg_attr( not( error_generic_member_access) , doc = "# _ = stringify!{" ) ]
683+ /// #![feature(error_generic_member_access)]
684+ ///
685+ /// use anyhow::anyhow;
686+ /// use std::backtrace::Backtrace;
687+ /// use thiserror::Error;
688+ ///
689+ /// #[derive(Error, Debug)]
690+ /// #[error("...")]
691+ /// struct MyError;
692+ ///
693+ /// let anyhow_error = anyhow!(MyError);
694+ /// println!("{}", anyhow_error.backtrace()); // has Backtrace
695+ /// assert!(anyhow_error.downcast_ref::<MyError>().is_some()); // can downcast
696+ ///
697+ /// let boxed_dyn_error = anyhow_error.reallocate_into_boxed_dyn_error_without_backtrace();
698+ /// assert!(std::error::request_ref::<Backtrace>(&*boxed_dyn_error).is_none()); // Backtrace lost
699+ /// assert!(boxed_dyn_error.downcast_ref::<MyError>().is_some()); // can downcast to &MyError
700+ /// assert!(boxed_dyn_error.downcast::<MyError>().is_ok()); // can downcast to Box<MyError>
701+ #[ cfg_attr( not( error_generic_member_access) , doc = "# };" ) ]
702+ /// ```
703+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
704+ #[ must_use]
705+ pub fn reallocate_into_boxed_dyn_error_without_backtrace (
706+ self ,
707+ ) -> Box < dyn StdError + Send + Sync + ' static > {
708+ let outer = ManuallyDrop :: new ( self ) ;
709+ unsafe {
710+ // Use vtable to attach E's native StdError vtable for the right
711+ // original type E.
712+ ( vtable ( outer. inner . ptr ) . object_reallocate_boxed ) ( outer. inner )
713+ }
714+ }
715+
612716 #[ cfg( error_generic_member_access) ]
613717 pub ( crate ) fn provide < ' a > ( & ' a self , request : & mut Request < ' a > ) {
614718 unsafe { ErrorImpl :: provide ( self . inner . by_ref ( ) , request) }
@@ -682,6 +786,8 @@ struct ErrorVTable {
682786 object_mut : unsafe fn ( Mut < ErrorImpl > ) -> & mut ( dyn StdError + Send + Sync + ' static ) ,
683787 #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
684788 object_boxed : unsafe fn ( Own < ErrorImpl > ) -> Box < dyn StdError + Send + Sync + ' static > ,
789+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
790+ object_reallocate_boxed : unsafe fn ( Own < ErrorImpl > ) -> Box < dyn StdError + Send + Sync + ' static > ,
685791 object_downcast : unsafe fn ( Ref < ErrorImpl > , TypeId ) -> Option < Ref < ( ) > > ,
686792 #[ cfg( anyhow_no_ptr_addr_of) ]
687793 object_downcast_mut : unsafe fn ( Mut < ErrorImpl > , TypeId ) -> Option < Mut < ( ) > > ,
@@ -752,6 +858,17 @@ where
752858 unsafe { unerased_own. boxed ( ) }
753859}
754860
861+ // Safety: requires layout of *e to match ErrorImpl<E>.
862+ #[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
863+ unsafe fn object_reallocate_boxed < E > ( e : Own < ErrorImpl > ) -> Box < dyn StdError + Send + Sync + ' static >
864+ where
865+ E : StdError + Send + Sync + ' static ,
866+ {
867+ // Attach E's native StdError vtable.
868+ let unerased_own = e. cast :: < ErrorImpl < E > > ( ) ;
869+ Box :: new ( unsafe { unerased_own. boxed ( ) } . _object )
870+ }
871+
755872// Safety: requires layout of *e to match ErrorImpl<E>.
756873unsafe fn object_downcast < E > ( e : Ref < ErrorImpl > , target : TypeId ) -> Option < Ref < ( ) > >
757874where
@@ -1060,26 +1177,23 @@ where
10601177impl From < Error > for Box < dyn StdError + Send + Sync + ' static > {
10611178 #[ cold]
10621179 fn from ( error : Error ) -> Self {
1063- let outer = ManuallyDrop :: new ( error) ;
1064- unsafe {
1065- // Use vtable to attach ErrorImpl<E>'s native StdError vtable for
1066- // the right original type E.
1067- ( vtable ( outer. inner . ptr ) . object_boxed ) ( outer. inner )
1068- }
1180+ error. into_boxed_dyn_error ( )
10691181 }
10701182}
10711183
10721184#[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
10731185impl From < Error > for Box < dyn StdError + Send + ' static > {
1186+ #[ cold]
10741187 fn from ( error : Error ) -> Self {
1075- Box :: < dyn StdError + Send + Sync > :: from ( error)
1188+ error. into_boxed_dyn_error ( )
10761189 }
10771190}
10781191
10791192#[ cfg( any( feature = "std" , not( anyhow_no_core_error) ) ) ]
10801193impl From < Error > for Box < dyn StdError + ' static > {
1194+ #[ cold]
10811195 fn from ( error : Error ) -> Self {
1082- Box :: < dyn StdError + Send + Sync > :: from ( error)
1196+ error. into_boxed_dyn_error ( )
10831197 }
10841198}
10851199
0 commit comments