Skip to content

Attribute definitions included in assemblies using Nullable on the latest framework #85612

@ericstj

Description

@ericstj

Description

I would expect that assemblies compiling against the latest framework would not need to define attribute types when using compiler features.

Instead I see a number of internal attributes included:

namespace System.Runtime.CompilerServices
{
    [CompilerGenerated]
    [Microsoft.CodeAnalysis.Embedded]
    internal sealed class IsUnmanagedAttribute : Attribute
    {
    }

    [CompilerGenerated]
    [Microsoft.CodeAnalysis.Embedded]
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
    internal sealed partial class NullableAttribute : Attribute
    {
        public readonly byte[] NullableFlags;
        public NullableAttribute(byte value) { }

        public NullableAttribute(byte[] value) { }
    }

    [CompilerGenerated]
    [Microsoft.CodeAnalysis.Embedded]
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
    internal sealed partial class NullableContextAttribute : Attribute
    {
        public readonly byte Flag;
        public NullableContextAttribute(byte value) { }
    }

    [CompilerGenerated]
    [Microsoft.CodeAnalysis.Embedded]
    [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
    internal sealed partial class NullablePublicOnlyAttribute : Attribute
    {
        public readonly bool IncludesInternals;
        public NullablePublicOnlyAttribute(bool value) { }
    }
    [CompilerGenerated]
    [Microsoft.CodeAnalysis.Embedded]
    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
    internal sealed class ScopedRefAttribute : Attribute
    {
    }
}

#29039 mentions that these were not included because

Any code reasoning about the attribute has to assume that attribute is emitted, so you can't optimize the path.

Correct. Language features shouldn't depend on type location, but that's true even for language feature supporting types we put in the framework. We don't put the type in the framework to make it easier for the compiler.

The size is small

I briefly measured the size and it seemed to increase an assembly by ~512 bytes by defining these types. While that's small it can add up. Across the framework assemblies in the ref packs and runtimes I found 476 assemblies defining these types accounting for >200KB size on disk. I'm also seeing another 300 assemblies in the SDK. Probably if you consider every customer assembly produced it would add up even more.

Reproduction Steps

Build a library using nullable and target net8.0.

Expected behavior

Only types defined by my project appear in my assembly.

Actual behavior

Language / framework types are emitted into my assembly.

Regression?

No

Known Workarounds

No response

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions