Skip to content

[API Proposal]: Unsafe evolution attributes #125134

Closed

Description

@jjonescz

Background and motivation

Attributes needed for the unsafe evolution C# language feature (dotnet/roslyn#81207).

API Proposal

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
    public sealed class RequiresUnsafeAttribute : Attribute { }
}

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Module, Inherited = false, AllowMultiple = false)]
    public sealed class MemorySafetyRulesAttribute : Attribute
    {
        public MemorySafetyRulesAttribute(int version) { Version = version; }
        public int Version;
    }
}

API Usage

The MemorySafetyRulesAttribute is used by the compiler (it is disallowed to use it in source). The compiler applies it to a module when updated memory safety rules are enabled.

The RequiresUnsafeAttribute is used by users but can be also applied by the compiler implicitly for extern members.

class C
{
    [RequiresUnsafe] public void M() { }
}

Alternative Designs

Since the RequiresUnsafe attribute is to be used by users, perhaps it should live in System.Diagnostics.CodeAnalysis instead - in fact, it's already defined there internally:

Risks

No response

Activity

  1. added
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    on Mar 3, 2026
  2. dotnet-policy-service commented on Mar 3, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
    See info in area-owners.md if you want to be subscribed.

  3. added this to the 11.0.0 milestone on Mar 3, 2026
  4. added
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    and removed
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    untriagedNew issue has not been triaged by the area owner
    on Mar 3, 2026
  5. hamarb123 commented on Mar 3, 2026

    @hamarb123
    Contributor

    Sholdn't it also be allowed on fields? It seems to be mentioned in https://github.com/dotnet/designs/blob/main/accepted/2025/memory-safety/caller-unsafe.md that it should be:

    unsafe will also be allowed on field declarations. This allows code to indicate that part of an unsafe contract is carried within a field. For example, the following simplified code appears in the dotnet/runtime core framework:

    public class ArrayWrapper<T>
    {
        private Array _array;
    
        public T GetItem(int index)
        {
            var typedArray = Unsafe.As<T[]>(ref _array);
            return typedArray[index];
        }
    }

    So unless this scenario has been deemed irrelevant in the last 4 months (in which case I would like to understand why, as I would have used this), then it should have AttributeTargets.Field I would think.

  6. 333fred commented on Mar 3, 2026

    @333fred
    Member

    It's an open question for the proposal. We will bring it up in review and get pre-approval to make the change should LDM sign off.

  7. added
    blockingMarks issues that we want to fast track in order to unblock other important work
    on Mar 3, 2026
  8. agocke commented on Mar 4, 2026

    @agocke
    Member

    Current namespace is System.Diagnostics.CodeAnalysis. That's what I'd prefer.

  9. hamarb123 commented on Mar 5, 2026

    @hamarb123
    Contributor

    Current namespace is System.Diagnostics.CodeAnalysis. That's what I'd prefer.

    Imo CompilerServices is the more appropriate namespace, and it was a mistake to put UnscopedRef in CodeAnalysis.

    If you look at the attributes (that are intended to be used by users) in CompilerServices vs CodeAnalysis:

    • CompilerServices: e.g., DllImport, LibraryImport, InlineArray, TypeForwardedTo, SkipLocalsInit, MethodImpl, InterpolatedStringHandler, IndexerName, CallerArgumentExpression, SpecialName, etc. - these generally all either can give compiler errors and/or directly affect compilation
    • CodeAnalysis: e.g., AllowNull, ConstantExpected, DynamicallyAccessedMembers, StringSyntax, MaybeNull, MaybeNullWhen, NotNull, Experimental, UnscopedRef, etc. - with the exception of the last one, these all either only give warnings or can be suppressed via #pragma warning disable / similar (in the case of experimental for example); only UnscopedRef (at least out of the examples I gave, plus I think also SetsRequiredMembers is the only other one) contribute to real compiler errors

    Furthermore, people writing code that has [RequiresUnsafe] applied likely already have CompilerServices imported for other reasons (e.g., for Unsafe, DllImport, MethodImpl, SkipLocalsInit, RuntimeHelpers, etc.).

    Therefore, I personally think it is more appropriate to place it in CompilerServices, and to follow this (pre-existing) pattern in the future, rather than following the "pattern" for the singluar exception to it in this area (UnscopedRef); and I think it would be more useful overall too.

    (I also personally find it more annoying when I am testing snippets on something like sharplab to import CodeAnalysis namespace for UnscopedRef already, since I likely already have to have CompilerServices imported if I'm testing something that would have [RequiresUnsafe] (and importing things on sharplab is a terrible experience) - or if I'm writing a small code snippet to run in dotnet script or similar (similar kind of issue here))

  10. tannergooding commented on Mar 5, 2026

    @tannergooding
    Member

    I also personally prefer CompilerServices for a similar reason, but as a bonus that is what the compiler is already doing and avoids it needing to churn and produce a new build.

    Either way we will discuss both options in API review, as we normally do. So lets present it as Roslyn has it implemented to avoid confusion in the review.

  11. agocke commented on Mar 5, 2026

    @agocke
    Member

    The main reason I would put it in Diagnostics.CodeAnalysis is to keep it alongside RequiresUnreferencedCode, RequiresDynamicCode, RequiresAssemblyFiles, et al.

  12. bartonjs commented on Mar 5, 2026

    @bartonjs
    Member

    I feel like things in CompilerServices should generally be things users aren't interacting with. MemorySafetyRulesAttribute seems like a thing the compiler writes down based on some external information, but RequiresUnsafeAttribute is less clearly that... if it's expected to be exceedingly rare (other than compiler-written) outside of the BCL (where we have Unsafe, Marshal, CollectionMarshal, etc) then CompilerServices might be OK... but if it has "general applicability" then I'd like it to be somewhere else.

  13. tannergooding commented on Mar 5, 2026

    @tannergooding
    Member

    It's used to annotate that code requires an unsafe { } context to be invoked, so we don't really "want" users using it regularly. I'd think it has the overall same level of user interaction as DllImport, LibraryImport, Unsafe, etc (all of which live in CompilerServices) and will frequently be coupled with such attributes/types. -- i.e. If you're using something from CompilerServices or InteropServices chances are you're working with some kind of unsafe code and so likely need to consider using RequiresUnsafe as well. The same is not true for needing System.Diagnostics.CodeAnalysis or vice-versa.

    That being said, System.Diagnostics.CodeAnalysis isn't the worst place and has many other compiler related attributes as well, so its the only other obvious location. The biggest downside being Roslyn has to churn and update themselves if it is moved here.

  14. 333fred commented on Mar 5, 2026

    @333fred
    Member

    My opinion is aligned with Jeremy. This is something that we expect users to interact with manually, and so should not be in CompilerServices. The compiler put it in there for the initial implementation when we assumed users would not be applying it by hand, so if we have to update for a better namespace, I'm perfectly happy with that.

  15. bartonjs commented on Mar 17, 2026

    @bartonjs
    Member

    Video

    • Moved RequiresUnsafeAttribute to System.Diagnostics.CodeAnalysis.
    • Added Field as an AttributeTarget for RequiresUnsafe, and we're open to it being left out or other targets being added in the future.
    • Corrected MemorySafetyRulesAttribute.Version to be a get-only property
    namespace System.Diagnostics.CodeAnalysis
    {
        [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
        public sealed class RequiresUnsafeAttribute : Attribute { }
    }
    
    namespace System.Runtime.CompilerServices
    {
        [AttributeUsage(AttributeTargets.Module, Inherited = false, AllowMultiple = false)]
        public sealed class MemorySafetyRulesAttribute : Attribute
        {
            public MemorySafetyRulesAttribute(int version) { Version = version; }
            public int Version { get; }
        }
    }
  16. added
    api-approvedAPI was approved in API review, it can be implemented
    and removed
    blockingMarks issues that we want to fast track in order to unblock other important work
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    on Mar 17, 2026
  17. locked and limited conversation to collaborators on Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions