From 5732dc49aae600c26c25b689cf48d99fe637bd6f Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Thu, 16 Apr 2020 10:34:55 -0700 Subject: [PATCH 1/5] Add reproducer --- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 8a9f23822203e..db35545f3f2d6 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -5606,5 +5606,30 @@ static async Task Main() var comp = CSharpTestBase.CreateCompilation(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "StructAwaitable"); } + + [Fact, WorkItem(40251, "https://github.com/dotnet/roslyn/issues/40251")] + public void Repro_40251() + { + const string source = @" +using System.Threading.Tasks; + +class IntCode +{ + public async Task Step(int i, Task t) + { + await t; + ReadMemory() = i switch + { + _ => throw null + }; + } + + private ref long ReadMemory() => throw null; +} +"; + + var comp = CreateCompilation(source, options: TestOptions.DebugDll); + comp.VerifyEmitDiagnostics(); + } } } From f24c58a7abf1e5f6ea7cf0320c3ae60f89e390a4 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Fri, 17 Apr 2020 15:43:26 -0700 Subject: [PATCH 2/5] Don't hoist ref locals --- .../IteratorAndAsyncCaptureWalker.cs | 2 +- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 32 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs index 609b2bc131564..2146dc596c258 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs @@ -121,7 +121,7 @@ private static bool HoistInDebugBuild(Symbol symbol) ParameterSymbol parameter => // in Debug build hoist all parameters that can be hoisted: !parameter.Type.IsRestrictedType(), - LocalSymbol { IsConst: false, IsPinned: false } local => + LocalSymbol { IsConst: false, IsPinned: false, IsRef: false } local => // hoist all user-defined locals and long-lived temps that can be hoisted: local.SynthesizedKind.MustSurviveStateMachineSuspension() && !local.Type.IsRestrictedType(), diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index db35545f3f2d6..f2d7a63ff7698 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -5608,7 +5608,7 @@ static async Task Main() } [Fact, WorkItem(40251, "https://github.com/dotnet/roslyn/issues/40251")] - public void Repro_40251() + public void AssignRefAfterAwait() { const string source = @" using System.Threading.Tasks; @@ -5630,6 +5630,36 @@ public async Task Step(int i, Task t) var comp = CreateCompilation(source, options: TestOptions.DebugDll); comp.VerifyEmitDiagnostics(); + comp = CreateCompilation(source, options: TestOptions.ReleaseDll); + comp.VerifyEmitDiagnostics(); + } + + [Fact, WorkItem(40251, "https://github.com/dotnet/roslyn/issues/40251")] + public void AssignRefWithAwait() + { + const string source = @" +using System.Threading.Tasks; + +class IntCode +{ + public async Task Step(Task t) + { + ReadMemory() = await t; + } + + private ref long ReadMemory() => throw null; +} +"; + var expected = new[] + { + // (8,9): error CS8178: 'await' cannot be used in an expression containing a call to 'IntCode.ReadMemory()' because it returns by reference + // ReadMemory() = await t; + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "ReadMemory()").WithArguments("IntCode.ReadMemory()").WithLocation(8, 9) + }; + var comp = CreateCompilation(source, options: TestOptions.DebugDll); + comp.VerifyEmitDiagnostics(expected); + comp = CreateCompilation(source, options: TestOptions.ReleaseDll); + comp.VerifyEmitDiagnostics(expected); } } } From 64f47e7c04fada460013f23f310b7aa8bb78cca0 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Mon, 20 Apr 2020 14:14:58 -0700 Subject: [PATCH 3/5] Address feedback --- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index f2d7a63ff7698..633301c44ecca 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -5612,26 +5612,53 @@ public void AssignRefAfterAwait() { const string source = @" using System.Threading.Tasks; +using System; class IntCode { - public async Task Step(int i, Task t) + public static async Task Main() { - await t; + await Step(0); + } + + public static async Task CompletedTask() + { + } + + public static async Task Step(int i) + { + Console.Write(field); + await CompletedTask(); ReadMemory() = i switch { - _ => throw null + _ => GetValue() }; + Console.Write(field); } - private ref long ReadMemory() => throw null; + public static long GetValue() + { + Console.Write(2); + return 3L; + } + + private static long field; + private static ref long ReadMemory() + { + Console.Write(1); + return ref field; + } } "; + var diags = new[] + { + // (12,30): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. + // public static async Task CompletedTask() + Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "CompletedTask").WithLocation(12, 30) + }; - var comp = CreateCompilation(source, options: TestOptions.DebugDll); - comp.VerifyEmitDiagnostics(); - comp = CreateCompilation(source, options: TestOptions.ReleaseDll); - comp.VerifyEmitDiagnostics(); + CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "0123").VerifyDiagnostics(diags); + CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "0123").VerifyDiagnostics(diags); } [Fact, WorkItem(40251, "https://github.com/dotnet/roslyn/issues/40251")] From 0e7f69f3d681ad6dcca325d894bb0e156c1e5676 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Mon, 20 Apr 2020 17:06:19 -0700 Subject: [PATCH 4/5] Skip verification --- src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 633301c44ecca..533933255ba7f 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -5657,8 +5657,8 @@ private static ref long ReadMemory() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "CompletedTask").WithLocation(12, 30) }; - CompileAndVerify(source, options: TestOptions.DebugExe, expectedOutput: "0123").VerifyDiagnostics(diags); - CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: "0123").VerifyDiagnostics(diags); + CompileAndVerify(source, options: TestOptions.DebugExe, verify: Verification.Skipped, expectedOutput: "0123").VerifyDiagnostics(diags); + CompileAndVerify(source, options: TestOptions.ReleaseExe, verify: Verification.Skipped, expectedOutput: "0123").VerifyDiagnostics(diags); } [Fact, WorkItem(40251, "https://github.com/dotnet/roslyn/issues/40251")] From 30256131e0ecab3548b7fc57530a1121b60f0d79 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 21 Apr 2020 11:24:22 -0700 Subject: [PATCH 5/5] Add compound assignment test --- src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 0383b6c3e2945..2f95f663db0c6 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -5673,6 +5673,7 @@ class IntCode public async Task Step(Task t) { ReadMemory() = await t; + ReadMemory() += await t; } private ref long ReadMemory() => throw null; @@ -5682,7 +5683,10 @@ public async Task Step(Task t) { // (8,9): error CS8178: 'await' cannot be used in an expression containing a call to 'IntCode.ReadMemory()' because it returns by reference // ReadMemory() = await t; - Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "ReadMemory()").WithArguments("IntCode.ReadMemory()").WithLocation(8, 9) + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "ReadMemory()").WithArguments("IntCode.ReadMemory()").WithLocation(8, 9), + // (9,9): error CS8178: 'await' cannot be used in an expression containing a call to 'IntCode.ReadMemory()' because it returns by reference + // ReadMemory() += await t; + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "ReadMemory()").WithArguments("IntCode.ReadMemory()").WithLocation(9, 9) }; var comp = CreateCompilation(source, options: TestOptions.DebugDll); comp.VerifyEmitDiagnostics(expected);