diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs index ecf39897dd..f7ea3f0106 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs @@ -71,6 +71,20 @@ public static async IAsyncEnumerable CountToWithConfigureAwait(int until) await Task.Delay(10).ConfigureAwait(continueOnCapturedContext: false); } } + + public static async IAsyncEnumerable AwaitInFinallyWithCancellation([EnumeratorCancellation] CancellationToken cancellationToken) + { + await Task.Yield(); + try + { + yield return 1; + await Task.Delay(10, cancellationToken); + } + finally + { + await Task.Yield(); + } + } } public struct TestStruct diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs index 8e5619d1f7..04baaf3584 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs @@ -911,6 +911,11 @@ private Block CheckSetResultReturnBlock(BlockContainer blockContainer, int setRe finalStateKnown = true; pos++; + // [optional] stfld <>u__N(ldloc this, ldnull) + // The hoisted-local cleanup may appear either before or after the combined-tokens disposal + // (the latter is present for async iterators with an [EnumeratorCancellation] token). + MatchHoistedLocalCleanup(block, ref pos); + if (pos + 2 == block.Instructions.Count && block.MatchIfAtEndOfBlock(out var condition, out var trueInst, out var falseInst)) { if (MatchDisposeCombinedTokens(blockContainer, condition, trueInst, falseInst, blocksAnalyzed, out var setResultAndExitBlock)) @@ -1088,6 +1093,12 @@ void ValidateCatchBlock() finalState = newState; finalStateKnown = true; } + + // [optional] stfld <>u__N(ldloc this, ldnull) + // The hoisted-local cleanup may appear either before or after the combined-tokens disposal + // (the latter is present for async iterators with an [EnumeratorCancellation] token). + MatchHoistedLocalCleanup(catchBlock, ref pos); + if (pos + 2 == catchBlock.Instructions.Count && catchBlock.MatchIfAtEndOfBlock(out var condition, out var trueInst, out var falseInst)) { if (MatchDisposeCombinedTokens(handlerContainer, condition, trueInst, falseInst, blocksAnalyzed, out var setResultAndExitBlock))