提交 b1a32b9f 编写于 作者: K Karlo 提交者: Andy Gocke

Preventing crash when a local function with iterators is using an out/ref parameter (#18836)

Change data flow analysis to pass a location for error reporting if a branch is compiler generated
or if it is null (which is effectively compiler generated).

Fixes #18813
上级 d58f06dd
......@@ -88,8 +88,7 @@ public SyntaxTree SyntaxTree
{
get
{
var syntax = Syntax;
return syntax == null ? null : syntax.SyntaxTree;
return Syntax?.SyntaxTree;
}
}
......
......@@ -163,9 +163,13 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen
{
this.State = pending.State;
BoundNode branch = pending.Branch;
LeaveParameters(localFuncSymbol.Parameters, branch?.Syntax,
branch?.WasCompilerGenerated == true
? location : null);
// Pass the local function identifier as a location if the branch
// is null or compiler generated.
LeaveParameters(localFuncSymbol.Parameters,
branch?.Syntax,
branch?.WasCompilerGenerated == false ? null : location);
IntersectWith(ref stateAtReturn, ref this.State);
}
......
......@@ -277,7 +277,14 @@ protected override ImmutableArray<PendingBranch> RemoveReturns()
protected virtual void ReportUnassignedOutParameter(ParameterSymbol parameter, SyntaxNode node, Location location)
{
if (!_requireOutParamsAssigned && topLevelMethod == currentMethodOrLambda) return;
if (!_requireOutParamsAssigned && topLevelMethod == currentMethodOrLambda)
{
return;
}
// If node and location are null "new SourceLocation(node);" will throw a NullReferenceException
Debug.Assert(node != null || location != null);
if (Diagnostics != null && this.State.Reachable)
{
if (location == null)
......
......@@ -1318,5 +1318,66 @@ void Local()
// Local();
Diagnostic(ErrorCode.ERR_UseDefViolationField, "Local()").WithArguments("_x").WithLocation(14, 9));
}
[Fact]
[WorkItem(18813, "https://github.com/dotnet/roslyn/issues/18813")]
public void LocalIEnumerableFunctionWithOutParameter1()
{
var comp = CreateStandardCompilation(@"
class c
{
static void Main(string[] args)
{
System.Collections.Generic.IEnumerable<string> getFoo(int count, out bool output)
{
output = true;
yield return ""foo"";
}
getFoo(1, out bool myBool);
}
}
}");
comp.VerifyDiagnostics(
// (6,83): error CS1623: Iterators cannot have ref or out parameters
// System.Collections.Generic.IEnumerable<string> getFoo(int count, out bool foobar)
Diagnostic(ErrorCode.ERR_BadIteratorArgType, "output"),
// (6,56): error CS0177: The out parameter 'foobar' must be assigned to before control leaves the current method
// System.Collections.Generic.IEnumerable<string> getFoo(int count, out bool foobar)
Diagnostic(ErrorCode.ERR_ParamUnassigned, "getFoo").WithArguments("output").WithLocation(6, 56));
}
[Fact]
[WorkItem(18813, "https://github.com/dotnet/roslyn/issues/18813")]
public void LocalIEnumerableFunctionWithOutParameter2()
{
var comp = CreateStandardCompilation(@"
class c
{
static void Main(string[] args)
{
System.Collections.Generic.IEnumerable<string> getFoo(int count, out bool output)
{
output = false;
for (int i = 0; i < count; i++)
{
foreach (var val in getFoo(3, out var bar))
yield return ""foo"";
}
yield return ""foo"";
}
getFoo(1, out bool myBool);
}
}");
comp.VerifyDiagnostics(
// (6,83): error CS1623: Iterators cannot have ref or out parameters
// System.Collections.Generic.IEnumerable<string> getFoo(int count, out bool foobar)
Diagnostic(ErrorCode.ERR_BadIteratorArgType, "output"),
// (6,56): error CS0177: The out parameter 'foobar' must be assigned to before control leaves the current method
// System.Collections.Generic.IEnumerable<string> getFoo(int count, out bool foobar)
Diagnostic(ErrorCode.ERR_ParamUnassigned, "getFoo").WithArguments("output").WithLocation(6, 56));
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册