@@ -659,11 +659,9 @@ try.cont: ; preds = %catch.start0
659659; --- try-delegate ends (call unwind mismatch)
660660; NOSORT: catch
661661; NOSORT: call {{.*}} __cxa_begin_catch
662- ; --- try-delegate starts (call unwind mismatch)
663- ; NOSORT: try
664- ; NOSORT: call __cxa_end_catch
665- ; NOSORT: delegate 3 # label/catch{{[0-9]+}}: to caller
666- ; --- try-delegate ends (call unwind mismatch)
662+ ; __cxa_end_catch doesn't need its own try-delegate because the enclosing
663+ ; catch-mismatch delegate already routes to caller.
664+ ; NOSORT: call __cxa_end_catch
667665; NOSORT: end_try
668666; NOSORT: delegate 1 # label/catch{{[0-9]+}}: to caller
669667; --- try-delegate ends (catch unwind mismatch)
@@ -1735,9 +1733,104 @@ unreachable: ; preds = %rethrow, %entry
17351733 unreachable
17361734}
17371735
1736+ ; Regression test for issue #187302: fixCallUnwindMismatches() was run first and
1737+ ; found that the rethrow had the correct unwind target so did not wrap it in a
1738+ ; try/delegate. Then fixCatchUnwindMismatches() added a try/delegate for
1739+ ;
1740+ ; invoke void @do_catch unwind label %terminate_catchswitch
1741+ ;
1742+ ; because otherwise it was going to unwind to outer_catchswitch rather than
1743+ ; terminate_catchswitch. But this made the rethrow incorrectly transfer control
1744+ ; to terminate_catchswitch rather than outer_catchswitch.
1745+ ; Fixed by running fixCatchUnwindMismatches() before fixCallUnwindMismatches().
1746+ ;
1747+ ; This pattern occurs in Rust's catch_unwind inside a destructor.
1748+
1749+ ; CHECK-LABEL: catch_unwind_in_cleanup:
1750+ ; CHECK: catch_all
1751+ ; CHECK: try
1752+ ; CHECK: try
1753+ ; CHECK: call resume_unwind
1754+ ; CHECK: catch {{.*}} __cpp_exception
1755+ ; CHECK: call do_catch
1756+ ; end_cleanup and rethrow are inside the inner catch's scope, but each gets
1757+ ; its own try-delegate to route exceptions to the correct destination rather
1758+ ; than going through the catch-mismatch delegate to the terminate handler.
1759+ ; CHECK: try
1760+ ; CHECK: call end_cleanup
1761+ ; CHECK: delegate 7
1762+ ; (caller)
1763+ ; CHECK: try
1764+ ; CHECK: rethrow 7
1765+ ; (Rethrow exception caught by outermost catch_all)
1766+ ; CHECK: delegate 2
1767+ ; (outer_catchswitch)
1768+ ; CHECK: end_try
1769+ ; CHECK: delegate 3
1770+ ; (terminate)
1771+ ; CHECK: catch {{.*}} __cpp_exception
1772+ ; CHECK: call do_catch
1773+ ; CHECK: return
1774+ define void @catch_unwind_in_cleanup () personality ptr @__gxx_wasm_personality_v0 {
1775+ start:
1776+ invoke void @resume_unwind (i32 1 )
1777+ to label %unreachable unwind label %outer_cleanuppad
1778+
1779+ outer_cleanuppad:
1780+ %outer_pad = cleanuppad within none []
1781+ call void @start_cleanup () [ "funclet" (token %outer_pad ) ]
1782+ invoke void @resume_unwind (i32 2 ) [ "funclet" (token %outer_pad ) ]
1783+ to label %unreachable unwind label %inner_catchswitch
1784+
1785+ inner_catchswitch:
1786+ %inner_cs = catchswitch within %outer_pad [label %inner_catchpad ] unwind label %terminate_catchswitch
1787+
1788+ inner_catchpad:
1789+ %inner_cp = catchpad within %inner_cs [ptr null ]
1790+ %exn = call ptr @llvm.wasm.get.exception (token %inner_cp )
1791+ %sel = call i32 @llvm.wasm.get.ehselector (token %inner_cp )
1792+ invoke void @do_catch (ptr %exn , i32 2 ) [ "funclet" (token %inner_cp ) ]
1793+ to label %inner_catchret unwind label %terminate_catchswitch
1794+
1795+ terminate_catchswitch:
1796+ %term_cs = catchswitch within %outer_pad [label %terminate_catchpad ] unwind label %outer_catchswitch
1797+
1798+ terminate_catchpad:
1799+ %term_pad = catchpad within %term_cs [ptr null ]
1800+ call void @panic_in_cleanup () [ "funclet" (token %term_pad ) ]
1801+ unreachable
1802+
1803+ inner_catchret:
1804+ catchret from %inner_cp to label %outer_cleanupret
1805+
1806+ outer_cleanupret:
1807+ call void @end_cleanup () [ "funclet" (token %outer_pad ) ]
1808+ cleanupret from %outer_pad unwind label %outer_catchswitch
1809+
1810+ outer_catchswitch:
1811+ %outer_cs = catchswitch within none [label %outer_catchpad ] unwind to caller
1812+ outer_catchpad:
1813+ %outer_cp = catchpad within %outer_cs [ptr null ]
1814+ %exn2 = call ptr @llvm.wasm.get.exception (token %outer_cp )
1815+ %sel2 = call i32 @llvm.wasm.get.ehselector (token %outer_cp )
1816+ call void @do_catch (ptr %exn2 , i32 1 ) [ "funclet" (token %outer_cp ) ]
1817+ catchret from %outer_cp to label %done
1818+
1819+ done:
1820+ ret void
1821+ unreachable:
1822+ unreachable
1823+ }
1824+
1825+ declare void @resume_unwind (i32 ) #1
1826+ declare void @do_catch (ptr , i32 ) #0
1827+ declare void @start_cleanup ()
1828+ declare void @end_cleanup ()
1829+ declare void @panic_in_cleanup () #2
1830+
17381831; Check if the unwind destination mismatch stats are correct
1739- ; NOSORT: 24 wasm-cfg-stackify - Number of call unwind mismatches found
1740- ; NOSORT: 5 wasm-cfg-stackify - Number of catch unwind mismatches found
1832+ ; NOSORT: 25 wasm-cfg-stackify - Number of call unwind mismatches found
1833+ ; NOSORT: 7 wasm-cfg-stackify - Number of catch unwind mismatches found
17411834
17421835declare void @foo ()
17431836declare void @bar ()
0 commit comments