diff --git a/src/codegen/dead_storage.rs b/src/codegen/dead_storage.rs index abf808efd..bc9738663 100644 --- a/src/codegen/dead_storage.rs +++ b/src/codegen/dead_storage.rs @@ -336,6 +336,11 @@ fn apply_transfers( debug_assert_eq!(transfers.len(), cfg.blocks[block_no].instr.len()); + if transfers.is_empty() { + block_vars.insert(block_no, vec![vars.clone()]); + return; + } + // this is done in two passes. The first pass just deals with variables. // The second pass deals with storage stores diff --git a/src/sema/yul/for_loop.rs b/src/sema/yul/for_loop.rs index 42ba9943b..a072e4136 100644 --- a/src/sema/yul/for_loop.rs +++ b/src/sema/yul/for_loop.rs @@ -42,6 +42,7 @@ pub(crate) fn resolve_for_loop( loop_scope.enter_scope(); + let body_reachable = next_reachable; let resolved_exec_block = resolve_yul_block( &yul_for.execution_block.loc, &yul_for.execution_block.statements, @@ -52,7 +53,8 @@ pub(crate) fn resolve_for_loop( symtable, ns, ); - next_reachable &= resolved_exec_block.1; + let post_reachable = body_reachable + && (resolved_exec_block.1 || block_ends_with_reachable_continue(&resolved_exec_block.0)); loop_scope.leave_scope(); @@ -60,7 +62,7 @@ pub(crate) fn resolve_for_loop( &yul_for.post_block.loc, &yul_for.post_block.statements, context, - next_reachable, + post_reachable, loop_scope, function_table, symtable, @@ -83,6 +85,28 @@ pub(crate) fn resolve_for_loop( )) } +fn block_ends_with_reachable_continue(block: &YulBlock) -> bool { + block + .statements + .iter() + .rev() + .find(|statement| statement.is_reachable()) + .map(statement_ends_with_reachable_continue) + .unwrap_or(false) +} + +fn statement_ends_with_reachable_continue(statement: &YulStatement) -> bool { + if !statement.is_reachable() { + return false; + } + + match statement { + YulStatement::Continue(..) => true, + YulStatement::Block(block) => block_ends_with_reachable_continue(block), + _ => false, + } +} + /// Resolve for initialization block. /// Returns the resolved block and a bool to indicate if the next statement is reachable. fn resolve_for_init_block( diff --git a/tests/polkadot_tests/yul.rs b/tests/polkadot_tests/yul.rs index bc428f065..f44b55009 100644 --- a/tests/polkadot_tests/yul.rs +++ b/tests/polkadot_tests/yul.rs @@ -315,3 +315,18 @@ fn storage_slot_on_return_data() { runtime.function("get", key.to_vec()); assert_eq!(runtime.output(), runtime.caller()) } + +#[test] +fn continue_only_for_body() { + build_solidity( + r#" +contract C { + function f() public pure { + assembly { + for { let i := 0 } lt(i, 1) { i := add(i, 1) } { continue } + } + } +} + "#, + ); +}