Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\IteratorStateMachineAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\ITuple.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\LoadHint.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\MemorySafetyRulesAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\MethodCodeType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\MethodImplAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\CompilerServices\MethodImplOptions.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>
/// Indicates that the specified method requires unsafe code that may not be available
/// in all execution environments.
/// Indicates that the specified member requires the caller to be in an unsafe context.
/// </summary>
/// <remarks>
/// This allows tools to understand which methods are unsafe to call when targeting
/// environments that do not support unsafe code.
/// </remarks>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)]
[Conditional("DEBUG")]
internal sealed class RequiresUnsafeAttribute : Attribute
[AttributeUsage(
AttributeTargets.Constructor | AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property,
Inherited = false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inherited=false is interesting. Is that correct? From a reflection standpoint, we wouldn't expect a derived type to inherit the requires unsafe nature of its base?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compiler doesn't consider inherited attributes though, so it seems better to disallow in reflection too, for consistency.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, as part of the language feature, we require that a derived API is not RequiresUnsafe if the base API is not RequiresUnsafe too.

AllowMultiple = false)]
public sealed class RequiresUnsafeAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="RequiresUnsafeAttribute"/> class.
/// </summary>
public RequiresUnsafeAttribute() { }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'm pretty sure we have really basic attribute tests that just validate the attribute can be constructed without throwing, or in the case of something like MemorySafetyRulesAttribute, that ctor arguments are properly roundtripped through properties. Could you do a quick search and add a couple tests in the right place?

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;

namespace System.Runtime.CompilerServices
{
/// <summary>Indicates the version of the memory safety rules used when the module was compiled.</summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[AttributeUsage(AttributeTargets.Module, Inherited = false, AllowMultiple = false)]
public sealed class MemorySafetyRulesAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="MemorySafetyRulesAttribute"/> class.</summary>
/// <param name="version">The version of the memory safety rules used when the module was compiled.</param>
public MemorySafetyRulesAttribute(int version) => Version = version;

/// <summary>Gets the version of the memory safety rules used when the module was compiled.</summary>
public int Version { get; }
}
}
12 changes: 12 additions & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9110,6 +9110,11 @@ public RequiresUnreferencedCodeAttribute(string message) { }
public string Message { get { throw null; } }
public string? Url { get { throw null; } set { } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Constructor | System.AttributeTargets.Event | System.AttributeTargets.Method | System.AttributeTargets.Property, Inherited=false, AllowMultiple=false)]
public sealed partial class RequiresUnsafeAttribute : System.Attribute
{
public RequiresUnsafeAttribute() { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Constructor, AllowMultiple=false, Inherited=false)]
public sealed partial class SetsRequiredMembersAttribute : System.Attribute
{
Expand Down Expand Up @@ -14028,6 +14033,13 @@ public enum LoadHint
Always = 1,
Sometimes = 2,
}
[System.AttributeUsageAttribute(System.AttributeTargets.Module, Inherited=false, AllowMultiple=false)]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public sealed partial class MemorySafetyRulesAttribute : System.Attribute
{
public MemorySafetyRulesAttribute(int version) { }
public int Version { get { throw null; } }
}
public enum MethodCodeType
{
IL = 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Xunit;

namespace System.Diagnostics.CodeAnalysis.Tests;

public class RequiresUnsafeAttributeTests
{
[Fact]
public static void TestConstructor()
{
new RequiresUnsafeAttribute();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,17 @@ public static void RefSafetyRulesAttributeTests(int version)
Assert.Equal(version, attr.Version);
}

[Theory]
[InlineData(-1)]
[InlineData(0)]
[InlineData(2)]
[InlineData(42)]
public static void MemorySafetyRulesAttributeTests(int version)
{
var attr = new MemorySafetyRulesAttribute(version);
Assert.Equal(version, attr.Version);
}

[Theory]
[InlineData("1")]
[InlineData("2")]
Expand Down
Loading