@@ -688,6 +688,30 @@ instructions[i].Operand is FieldDefinition reloadedField &&
688
688
689
689
bool CheckForCleanup ( List < Instruction > instructions , Instruction instruction , int currentIndex )
690
690
{
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
+
691
715
if ( instruction . OpCode != OpCodes . Beq &&
692
716
instruction . OpCode != OpCodes . Beq_S &&
693
717
instruction . OpCode != OpCodes . Bne_Un &&
0 commit comments