Skip to content

CFG does not handle pattern dispose correctly #49267

@333fred

Description

@333fred
        [Fact]
        public void AsyncForeach_StructEnumerator()
        {
            var compilation = CreateCompilation(@"
#pragma warning disable CS1998 // async method lacks awaits
using System.Threading.Tasks;
class C
{
    static async Task Main()
    /*<bind>*/{
        await foreach (var i in new C())
        {
        }
    }/*</bind>*/
    public AsyncEnumerator GetAsyncEnumerator() => throw null;
    public struct AsyncEnumerator
    {
        public int Current => throw null;
        public async Task<bool> MoveNextAsync() => throw null;
        public async ValueTask DisposeAsync() => throw null;
    }
}", targetFramework: TargetFramework.NetCoreApp30);

            VerifyOperationTreeAndDiagnosticsForTest<BlockSyntax>(compilation, @"
IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }')
  IForEachLoopOperation (LoopKind.ForEach, IsAsynchronous, Continue Label Id: 0, Exit Label Id: 1) (OperationKind.Loop, Type: null) (Syntax: 'await forea ... }')
    Locals: Local_1: System.Int32 i
    LoopControlVariable: 
      IVariableDeclaratorOperation (Symbol: System.Int32 i) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'var')
        Initializer: 
          null
    Collection: 
      IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: C, IsImplicit) (Syntax: 'new C()')
        Conversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
        Operand: 
          IObjectCreationOperation (Constructor: C..ctor()) (OperationKind.ObjectCreation, Type: C) (Syntax: 'new C()')
            Arguments(0)
            Initializer: 
              null
    Body: 
      IBlockOperation (0 statements) (OperationKind.Block, Type: null) (Syntax: '{ ... }')
    NextVariables(0)
            ", DiagnosticDescription.None);

            VerifyFlowGraphForTest<BlockSyntax>(compilation, @"");
        }

This causes an assertion in ControlFlowGraphBuilder.AddDisposingFinally, which was not updated to handle pattern-based dispose on ref structs or async contexts.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions