From b5829098dcfc58653ed2bf0ec61d84282f1edf56 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Wed, 15 May 2024 12:16:52 +0200 Subject: [PATCH] Add more "ref in async" tests (#73444) * Add more "ref in async" tests * Link langversion diagnostic mismatch issue in more tests * Test inline array init with awaits --- .../Emit/CodeGen/CodeGenAwaitForeachTests.cs | 602 ++++++++- .../Emit/CodeGen/CodeGenAwaitUsingTests.cs | 435 +++++++ .../Test/Emit2/Emit/NumericIntPtrTests.cs | 1 + .../Test/Emit2/Semantics/InlineArrayTests.cs | 213 ++++ .../Emit3/RefUnsafeInIteratorAndAsyncTests.cs | 1099 +++++++++++++++++ .../Semantics/RefLocalsAndReturnsTests.cs | 288 ++++- .../Semantics/SpanStackSafetyTests.cs | 31 + .../Test/Semantic/Semantics/UnsafeTests.cs | 210 +++- 8 files changed, 2871 insertions(+), 8 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Emit3/RefUnsafeInIteratorAndAsyncTests.cs diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs index 9a099be01840b..2dcb0b215b19d 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs @@ -2062,7 +2062,7 @@ public S(int i) } [Fact] - public void TestWithPattern_RefStructEnumerator() + public void TestWithPattern_RefStructEnumerator_Async() { var source = """ using System.Threading.Tasks; @@ -2096,7 +2096,206 @@ public ref struct Enumerator } [Fact] - public void TestWithPattern_RefStructCurrent() + public void TestWithPattern_RefStructEnumerator_AsyncIterator() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async IAsyncEnumerable M() + { + await foreach (var x in new C()) + { + yield return x; + } + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public ref struct Enumerator + { + public int Current => 0; + public Task MoveNextAsync() => throw null; + } + } + """ + s_IAsyncEnumerable; + + var expectedDiagnostics = new[] + { + // (7,15): error CS8344: foreach statement cannot operate on enumerators of type 'C.Enumerator' in async or iterator methods because 'C.Enumerator' is a ref struct. + // await foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(7, 15) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void TestWithPattern_RefStructEnumerator_Iterator() + { + var source = """ + using System.Collections.Generic; + public class C + { + public static IEnumerable M() + { + foreach (var x in new C()) + { + yield return x; + } + } + public Enumerator GetEnumerator() => new Enumerator(); + public ref struct Enumerator + { + public int Current => 0; + public bool MoveNext() => throw null; + } + } + """; + + var expectedDiagnostics = new[] + { + // (6,9): error CS8344: foreach statement cannot operate on enumerators of type 'C.Enumerator' in async or iterator methods because 'C.Enumerator' is a ref struct. + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(6, 9) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void TestWithPattern_RefStructEnumerable_Async() + { + var source = """ + using System; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var x in new Enumerable()) + { + await Task.Yield(); + Console.Write($"{x} "); + } + Console.Write("Done"); + } + public ref struct Enumerable + { + public Enumerator GetAsyncEnumerator() => new(); + } + public class Enumerator + { + int i = 0; + public int Current => i; + public async Task MoveNextAsync() + { + i++; + await Task.Yield(); + return i < 3; + } + } + } + """ + s_IAsyncEnumerable; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "1 2 Done").VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructEnumerable_AsyncIterator() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var i in M()) + { + Console.Write($"{i} "); + } + Console.Write("Done"); + } + public static async IAsyncEnumerable M() + { + await foreach (var x in new Enumerable()) + { + await Task.Yield(); + yield return x * 2; + } + yield return -1; + } + public ref struct Enumerable + { + public Enumerator GetAsyncEnumerator() => new(); + } + public class Enumerator + { + int i = 0; + public int Current => i; + public async Task MoveNextAsync() + { + i++; + await Task.Yield(); + return i < 3; + } + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "2 4 -1 Done").VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructEnumerable_Iterator() + { + var source = """ + using System; + using System.Collections.Generic; + public class C + { + public static void Main() + { + foreach (var i in M()) + { + Console.Write($"{i} "); + } + Console.Write("Done"); + } + public static IEnumerable M() + { + foreach (var x in new Enumerable()) + { + yield return x * 2; + } + yield return -1; + } + public ref struct Enumerable + { + public Enumerator GetEnumerator() => new(); + } + public class Enumerator + { + int i = 0; + public int Current => i; + public bool MoveNext() + { + i++; + return i < 3; + } + } + } + """; + CompileAndVerify(source, expectedOutput: "2 4 -1 Done").VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructCurrent_Async() { var source = """ using System; @@ -2119,7 +2318,8 @@ public sealed class Enumerator : IAsyncDisposable public async Task MoveNextAsync() { i++; - return await Task.FromResult(i < 3); + await Task.Yield(); + return i < 3; } public async ValueTask DisposeAsync() { @@ -2157,7 +2357,132 @@ public S(int i) } [Fact] - public void TestWithPattern_RefReturningCurrent() + public void TestWithPattern_RefStructCurrent_AsyncIterator() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var s in M()) + { + Console.Write($"M:{s} "); + } + Console.Write("MainDone"); + } + public static async IAsyncEnumerable M() + { + await foreach (var s in new C()) + { + yield return s.ToString(); + } + yield return "Done"; + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator : IAsyncDisposable + { + int i = 0; + public S Current => new S(i); + public async Task MoveNextAsync() + { + i++; + await Task.Yield(); + return i < 3; + } + public async ValueTask DisposeAsync() + { + await Task.Yield(); + } + } + } + public ref struct S + { + int i; + public S(int i) + { + this.i = i; + } + public override string ToString() => i.ToString(); + } + """ + AsyncStreamsTypes; + + var expectedDiagnostics = new[] + { + // (16,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(16, 24) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + + var expectedOutput = "M:1 M:2 M:Done MainDone"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructCurrent_Iterator() + { + var source = """ + using System; + using System.Collections.Generic; + public class C + { + public static void Main() + { + foreach (var s in M()) + { + Console.Write($"M:{s} "); + } + Console.Write("MainDone"); + } + public static IEnumerable M() + { + foreach (var s in new C()) + { + yield return s.ToString(); + } + yield return "Done"; + } + public Enumerator GetEnumerator() => new Enumerator(); + public sealed class Enumerator + { + int i = 0; + public S Current => new S(i); + public bool MoveNext() + { + i++; + return i < 3; + } + } + } + public ref struct S + { + int i; + public S(int i) + { + this.i = i; + } + public override string ToString() => i.ToString(); + } + """; + + var expectedOutput = "M:1 M:2 M:Done MainDone"; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_Async() { string source = @" using static System.Console; @@ -2208,6 +2533,275 @@ public override string ToString() CompileAndVerify(comp, expectedOutput: "1 2 3 Done", verify: Verification.Fails); } + [Fact] + public void TestWithPattern_RefReturningCurrent_Async_RefVariable() + { + string source = """ + using System; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (ref var s in new C()) + { + Console.Write($"{s} "); + s.F++; + } + Console.Write("Done"); + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator + { + S _current; + public ref S Current => ref _current; + public async Task MoveNextAsync() + { + Current = new S(Current.F + 1); + await Task.Yield(); + return Current.F < 4; + } + } + } + public struct S + { + public int F; + public S(int i) + { + this.F = i; + } + public override string ToString() => F.ToString(); + } + """ + s_IAsyncEnumerable; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,32): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 32)); + + var expectedOutput = "1 3 Done"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_AsyncIterator_RefVariable_01() + { + string source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var s in M()) + { + Console.Write($"M:{s} "); + } + Console.Write("MainDone"); + } + public static async IAsyncEnumerable M() + { + await foreach (ref var s in new C()) + { + s.F++; + yield return s.ToString(); + } + yield return "Done"; + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator + { + S _current; + public ref S Current => ref _current; + public async Task MoveNextAsync() + { + Current = new S(Current.F + 1); + await Task.Yield(); + return Current.F < 4; + } + } + } + public struct S + { + public int F; + public S(int i) + { + this.F = i; + } + public override string ToString() => F.ToString(); + } + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (16,32): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(16, 32)); + + var expectedOutput = "M:2 M:4 M:Done MainDone"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_AsyncIterator_RefVariable_02() + { + string source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async IAsyncEnumerable M() + { + await foreach (ref var s in new C()) + { + yield return s.ToString(); + s.F++; + } + yield return "Done"; + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator + { + public ref S Current => throw null; + public Task MoveNextAsync() => throw null; + } + } + public struct S + { + public int F; + } + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,32): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 32)); + + var expectedDiagnostics = new[] + { + // (10,13): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // s.F++; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "s.F").WithLocation(10, 13) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_Iterator_RefVariable_01() + { + string source = """ + using System; + using System.Collections.Generic; + public class C + { + public static void Main() + { + foreach (var s in M()) + { + Console.Write($"M:{s} "); + } + Console.Write("MainDone"); + } + public static IEnumerable M() + { + foreach (ref var s in new C()) + { + s.F++; + yield return s.ToString(); + } + yield return "Done"; + } + public Enumerator GetEnumerator() => new Enumerator(); + public sealed class Enumerator + { + S _current; + public ref S Current => ref _current; + public bool MoveNext() + { + Current = new S(Current.F + 1); + return Current.F < 4; + } + } + } + public struct S + { + public int F; + public S(int i) + { + this.F = i; + } + public override string ToString() => F.ToString(); + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (15,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(15, 26)); + + var expectedOutput = "M:2 M:4 M:Done MainDone"; + + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_Iterator_RefVariable_02() + { + string source = """ + using System.Collections.Generic; + public class C + { + public static IEnumerable M() + { + foreach (ref var s in new C()) + { + yield return s.ToString(); + s.F++; + } + yield return "Done"; + } + public Enumerator GetEnumerator() => new Enumerator(); + public sealed class Enumerator + { + public ref S Current => throw null; + public bool MoveNext() => throw null; + } + } + public struct S + { + public int F; + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 26)); + + var expectedDiagnostics = new[] + { + // (9,13): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // s.F++; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "s.F").WithLocation(9, 13) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + [Fact] public void TestWithPattern_IterationVariableIsReadOnly() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitUsingTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitUsingTests.cs index c388178fb6771..7282e99ed475f 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitUsingTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitUsingTests.cs @@ -3084,5 +3084,440 @@ public void Dispose() comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "DISPOSED"); } + + [Fact] + public void RefStruct_AwaitInside() + { + var source = """ + using System.Threading.Tasks; + class C + { + async Task M() + { + using (new R()) + { + await Task.Yield(); + } + } + } + ref struct R + { + public void Dispose() { } + } + """; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,16): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 16)); + + var expectedDiagnostics = new[] + { + // (6,16): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // using (new R()) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new R()").WithArguments("R").WithLocation(6, 16) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_YieldReturnInside() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M() + { + using (new R()) + { + yield return 1; + } + } + } + ref struct R + { + public void Dispose() { } + } + """; + + var expectedDiagnostics = new[] + { + // (6,16): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // using (new R()) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new R()").WithArguments("R").WithLocation(6, 16) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_YieldBreakInside() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var x in M(true)) { Console.Write(x); } + Console.Write(" "); + foreach (var x in M(false)) { Console.Write(x); } + } + static IEnumerable M(bool b) + { + yield return 123; + using (new R()) + { + if (b) { yield break; } + } + yield return 456; + } + } + ref struct R + { + public R() => Console.Write("C"); + public void Dispose() => Console.Write("D"); + } + """; + + var expectedOutput = "123CD 123CD456"; + + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular12).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_AwaitResource() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + Console.Write("1"); + using ((await GetC()).GetR()) + { + Console.Write("2"); + } + Console.Write("3"); + } + static async Task GetC() + { + Console.Write("Ga"); + await Task.Yield(); + Console.Write("Gb"); + return new C(); + } + R GetR() => new R(); + } + ref struct R + { + public R() => Console.Write("C"); + public void Dispose() => Console.Write("D"); + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,16): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // using ((await GetC()).GetR()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "(await GetC()).GetR()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 16)); + + var expectedOutput = "1GaGbC2D3"; + + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, verify: Verification.FailsILVerify).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_AwaitOutside() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + Console.Write("1"); + await Task.Yield(); + Console.Write("2"); + using (new R()) + { + Console.Write("3"); + } + Console.Write("4"); + await Task.Yield(); + Console.Write("5"); + } + } + ref struct R + { + public R() => Console.Write("C"); + public void Dispose() => Console.Write("D"); + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (10,16): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 16)); + + var expectedOutput = "12C3D45"; + + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_YieldReturnOutside() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var x in M()) + { + Console.Write(x); + } + } + static IEnumerable M() + { + Console.Write("1"); + yield return "a"; + Console.Write("2"); + using (new R()) + { + Console.Write("3"); + } + Console.Write("4"); + yield return "b"; + Console.Write("5"); + } + } + ref struct R + { + public R() => Console.Write("C"); + public void Dispose() => Console.Write("D"); + } + """; + + var expectedOutput = "1a2C3D4b5"; + + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular12).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_AwaitUsing() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + Console.Write("1"); + await using (new R()) + { + Console.Write("2"); + } + Console.Write("3"); + } + } + ref struct R + { + public R() => Console.Write("C"); + public ValueTask DisposeAsync() + { + Console.Write("D"); + return default; + } + } + """; + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22)); + + var expectedOutput = "1C2D3"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_AwaitUsing_AwaitInside() + { + var source = """ + using System.Threading.Tasks; + class C + { + async Task M() + { + await using (new R()) + { + await Task.Yield(); + } + } + } + ref struct R + { + public ValueTask DisposeAsync() => default; + } + """; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22)); + + var expectedDiagnostics = new[] + { + // (6,22): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // await using (new R()) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new R()").WithArguments("R").WithLocation(6, 22) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_AwaitUsing_YieldReturnInside() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M() + { + await using (new R()) + { + yield return 123; + } + } + } + ref struct R + { + public ValueTask DisposeAsync() => default; + } + """ + AsyncStreamsTypes; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22)); + + var expectedDiagnostics = new[] + { + // (7,22): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // await using (new R()) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new R()").WithArguments("R").WithLocation(7, 22) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_AwaitUsing_YieldReturnInside_Var() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M() + { + await using var _ = new R(); + yield return 123; + } + } + ref struct R + { + public ValueTask DisposeAsync() => default; + } + """ + AsyncStreamsTypes; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,21): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using var _ = new R(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 21)); + + var expectedDiagnostics = new[] + { + // (7,25): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // await using var _ = new R(); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "_ = new R()").WithArguments("R").WithLocation(7, 25) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_AwaitUsing_YieldBreakInside() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var x in M(true)) { Console.Write(x); } + Console.Write(" "); + await foreach (var x in M(false)) { Console.Write(x); } + } + static async IAsyncEnumerable M(bool b) + { + yield return 1; + await using (new R()) + { + if (b) { yield break; } + } + yield return 2; + } + } + ref struct R + { + public R() => Console.Write("C"); + public ValueTask DisposeAsync() + { + Console.Write("D"); + return default; + } + } + """ + AsyncStreamsTypes; + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (15,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(15, 22)); + + var expectedOutput = "1CD 1CD2"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs index c12ba96764e8a..458de9f14813a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs @@ -1359,6 +1359,7 @@ static IEnumerable F() yield return sizeof(System.UIntPtr); } }"; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 var expectedDiagnostics = new[] { // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs index 3c90e1f58fc4f..d5d80837c3439 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs @@ -23106,5 +23106,218 @@ struct ThreeStringBuffer { var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "123124").VerifyDiagnostics(); } + + [Fact] + public void Initialization_Await_RefStruct() + { + var src = """ + using System.Threading.Tasks; + + var b = new Buffer(); + b[0] = await GetInt(); + b[1] = await GetInt(); + + static Task GetInt() => Task.FromResult(42); + + [System.Runtime.CompilerServices.InlineArray(4)] + ref struct Buffer + { + private int _element0; + } + """; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (3,1): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var b = new Buffer(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 1), + // (4,1): error CS0306: The type 'Buffer' may not be used as a type argument + // b[0] = await GetInt(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "b[0]").WithArguments("Buffer").WithLocation(4, 1), + // (5,1): error CS0306: The type 'Buffer' may not be used as a type argument + // b[1] = await GetInt(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "b[1]").WithArguments("Buffer").WithLocation(5, 1), + // (10,12): warning CS9184: 'Inline arrays' language feature is not supported for an inline array type that is not valid as a type argument, or has element type that is not valid as a type argument. + // ref struct Buffer + Diagnostic(ErrorCode.WRN_InlineArrayNotSupportedByLanguage, "Buffer").WithLocation(10, 12)); + + var expectedDiagnostics = new[] + { + // (4,1): error CS0306: The type 'Buffer' may not be used as a type argument + // b[0] = await GetInt(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "b[0]").WithArguments("Buffer").WithLocation(4, 1), + // (5,1): error CS0306: The type 'Buffer' may not be used as a type argument + // b[1] = await GetInt(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "b[1]").WithArguments("Buffer").WithLocation(5, 1), + // (10,12): warning CS9184: 'Inline arrays' language feature is not supported for an inline array type that is not valid as a type argument, or has element type that is not valid as a type argument. + // ref struct Buffer + Diagnostic(ErrorCode.WRN_InlineArrayNotSupportedByLanguage, "Buffer").WithLocation(10, 12) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Initialization_Await() + { + var src = """ + using System.Threading.Tasks; + + var b = new Buffer(); + b[0] = await GetInt(); + System.Console.Write(b[1]); + b[1] = await GetInt(); + System.Console.Write(b[1]); + + static Task GetInt() => Task.FromResult(42); + + [System.Runtime.CompilerServices.InlineArray(4)] + struct Buffer + { + private int _element0; + } + """; + foreach (var parseOptions in new[] { TestOptions.Regular12, TestOptions.RegularNext, TestOptions.RegularPreview }) + { + var verifier = CompileAndVerify(src, expectedOutput: ExecutionConditionUtil.IsDesktop ? null : "042", + parseOptions: parseOptions, targetFramework: TargetFramework.Net80, verify: Verification.FailsPEVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<
$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", """ + { + // Code size 316 (0x13c) + .maxstack 3 + .locals init (int V_0, + int V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<
$>d__0.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0054 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq IL_00cb + IL_0011: ldarg.0 + IL_0012: ldflda "Buffer Program.<
$>d__0.5__2" + IL_0017: initobj "Buffer" + IL_001d: call "System.Threading.Tasks.Task Program.<
$>g__GetInt|0_0()" + IL_0022: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_0027: stloc.2 + IL_0028: ldloca.s V_2 + IL_002a: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_002f: brtrue.s IL_0070 + IL_0031: ldarg.0 + IL_0032: ldc.i4.0 + IL_0033: dup + IL_0034: stloc.0 + IL_0035: stfld "int Program.<
$>d__0.<>1__state" + IL_003a: ldarg.0 + IL_003b: ldloc.2 + IL_003c: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_0041: ldarg.0 + IL_0042: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder" + IL_0047: ldloca.s V_2 + IL_0049: ldarg.0 + IL_004a: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)" + IL_004f: leave IL_013b + IL_0054: ldarg.0 + IL_0055: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_005a: stloc.2 + IL_005b: ldarg.0 + IL_005c: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_0061: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0067: ldarg.0 + IL_0068: ldc.i4.m1 + IL_0069: dup + IL_006a: stloc.0 + IL_006b: stfld "int Program.<
$>d__0.<>1__state" + IL_0070: ldloca.s V_2 + IL_0072: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_0077: stloc.1 + IL_0078: ldarg.0 + IL_0079: ldflda "Buffer Program.<
$>d__0.5__2" + IL_007e: call "ref int .InlineArrayFirstElementRef(ref Buffer)" + IL_0083: ldloc.1 + IL_0084: stind.i4 + IL_0085: ldarg.0 + IL_0086: ldflda "Buffer Program.<
$>d__0.5__2" + IL_008b: ldc.i4.1 + IL_008c: call "ref int .InlineArrayElementRef(ref Buffer, int)" + IL_0091: ldind.i4 + IL_0092: call "void System.Console.Write(int)" + IL_0097: call "System.Threading.Tasks.Task Program.<
$>g__GetInt|0_0()" + IL_009c: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_00a1: stloc.2 + IL_00a2: ldloca.s V_2 + IL_00a4: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_00a9: brtrue.s IL_00e7 + IL_00ab: ldarg.0 + IL_00ac: ldc.i4.1 + IL_00ad: dup + IL_00ae: stloc.0 + IL_00af: stfld "int Program.<
$>d__0.<>1__state" + IL_00b4: ldarg.0 + IL_00b5: ldloc.2 + IL_00b6: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_00bb: ldarg.0 + IL_00bc: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder" + IL_00c1: ldloca.s V_2 + IL_00c3: ldarg.0 + IL_00c4: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)" + IL_00c9: leave.s IL_013b + IL_00cb: ldarg.0 + IL_00cc: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_00d1: stloc.2 + IL_00d2: ldarg.0 + IL_00d3: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_00d8: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_00de: ldarg.0 + IL_00df: ldc.i4.m1 + IL_00e0: dup + IL_00e1: stloc.0 + IL_00e2: stfld "int Program.<
$>d__0.<>1__state" + IL_00e7: ldloca.s V_2 + IL_00e9: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_00ee: stloc.1 + IL_00ef: ldarg.0 + IL_00f0: ldflda "Buffer Program.<
$>d__0.5__2" + IL_00f5: ldc.i4.1 + IL_00f6: call "ref int .InlineArrayElementRef(ref Buffer, int)" + IL_00fb: ldloc.1 + IL_00fc: stind.i4 + IL_00fd: ldarg.0 + IL_00fe: ldflda "Buffer Program.<
$>d__0.5__2" + IL_0103: ldc.i4.1 + IL_0104: call "ref int .InlineArrayElementRef(ref Buffer, int)" + IL_0109: ldind.i4 + IL_010a: call "void System.Console.Write(int)" + IL_010f: leave.s IL_0128 + } + catch System.Exception + { + IL_0111: stloc.3 + IL_0112: ldarg.0 + IL_0113: ldc.i4.s -2 + IL_0115: stfld "int Program.<
$>d__0.<>1__state" + IL_011a: ldarg.0 + IL_011b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder" + IL_0120: ldloc.3 + IL_0121: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0126: leave.s IL_013b + } + IL_0128: ldarg.0 + IL_0129: ldc.i4.s -2 + IL_012b: stfld "int Program.<
$>d__0.<>1__state" + IL_0130: ldarg.0 + IL_0131: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder" + IL_0136: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_013b: ret + } + """); + } + } } } diff --git a/src/Compilers/CSharp/Test/Emit3/RefUnsafeInIteratorAndAsyncTests.cs b/src/Compilers/CSharp/Test/Emit3/RefUnsafeInIteratorAndAsyncTests.cs new file mode 100644 index 0000000000000..d3b9880ee2a9d --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit3/RefUnsafeInIteratorAndAsyncTests.cs @@ -0,0 +1,1099 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public class RefUnsafeInIteratorAndAsyncTests : CSharpTestBase +{ + private static string? IfSpans(string expectedOutput) + => ExecutionConditionUtil.IsDesktop ? null : expectedOutput; + + [Fact] + public void LangVersion_RefLocalInAsync() + { + var source = """ + using System.Threading.Tasks; + class C + { + async Task M(int x) + { + ref int y = ref x; + ref readonly int z = ref y; + await Task.Yield(); + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 17), + // (7,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly int z = ref y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 26)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RefLocalInIterator() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + ref int y = ref x; + ref readonly int z = ref y; + yield return x; + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 17), + // (7,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly int z = ref y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 26)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RefLocalInIterator_IEnumerator() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerator M(int x) + { + ref int y = ref x; + ref readonly int z = ref y; + yield return x; + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 17), + // (7,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly int z = ref y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 26)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RefStructInAsync() + { + var source = """ + #pragma warning disable CS0219 // variable unused + using System.Threading.Tasks; + class C + { + async Task M() + { + R y = default; + scoped R z = default; + await Task.Yield(); + } + } + ref struct R { } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // R y = default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "R").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 9), + // (8,16): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // scoped R z = default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "R").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 16)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RefStructInIterator() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(R r) + { + M(r); + yield return -1; + } + } + ref struct R { } + """; + + var expectedDiagnostics = new[] + { + // (6,11): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // M(r); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "r").WithArguments("R").WithLocation(6, 11) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void LangVersion_RestrictedInAsync() + { + var source = """ + #pragma warning disable CS0219 // variable unused + using System.Threading.Tasks; + class C + { + async Task M() + { + System.TypedReference t = default; + await Task.Yield(); + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // System.TypedReference t = default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.TypedReference").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 9)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RestrictedInIterator() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(System.TypedReference t) + { + t.GetHashCode(); + yield return -1; + } + } + """; + + var expectedDiagnostics = new[] + { + // (6,9): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // t.GetHashCode(); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "t").WithArguments("System.TypedReference").WithLocation(6, 9) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Await_RefLocal_Across() + { + var source = """ + using System.Threading.Tasks; + class C + { + async Task M(int x) + { + ref int y = ref x; + await Task.Yield(); + System.Console.Write(y); + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (8,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(8, 30)); + } + + [Fact] + public void Await_RefLocal_Across_Reassign() + { + var source = """ + using System.Threading.Tasks; + class C + { + static Task Main() => M(123, 456); + static async Task M(int x, int z) + { + ref int y = ref x; + await Task.Yield(); + y = ref z; + System.Console.Write(y); + } + } + """; + CompileAndVerify(source, expectedOutput: "456").VerifyDiagnostics(); + } + + [Fact] + public void Await_RefLocal_Between() + { + var source = """ + using System.Threading.Tasks; + class C + { + static Task Main() => M(123); + static async Task M(int x) + { + ref int y = ref x; + System.Console.Write(y); + await Task.Yield(); + } + } + """; + CompileAndVerify(source, expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void Await_RefStruct_Across() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + async Task M(int x) + { + Span y = new(ref x); + await Task.Yield(); + Console.Write(y.ToString()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(9, 23)); + } + + [Fact] + public void Await_RefStruct_Across_Reassign() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static Task Main() => M(123, 456); + static async Task M(int x, int z) + { + Span y = new(ref x); + await Task.Yield(); + y = new(ref z); + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("456"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void Await_RefStruct_Between() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static Task Main() => M(123); + static async Task M(int x) + { + Span y = new(ref x); + Console.Write(y[0]); + await Task.Yield(); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("123"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void Await_Restricted_Across() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + async Task M() + { + TypedReference y = default; + await Task.Yield(); + Console.Write(y.GetHashCode()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.GetHashCode()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.TypedReference").WithLocation(9, 23)); + } + + [Fact] + public void Await_Restricted_Across_Reassign() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + TypedReference y = default; + await Task.Yield(); + y = default; + Console.Write(y.GetHashCode()); + } + } + """; + CompileAndVerify(source, expectedOutput: "0").VerifyDiagnostics(); + } + + [Fact] + public void Await_Restricted_Between() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + TypedReference y = default; + Console.Write(y.GetHashCode()); + await Task.Yield(); + } + } + """; + CompileAndVerify(source, expectedOutput: "0").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Across() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + ref int y = ref x; + yield return 1; + System.Console.Write(y); + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (8,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(8, 30)); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Indexer() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable this[int x] + { + get + { + ref int y = ref x; + yield return 1; + System.Console.Write(y); + } + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (10,34): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(10, 34)); + } + + [Fact] + public void YieldReturn_RefLocal_Across_NestedBlock() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + ref int y = ref x; + if (x != 0) { yield return 1; } + System.Console.Write(y); + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (8,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(8, 30)); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Async() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M(int x) + { + ref int y = ref x; + yield return 1; await Task.Yield(); + System.Console.Write(y); + } + } + """ + AsyncStreamsTypes; + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics( + // (9,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(9, 30)); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Reassign() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M(123, 456)) + { + Console.Write(i + " "); + } + } + static IEnumerable M(int x, int z) + { + ref int y = ref x; + yield return -1; + y = ref z; + Console.Write(y); + } + } + """; + CompileAndVerify(source, expectedOutput: "-1 456").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Reassign_Indexer() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in new C()[123, 456]) + { + Console.Write(i + " "); + } + } + IEnumerable this[int x, int z] + { + get + { + ref int y = ref x; + yield return -1; + y = ref z; + Console.Write(y); + } + } + } + """; + CompileAndVerify(source, expectedOutput: "-1 456").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Reassign_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var i in M(123, 456)) + { + Console.Write(i + " "); + } + } + static async IAsyncEnumerable M(int x, int z) + { + ref int y = ref x; + yield return -1; await Task.Yield(); + y = ref z; + Console.Write(y); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "-1 456").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Between() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M(123)) + { + Console.Write(i + " "); + } + } + static IEnumerable M(int x) + { + ref int y = ref x; + Console.Write(y); + yield return -1; + } + } + """; + CompileAndVerify(source, expectedOutput: "123-1").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Between_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var i in M(123)) + { + Console.Write(i + " "); + } + } + static async IAsyncEnumerable M(int x) + { + ref int y = ref x; + Console.Write(y); + yield return -1; await Task.Yield(); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "123-1").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefStruct_Across() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + Span y = new(ref x); + yield return -1; + Console.Write(y.ToString()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(9, 23)); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Indexer() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + IEnumerable this[int x] + { + get + { + Span y = new(ref x); + yield return -1; + Console.Write(y.ToString()); + } + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (11,27): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(11, 27)); + } + + [Fact] + public void YieldReturn_RefStruct_Across_NestedBlock() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + Span y = new(ref x); + if (x != 0) { yield return -1; } + Console.Write(y.ToString()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(9, 23)); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M(int x) + { + Span y = new(ref x); + yield return -1; await Task.Yield(); + Console.Write(y.ToString()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (10,23): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(10, 23)); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Reassign() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M(123, 456)) + { + Console.Write(i + " "); + } + } + static IEnumerable M(int x, int z) + { + Span y = new(ref x); + yield return -1; + y = new(ref z); + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("-1 456"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Reassign_Indexer() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in new C()[123, 456]) + { + Console.Write(i + " "); + } + } + IEnumerable this[int x, int z] + { + get + { + Span y = new(ref x); + yield return -1; + y = new(ref z); + Console.Write(y[0]); + } + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("-1 456"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Reassign_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var i in M(123, 456)) + { + Console.Write(i + " "); + } + } + static async IAsyncEnumerable M(int x, int z) + { + Span y = new(ref x); + yield return -1; await Task.Yield(); + y = new(ref z); + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("-1 456"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefStruct_Between() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M(123)) + { + Console.Write(i + " "); + } + } + static IEnumerable M(int x) + { + Span y = new(ref x); + Console.Write(y[0]); + yield return -1; + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("123-1"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_Restricted_Across() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + IEnumerable M() + { + TypedReference y = default; + yield return -1; + Console.Write(y.GetHashCode()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.GetHashCode()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.TypedReference").WithLocation(9, 23)); + } + + [Fact] + public void YieldReturn_Restricted_Across_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M() + { + TypedReference y = default; + yield return -1; await Task.Yield(); + Console.Write(y.GetHashCode()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (10,23): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.GetHashCode()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.TypedReference").WithLocation(10, 23)); + } + + [Fact] + public void YieldReturn_Restricted_Across_Reassign() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M()) + { + Console.Write(i + " "); + } + } + static IEnumerable M() + { + TypedReference y = default; + yield return -1; + y = default; + Console.Write(y.GetHashCode()); + } + } + """; + CompileAndVerify(source, expectedOutput: "-1 0").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_Restricted_Across_Reassign_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var i in M()) + { + Console.Write(i + " "); + } + } + static async IAsyncEnumerable M() + { + TypedReference y = default; + yield return -1; await Task.Yield(); + y = default; + Console.Write(y.GetHashCode()); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "-1 0").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_Restricted_Between() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M()) + { + Console.Write(i + " "); + } + } + static IEnumerable M() + { + TypedReference y = default; + Console.Write(y.GetHashCode()); + yield return -1; + } + } + """; + CompileAndVerify(source, expectedOutput: "0-1").VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_RefLocal_Across() + { + var source = """ + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var a in M(10)) { throw null; } + foreach (var b in M(123)) { throw null; } + } + static IEnumerable M(int x) + { + ref int y = ref x; + if (x < 100) yield break; + System.Console.Write(y); + } + } + """; + CompileAndVerify(source, expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_RefLocal_Across_Async() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var a in M(10)) { throw null; } + await foreach (var b in M(123)) { throw null; } + } + static async IAsyncEnumerable M(int x) + { + ref int y = ref x; + if (x < 100) { await Task.Yield(); yield break; } + System.Console.Write(y); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_RefStruct_Across() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var a in M(10)) { throw null; } + foreach (var b in M(123)) { throw null; } + } + static IEnumerable M(int x) + { + Span y = new(ref x); + if (x < 100) yield break; + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("123"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_RefStruct_Across_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var a in M(10)) { throw null; } + await foreach (var b in M(123)) { throw null; } + } + static async IAsyncEnumerable M(int x) + { + Span y = new(ref x); + if (x < 100) { await Task.Yield(); yield break; } + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("123"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_Restricted_Across() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var a in M(10)) { throw null; } + foreach (var b in M(123)) { throw null; } + } + static IEnumerable M(int x) + { + TypedReference t = default; + if (x < 100) yield break; + Console.Write(x + t.GetHashCode()); + } + } + """; + CompileAndVerify(source, expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_Restricted_Across_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var a in M(10)) { throw null; } + await foreach (var b in M(123)) { throw null; } + } + static async IAsyncEnumerable M(int x) + { + TypedReference t = default; + if (x < 100) { await Task.Yield(); yield break; } + Console.Write(x + t.GetHashCode()); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "123").VerifyDiagnostics(); + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs index 6ae6534c5b23f..7299939536559 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs @@ -3152,10 +3152,149 @@ IEnumerable localFunction() } } }"; - + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 17), + // (13,21): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int z = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 21)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); CreateCompilation(code).VerifyEmitDiagnostics(); } + [Fact] + public void RefLocal_Iterator_LocalFunction_01() + { + var code = """ + using System; + using System.Collections.Generic; + + int x = 5; + + foreach (var z in func()) + { + Console.Write(z); + x++; + } + + IEnumerable func() + { + ref int y = ref x; + yield return y; + y = ref x; + yield return y; + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (14,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 13)); + + var expectedOutput = "56"; + + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefLocal_Iterator_LocalFunction_02() + { + var code = """ + using System.Collections.Generic; + + int x = 5; + + IEnumerable func() + { + ref int y = ref x; + yield return y; + yield return y; + } + + func(); + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 13)); + + var expectedDiagnostics = new[] + { + // (9,18): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // yield return y; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(9, 18) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_Iterator_LocalFunction_01() + { + var code = """ + using System; + using System.Collections.Generic; + + int x = 5; + + foreach (var z in func()) + { + Console.Write(z); + x++; + } + + IEnumerable func() + { + Span y = new(ref x); + yield return y[0]; + y = new(ref x); + yield return y[0]; + } + """; + + var expectedOutput = ExecutionConditionUtil.IsDesktop ? null : "56"; + + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_Iterator_LocalFunction_02() + { + var code = """ + using System; + using System.Collections.Generic; + + int x = 5; + + IEnumerable func() + { + Span y = new(ref x); + yield return y[0]; + yield return y[0]; + } + + func(); + """; + + var expectedDiagnostics = new[] + { + // (10,18): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // yield return y[0]; + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(10, 18) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); + } + [Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")] public void AsyncMethodsCannotHaveRefLocals() { @@ -3174,7 +3313,152 @@ await Task.Run(async () => }); } }"; - CreateCompilationWithMscorlib45(code).VerifyEmitDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 17), + // (11,21): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int z = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 21)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code).VerifyEmitDiagnostics(); + } + + [Fact] + public void RefLocal_Async_LocalFunction_01() + { + var code = """ + using System; + using System.Threading.Tasks; + + int x = 5; + + await func(); + + async Task func() + { + ref int y = ref x; + Console.Write(y); + await Task.Yield(); + y = ref x; + Console.Write(y); + await Task.Yield(); + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (10,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 13)); + + var expectedOutput = "55"; + + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefLocal_Async_LocalFunction_02() + { + var code = """ + using System; + using System.Threading.Tasks; + + int x = 5; + + async Task func() + { + ref int y = ref x; + await Task.Yield(); + Console.Write(y); + } + + await func(); + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 13)); + + var expectedDiagnostics = new[] + { + // (10,19): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(10, 19) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_Async_LocalFunction_01() + { + var code = """ + using System; + using System.Threading.Tasks; + + int x = 5; + + await func(); + + async Task func() + { + Span y = new(ref x); + Console.Write(y[0]); + await Task.Yield(); + y = new(ref x); + Console.Write(y[0]); + await Task.Yield(); + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyDiagnostics( + // (10,5): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Span y = new(ref x); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Span").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 5)); + + var expectedOutput = ExecutionConditionUtil.IsDesktop ? null : "55"; + + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_Async_LocalFunction_02() + { + var code = """ + using System; + using System.Threading.Tasks; + + int x = 5; + + async Task func() + { + Span y = new(ref x); + await Task.Yield(); + Console.Write(y[0]); + } + + await func(); + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyDiagnostics( + // (8,5): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Span y = new(ref x); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Span").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 5)); + + var expectedDiagnostics = new[] + { + // (10,19): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y[0]); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(10, 19) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs index f2d5e86fc2836..e3e2312163fa8 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs @@ -1480,6 +1480,37 @@ public static async Task I1() comp.VerifyEmitDiagnostics(expectedDiagnostics); } + [Fact] + public void AwaitAssignSpan() + { + var source = """ + using System; + using System.Threading.Tasks; + + ReadOnlySpan r = await M(); + Console.Write(r[1]); + + async Task M() + { + await Task.Yield(); + return new[] { 4, 5, 6 }; + } + """; + + CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,1): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ReadOnlySpan r = await M(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ReadOnlySpan").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 1)); + + var expectedOutput = "5"; + + var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.RegularNext); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithSpan(source); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + [Fact] public void BaseMethods() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index b34a35cf0c104..ccfc049d18034 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -938,7 +938,7 @@ System.Collections.Generic.IEnumerable M() } [Fact] - public void UnsafeContext_LocalFunctionInIterator_Unsafe() + public void UnsafeContext_LocalFunctionInIterator_BreakingChange() { var code = """ unsafe class C @@ -966,7 +966,7 @@ System.Collections.Generic.IEnumerable M() } [Fact] - public void UnsafeContext_LocalFunctionInIterator_Unsafe_BreakingChangeWorkaround() + public void UnsafeContext_LocalFunctionInIterator_BreakingChangeWorkaround() { var code = """ unsafe class C @@ -985,6 +985,129 @@ System.Collections.Generic.IEnumerable M() CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange_Property() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable P + { + get + { + yield return 1; + local(); + void local() { int* p = null; } + } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (9,28): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(9, 28) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange_Operator() + { + var code = """ + unsafe class C + { + public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) + { + yield return 1; + local(); + void local() { int* p = null; } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (7,24): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(7, 24) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange_Nested_01() + { + var code = """ + unsafe class C + { + void M() + { + local1(); + System.Collections.Generic.IEnumerable local1() + { + yield return 1; + local2(); + void local2() { int* p = null; } + } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (10,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local2() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 29) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange_Nested_02() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return 1; + local1(); + void local1() + { + local2(); + void local2() { int* p = null; } + } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (10,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local2() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 29) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73280")] public void UnsafeContext_LangVersion() { @@ -1189,6 +1312,26 @@ System.Collections.Generic.IEnumerable M() Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22)); } + [Fact] + public void UnsafeContext_Method_Iterator_Body_CSharp12_Safe_NestedBlock() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable M() + { + { + yield return sizeof(nint); + } + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,26): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 26)); + } + [Fact] public void UnsafeContext_Method_Iterator_Body_CSharp12_Unsafe() { @@ -1205,6 +1348,24 @@ System.Collections.Generic.IEnumerable M() CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); } + [Fact] + public void UnsafeContext_Method_Iterator_Body_CSharp12_Unsafe_NestedBlock() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + { + yield return local(); + } + int local() => sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + [Theory, CombinatorialData] public void UnsafeContext_Method_Iterator_Body_CSharp13(bool unsafeClass, bool unsafeMethod) { @@ -1229,6 +1390,32 @@ public void UnsafeContext_Method_Iterator_Body_CSharp13(bool unsafeClass, bool u CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } + [Theory, CombinatorialData] + public void UnsafeContext_Method_Iterator_Body_CSharp13_NestedBlock(bool unsafeClass, bool unsafeMethod) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} System.Collections.Generic.IEnumerable M() + { + { + yield return sizeof(nint); + } + } + } + """; + + var expectedDiagnostics = new[] + { + // (6,26): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 26) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + [Theory, CombinatorialData] public void UnsafeContext_Operator_Signature_Unsafe(bool unsafeClass, bool unsafeOperator) { @@ -2391,6 +2578,25 @@ public void UnsafeContext_Lambda_Iterator_Body_Safe() CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); } + [Fact] + public void UnsafeBlock_InAsyncMethod() + { + var code = """ + using System.Threading.Tasks; + class C + { + async Task M(int x) + { + unsafe { x = sizeof(nint); } + await Task.Yield(); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + [Fact] public void UnsafeModifier() {