From 56e4c037c2b04a848226ef66150c8687edc03cf0 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Mon, 27 Jun 2022 09:50:07 -0700 Subject: [PATCH] Add annotations for ref fields to public API surface (#71265) Matching preview 6 changes. Will change when C#11 language support is available. --- .../System.Memory/ref/System.Memory.cs | 19 +++++++++++--- .../System.Private.CoreLib.Shared.projitems | 1 + .../LifetimeAnnotationAttribute.cs | 25 +++++++++++++++++++ .../System/Runtime/CompilerServices/Unsafe.cs | 2 +- .../Runtime/InteropServices/MemoryMarshal.cs | 8 +++--- .../System.Runtime/ref/System.Runtime.cs | 10 +++++++- 6 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs index 088efa1c8eb..c96b01b0f7f 100644 --- a/src/libraries/System.Memory/ref/System.Memory.cs +++ b/src/libraries/System.Memory/ref/System.Memory.cs @@ -530,6 +530,17 @@ public static partial class Utf8Parser public static bool TryParse(System.ReadOnlySpan source, out ulong value, out int bytesConsumed, char standardFormat = '\0') { throw null; } } } +namespace System.Runtime.CompilerServices +{ + // See src\libraries\System.Private.CoreLib\src\System\Runtime\CompilerServices\LifetimeAnnotationAttribute.cs + [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + internal sealed class LifetimeAnnotationAttribute : System.Attribute + { + public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped) { throw null; } + public bool IsRefScoped { get { throw null; } } + public bool IsValueScoped { get { throw null; } } + } +} namespace System.Runtime.InteropServices { public static partial class MemoryMarshal @@ -542,16 +553,16 @@ public static partial class MemoryMarshal public static System.ReadOnlySpan Cast(System.ReadOnlySpan span) where TFrom : struct where TTo : struct { throw null; } public static System.Span Cast(System.Span span) where TFrom : struct where TTo : struct { throw null; } public static System.Memory CreateFromPinnedArray(T[]? array, int start, int length) { throw null; } - public static System.ReadOnlySpan CreateReadOnlySpan(ref T reference, int length) { throw null; } + public static System.ReadOnlySpan CreateReadOnlySpan([System.Runtime.CompilerServices.LifetimeAnnotation(true, false)] ref T reference, int length) { throw null; } [System.CLSCompliant(false)] public static unsafe ReadOnlySpan CreateReadOnlySpanFromNullTerminated(byte* value) { throw null; } [System.CLSCompliant(false)] public static unsafe ReadOnlySpan CreateReadOnlySpanFromNullTerminated(char* value) { throw null; } - public static System.Span CreateSpan(ref T reference, int length) { throw null; } + public static System.Span CreateSpan([System.Runtime.CompilerServices.LifetimeAnnotation(true, false)] ref T reference, int length) { throw null; } public static ref T GetArrayDataReference(T[] array) { throw null; } public static ref byte GetArrayDataReference(System.Array array) { throw null; } - public static ref T GetReference(System.ReadOnlySpan span) { throw null; } - public static ref T GetReference(System.Span span) { throw null; } + public static ref T GetReference([System.Runtime.CompilerServices.LifetimeAnnotation(false, true)] System.ReadOnlySpan span) { throw null; } + public static ref T GetReference([System.Runtime.CompilerServices.LifetimeAnnotation(false, true)] System.Span span) { throw null; } public static T Read(System.ReadOnlySpan source) where T : struct { throw null; } public static System.Collections.Generic.IEnumerable ToEnumerable(System.ReadOnlyMemory memory) { throw null; } public static bool TryGetArray(System.ReadOnlyMemory memory, out System.ArraySegment segment) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index a079ceb5f11..93eab8cdde9 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -758,6 +758,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs new file mode 100644 index 00000000000..f792a7a8e22 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace System.Runtime.CompilerServices +{ + /// + /// This type is defined until we consume the C# 11 compiler. + /// + /// + /// Also remove in the reference assemblies. + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + internal sealed class LifetimeAnnotationAttribute : Attribute + { + public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped) + { + IsRefScoped = isRefScoped; + IsValueScoped = isValueScoped; + } + public bool IsRefScoped { get; } + public bool IsValueScoped { get; } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs index 2c17b9f4ca3..d006bd58cbc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -671,7 +671,7 @@ public static void Write(void* destination, T value) // Mono:AsRef [NonVersionable] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref T AsRef(in T source) + public static ref T AsRef([LifetimeAnnotation(true, false)] in T source) { throw new PlatformNotSupportedException(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index c0c2bf3e0c0..f089434fa33 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -77,13 +77,13 @@ public static ReadOnlySpan AsBytes(ReadOnlySpan span) /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// - public static ref T GetReference(Span span) => ref span._reference.Value; + public static ref T GetReference([LifetimeAnnotation(false, true)] Span span) => ref span._reference.Value; /// /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// - public static ref T GetReference(ReadOnlySpan span) => ref span._reference.Value; + public static ref T GetReference([LifetimeAnnotation(false, true)] ReadOnlySpan span) => ref span._reference.Value; /// /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used @@ -219,7 +219,7 @@ public static ReadOnlySpan AsBytes(ReadOnlySpan span) /// A span representing the specified reference and length. /// The lifetime of the returned span will not be validated for safety by span-aware languages. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span CreateSpan(ref T reference, int length) => new Span(ref reference, length); + public static Span CreateSpan([LifetimeAnnotation(true, false)] ref T reference, int length) => new Span(ref reference, length); /// /// Creates a new read-only span over a portion of a regular managed object. This can be useful @@ -231,7 +231,7 @@ public static ReadOnlySpan AsBytes(ReadOnlySpan span) /// A read-only span representing the specified reference and length. /// The lifetime of the returned span will not be validated for safety by span-aware languages. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan CreateReadOnlySpan(ref T reference, int length) => new ReadOnlySpan(ref reference, length); + public static ReadOnlySpan CreateReadOnlySpan([LifetimeAnnotation(true, false)] ref T reference, int length) => new ReadOnlySpan(ref reference, length); /// Creates a new read-only span for a null-terminated string. /// The pointer to the null-terminated string of characters. diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 27ab63296fb..34a334d5317 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -12523,6 +12523,14 @@ public partial interface ITuple object? this[int index] { get; } int Length { get; } } + // See src\libraries\System.Private.CoreLib\src\System\Runtime\CompilerServices\LifetimeAnnotationAttribute.cs + [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + internal sealed class LifetimeAnnotationAttribute : System.Attribute + { + public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped) { throw null; } + public bool IsRefScoped { get { throw null; } } + public bool IsValueScoped { get { throw null; } } + } public enum LoadHint { Default = 0, @@ -12766,7 +12774,7 @@ public static partial class Unsafe public unsafe static void* AsPointer(ref T value) { throw null; } [System.CLSCompliantAttribute(false)] public unsafe static ref T AsRef(void* source) { throw null; } - public static ref T AsRef(in T source) { throw null; } + public static ref T AsRef([System.Runtime.CompilerServices.LifetimeAnnotation(true, false)] in T source) { throw null; } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("o")] public static T? As(object? o) where T : class? { throw null; } public static ref TTo As(ref TFrom source) { throw null; } -- GitLab