Skip to content

Commit 84baa35

Browse files
authored
Fix flow analysis of extern local functions (#79741)
1 parent 3f1b9b0 commit 84baa35

File tree

3 files changed

+82
-1
lines changed

3 files changed

+82
-1
lines changed

src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,8 @@ protected virtual void VisitLocalFunctionUse(
14031403
SyntaxNode syntax,
14041404
bool isCall)
14051405
{
1406-
if (isCall)
1406+
// Extern local function bodies are not visited, so ignore their state.
1407+
if (isCall && !symbol.IsExtern)
14071408
{
14081409
Join(ref State, ref localFunctionState.StateFromBottom);
14091410

src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6103,5 +6103,66 @@ public Base(int x){}
61036103
Diagnostic(ErrorCode.ERR_ParamUnassigned, "C").WithArguments("a").WithLocation(1, 7)
61046104
);
61056105
}
6106+
6107+
[Fact]
6108+
public void OutParameterIsNotAssigned_LocalFunction()
6109+
{
6110+
var source = """
6111+
class C
6112+
{
6113+
void M(out int i)
6114+
{
6115+
f();
6116+
static void f() { }
6117+
}
6118+
}
6119+
""";
6120+
CreateCompilation(source).VerifyDiagnostics(
6121+
// (3,10): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
6122+
// void M(out int i)
6123+
Diagnostic(ErrorCode.ERR_ParamUnassigned, "M").WithArguments("i").WithLocation(3, 10));
6124+
}
6125+
6126+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79437")]
6127+
public void OutParameterIsNotAssigned_LocalFunction_Extern()
6128+
{
6129+
var source = """
6130+
using System.Runtime.InteropServices;
6131+
class C
6132+
{
6133+
void M(out int i)
6134+
{
6135+
f();
6136+
[DllImport("test")] static extern void f();
6137+
}
6138+
}
6139+
""";
6140+
CreateCompilation(source).VerifyDiagnostics(
6141+
// (4,10): error CS0177: The out parameter 'i' must be assigned to before control leaves the current method
6142+
// void M(out int i)
6143+
Diagnostic(ErrorCode.ERR_ParamUnassigned, "M").WithArguments("i").WithLocation(4, 10));
6144+
}
6145+
6146+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79437")]
6147+
public void UnassignedVariable_LocalFunction_Extern()
6148+
{
6149+
var source = """
6150+
using System.Runtime.InteropServices;
6151+
class C
6152+
{
6153+
void M()
6154+
{
6155+
int i;
6156+
f();
6157+
i.ToString();
6158+
[DllImport("test")] extern static void f();
6159+
}
6160+
}
6161+
""";
6162+
CreateCompilation(source).VerifyDiagnostics(
6163+
// (8,9): error CS0165: Use of unassigned local variable 'i'
6164+
// i.ToString();
6165+
Diagnostic(ErrorCode.ERR_UseDefViolation, "i").WithArguments("i").WithLocation(8, 9));
6166+
}
61066167
}
61076168
}

src/Compilers/CSharp/Test/Emit3/FlowAnalysis/LocalFunctions.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,25 @@ public static void Main()
705705
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local").WithArguments("Local").WithLocation(7, 14));
706706
}
707707

708+
[Fact]
709+
public void UnusedLocalFunc_Extern()
710+
{
711+
var comp = CreateCompilation("""
712+
using System.Runtime.InteropServices;
713+
class C
714+
{
715+
public static void Main()
716+
{
717+
[DllImport("test")] static extern bool Local();
718+
}
719+
}
720+
""");
721+
comp.VerifyDiagnostics(
722+
// (6,48): warning CS8321: The local function 'Local' is declared but never used
723+
// [DllImport("test")] static extern bool Local();
724+
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local").WithArguments("Local").WithLocation(6, 48));
725+
}
726+
708727
[Fact]
709728
public void UnassignedInStruct()
710729
{

0 commit comments

Comments
 (0)