@@ -112,8 +112,16 @@ pub fn dfs_in_order<'instr>(
112112
113113 // Pause iteration through this sequence's instructions.
114114 // Traverse the try_table body.
115- Instr :: TryTable ( TryTable { seq, .. } ) => {
115+ Instr :: TryTable ( TryTable { seq, catches } ) => {
116116 stack. push ( ( seq_id, index + 1 ) ) ;
117+ // Visit catch clauses to mark tags as used.
118+ // Note: The labels in TryTable catches are branch targets, not handler
119+ // blocks. They reference blocks already in the control flow and will be
120+ // visited naturally during traversal.
121+ for catch in catches. iter ( ) {
122+ log:: trace!( "dfs_in_order: ({:?}).visit(..)" , catch) ;
123+ catch. visit ( visitor) ;
124+ }
117125 stack. push ( ( * seq, 0 ) ) ;
118126 continue ' traversing_blocks;
119127 }
@@ -242,7 +250,14 @@ pub fn dfs_pre_order_mut(
242250 stack. push ( * consequent) ;
243251 }
244252
245- Instr :: TryTable ( TryTable { seq, .. } ) => {
253+ Instr :: TryTable ( TryTable { seq, catches } ) => {
254+ // Visit catch clauses to mark tags as used.
255+ // Note: The labels in TryTable catches are branch targets, not handler
256+ // blocks. They reference blocks already in the control flow and will be
257+ // visited naturally during traversal.
258+ for catch in catches. iter_mut ( ) {
259+ catch. visit_mut ( visitor) ;
260+ }
246261 stack. push ( * seq) ;
247262 }
248263
@@ -296,6 +311,14 @@ mod tests {
296311 fn visit_if_else ( & mut self , _: & IfElse ) {
297312 self . push ( "if-else" ) ;
298313 }
314+
315+ fn visit_try_table ( & mut self , _: & TryTable ) {
316+ self . push ( "try-table" ) ;
317+ }
318+
319+ fn visit_tag_id ( & mut self , _: & crate :: TagId ) {
320+ self . push ( "tag" ) ;
321+ }
299322 }
300323
301324 impl VisitorMut for TestVisitor {
@@ -328,6 +351,14 @@ mod tests {
328351 fn visit_if_else_mut ( & mut self , _: & mut IfElse ) {
329352 self . push ( "if-else" ) ;
330353 }
354+
355+ fn visit_try_table_mut ( & mut self , _: & mut TryTable ) {
356+ self . push ( "try-table" ) ;
357+ }
358+
359+ fn visit_tag_id_mut ( & mut self , _: & mut crate :: TagId ) {
360+ self . push ( "tag" ) ;
361+ }
331362 }
332363
333364 fn make_test_func ( module : & mut crate :: Module ) -> & mut LocalFunction {
@@ -419,4 +450,78 @@ mod tests {
419450 expected. iter( ) . map( |s| s. to_string( ) ) . collect:: <Vec <_>>( )
420451 ) ;
421452 }
453+
454+ #[ test]
455+ fn dfs_in_order_try_table ( ) {
456+ let mut module = crate :: Module :: default ( ) ;
457+
458+ let tag_type = module. types . add ( & [ crate :: ValType :: I32 ] , & [ ] ) ;
459+ let tag_id = module. tags . add ( tag_type) ;
460+
461+ let block_ty = module. types . add ( & [ ] , & [ ] ) ;
462+ let mut builder = crate :: FunctionBuilder :: new ( & mut module. types , & [ ] , & [ ] ) ;
463+
464+ let mut func_body = builder. func_body ( ) ;
465+
466+ // Build the try body
467+ let try_body = func_body. dangling_instr_seq ( block_ty) . id ( ) ;
468+ func_body. instr_seq ( try_body) . i32_const ( 5 ) . drop ( ) ;
469+
470+ // Create dummy label targets (these are branch targets, not handler blocks)
471+ let catch_label = func_body. dangling_instr_seq ( block_ty) . id ( ) ;
472+ let catch_all_label = func_body. dangling_instr_seq ( block_ty) . id ( ) ;
473+
474+ func_body
475+ . i32_const ( 1 )
476+ . drop ( )
477+ . instr ( TryTable {
478+ seq : try_body,
479+ catches : vec ! [
480+ TryTableCatch :: Catch {
481+ tag: tag_id,
482+ label: catch_label,
483+ } ,
484+ TryTableCatch :: CatchAll {
485+ label: catch_all_label,
486+ } ,
487+ ] ,
488+ } )
489+ . i32_const ( 99 )
490+ . drop ( ) ;
491+
492+ let func_id = builder. finish ( vec ! [ ] , & mut module. funcs ) ;
493+ let func = module. funcs . get_mut ( func_id) . kind . unwrap_local_mut ( ) ;
494+
495+ let mut visitor = TestVisitor :: default ( ) ;
496+ crate :: ir:: dfs_in_order ( & mut visitor, func, func. entry_block ( ) ) ;
497+
498+ // Expected order:
499+ // - start (entry block)
500+ // - 1, drop (before try-table)
501+ // - try-table instruction
502+ // - tag (from Catch clause visiting tag ID)
503+ // - start, 5, drop, end (try body)
504+ // - 99, drop (after try-table)
505+ // - end (entry block)
506+ // Note: catch labels are branch targets, not separate blocks to traverse
507+ let expected = [
508+ "start" ,
509+ "1" ,
510+ "drop" ,
511+ "try-table" ,
512+ "tag" ,
513+ "start" ,
514+ "5" ,
515+ "drop" ,
516+ "end" , // try body
517+ "99" ,
518+ "drop" ,
519+ "end" ,
520+ ] ;
521+
522+ assert_eq ! (
523+ visitor. visits,
524+ expected. iter( ) . map( |s| s. to_string( ) ) . collect:: <Vec <_>>( )
525+ ) ;
526+ }
422527}
0 commit comments