diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml
index f10548a4a70dc..a66cc3b616de2 100644
--- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml
+++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml
@@ -141,6 +141,9 @@
+
+
+
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 c19e0f2a827d8..8befa9e63d06f 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
@@ -259,6 +259,7 @@
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/ExperimentalAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/ExperimentalAttribute.cs
new file mode 100644
index 0000000000000..5619e669d5711
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/ExperimentalAttribute.cs
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Diagnostics.CodeAnalysis
+{
+ ///
+ /// Indicates that an API is experimental and it may change in the future.
+ ///
+ ///
+ /// This attribute allows call sites to be flagged with a diagnostic that indicates that an experimental
+ /// feature is used. Authors can use this attribute to ship preview features in their assemblies.
+ ///
+ [AttributeUsage(AttributeTargets.Assembly |
+ AttributeTargets.Module |
+ AttributeTargets.Class |
+ AttributeTargets.Struct |
+ AttributeTargets.Enum |
+ AttributeTargets.Constructor |
+ AttributeTargets.Method |
+ AttributeTargets.Property |
+ AttributeTargets.Field |
+ AttributeTargets.Event |
+ AttributeTargets.Interface |
+ AttributeTargets.Delegate, Inherited = false)]
+ public sealed class ExperimentalAttribute : Attribute
+ {
+ ///
+ /// Initializes a new instance of the class, specifying the ID that the compiler will use
+ /// when reporting a use of the API the attribute applies to.
+ ///
+ /// The ID that the compiler will use when reporting a use of the API the attribute applies to.
+ public ExperimentalAttribute(string diagnosticId)
+ {
+ DiagnosticId = diagnosticId;
+ }
+
+ ///
+ /// Gets or sets the ID that the compiler will use when reporting a use of the API the attribute applies to.
+ ///
+ /// The unique diagnostic ID.
+ ///
+ /// The diagnostic ID is shown in build output for warnings and errors.
+ /// This property represents the unique ID that can be used to suppress the warnings or errors, if needed.
+ ///
+ public string DiagnosticId { get; }
+
+ ///
+ /// Gets or sets the URL for corresponding documentation.
+ /// The API accepts a format string instead of an actual URL, creating a generic URL that includes the diagnostic ID.
+ ///
+ /// The format string that represents a URL to corresponding documentation.
+ /// An example format string is https://contoso.com/obsoletion-warnings/{0}.
+ public string? UrlFormat { get; set; }
+ }
+}
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index 5362c12fcb659..8573cdb9bb021 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -8281,6 +8281,13 @@ public sealed partial class ExcludeFromCodeCoverageAttribute : System.Attribute
public ExcludeFromCodeCoverageAttribute() { }
public string? Justification { get { throw null; } set { } }
}
+ [System.AttributeUsage(System.AttributeTargets.Assembly | System.AttributeTargets.Module | System.AttributeTargets.Class | System.AttributeTargets.Struct | System.AttributeTargets.Enum | System.AttributeTargets.Constructor | System.AttributeTargets.Method | System.AttributeTargets.Property | System.AttributeTargets.Field | System.AttributeTargets.Event | System.AttributeTargets.Interface | System.AttributeTargets.Delegate, Inherited = false)]
+ public sealed class ExperimentalAttribute : System.Attribute
+ {
+ public ExperimentalAttribute(string diagnosticId) { }
+ public string DiagnosticId { get { throw null; } }
+ public string? UrlFormat { get; set; }
+ }
[System.AttributeUsageAttribute(System.AttributeTargets.Field | System.AttributeTargets.Parameter | System.AttributeTargets.Property | System.AttributeTargets.ReturnValue, Inherited=false)]
public sealed partial class MaybeNullAttribute : System.Attribute
{
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj
index b4e389485006a..359d3158aeea4 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj
@@ -68,6 +68,7 @@
+
diff --git a/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/ExperimentalAttributeTests.cs b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/ExperimentalAttributeTests.cs
new file mode 100644
index 0000000000000..91beaf2991fca
--- /dev/null
+++ b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/ExperimentalAttributeTests.cs
@@ -0,0 +1,40 @@
+// 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 ExperimentalAttributeTests
+ {
+ [Theory]
+ // Note: Once the compiler support is implemented these should fail
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("\t")]
+ // Note end
+ [InlineData("diagnosticId")]
+ public void TestConstructor(string expected)
+ {
+ var attr = new ExperimentalAttribute(expected);
+
+ Assert.Equal(expected, attr.DiagnosticId);
+ Assert.Null(attr.UrlFormat);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("https://contoso.com/obsoletion-warnings/{0}")]
+ public void TestSetUrlFormat(string urlFormat)
+ {
+ var attr = new ExperimentalAttribute("diagnosticId")
+ {
+ UrlFormat = urlFormat
+ };
+
+ Assert.Equal("diagnosticId", attr.DiagnosticId);
+ Assert.Equal(urlFormat, attr.UrlFormat);
+ }
+ }
+}