@@ -715,16 +715,19 @@ def transform_try_finally_stmt_async(
715
715
builder : IRBuilder , try_body : GenFunc , finally_body : GenFunc , line : int = - 1
716
716
) -> None :
717
717
"""Async-aware try/finally handling for when finally contains await.
718
-
718
+
719
719
This version uses a modified approach that preserves exceptions across await."""
720
-
720
+
721
721
# We need to handle returns properly, so we'll use TryFinallyNonlocalControl
722
722
# to track return values, similar to the regular try/finally implementation
723
-
723
+
724
724
err_handler , main_entry , return_entry , finally_entry = (
725
- BasicBlock (), BasicBlock (), BasicBlock (), BasicBlock ()
725
+ BasicBlock (),
726
+ BasicBlock (),
727
+ BasicBlock (),
728
+ BasicBlock (),
726
729
)
727
-
730
+
728
731
# Track if we're returning from the try block
729
732
control = TryFinallyNonlocalControl (return_entry )
730
733
builder .builder .push_error_handler (err_handler )
@@ -735,76 +738,76 @@ def transform_try_finally_stmt_async(
735
738
builder .nonlocal_control .pop ()
736
739
builder .builder .pop_error_handler ()
737
740
ret_reg = control .ret_reg
738
-
741
+
739
742
# Normal case - no exception or return
740
743
builder .activate_block (main_entry )
741
744
builder .goto (finally_entry )
742
-
745
+
743
746
# Return case
744
747
builder .activate_block (return_entry )
745
748
builder .goto (finally_entry )
746
-
749
+
747
750
# Exception case - need to catch to clear the error indicator
748
751
builder .activate_block (err_handler )
749
752
# Catch the error to clear Python's error indicator
750
753
old_exc = builder .call_c (error_catch_op , [], line )
751
754
# We're not going to use old_exc since it won't survive await
752
755
# The exception is now in sys.exc_info()
753
756
builder .goto (finally_entry )
754
-
757
+
755
758
# Finally block
756
759
builder .activate_block (finally_entry )
757
-
760
+
758
761
# Execute finally body
759
762
finally_body ()
760
-
763
+
761
764
# After finally, we need to handle exceptions carefully:
762
765
# 1. If finally raised a new exception, it's in the error indicator - let it propagate
763
766
# 2. If finally didn't raise, check if we need to reraise the original from sys.exc_info()
764
767
# 3. If there was a return, return that value
765
768
# 4. Otherwise, normal exit
766
-
769
+
767
770
# First, check if there's a current exception in the error indicator
768
771
# (this would be from the finally block)
769
772
no_current_exc = builder .call_c (no_err_occurred_op , [], line )
770
773
finally_raised = BasicBlock ()
771
774
check_original = BasicBlock ()
772
775
builder .add (Branch (no_current_exc , check_original , finally_raised , Branch .BOOL ))
773
-
776
+
774
777
# Finally raised an exception - let it propagate naturally
775
778
builder .activate_block (finally_raised )
776
779
builder .call_c (keep_propagating_op , [], NO_TRACEBACK_LINE_NO )
777
780
builder .add (Unreachable ())
778
-
781
+
779
782
# No exception from finally, check if we need to handle return or original exception
780
783
builder .activate_block (check_original )
781
-
784
+
782
785
# Check if we have a return value
783
786
if ret_reg :
784
787
return_block , check_old_exc = BasicBlock (), BasicBlock ()
785
788
builder .add (Branch (builder .read (ret_reg ), check_old_exc , return_block , Branch .IS_ERROR ))
786
-
789
+
787
790
builder .activate_block (return_block )
788
791
builder .nonlocal_control [- 1 ].gen_return (builder , builder .read (ret_reg ), - 1 )
789
-
792
+
790
793
builder .activate_block (check_old_exc )
791
-
794
+
792
795
# Check if we need to reraise the original exception from sys.exc_info
793
796
exc_info = builder .call_c (get_exc_info_op , [], line )
794
797
exc_type = builder .add (TupleGet (exc_info , 0 , line ))
795
-
798
+
796
799
# Check if exc_type is None
797
800
none_obj = builder .none_object ()
798
801
has_exc = builder .binary_op (exc_type , none_obj , "is not" , line )
799
-
802
+
800
803
reraise_block , exit_block = BasicBlock (), BasicBlock ()
801
804
builder .add (Branch (has_exc , reraise_block , exit_block , Branch .BOOL ))
802
-
805
+
803
806
# Reraise the original exception
804
807
builder .activate_block (reraise_block )
805
808
builder .call_c (reraise_exception_op , [], NO_TRACEBACK_LINE_NO )
806
809
builder .add (Unreachable ())
807
-
810
+
808
811
# Normal exit
809
812
builder .activate_block (exit_block )
810
813
@@ -850,9 +853,13 @@ def transform_try_body() -> None:
850
853
body = t .finally_body
851
854
852
855
if use_async_version :
853
- transform_try_finally_stmt_async (builder , transform_try_body , lambda : builder .accept (body ), t .line )
856
+ transform_try_finally_stmt_async (
857
+ builder , transform_try_body , lambda : builder .accept (body ), t .line
858
+ )
854
859
else :
855
- transform_try_finally_stmt (builder , transform_try_body , lambda : builder .accept (body ), t .line )
860
+ transform_try_finally_stmt (
861
+ builder , transform_try_body , lambda : builder .accept (body ), t .line
862
+ )
856
863
else :
857
864
transform_try_except_stmt (builder , t )
858
865
@@ -943,7 +950,7 @@ def finally_body() -> None:
943
950
builder ,
944
951
lambda : transform_try_except (builder , try_body , [(None , None , except_body )], None , line ),
945
952
finally_body ,
946
- line
953
+ line ,
947
954
)
948
955
949
956
0 commit comments