@@ -688,6 +688,30 @@ instructions[i].Operand is FieldDefinition reloadedField &&
688688
689689 bool CheckForCleanup ( List < Instruction > instructions , Instruction instruction , int currentIndex )
690690 {
691+ // The pattern we're looking for here is this:
692+ //
693+ // IL_00c6: ldloc.s 5
694+ // IL_00c8: call class [System.Private.CoreLib]System.Runtime.ExceptionServices.ExceptionDispatchInfo [System.Private.CoreLib]System.Runtime.ExceptionServices.ExceptionDispatchInfo::Capture(class [System.Private.CoreLib]System.Exception)
695+ // IL_00cd: callvirt instance void [System.Private.CoreLib]System.Runtime.ExceptionServices.ExceptionDispatchInfo::Throw()
696+ // IL_00d2: nop
697+ // IL_00d3: ldarg.0
698+ // IL_00d4: ldfld int32 Coverlet.Core.Samples.Tests.AwaitUsing/'<Issue914_Repro_Example1>d__2'::'<>s__3'
699+ // IL_00d9: stloc.s 6
700+ // IL_00db: ldloc.s 6
701+ // IL_00dd: ldc.i4.1
702+ // IL_00de: beq.s IL_00e2
703+ // IL_00e0: br.s IL_00e4
704+ // IL_00e2: leave.s IL_0115
705+ //
706+ // It appears that this pattern is not generated in every "await using",
707+ // but only in an "await using" without curly braces (i.e., that is
708+ // scoped to the end of the method). It's also a slightly different
709+ // pattern in Release vs. Debug (bne.un.s instead of beq.s followed by
710+ // br.s). To be as safe as we can, we'll expect an ldc.i4 to precede
711+ // the branch, then we want a load from a compiler-generated field within
712+ // a few instructions before that, then we want an exception to be
713+ // rethrown before that.
714+
691715 if ( instruction . OpCode != OpCodes . Beq &&
692716 instruction . OpCode != OpCodes . Beq_S &&
693717 instruction . OpCode != OpCodes . Bne_Un &&
0 commit comments