Skip to content

[API Proposal]: System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute #66167

@333fred

Description

@333fred

Background and motivation

We've had a few times now in C# language design where the traditional method of requiring that a compiler understand a feature, a modreq, has been insufficient in one of a couple of ways:

  • The context doesn't allow modreqs to be applied, such as a type declaration. This is the case for ref structs.
  • The fact that modreqs affect binary compatibility isn't desired. For example, the required members feature doesn't want to mark constructors with a modreq because that would break binary compat if all required members were later removed from a type, as the modreq is part of the signature.

For these cases, our strategy so far has been to use ObsoleteAttribute with a specific error message the compiler knows to ignore. This is not a great solution, however. If the user puts an obsolete attribute of their own set to warning, it overrides ours. Obsolete methods and types are also perfectly fine to use from an obsolete context. To address these deficiencies going forward, we'd like to add a new tool to our toolbox, a poison attribute of sorts, that allows the compiler to mark a type or other symbol that supports attributes as requiring an understanding of a specific feature. For equal flexibility with modopt vs modreq, I've also added an ability to say that this feature only applies to a single language, if that language wants to allow other languages free access, but prevent older versions of its own compiler from using the API without correct understanding.

The semantics of this attribute are:

  • If Language is null, any compiler that does not understand FeatureName is required to disallow usage of the member attributed with it.
  • If Language is not null, any compiler for that language that does not understand FeatureName is required to disallow usage of the member attributed with it. Compilers for other languages are free to ignore the attribute.

API Proposal

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
    public sealed class CompilerFeatureRequiredAttribute : Attribute
    {
        public CompilerFeatureRequiredAttribute(string featureName)
        {
            FeatureName = featureName;
        }
        public string FeatureName { get; }
        public string? Language { get; init; }
    }
}

API Usage

ref struct S {}

will be emitted as

[CompilerFeatureRequired("ref-struct")]
struct S {}

Alternative Designs

We might also consider putting a list of features into the runtime, but that runs the risk of the runtime effectively becoming an arbiter of language features: if some third-party .NET language wanted to add their own strings, what would the process for that be?

Risks

It is important to note that this enforcement mechanism will only work going forward. Older compilers are going to have no idea that this is a thing and not block access. That being said, if we don't add something like this now, we'll never get to a point where we can solely rely on this attribute as the enforcement mechanism.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-System.Runtime.CompilerServicesblockingMarks issues that we want to fast track in order to unblock other important work

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions