Skip to content

Attributes on generic parameters of async local functions don't flow to generated code #79333

@sbomer

Description

@sbomer

Repro:

using System.Diagnostics.CodeAnalysis;

class Test
{
    static void Method()
    {
        void LocalFunction<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>()
        {
            Console.WriteLine(typeof(T).FullName);
        }

        async Task AsyncLocalFunction<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>()
        {
            await Task.Run(() => Console.WriteLine(typeof(T).FullName));
        }
    }

    static async void AsyncMethod<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>()
    {
        await Task.Run(() => Console.WriteLine(typeof(T).FullName));
    }

    static IEnumerable<T> IteratorMethod<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>()
    {
        yield return default(T);
    }
}

namespace System.Diagnostics.CodeAnalysis
{
    using System.Runtime.CompilerServices;

    [CompilerLoweringPreserve]
    [AttributeUsage(
        AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
        AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method |
        AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct,
        Inherited = false)]
    public sealed class DynamicallyAccessedMembersAttribute : Attribute
    {
        public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
        {
            MemberTypes = memberTypes;
        }

        public DynamicallyAccessedMemberTypes MemberTypes { get; }
    }
}

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
    public class CompilerLoweringPreserveAttribute : Attribute

    {
        public CompilerLoweringPreserveAttribute() { }
    }
}

IL for the AsyncLocalFunction state machine:

.class auto ansi sealed nested private beforefieldinit '<<Method>g__AsyncLocalFunction|0_1>d`1'<T>
         extends [System.Runtime]System.Object
         implements [System.Runtime]System.Runtime.CompilerServices.IAsyncStateMachine
  {
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
    .field public int32 '<>1__state'
    .field public [System.Runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder '<>t__builder'
    .field private [System.Runtime]System.Runtime.CompilerServices.TaskAwaiter '<>u__1'
    .method public hidebysig specialname rtspecialname 
            instance void  .ctor() cil managed

Note the absence of DynamicallyAccessedMembers on the T param. By contrast, T on the AsyncMethod state machine does have the attribute.

Seems this case is not covered by the implementation for #73920.

Found while implementing a fix for dotnet/runtime#101861.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions