Skip to content

[API Proposal]: System.Diagnostics.CodeAnalysis.UnscopedRefAttribute #72074

@cston

Description

@cston

Background and motivation

There are several cases where the C# compiler treats a ref as implicitly scoped, where the compiler does not allow the ref to escape the method.

  1. this for struct instance methods
  2. ref parameters that refer to ref struct types
  3. out parameters

For specific instances where the ref should be allowed to escape, we should provide a well-known attribute that the compiler will recognize that indicates the ref is not scoped.

See low-level-struct-improvements.md.

API Proposal

namespace System.Diagnostics.CodeAnalysis
{
    [AttributeUsage(
        AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter,
        AllowMultiple = false,
        Inherited = false)]
    public sealed class RefEscapesAttribute : Attribute
    {
    }
}

API Usage

When applied to struct instance methods and properties, this ref is unscoped.

struct S1
{
    private int _field;
    [RefEscapes] public ref int Property => ref _field; // ok
    [RefEscapes] public ref int GetField() => ref _field; // ok
}

When applied to a struct type, this ref is unscoped for all instance methods and properties.

[RefEscapes]
struct S2
{
    private int _field;
    public ref int Property => ref _field; // ok
    public ref int GetField() => ref _field; // ok
}

[RefEscapes]
struct S3
{
    private S2 _child;
    public ref int Value => ref _child.Property; // ok
}

When applied to a ref parameter, the ref is unscoped.

ref struct R { }

ref R ReturnRefStructRef(bool b, ref R x, [RefEscapes] ref R y)
{
    if (b)
        return ref x; // error: Cannot return parameter by reference
    else
        return ref y; // ok
}

When applied to an out parameter, the ref is unscoped.

ref int ReturnOut(bool b, out int x, [RefEscapes] out int y)
{
    x = 1;
    y = 2;
    if (b)
        return ref x; // error: Cannot return parameter by reference
    else
        return ref y; // ok
}

Alternative Designs

Without a well-known attribute recognized by the compiler, callers will need to use Unsafe.AsRef() and similar methods to return a scoped ref.

An alternative attribute name: UnscopedAttribute.

Risks

No response

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