Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -694,14 +694,15 @@ protected virtual void Scan(MethodIL methodIL, ref InterproceduralState interpro

case Code.Ret:
{

bool hasReturnValue = !methodBody.Method.ReturnsVoid();

if (currentStack.Count != (hasReturnValue ? 1 : 0))
if (!methodBody.Method.IsRuntimeAsync())
{
WarnAboutInvalidILInMethod(methodIL, operation.Offset);
bool ilHasReturnValue = !methodBody.Method.ReturnsVoid();
if (currentStack.Count != (ilHasReturnValue ? 1 : 0))
{
WarnAboutInvalidILInMethod(methodIL, operation.Offset);
}
}
if (hasReturnValue)
if (currentStack.Count == 1)
{
StackSlot retStackSlot = PopUnknown(currentStack, 1, methodIL, operation.Offset);
// If the return value is a reference, treat it as the value itself for now
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ public static bool IsEventMethod(this MethodDefinition md)
(md.SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0;
}

public static bool IsRuntimeAsync(this MethodDefinition md)
{
return (md.ImplAttributes & (MethodImplAttributes)0x2000) == (MethodImplAttributes)0x2000;
}

public static bool TryGetProperty(this MethodDefinition md, [NotNullWhen(true)] out PropertyDefinition? property)
{
property = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Cases.Expectations.Helpers;
using Mono.Linker.Tests.Cases.Expectations.Metadata;

namespace Mono.Linker.Tests.Cases.DataFlow
{
[SkipKeptItemsValidation]
[SetupCompileArgument("/features:runtime-async=on")]
[SetupCompileArgument("/nowarn:SYSLIB5007")]
public class RuntimeAsyncMethods
{
public static async Task Main()
{
await BasicRuntimeAsyncMethod();
await RuntimeAsyncWithDataFlowAnnotations(null);
await RuntimeAsyncWithCapturedLocalDataFlow();
await RuntimeAsyncWithMultipleAwaits();
await RuntimeAsyncWithReassignment(true);
await RuntimeAsyncReturningAnnotatedType();
await RuntimeAsyncWithCorrectParameter(null);
await RuntimeAsyncWithLocalAll();
}

static async Task BasicRuntimeAsyncMethod()
{
await Task.Delay(1);
Console.WriteLine("Basic runtime async");
}

[ExpectedWarning("IL2067", "type", nameof(DataFlowTypeExtensions.RequiresAll), nameof(RuntimeAsyncWithDataFlowAnnotations))]
static async Task RuntimeAsyncWithDataFlowAnnotations([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
{
await Task.Delay(1);
type.RequiresAll();
}

[ExpectedWarning("IL2072", nameof(DataFlowTypeExtensions.RequiresAll), nameof(GetWithPublicMethods))]
static async Task RuntimeAsyncWithCapturedLocalDataFlow()
{
Type t = GetWithPublicMethods();
await Task.Delay(1);
t.RequiresAll();
}

[ExpectedWarning("IL2072", nameof(DataFlowTypeExtensions.RequiresAll), nameof(GetWithPublicMethods))]
static async Task RuntimeAsyncWithMultipleAwaits()
{
Type t = GetWithPublicMethods();
await Task.Delay(1);
t.RequiresPublicMethods();
await Task.Delay(1);
t.RequiresAll();
}

[ExpectedWarning("IL2072", nameof(DataFlowTypeExtensions.RequiresAll), nameof(GetWithPublicMethods))]
[ExpectedWarning("IL2072", nameof(DataFlowTypeExtensions.RequiresAll), nameof(GetWithPublicFields))]
static async Task RuntimeAsyncWithReassignment(bool condition)
{
Type t = GetWithPublicMethods();
await Task.Delay(1);
if (condition)
{
t = GetWithPublicFields();
}
await Task.Delay(1);
t.RequiresAll();
}

[ExpectedWarning("IL2106", nameof(RuntimeAsyncReturningAnnotatedType))]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
static async Task<Type> RuntimeAsyncReturningAnnotatedType()
{
await Task.Delay(1);
return GetWithPublicMethods();
}

[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
static Type GetWithPublicMethods() => null;

[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
static Type GetWithPublicFields() => null;

[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
static Type GetWithAllMembers() => null;

static async Task RuntimeAsyncWithCorrectParameter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type type)
{
type ??= GetWithAllMembers();
await Task.Delay(1);
type.RequiresAll();
}

static async Task RuntimeAsyncWithLocalAll()
{
Type t = GetWithAllMembers();
await Task.Delay(1);
t.RequiresAll();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ protected virtual NPath CompileCSharpAssemblyWithRoslyn(CompilerOptions options)
// Default debug info format for the current platform.
DebugInformationFormat debugType = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb;
bool emitPdb = false;
Dictionary<string, string> features = [];
if (options.AdditionalArguments != null)
{
foreach (var option in options.AdditionalArguments)
Expand Down Expand Up @@ -303,11 +304,27 @@ protected virtual NPath CompileCSharpAssemblyWithRoslyn(CompilerOptions options)
compilationOptions = compilationOptions.WithMainTypeName(mainTypeName);
break;
}
else if (splitIndex != -1 && option[..splitIndex] == "/features")
{
var feature = option[(splitIndex + 1)..];
var featureSplit = feature.IndexOf('=');
if (featureSplit == -1)
throw new InvalidOperationException($"Argument is malformed: '{option}'");
features.Add(feature[..featureSplit], feature[(featureSplit + 1)..]);
break;
}
else if(splitIndex != -1 && option[..splitIndex] == "/nowarn")
{
var nowarn = option[(splitIndex + 1)..];
var withNoWarn = compilationOptions.SpecificDiagnosticOptions.SetItem(nowarn, ReportDiagnostic.Suppress);
compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(withNoWarn);
break;
}
throw new NotImplementedException(option);
}
}
}
var parseOptions = new CSharpParseOptions(preprocessorSymbols: options.Defines, languageVersion: languageVersion);
var parseOptions = new CSharpParseOptions(preprocessorSymbols: options.Defines, languageVersion: languageVersion).WithFeatures(features);
var emitOptions = new EmitOptions(debugInformationFormat: debugType);
var pdbPath = (!emitPdb || debugType == DebugInformationFormat.Embedded) ? null : options.OutputPath.ChangeExtension(".pdb").ToString();

Expand Down
Loading