Skip to content

Commit

Permalink
Report spill local await boundary errors at their declaration
Browse files Browse the repository at this point in the history
  • Loading branch information
jjonescz committed Apr 8, 2024
1 parent 1804c58 commit b4cc4b5
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,18 @@ public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSy

if (variable is LocalSymbol local)
{
if (local.SynthesizedKind is SynthesizedLocalKind.Spill)
{
reportLocalAcrossAwaitError(diagnostics, local, local.GetFirstLocation());
}
else
foreach (var syntax in kvp.Value)
{
foreach (var syntax in kvp.Value)
if (local.TypeWithAnnotations.IsRestrictedType())
{
reportLocalAcrossAwaitError(diagnostics, local, syntax.Location);
// CS4007: Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary.
diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, syntax.Location, local.TypeWithAnnotations);
}
else
{
Debug.Assert(local.RefKind != RefKind.None);
// CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
diagnostics.Add(ErrorCode.ERR_RefLocalAcrossAwait, syntax.Location);
}
}
}
Expand Down Expand Up @@ -128,21 +131,6 @@ public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSy
walker.Free();

return variablesToHoist;

static void reportLocalAcrossAwaitError(DiagnosticBag diagnostics, LocalSymbol local, Location location)
{
if (local.TypeWithAnnotations.IsRestrictedType())
{
// CS4007: Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary.
diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, location, local.TypeWithAnnotations);
}
else
{
Debug.Assert(local.RefKind != RefKind.None);
// CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
diagnostics.Add(ErrorCode.ERR_RefLocalAcrossAwait, location);
}
}
}

private static bool HoistInDebugBuild(Symbol symbol)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3789,9 +3789,11 @@ static async Task Main()
var comp = CreateCompilationWithMscorlibAndSpan(source, options: options);
comp.VerifyDiagnostics();
comp.VerifyEmitDiagnostics(
// (9,66): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// await Async1(F1(), G(F2(), stackalloc int[] { 1, 2, 3 }, await F3()));
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await F3()").WithArguments("System.Span<int>").WithLocation(9, 66)
// (8,5): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// {
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"{
await Async1(F1(), G(F2(), stackalloc int[] { 1, 2, 3 }, await F3()));
}").WithArguments("System.Span<int>").WithLocation(8, 5)
);
}
}
Expand Down
18 changes: 12 additions & 6 deletions src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4691,9 +4691,12 @@ static async Task<T> FromResult<T>(T r)
";
var comp = CreateCompilation(src + Buffer10Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics(
// (24,22): error CS4007: Instance of type 'System.ReadOnlySpan<Buffer10<int>>' cannot be preserved across 'await' or 'yield' boundary.
// [Get01()][await FromResult(Get02(x))];
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await FromResult(Get02(x))").WithArguments("System.ReadOnlySpan<Buffer10<int>>").WithLocation(24, 22)
// (20,12): error CS4007: Instance of type 'System.ReadOnlySpan<Buffer10<int>>' cannot be preserved across 'await' or 'yield' boundary.
// => MemoryMarshal.CreateReadOnlySpan(
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"MemoryMarshal.CreateReadOnlySpan(
ref Unsafe.As<Buffer10<Buffer10<int>>, Buffer10<int>>(
ref Unsafe.AsRef(in GetC(x).F)),
10)").WithArguments("System.ReadOnlySpan<Buffer10<int>>").WithLocation(20, 12)
);
}

Expand Down Expand Up @@ -4743,9 +4746,12 @@ static async Task<T> FromResult<T>(T r)
";
var comp = CreateCompilation(src + Buffer10Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe);
comp.VerifyEmitDiagnostics(
// (24,13): error CS4007: Instance of type 'System.ReadOnlySpan<int>' cannot be preserved across 'await' or 'yield' boundary.
// [await FromResult(Get02(x))];
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await FromResult(Get02(x))").WithArguments("System.ReadOnlySpan<int>").WithLocation(24, 13)
// (20,12): error CS4007: Instance of type 'System.ReadOnlySpan<int>' cannot be preserved across 'await' or 'yield' boundary.
// => MemoryMarshal.CreateReadOnlySpan(
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"MemoryMarshal.CreateReadOnlySpan(
ref Unsafe.As<Buffer10<int>, int>(
ref Unsafe.AsRef(in GetC(x).F[Get01()])),
10)").WithArguments("System.ReadOnlySpan<int>").WithLocation(20, 12)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ static async Task Goo()
comp.VerifyEmitDiagnostics(
// (8,27): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary.
// Console.WriteLine(new TypedReference().Equals(await Task.FromResult(0)));
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await Task.FromResult(0)").WithArguments("System.TypedReference").WithLocation(8, 55));
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new TypedReference()").WithArguments("System.TypedReference").WithLocation(8, 27));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1418,9 +1418,9 @@ public static async Task<int> I1()

var expectedDiagnostics = new[]
{
// (17,39): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// (17,19): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// TakesSpan(default(Span<int>), await I1());
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span<int>").WithLocation(17, 39)
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "default(Span<int>)").WithArguments("System.Span<int>").WithLocation(17, 19)
};

comp.VerifyEmitDiagnostics(expectedDiagnostics);
Expand Down Expand Up @@ -1468,9 +1468,9 @@ public static async Task<int> I1()

var expectedDiagnostics = new[]
{
// (14,45): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// (14,22): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// TakesSpan(s: default(Span<int>), i: await I1());
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span<int>").WithLocation(14, 45)
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "default(Span<int>)").WithArguments("System.Span<int>").WithLocation(14, 22)
};

comp.VerifyEmitDiagnostics(expectedDiagnostics);
Expand Down

0 comments on commit b4cc4b5

Please sign in to comment.