未验证 提交 f7ca4ebf 编写于 作者: R Rikki Gibson 提交者: GitHub

Diagnose bad 'ref' locals in switch sections (#44194)

上级 b61d9d28
......@@ -969,10 +969,9 @@ protected BoundExpression BindInferredVariableInitializer(DiagnosticBag diagnost
bool nameConflict = localSymbol.ScopeBinder.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics);
bool hasErrors = false;
var containingMethod = this.ContainingMemberOrLambda as MethodSymbol;
if (containingMethod != null && containingMethod.IsAsync && localSymbol.RefKind != RefKind.None)
if (localSymbol.RefKind != RefKind.None)
{
Error(diagnostics, ErrorCode.ERR_BadAsyncLocalType, declarator);
CheckRefLocalInAsyncOrIteratorMethod(localSymbol.IdentifierToken, diagnostics);
}
EqualsValueClauseSyntax equalsClauseSyntax = declarator.Initializer;
......@@ -1150,6 +1149,22 @@ protected BoundExpression BindInferredVariableInitializer(DiagnosticBag diagnost
hasErrors: hasErrors | nameConflict);
}
protected bool CheckRefLocalInAsyncOrIteratorMethod(SyntaxToken identifierToken, DiagnosticBag diagnostics)
{
if (IsInAsyncMethod())
{
Error(diagnostics, ErrorCode.ERR_BadAsyncLocalType, identifierToken);
return true;
}
else if (IsDirectlyInIterator)
{
Error(diagnostics, ErrorCode.ERR_BadIteratorLocalType, identifierToken);
return true;
}
return false;
}
internal ImmutableArray<BoundExpression> BindDeclaratorArguments(VariableDeclaratorSyntax declarator, DiagnosticBag diagnostics)
{
// It is possible that we have a bracketed argument list, like "int x[];" or "int x[123];"
......@@ -1732,14 +1747,6 @@ private BoundBlock BindBlockParts(BlockSyntax node, DiagnosticBag diagnostics)
{
Debug.Assert(!diagnostics.IsEmptyWithoutResolution);
}
foreach (var local in locals)
{
if (local.RefKind != RefKind.None)
{
diagnostics.Add(ErrorCode.ERR_BadIteratorLocalType, local.Locations[0]);
}
}
}
return new BoundBlock(
......
......@@ -269,18 +269,12 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
if (local.RefKind != RefKind.None)
{
// The ref-escape of a ref-returning property is decided
// by the value escape of its receiverm, in this case the
// by the value escape of its receiver, in this case the
// collection
local.SetRefEscape(collectionEscape);
if (IsDirectlyInIterator)
if (CheckRefLocalInAsyncOrIteratorMethod(local.IdentifierToken, diagnostics))
{
diagnostics.Add(ErrorCode.ERR_BadIteratorLocalType, local.IdentifierToken.GetLocation());
hasErrors = true;
}
else if (IsInAsyncMethod())
{
diagnostics.Add(ErrorCode.ERR_BadAsyncLocalType, local.IdentifierToken.GetLocation());
hasErrors = true;
}
}
......
......@@ -1174,7 +1174,7 @@ async Task M()
comp.VerifyDiagnostics(
// (7,26): error CS8177: Async methods cannot have by-reference locals
// ref readonly int x = ref (new int[1])[0];
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "x = ref (new int[1])[0]").WithLocation(7, 26));
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "x").WithLocation(7, 26));
}
[Fact]
......@@ -1197,6 +1197,140 @@ IEnumerable<int> M()
Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(7, 26));
}
[Fact]
public void RefReadonlyInSwitchCaseInIterator_01()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
switch (this)
{
default:
ref readonly int x = ref (new int[1])[0]; // 1
yield return 1;
yield return x;
local();
void local()
{
ref readonly int z = ref (new int[1])[0];
}
break;
}
}
}");
comp.VerifyDiagnostics(
// (10,34): error CS8176: Iterators cannot have by-reference locals
// ref readonly int x = ref (new int[1])[0]; // 1
Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(10, 34));
}
[Fact]
public void RefReadonlyInSwitchCaseInIterator_02()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
switch (this)
{
default:
ref readonly int x; // 1, 2
yield return 1;
yield return x; // 3
break;
}
}
}");
comp.VerifyDiagnostics(
// (10,34): error CS8176: Iterators cannot have by-reference locals
// ref readonly int x; // 1, 2
Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(10, 34),
// (10,34): error CS8174: A declaration of a by-reference variable must have an initializer
// ref readonly int x; // 1, 2
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "x").WithLocation(10, 34),
// (12,30): error CS0165: Use of unassigned local variable 'x'
// yield return x; // 3
Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(12, 30));
}
[Fact]
public void RefReadonlyInSwitchCaseInIterator_03()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
switch (this)
{
default:
foreach (ref readonly int x in (new int[1]))
yield return 1;
break;
}
}
}");
comp.VerifyDiagnostics(
// (10,43): error CS8176: Iterators cannot have by-reference locals
// foreach (ref readonly int x in (new int[1]))
Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(10, 43));
}
[Fact]
public void RefReadonlyInEmbeddedStatementInIterator()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
if (true)
ref int x = ref (new int[1])[0]; // 1, 2
yield return 1;
}
}");
comp.VerifyDiagnostics(
// (8,13): error CS1023: Embedded statement cannot be a declaration or labeled statement
// ref int x = ref (new int[1])[0]; // 1, 2
Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "ref int x = ref (new int[1])[0];").WithLocation(8, 13),
// (8,21): error CS8176: Iterators cannot have by-reference locals
// ref int x = ref (new int[1])[0]; // 1, 2
Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(8, 21));
}
[Fact]
public void RefReadonlyInEmbeddedStatementInAsync()
{
var comp = CreateCompilation(@"
using System.Threading.Tasks;
class C
{
async Task M()
{
if (true)
ref int x = ref (new int[1])[0]; // 1, 2
await Task.Yield();
}
}");
comp.VerifyDiagnostics(
// (8,13): error CS1023: Embedded statement cannot be a declaration or labeled statement
// ref int x = ref (new int[1])[0]; // 1, 2
Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "ref int x = ref (new int[1])[0];").WithLocation(8, 13),
// (8,21): error CS8177: Async methods cannot have by-reference locals
// ref int x = ref (new int[1])[0]; // 1, 2
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "x").WithLocation(8, 21));
}
[Fact]
public void RefReadonlyLocalNotWritable()
{
......@@ -2711,10 +2845,10 @@ async Task TestMethod()
CreateCompilationWithMscorlib45(code).VerifyDiagnostics(
// (8,17): error CS8177: Async methods cannot have by-reference locals
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "y = ref x").WithLocation(8, 17),
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "y").WithLocation(8, 17),
// (11,21): error CS8177: Async methods cannot have by-reference locals
// ref int z = ref x;
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "z = ref x").WithLocation(11, 21));
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "z").WithLocation(11, 21));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
......@@ -3029,9 +3163,9 @@ static async void Goo()
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,17): error CS8932: Async methods cannot have by-reference locals
// (8,17): error CS8177: Async methods cannot have by-reference locals
// ref int i = ref field;
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "i = ref field").WithLocation(8, 17),
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "i").WithLocation(8, 17),
// (6,23): 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.
// static async void Goo()
Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Goo").WithLocation(6, 23));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册