Skip to content

Commit

Permalink
Correctly support local functions in function pointer loads. Fixes do…
Browse files Browse the repository at this point in the history
  • Loading branch information
333fred committed Jun 26, 2020
1 parent 7a836c8 commit 3c614d2
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ private void PerformMemberOverloadResolution<TMember>(
if (isFunctionPointerResolution)
{
RemoveCallingConventionMismatches(results, callingConvention);
RemoveStaticInstanceMismatches(results, requireStatic: true);
RemoveMethodsNotDeclaredStatic(results);
}

// NB: As in dev12, we do this AFTER removing less derived members.
Expand Down Expand Up @@ -387,6 +387,22 @@ private static void RemoveStaticInstanceMismatches<TMember>(ArrayBuilder<MemberR
}
}

private static void RemoveMethodsNotDeclaredStatic<TMember>(ArrayBuilder<MemberResolutionResult<TMember>> results) where TMember : Symbol
{
// RemoveStaticInstanceMistmatches allows methods that do not need a reciever but are not declared static,
// such as a local function that is not declared static. This eliminates methods that are not actually
// declared as static
for (int f = 0; f < results.Count; f++)
{
var result = results[f];
TMember member = result.Member;
if (result.Result.IsValid && !member.IsStatic)
{
results[f] = new MemberResolutionResult<TMember>(member, result.LeastOverriddenMember, MemberAnalysisResult.StaticInstanceMismatch());
}
}
}

private void RemoveConstraintViolations<TMember>(ArrayBuilder<MemberResolutionResult<TMember>> results) where TMember : Symbol
{
// When the feature 'ImprovedOverloadCandidates' is enabled, we do not include methods for which the type arguments
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,30 @@ public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationE
return base.VisitDelegateCreationExpression(node);
}

public override BoundNode VisitFunctionPointerLoad(BoundFunctionPointerLoad node)
{
if (node.TargetMethod.MethodKind == MethodKind.LocalFunction)
{
Debug.Assert(node.TargetMethod is { RequiresInstanceReceiver: false, IsStatic: true });
ImmutableArray<BoundExpression> arguments = default;
ImmutableArray<RefKind> argRefKinds = default;

RemapLocalFunction(
node.Syntax,
node.TargetMethod,
out var receiver,
out var remappedMethod,
ref arguments,
ref argRefKinds);

Debug.Assert(arguments.IsDefault && argRefKinds.IsDefault && receiver.Kind == BoundKind.TypeExpression);

return node.Update(remappedMethod, node.Type);
}

return base.VisitFunctionPointerLoad(node);
}

public override BoundNode VisitConversion(BoundConversion conversion)
{
// a conversion with a method should have been rewritten, e.g. to an invocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7101,6 +7101,62 @@ .locals init (delegate*<System.Span<char>, System.Span<char>> V_0)
");
}

[Fact, WorkItem(45447, "https://github.com/dotnet/roslyn/issues/45447")]
public void LocalFunction_ValidStatic()
{
var verifier = CompileAndVerifyFunctionPointers(@"
unsafe class FunctionPointer
{
public static void Main()
{
delegate*<void> a = &local;
a();
static void local() => System.Console.Write(""local"");
}
}
", expectedOutput: "local");


verifier.VerifyIL("FunctionPointer.Main", @"
{
// Code size 12 (0xc)
.maxstack 1
IL_0000: ldftn ""void FunctionPointer.<Main>g__local|0_0()""
IL_0006: calli ""delegate*<void>""
IL_000b: ret
}
");
}

[Fact, WorkItem(45447, "https://github.com/dotnet/roslyn/issues/45447")]
public void LocalFunction_InvalidNonStatic()
{
var comp = CreateCompilationWithFunctionPointers(@"
unsafe class FunctionPointer
{
public static void M()
{
int local = 1;
delegate*<void> first = &noCaptures;
delegate*<void> second = &capturesLocal;
void noCaptures() { }
void capturesLocal() { local++; }
}
}");

comp.VerifyDiagnostics(
// (8,34): error CS8759: Cannot create a function pointer for 'noCaptures()' because it is not a static method
// delegate*<void> first = &noCaptures;
Diagnostic(ErrorCode.ERR_FuncPtrMethMustBeStatic, "noCaptures").WithArguments("noCaptures()").WithLocation(8, 34),
// (9,35): error CS8759: Cannot create a function pointer for 'capturesLocal()' because it is not a static method
// delegate*<void> second = &capturesLocal;
Diagnostic(ErrorCode.ERR_FuncPtrMethMustBeStatic, "capturesLocal").WithArguments("capturesLocal()").WithLocation(9, 35)
);
}

private static readonly Guid s_guid = new Guid("97F4DBD4-F6D1-4FAD-91B3-1001F92068E5");
private static readonly BlobContentId s_contentId = new BlobContentId(s_guid, 0x04030201);

Expand Down

0 comments on commit 3c614d2

Please sign in to comment.