@@ -688,3 +688,58 @@ fn no_infer_outlives() {
688
688
_x : <Example < A > as Bar < B > >:: Y ,
689
689
}
690
690
}
691
+
692
+ // https://github.com/rust-lang/rust/issues/47949
693
+ // https://github.com/taiki-e/pin-project/pull/194#discussion_r419098111
694
+ #[ test]
695
+ fn project_replace_panic ( ) {
696
+ use std:: panic;
697
+
698
+ #[ pin_project( Replace ) ]
699
+ struct S < T , U > {
700
+ #[ pin]
701
+ pinned : T ,
702
+ unpinned : U ,
703
+ }
704
+
705
+ struct D < ' a > ( & ' a mut bool , bool ) ;
706
+ impl Drop for D < ' _ > {
707
+ fn drop ( & mut self ) {
708
+ * self . 0 = true ;
709
+ if self . 1 {
710
+ panic ! ( )
711
+ }
712
+ }
713
+ }
714
+
715
+ let ( mut a, mut b, mut c, mut d) = ( false , false , false , false ) ;
716
+ let res = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
717
+ let mut x = S { pinned : D ( & mut a, true ) , unpinned : D ( & mut b, false ) } ;
718
+ let _y = Pin :: new ( & mut x)
719
+ . project_replace ( S { pinned : D ( & mut c, false ) , unpinned : D ( & mut d, false ) } ) ;
720
+ // Previous `x.pinned` was dropped and panicked when `project_replace` is called, so this is unreachable.
721
+ unreachable ! ( ) ;
722
+ } ) ) ;
723
+ assert ! ( res. is_err( ) ) ;
724
+ assert ! ( a) ;
725
+ assert ! ( b) ;
726
+ assert ! ( c) ;
727
+ assert ! ( d) ;
728
+
729
+ let ( mut a, mut b, mut c, mut d) = ( false , false , false , false ) ;
730
+ let res = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
731
+ let mut x = S { pinned : D ( & mut a, false ) , unpinned : D ( & mut b, true ) } ;
732
+ {
733
+ let _y = Pin :: new ( & mut x)
734
+ . project_replace ( S { pinned : D ( & mut c, false ) , unpinned : D ( & mut d, false ) } ) ;
735
+ // `_y` (previous `x.unpinned`) live to the end of this scope, so this is not unreachable,
736
+ // unreachable!();
737
+ }
738
+ unreachable ! ( ) ;
739
+ } ) ) ;
740
+ assert ! ( res. is_err( ) ) ;
741
+ assert ! ( a) ;
742
+ assert ! ( b) ;
743
+ assert ! ( c) ;
744
+ assert ! ( d) ;
745
+ }
0 commit comments